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/article/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/article/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/article/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/upload/image',
 | 
						||
                    accept: 'images',
 | 
						||
                    acceptMime: 'image/*',
 | 
						||
                    done: function (res) {
 | 
						||
                        if (res.code === 0) {
 | 
						||
                            $('#uploadPreview').removeClass('layui-hide').find('img').attr('src', res.data.url);
 | 
						||
                            $('#imageInput').val(res.data.url);
 | 
						||
                            layer.msg('上传成功');
 | 
						||
                        } else {
 | 
						||
                            layer.msg('上传失败');
 | 
						||
                        }
 | 
						||
                    }
 | 
						||
                });
 | 
						||
 | 
						||
                // 监听表单提交
 | 
						||
                form.on('submit(saveCategory)', function (data) {
 | 
						||
                    var url = data.field.id ? '/admin/article/cateedit' : '/admin/article/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/article/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> |