feat: 统一文件上传接口 + 模板图片展示 + 导航页 + 侧边栏调整

This commit is contained in:
admin
2026-07-10 20:43:02 +08:00
parent cbd0430452
commit ce6823e282
25 changed files with 933 additions and 166 deletions

View File

@@ -630,6 +630,27 @@ function esc(s) {
});
}
/* ---- 工具:判断 icon 字段是否为图片 URL ---- */
function isIconURL(icon) {
if (!icon) return false;
var v = String(icon).trim();
return v.indexOf('/uploads/') === 0 || v.indexOf('http://') === 0 || v.indexOf('https://') === 0;
}
/* ---- 工具:生成应用图标 HTML(有 URL 用真实图片,否则渐变占位) ---- */
function appIconHTML(app, cls) {
var grad = gradFromName(app.name);
var clsAttr = 'app-icon' + (cls ? ' ' + cls : '');
var iconURL = isIconURL(app.icon) ? String(app.icon).trim() : '';
if (iconURL) {
return '<div class="' + clsAttr + '" style="background:' + grad + ';">'
+ '<img src="' + esc(iconURL) + '" alt="' + esc(app.name) + '" style="position:absolute;inset:0;width:100%;height:100%;object-fit:cover" onerror="this.style.display=\'none\';this.nextElementSibling.style.display=\'block\'">'
+ '<span style="display:none">' + esc(initials(app.name)) + '</span>'
+ '</div>';
}
return '<div class="' + clsAttr + '" style="background:' + grad + ';">' + esc(initials(app.name)) + '</div>';
}
/* ---- 工具:debounce ---- */
function debounce(fn, wait) {
var t;
@@ -887,7 +908,7 @@ function renderNew(list) {
html += '<div class="new-card fade-in" onclick="openApp(' + app.id + ')">'
+ '<span class="new-badge">NEW</span>'
+ '<div class="nc-head">'
+ '<div class="app-icon sm" style="background:' + grad + ';">' + esc(initials(app.name)) + '</div>'
+ appIconHTML(app, 'sm')
+ '<div><div class="nc-name">' + esc(app.name) + '</div><div class="nc-dev">' + esc(app.developer) + '</div></div>'
+ '</div>'
+ '<p class="nc-desc">' + esc(app.description) + '</p>'
@@ -916,7 +937,7 @@ function renderAppGrid(list) {
var grad = gradFromName(app.name);
html += '<div class="app-card fade-in" onclick="openApp(' + app.id + ')">'
+ '<div class="ac-head">'
+ '<div class="app-icon" style="background:' + grad + ';">' + esc(initials(app.name)) + '</div>'
+ appIconHTML(app, '')
+ '<div class="ac-info"><div class="ac-name">' + esc(app.name) + '</div><div class="ac-cat">' + esc(app.category_name) + '</div></div>'
+ '</div>'
+ '<p class="ac-desc">' + esc(app.description) + '</p>'
@@ -1082,7 +1103,7 @@ function renderModal(app) {
body.innerHTML =
'<div class="modal-hero">'
+ '<div class="app-icon lg" style="background:' + grad + ';">' + esc(initials(app.name)) + '</div>'
+ appIconHTML(app, 'lg')
+ '<div class="mh-info">'
+ '<h2>' + esc(app.name) + '</h2>'
+ '<div class="mh-dev">' + esc(app.developer) + '</div>'