525 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			525 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| {include file="public/header" /}
 | ||
| <div class="config-container">
 | ||
|     <!-- 页面头部样式 -->
 | ||
|     <div class="config-header" style="display: flex;flex-direction: column;flex-wrap: wrap;align-items: flex-start;">
 | ||
|         <div class="maintitle">
 | ||
|             <i class="layui-icon layui-icon-app"></i>
 | ||
|             <span>文章分类管理</span>
 | ||
|         </div>
 | ||
|         <div style="display: flex;align-items: flex-start;flex-direction: column;gap: 15px;margin-bottom: 10px;">
 | ||
|             <div>
 | ||
|                 <button type="button" class="layui-btn layui-btn-normal" onclick="add()">
 | ||
|                     <i class="layui-icon layui-icon-add-1"></i>添加分类
 | ||
|                 </button>
 | ||
|                 <button type="button" class="layui-btn layui-btn-primary layui-border-blue" onclick="refresh()">
 | ||
|                     <i class="layui-icon layui-icon-refresh"></i>刷新
 | ||
|                 </button>
 | ||
|             </div>
 | ||
|         </div>
 | ||
|     </div>
 | ||
| 
 | ||
|     <!-- 主要内容区 -->
 | ||
|     <div class="main-content">
 | ||
|         <div class="layui-row layui-col-space20">
 | ||
|             <!-- 左侧分类列表 -->
 | ||
|             <div class="layui-col-md7">
 | ||
|                 <div class="layui-card">
 | ||
|                     <div class="layui-card-header">
 | ||
|                         <span>分类列表</span>
 | ||
|                         <small class="text-muted">支持两级分类结构</small>
 | ||
|                     </div>
 | ||
|                     <div class="layui-card-body">
 | ||
|                         <div id="categoryList" class="category-tree"></div>
 | ||
|                     </div>
 | ||
|                 </div>
 | ||
|             </div>
 | ||
| 
 | ||
|             <!-- 右侧分类信息 -->
 | ||
|             <div class="layui-col-md5">
 | ||
|                 <div class="layui-card">
 | ||
|                     <div class="layui-card-header">
 | ||
|                         <span>分类信息</span>
 | ||
|                     </div>
 | ||
|                     <div class="layui-card-body">
 | ||
|                         <!-- 默认提示 -->
 | ||
|                         <div id="defaultTip" class="empty-tip">
 | ||
|                             <i class="layui-icon layui-icon-face-surprised"></i>
 | ||
|                             <p>请选择左侧分类或点击新增按钮</p>
 | ||
|                         </div>
 | ||
| 
 | ||
|                         <!-- 分类表单 -->
 | ||
|                         <form class="layui-form category-form" lay-filter="categoryForm" style="display: none;">
 | ||
|                             <input type="hidden" name="id" id="categoryId">
 | ||
| 
 | ||
|                             <div class="layui-form-item">
 | ||
|                                 <label class="layui-form-label">分类名称</label>
 | ||
|                                 <div class="layui-input-block">
 | ||
|                                     <input type="text" name="name" required lay-verify="required" placeholder="请输入分类名称"
 | ||
|                                         autocomplete="off" class="layui-input">
 | ||
|                                 </div>
 | ||
|                             </div>
 | ||
| 
 | ||
|                             <div class="layui-form-item">
 | ||
|                                 <label class="layui-form-label">父级分类</label>
 | ||
|                                 <div class="layui-input-block">
 | ||
|                                     <select name="cid" lay-verify="required">
 | ||
|                                         <option value="0">顶级分类</option>
 | ||
|                                     </select>
 | ||
|                                 </div>
 | ||
|                             </div>
 | ||
| 
 | ||
|                             <div class="layui-form-item">
 | ||
|                                 <label class="layui-form-label">封面图片</label>
 | ||
|                                 <div class="layui-input-block">
 | ||
|                                     <div class="layui-upload-drag" id="uploadImage">
 | ||
|                                         <i class="layui-icon layui-icon-upload"></i>
 | ||
|                                         <p>点击上传或拖拽图片至此处</p>
 | ||
|                                         <div class="layui-hide" id="uploadPreview">
 | ||
|                                             <hr>
 | ||
|                                             <img src="" alt="封面图片" style="max-width: 100%">
 | ||
|                                         </div>
 | ||
|                                     </div>
 | ||
|                                     <input type="hidden" name="image" id="imageInput">
 | ||
|                                     <div class="layui-form-mid layui-word-aux">建议尺寸:250px * 140px</div>
 | ||
|                                 </div>
 | ||
|                             </div>
 | ||
