fix(popadmin): 音乐分类可编辑与勾选绑定
分类列表提供编辑面板(名称/排序/启用),单曲分类改为勾选保存,走既有 PATCH/PUT API。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
0ac9b8330f
commit
1498c0258f
@ -2539,6 +2539,17 @@ const pages = {
|
|||||||
<input id="catSort" type="number" placeholder="排序" value="0" style="width:80px;padding:8px;border-radius:8px;border:1px solid var(--border);background:#0b1220;color:var(--text)">
|
<input id="catSort" type="number" placeholder="排序" value="0" style="width:80px;padding:8px;border-radius:8px;border:1px solid var(--border);background:#0b1220;color:var(--text)">
|
||||||
<button type="button" id="catCreate">新建分类</button>
|
<button type="button" id="catCreate">新建分类</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="musicCatEditPanel" class="hidden" style="margin-bottom:10px;padding:12px;border:1px solid var(--border);border-radius:8px;background:#0b1220">
|
||||||
|
<div class="toolbar" style="flex-wrap:wrap;gap:8px;align-items:center;margin-bottom:0">
|
||||||
|
<span class="muted">编辑分类 #<span id="catEditIdLabel"></span></span>
|
||||||
|
<input type="hidden" id="catEditId">
|
||||||
|
<input id="catEditName" placeholder="名称" style="padding:8px;border-radius:8px;border:1px solid var(--border);background:#111827;color:var(--text);min-width:140px">
|
||||||
|
<input id="catEditSort" type="number" placeholder="排序" style="width:80px;padding:8px;border-radius:8px;border:1px solid var(--border);background:#111827;color:var(--text)">
|
||||||
|
<label style="display:flex;align-items:center;gap:6px"><input type="checkbox" id="catEditEnabled">启用</label>
|
||||||
|
<button type="button" id="catEditSave">保存</button>
|
||||||
|
<button type="button" class="secondary" id="catEditCancel">取消</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<table>
|
<table>
|
||||||
<thead><tr><th>ID</th><th>名称</th><th>层级</th><th>父级</th><th>排序</th><th>启用</th><th>操作</th></tr></thead>
|
<thead><tr><th>ID</th><th>名称</th><th>层级</th><th>父级</th><th>排序</th><th>启用</th><th>操作</th></tr></thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@ -2554,7 +2565,7 @@ const pages = {
|
|||||||
<td>${esc(c.sortOrder)}</td>
|
<td>${esc(c.sortOrder)}</td>
|
||||||
<td>${c.enabled ? '是' : '否'}</td>
|
<td>${c.enabled ? '是' : '否'}</td>
|
||||||
<td style="white-space:nowrap">
|
<td style="white-space:nowrap">
|
||||||
<button type="button" class="secondary btn-sm" data-catedit="${esc(c.id)}">改</button>
|
<button type="button" class="secondary btn-sm" data-catedit="${esc(c.id)}">编辑</button>
|
||||||
<button type="button" class="secondary btn-sm" data-catdel="${esc(c.id)}">删</button>
|
<button type="button" class="secondary btn-sm" data-catdel="${esc(c.id)}">删</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>`
|
</tr>`
|
||||||
@ -2565,6 +2576,16 @@ const pages = {
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="musicTrackCatPanel" class="hidden section-block note" style="border:1px solid var(--border);padding:14px 16px;border-radius:10px;margin-bottom:12px">
|
||||||
|
<h3 style="margin:0 0 8px">曲目分类绑定 · #<span id="trackCatIdLabel"></span> <span id="trackCatTitle" class="muted"></span></h3>
|
||||||
|
<input type="hidden" id="trackCatTrackId">
|
||||||
|
<div id="trackCatChecks" style="display:flex;flex-direction:column;gap:6px;max-height:240px;overflow:auto;margin-bottom:10px"></div>
|
||||||
|
<div class="toolbar" style="gap:8px">
|
||||||
|
<button type="button" id="trackCatSave">保存分类</button>
|
||||||
|
<button type="button" class="secondary" id="trackCatCancel">取消</button>
|
||||||
|
<span class="muted">可多选;清空勾选并保存=清除绑定</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="toolbar" style="flex-wrap:wrap;gap:8px;margin-bottom:12px">
|
<div class="toolbar" style="flex-wrap:wrap;gap:8px;margin-bottom:12px">
|
||||||
<input id="musicTitle" placeholder="曲名" style="padding:8px;border-radius:8px;border:1px solid var(--border);background:#0b1220;color:var(--text);min-width:180px">
|
<input id="musicTitle" placeholder="曲名" style="padding:8px;border-radius:8px;border:1px solid var(--border);background:#0b1220;color:var(--text);min-width:180px">
|
||||||
<label style="display:flex;align-items:center;gap:6px"><input type="checkbox" id="musicMember">需要会员</label>
|
<label style="display:flex;align-items:center;gap:6px"><input type="checkbox" id="musicMember">需要会员</label>
|
||||||
@ -2649,24 +2670,44 @@ const pages = {
|
|||||||
await api('/spark/music/categories', { method: 'POST', body: JSON.stringify(body) });
|
await api('/spark/music/categories', { method: 'POST', body: JSON.stringify(body) });
|
||||||
pages.music();
|
pages.music();
|
||||||
};
|
};
|
||||||
$('content').querySelectorAll('[data-catedit]').forEach((btn) => {
|
const hideCatEdit = () => {
|
||||||
btn.onclick = async () => {
|
const panel = $('musicCatEditPanel');
|
||||||
const id = btn.dataset.catedit;
|
if (panel) panel.classList.add('hidden');
|
||||||
const row = flatCats.find((x) => String(x.id) === String(id));
|
};
|
||||||
const name = prompt('分类名称', row?.name || '');
|
$('catEditCancel').onclick = hideCatEdit;
|
||||||
if (name == null) return;
|
$('catEditSave').onclick = async () => {
|
||||||
const sortRaw = prompt('排序(数字,越小越前)', String(row?.sortOrder ?? 0));
|
const id = $('catEditId').value;
|
||||||
if (sortRaw == null) return;
|
if (!id) return;
|
||||||
const enabled = confirm('是否启用?(确定=是,取消=否)');
|
const name = ($('catEditName').value || '').trim();
|
||||||
|
if (!name) return alert('分类名称不能为空');
|
||||||
|
const sortOrder = parseInt($('catEditSort').value, 10);
|
||||||
|
try {
|
||||||
await api('/spark/music/categories/' + id, {
|
await api('/spark/music/categories/' + id, {
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
name: name.trim(),
|
name,
|
||||||
sortOrder: parseInt(sortRaw, 10) || 0,
|
sortOrder: Number.isFinite(sortOrder) ? sortOrder : 0,
|
||||||
enabled,
|
enabled: !!$('catEditEnabled').checked,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
alert('分类已保存');
|
||||||
pages.music();
|
pages.music();
|
||||||
|
} catch (e) {
|
||||||
|
alert('分类保存失败:' + e.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
$('content').querySelectorAll('[data-catedit]').forEach((btn) => {
|
||||||
|
btn.onclick = () => {
|
||||||
|
const id = btn.dataset.catedit;
|
||||||
|
const row = flatCats.find((x) => String(x.id) === String(id));
|
||||||
|
if (!row) return alert('分类不存在');
|
||||||
|
$('catEditId').value = id;
|
||||||
|
$('catEditIdLabel').textContent = id;
|
||||||
|
$('catEditName').value = row.name || '';
|
||||||
|
$('catEditSort').value = String(row.sortOrder ?? 0);
|
||||||
|
$('catEditEnabled').checked = !!row.enabled;
|
||||||
|
$('musicCatEditPanel').classList.remove('hidden');
|
||||||
|
$('catEditName').focus();
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
$('content').querySelectorAll('[data-catdel]').forEach((btn) => {
|
$('content').querySelectorAll('[data-catdel]').forEach((btn) => {
|
||||||
@ -2727,32 +2768,52 @@ const pages = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
$('content').querySelectorAll('[data-mcats]').forEach((btn) => {
|
const hideTrackCat = () => {
|
||||||
btn.onclick = async () => {
|
const panel = $('musicTrackCatPanel');
|
||||||
const id = btn.dataset.mcats;
|
if (panel) panel.classList.add('hidden');
|
||||||
const row = items.find((x) => String(x.id) === String(id));
|
};
|
||||||
const selected = new Set((row?.categoryIds || []).map(String));
|
$('trackCatCancel').onclick = hideTrackCat;
|
||||||
const lines = flatCats.map((c) => {
|
$('trackCatSave').onclick = async () => {
|
||||||
const mark = selected.has(String(c.id)) ? '[x]' : '[ ]';
|
const id = $('trackCatTrackId').value;
|
||||||
const pad = c.depth ? ' ' : '';
|
if (!id) return;
|
||||||
return `${mark} ${pad}${c.id} ${c.name}`;
|
const categoryIds = Array.from($('trackCatChecks').querySelectorAll('input[type=checkbox]:checked'))
|
||||||
});
|
.map((el) => parseInt(el.value, 10))
|
||||||
const tip =
|
.filter((n) => Number.isFinite(n) && n > 0);
|
||||||
'勾选归属分类(多对多)。输入要归属的分类 ID,逗号分隔;留空=清除。\n\n' +
|
try {
|
||||||
lines.join('\n') +
|
|
||||||
'\n\n当前:' +
|
|
||||||
(row?.categoryIds || []).join(',');
|
|
||||||
const raw = prompt(tip, (row?.categoryIds || []).join(','));
|
|
||||||
if (raw == null) return;
|
|
||||||
const categoryIds = raw
|
|
||||||
.split(/[,,\s]+/)
|
|
||||||
.map((s) => parseInt(s.trim(), 10))
|
|
||||||
.filter((n) => Number.isFinite(n) && n > 0);
|
|
||||||
await api('/spark/music/' + id + '/categories', {
|
await api('/spark/music/' + id + '/categories', {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
body: JSON.stringify({ categoryIds }),
|
body: JSON.stringify({ categoryIds }),
|
||||||
});
|
});
|
||||||
|
alert('分类绑定已保存');
|
||||||
pages.music();
|
pages.music();
|
||||||
|
} catch (e) {
|
||||||
|
alert('分类绑定失败:' + e.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
$('content').querySelectorAll('[data-mcats]').forEach((btn) => {
|
||||||
|
btn.onclick = () => {
|
||||||
|
const id = btn.dataset.mcats;
|
||||||
|
const row = items.find((x) => String(x.id) === String(id));
|
||||||
|
if (!row) return;
|
||||||
|
const selected = new Set((row.categoryIds || []).map(String));
|
||||||
|
$('trackCatTrackId').value = id;
|
||||||
|
$('trackCatIdLabel').textContent = id;
|
||||||
|
$('trackCatTitle').textContent = row.title ? '· ' + row.title : '';
|
||||||
|
$('trackCatChecks').innerHTML = flatCats.length
|
||||||
|
? flatCats
|
||||||
|
.map((c) => {
|
||||||
|
const pad = c.depth ? 'padding-left:18px;' : '';
|
||||||
|
const checked = selected.has(String(c.id)) ? 'checked' : '';
|
||||||
|
const tier = c.depth === 0 ? '总分类' : '子分类';
|
||||||
|
return `<label style="display:flex;align-items:center;gap:8px;${pad}">
|
||||||
|
<input type="checkbox" value="${esc(c.id)}" ${checked}>
|
||||||
|
<span>${esc(c.name)} <span class="muted">(#${esc(c.id)} · ${tier})</span></span>
|
||||||
|
</label>`;
|
||||||
|
})
|
||||||
|
.join('')
|
||||||
|
: '<div class="muted">暂无分类,请先在上方新建</div>';
|
||||||
|
$('musicTrackCatPanel').classList.remove('hidden');
|
||||||
|
$('musicTrackCatPanel').scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
$('content').querySelectorAll('[data-mdel]').forEach((btn) => {
|
$('content').querySelectorAll('[data-mdel]').forEach((btn) => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user