feat: 分类系统 + 标签系统 — Phase 4 完成
分类:Model/Repo/Service/Controller + 管理后台树形页面 + 首页导航栏
标签:Model/Repo/Service/Controller + /tags/{slug} 落地页 + 写文章页输入
Post 加 CategoryID,Create/Update 支持分类和标签
SQL 迁移含 categories/tags/post_tags 表及预设未分类
This commit is contained in:
118
templates/admin/static/js/categories.js
Normal file
118
templates/admin/static/js/categories.js
Normal file
@ -0,0 +1,118 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var modalOverlay = document.getElementById('modalOverlay');
|
||||
var modalTitle = document.getElementById('modalTitle');
|
||||
var modalClose = document.getElementById('modalClose');
|
||||
var modalCancel = document.getElementById('modalCancel');
|
||||
var modalSave = document.getElementById('modalSave');
|
||||
var catId = document.getElementById('catId');
|
||||
var catParentId = document.getElementById('catParentId');
|
||||
var catName = document.getElementById('catName');
|
||||
var catSlug = document.getElementById('catSlug');
|
||||
var catDesc = document.getElementById('catDesc');
|
||||
var catSort = document.getElementById('catSort');
|
||||
var toast = document.getElementById('toast');
|
||||
|
||||
function showToast(msg, isError) {
|
||||
toast.textContent = msg;
|
||||
toast.className = 'toast' + (isError ? ' toast-error' : ' toast-success');
|
||||
toast.style.display = 'block';
|
||||
setTimeout(function () { toast.style.display = 'none'; }, 2500);
|
||||
}
|
||||
|
||||
function closeModal() { modalOverlay.classList.remove('active'); }
|
||||
modalClose.addEventListener('click', closeModal);
|
||||
modalCancel.addEventListener('click', closeModal);
|
||||
modalOverlay.addEventListener('click', function (e) { if (e.target === modalOverlay) closeModal(); });
|
||||
|
||||
function openModal(data) {
|
||||
if (data) {
|
||||
modalTitle.textContent = '编辑分类';
|
||||
catId.value = data.id || '';
|
||||
catParentId.value = data.parentId || '';
|
||||
catName.value = data.name || '';
|
||||
catSlug.value = data.slug || '';
|
||||
catDesc.value = data.desc || '';
|
||||
catSort.value = data.sort || 0;
|
||||
} else {
|
||||
modalTitle.textContent = '新建分类';
|
||||
catId.value = '';
|
||||
// Keep parentId for child categories
|
||||
catName.value = '';
|
||||
catSlug.value = '';
|
||||
catDesc.value = '';
|
||||
catSort.value = 0;
|
||||
}
|
||||
modalOverlay.classList.add('active');
|
||||
}
|
||||
|
||||
document.getElementById('btnNewCategory').addEventListener('click', function () {
|
||||
catParentId.value = '';
|
||||
openModal(null);
|
||||
});
|
||||
|
||||
document.addEventListener('click', function (e) {
|
||||
if (e.target.classList.contains('cat-btn-add-child')) {
|
||||
e.preventDefault();
|
||||
catParentId.value = e.target.getAttribute('data-parent-id');
|
||||
openModal(null);
|
||||
}
|
||||
if (e.target.classList.contains('cat-btn-edit')) {
|
||||
e.preventDefault();
|
||||
openModal({
|
||||
id: e.target.getAttribute('data-id'),
|
||||
parentId: e.target.getAttribute('data-parent-id') || '',
|
||||
name: e.target.getAttribute('data-name'),
|
||||
slug: e.target.getAttribute('data-slug'),
|
||||
desc: e.target.getAttribute('data-desc'),
|
||||
sort: e.target.getAttribute('data-sort'),
|
||||
});
|
||||
}
|
||||
if (e.target.classList.contains('cat-btn-delete')) {
|
||||
e.preventDefault();
|
||||
var id = e.target.getAttribute('data-id');
|
||||
if (!confirm('确定删除此分类?')) return;
|
||||
fetch('/api/admin/categories/' + id, { method: 'DELETE' })
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (resp) {
|
||||
showToast(resp.message || '已删除', !resp.success);
|
||||
if (resp.success) window.location.reload();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
modalSave.addEventListener('click', function () {
|
||||
var data = {
|
||||
name: catName.value.trim(),
|
||||
slug: catSlug.value.trim() || slugify(catName.value.trim()),
|
||||
description: catDesc.value.trim(),
|
||||
sort: parseInt(catSort.value) || 0,
|
||||
};
|
||||
var pid = catParentId.value;
|
||||
if (pid) data.parent_id = parseInt(pid);
|
||||
|
||||
if (!data.name) { showToast('请输入名称', true); return; }
|
||||
|
||||
var url = '/api/admin/categories';
|
||||
var method = 'POST';
|
||||
var id = catId.value;
|
||||
if (id) { url += '/' + id; method = 'PUT'; }
|
||||
|
||||
fetch(url, {
|
||||
method: method,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (resp) {
|
||||
showToast(resp.message || '保存成功', !resp.success);
|
||||
if (resp.success) window.location.reload();
|
||||
})
|
||||
.catch(function () { showToast('网络异常', true); });
|
||||
});
|
||||
|
||||
function slugify(s) {
|
||||
return s.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9\-]/g, '');
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user