| 
 | ||
|                             <div class="layui-form-item">
 | ||
|                                 <label class="layui-form-label">排序</label>
 | ||
|                                 <div class="layui-input-block">
 | ||
|                                     <input type="number" name="sort" value="0" class="layui-input"
 | ||
|                                         placeholder="数字越大越靠前">
 | ||
|                                 </div>
 | ||
|                             </div>
 | ||
| 
 | ||
|                             <div class="layui-form-item">
 | ||
|                                 <label class="layui-form-label">状态</label>
 | ||
|                                 <div class="layui-input-block">
 | ||
|                                     <input type="radio" name="status" value="1" title="正常" checked>
 | ||
|                                     <input type="radio" name="status" value="0" title="禁用">
 | ||
|                                 </div>
 | ||
|                             </div>
 | ||
| 
 | ||
|                             <div class="layui-form-item form-actions">
 | ||
|                                 <div class="layui-input-block">
 | ||
|                                     <button class="layui-btn" lay-submit lay-filter="saveCategory">保存</button>
 | ||
|                                     <button type="reset" class="layui-btn layui-btn-primary">重置</button>
 | ||
|                                     <button type="button" class="layui-btn layui-btn-danger" id="deleteBtn"
 | ||
|                                         style="display: none;">删除</button>
 | ||
|                                 </div>
 | ||
|                             </div>
 | ||
|                         </form>
 | ||
|                     </div>
 | ||
|                 </div>
 | ||
|             </div>
 | ||
|         </div>
 | ||
|     </div>
 | ||
| </div>
 | ||
| 
 | ||
| <style>
 | ||
|     /* 页面整体样式 */
 | ||
|     .config-container {
 | ||
|         padding: 15px;
 | ||
|         /* background: #f2f2f2; */
 | ||
|     }
 | ||
| 
 | ||
|     .layui-col-md7 .layui-btn-primary {
 | ||
|         border-color: #d2d2d2;
 | ||
|         background: 0 0;
 | ||
|         color: #5f5f5f
 | ||
|     }
 | ||
| 
 | ||
|     .layui-col-md7 .layui-btn-primary:hover {
 | ||
|         background-color: #1e9fff;
 | ||
|         color: #efefef
 | ||
|     }
 | ||
| 
 | ||
|     /* 页面头部样式 */
 | ||
|     .page-header {
 | ||
|         display: flex;
 | ||
|         justify-content: space-between;
 | ||
|         align-items: center;
 | ||
|         margin-bottom: 15px;
 | ||
|         padding: 10px 15px;
 | ||
|         background: #fff;
 | ||
|         border-radius: 2px;
 | ||
|         box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
 | ||
|     }
 | ||
| 
 | ||
|     .header-title {
 | ||
|         display: flex;
 | ||
|         align-items: center;
 | ||
|         font-size: 16px;
 | ||
|         font-weight: 500;
 | ||
|     }
 | ||
| 
 | ||
|     .header-title .layui-icon {
 | ||
|         margin-right: 8px;
 | ||
|         font-size: 18px;
 | ||
|     }
 | ||
| 
 | ||
|     .header-actions .layui-btn {
 | ||
|         margin-left: 8px;
 | ||
|     }
 | ||
| 
 | ||
|     /* 主要内容区样式 */
 | ||
|     .main-content {
 | ||
|         min-height: calc(100vh - 170px);
 | ||
|     }
 | ||
| 
 | ||
|     .layui-card {
 | ||
|         margin-bottom: 0;
 | ||
|         border-radius: 8px;
 | ||
|         box-shadow: 0 3px 6px rgba(0, 0, 0, 0.1);
 | ||
|     }
 | ||
| 
 | ||
|     .layui-card-header {
 | ||
|         display: flex;
 | ||
|         align-items: center;
 | ||
|         height: auto;
 | ||
|         padding: 12px 15px;
 | ||
|         font-size: 15px;
 | ||
|         font-weight: 500;
 | ||
|     }
 | ||
| 
 | ||
|     .text-muted {
 | ||
|         margin-left: 10px;
 | ||
|         font-size: 12px;
 | ||
|         font-weight: normal;
 | ||
|         color: #999;
 | ||
|     }
 | ||
| 
 | ||
|     /* 分类树样式 */
 | ||
|     .category-tree {
 | ||
|         padding: 10px 0;
 | ||
|     }
 | ||
| 
 | ||
|     .category-item {
 | ||
|         margin: 5px 0;
 | ||
|     }
 | ||
| 
 | ||
|     .category-header {
 | ||
|         display: flex;
 | ||
|         align-items: center;
 | ||
|         justify-content: space-between;
 | ||
|         padding: 10px 15px;
 | ||
|         background-color: #f8f8f8;
 | ||
|         border-radius: 2px;
 | ||
|         transition: all 0.3s;
 | ||
|         cursor: pointer;
 | ||
|     }
 | ||
| 
 | ||
|     .category-header:hover {
 | ||
|         background-color: #f2f2f2;
 | ||
|     }
 | ||
| 
 | ||
|     .category-header.active {
 | ||
|         background-color: #e6f7ff;
 | ||
|         border-right: 3px solid #1890ff;
 | ||
|     }
 | ||
| 
 | ||
|     .category-name {
 | ||
|         flex: 1;
 | ||
|         font-size: 14px;
 | ||
|     }
 | ||
| 
 | ||
|     .category-actions {
 | ||
|         /* opacity: 0; */
 | ||
|         transition: opacity 0.3s;
 | ||
|     }
 | ||
| 
 | ||
|     .category-header:hover .category-actions {
 | ||
|         opacity: 1;
 | ||
|     }
 | ||
| 
 | ||
|     .category-children {
 | ||
|         margin-left: 20px;
 | ||
|         padding-left: 15px;
 | ||
|         border-left: 1px dashed #e6e6e6;
 | ||
|     }
 | ||
| 
 | ||
|     .add-child {
 | ||
|         padding: 3px 8px;
 | ||
|         font-size: 12px;
 | ||
|     }
 | ||
| 
 | ||
|     .add-child .layui-icon {
 | ||
|         font-size: 12px;
 | ||
|         margin-right: 3px;
 | ||
|     }
 | ||
| 
 | ||
|     /* 空状态提示 */
 | ||
|     .empty-tip {
 | ||
|         display: flex;
 | ||
|         flex-direction: column;
 | ||
|         align-items: center;
 | ||
|         justify-content: center;
 | ||
|         padding: 40px 0;
 | ||
|         color: #999;
 | ||
|     }
 | ||
| 
 | ||
|     .empty-tip .layui-icon {
 | ||
|         font-size: 32px;
 | ||
|         margin-bottom: 10px;
 | ||
|     }
 | ||
| 
 | ||
|     /* 表单样式优化 */
 | ||
|     .category-form {
 | ||
|         padding: 10px 0;
 | ||
|     }
 | ||
| 
 | ||
|     .layui-form-label {
 | ||
|         width: 100px;
 | ||
|     }
 | ||
| 
 | ||
|     .layui-input-block {
 | ||
|         margin-left: 130px;
 | ||
|     }
 | ||
| 
 | ||
|     .form-actions {
 | ||
|         margin-top: 30px;
 | ||
|     }
 | ||
| 
 | ||
|     .layui-upload-drag {
 | ||
|         padding: 20px;
 | ||
|         border: 1px dashed #e2e2e2;
 | ||
|         background-color: #fff;
 | ||
|         text-align: center;
 | ||
|         cursor: pointer;
 | ||
|     }
 | ||
| 
 | ||
|     .layui-upload-drag:hover {
 | ||
|         border-color: #009688;
 | ||
|     }
 | ||
| 
 | ||
|     .layui-upload-drag img {
 | ||
|         max-width: 100%;
 | ||
|         margin: 10px 0;
 | ||
|     }
 | ||
| 
 | ||
|     .layui-btn-xs {
 | ||
|         height: 30px;
 | ||
|         line-height: 25px;
 | ||
|         font-size: 12px;
 | ||
|     }
 | ||
| </style>
 | ||
| 
 | ||
| <script>
 | ||
|     // 定义全局变量和函数
 | ||
|     var categoryManager = {
 | ||
|         init: function () {
 | ||
|             this.initLayui();
 | ||
|         },
 | ||
| 
 | ||
|         initLayui: function () {
 | ||
|             var that = this;
 | ||
|             layui.use(['layer', 'form', 'upload'], function () {
 | ||
|                 var layer = layui.layer;
 | ||
|                 var form = layui.form;
 | ||
|                 var upload = layui.upload;
 | ||
|                 var $ = layui.jquery;
 | ||
| 
 | ||
|                 // 初始化分类列表
 | ||
|                 that.initCategoryList = function () {
 | ||
|                     $.ajax({
 | ||
|                         url: '/admin/articles/articlecate',
 | ||
|                         type: 'POST',
 | ||
|                         success: function (res) {
 | ||
|                             if (res.code === 0) {
 | ||
|                                 var html = '';
 | ||
|                                 res.data.forEach(function (item) {
 | ||
|                                     html += that.renderCategory(item);
 | ||
|                                 });
 | ||
|                                 $('#categoryList').html(html);
 | ||
|                                 that.bindEvents();
 | ||
|                             } else {
 | ||
|                                 layer.msg('获取分类数据失败', { icon: 2 });
 | ||
|                             }
 | ||
|                         }
 | ||
|                     });
 | ||
|                 };
 | ||
| 
 | ||
|                 // 渲染分类项
 | ||
|                 that.renderCategory = function (category, level = 0) {
 | ||
|                     var html = '<div class="category-item" data-id="' + category.id + '">';
 | ||
|                     html += '<div class="category-header">';
 | ||
|                     html += '<div class="category-name">' + category.title + '</div>';
 | ||
|                     if (level === 0) {
 | ||
|                         html += '<div class="category-actions">';
 | ||
|                         html += '<button type="button" class="layui-btn layui-btn-primary layui-btn-xs add-child">';
 | ||
|                         html += '<i class="layui-icon layui-icon-add-1"></i>添加子分类</button>';
 | ||
|                         html += '</div>';
 | ||
|                     }
 | ||
|                     html += '</div>';
 | ||
| 
 | ||
|                     if (category.children && category.children.length > 0) {
 | ||
|                         html += '<div class="category-children">';
 | ||
|                         category.children.forEach(function (child) {
 | ||
|                             html += that.renderCategory(child, level + 1);
 | ||
|                         });
 | ||
|                         html += '</div>';
 | ||
|                     }
 | ||
|                     html += '</div>';
 | ||
|                     return html;
 | ||
|                 };
 | ||
| 
 | ||
|                 // 绑定事件
 | ||
|                 that.bindEvents = function () {
 | ||
|                     // 点击分类项加载编辑信息
 | ||
|                     $('.category-header').off('click').on('click', function (e) {
 | ||
|                         if (!$(e.target).closest('.add-child').length) {
 | ||
|                             var id = $(this).closest('.category-item').data('id');
 | ||
|                             that.loadCategoryInfo(id);
 | ||
| 
 | ||
|                             // 添加选中效果
 | ||
|                             $('.category-header').removeClass('active');
 | ||
|                             $(this).addClass('active');
 | ||
|                         }
 | ||
|                     });
 | ||
| 
 | ||
|                     // 添加子分类
 | ||
|                     $('.add-child').off('click').on('click', function (e) {
 | ||
|                         e.stopPropagation();
 | ||
|                         var parentId = $(this).closest('.category-item').data('id');
 | ||
|                         that.showCategoryForm(parentId);
 | ||
|                     });
 | ||
|                 };
 | ||
| 
 | ||
|                 // 加载分类信息
 | ||
|                 that.loadCategoryInfo = function (id) {
 | ||
|                     $.get('/admin/articles/cateedit?id=' + id, function (res) {
 | ||
|                         if (res.code === 0) {
 | ||
|                             that.showCategoryForm(0, res.data);
 | ||
|                         }
 | ||
|                     });
 | ||
|                 };
 | ||
| 
 | ||
|                 // 显示分类表单
 | ||
|                 that.showCategoryForm = function (parentId = 0, data = null) {
 | ||
|                     $('#defaultTip').hide();
 | ||
|                     $('.category-form').show();
 | ||
| 
 | ||
|                     // 重置表单
 | ||
|                     form.val('categoryForm', {
 | ||
|                         id: data ? data.info.id : '',
 | ||
|                         name: data ? data.info.name : '',
 | ||
|                         cid: data ? data.info.cid : parentId,
 | ||
|                         sort: data ? data.info.sort : 0,
 | ||
|                         status: data ? data.info.status : 1
 | ||
|                     });
 | ||
| 
 | ||
|                     // 更新父级分类选项
 | ||
|                     var $select = $('select[name="cid"]');
 | ||
|                     $select.empty().append('<option value="0">顶级分类</option>');
 | ||
|                     // 获取所有分类作为父级选项
 | ||
|                     $.ajax({
 | ||
|                         url: '/admin/articles/articlecate',
 | ||
|                         type: 'POST',
 | ||
|                         async: false,
 | ||
|                         success: function (res) {
 | ||
|                             if (res.code === 0) {
 | ||
|                                 // 当前编辑的分类ID
 | ||
|                                 var currentId = data ? data.info.id : 0;
 | ||
|                                 // 递归构建分类选项
 | ||
|                                 function buildOptions(categories, level) {
 | ||
|                                     categories.forEach(function (category) {
 | ||
|                                         // 不能选择自己或自己的子分类作为父级
 | ||
|                                         if (category.id != currentId) {
 | ||
|                                             var prefix = new Array(level + 1).join('├─ ');
 | ||
|                                             $select.append('<option value="' + category.id + '">' + prefix + category.title + '</option>'); if (category.children && category.children.length > 0) { buildOptions(category.children, level + 1); }
 | ||
|                                         }
 | ||
|                                     });
 | ||
|                                 } buildOptions(res.data, 0);
 | ||
|                             }
 | ||
|                         }
 | ||
|                     });
 | ||
|                     // 设置选中的父级分类
 | ||
|                     if (data && data.info.cid) {
 | ||
|                         $select.val(data.info.cid);
 | ||
|                     }
 | ||
| 
 | ||
|                     // 更新图片预览
 | ||
|                     if (data && data.info.image) {
 | ||
|                         $('#uploadPreview').removeClass('layui-hide').find('img').attr('src', data.info.image);
 | ||
|                         $('#imageInput').val(data.info.image);
 | ||
|                     } else {
 | ||
|                         $('#uploadPreview').addClass('layui-hide').find('img').attr('src', '');
 | ||
|                         $('#imageInput').val('');
 | ||
|                     }
 | ||
| 
 | ||
|                     // 显示/隐藏删除按钮
 | ||
|                     $('#deleteBtn')[data ? 'show' : 'hide']();
 | ||
| 
 | ||
|                     form.render();
 | ||
|                 };
 | ||
| 
 | ||
|                 // 初始化上传组件
 | ||
|                 upload.render({
 | ||
|                     elem: '#uploadImage',
 | ||
|                     url: '/admin/index/upload_img',
 | ||
|                     accept: 'images',
 | ||
|                     acceptMime: 'image/*',
 | ||
|                     done: function (res) {
 | ||
|                         if (res.code === 0) {
 | ||
|                             $('#uploadPreview').removeClass('layui-hide').find('img').attr('src', typeof res.data === 'object' ? res.data.url : res.data);
 | ||
|                             $('#imageInput').val(typeof res.data === 'object' ? res.data : res.data);
 | ||
|                             layer.msg('上传成功');
 | ||
|                         } else {
 | ||
|                             layer.msg('上传失败');
 | ||
|                         }
 | ||
|                     }
 | ||
|                 });
 | ||
| 
 | ||
|                 // 监听表单提交
 | ||
|                 form.on('submit(saveCategory)', function (data) {
 | ||
|                     var url = data.field.id ? '/admin/articles/cateedit' : '/admin/articles/cateadd';
 | ||
|                     $.post(url, data.field, function (res) {
 | ||
|                         if (res.code === 0) {
 | ||
|                             layer.msg(res.msg, { icon: 1 });
 | ||
|                             that.initCategoryList();
 | ||
|                         } else {
 | ||
|                             layer.msg(res.msg, { icon: 2 });
 | ||
|                         }
 | ||
|                     });
 | ||
|                     return false;
 | ||
|                 });
 | ||
| 
 | ||
|                 // 监听删除按钮
 | ||
|                 $('#deleteBtn').on('click', function () {
 | ||
|                     var id = $('#categoryId').val();
 | ||
|                     if (!id) return;
 | ||
| 
 | ||
|                     layer.confirm('确定要删除该分类吗?', function (index) {
 | ||
|                         $.post('/admin/articles/catedel', { id: id }, function (res) {
 | ||
|                             if (res.code === 0) {
 | ||
|                                 layer.msg(res.msg, { icon: 1 });
 | ||
|                                 that.initCategoryList();
 | ||
|                                 $('#defaultTip').show();
 | ||
|                                 $('.category-form').hide();
 | ||
|                             } else {
 | ||
|                                 layer.msg(res.msg, { icon: 2 });
 | ||
|                             }
 | ||
|                         });
 | ||
|                         layer.close(index);
 | ||
|                     });
 | ||
|                 });
 | ||
| 
 | ||
|                 // 初始化页面
 | ||
|                 that.initCategoryList();
 | ||
|             });
 | ||
|         }
 | ||
|     };
 | ||
| 
 | ||
|     // 初始化
 | ||
|     categoryManager.init();
 | ||
| 
 | ||
|     // 新增分类
 | ||
|     function add() {
 | ||
|         categoryManager.showCategoryForm();
 | ||
|     }
 | ||
| 
 | ||
|     // 刷新列表
 | ||
|     function refresh() {
 | ||
|         categoryManager.initCategoryList();
 | ||
|     }
 | ||
| </script> |