<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>内容表单</title>
    <link rel="stylesheet" href="{{ asset('CmsProUi/component/pear/css/pear.css') }}">
    <link rel="stylesheet" href="{{ asset('CmsProUi/font-awesome/4.7.0/css/font-awesome.min.css') }}">
    <link rel="stylesheet" href="{{ asset('Admin/css/admin.css') }}">
    <link rel="stylesheet" href="{{ asset('Admin/css/variables.css') }}">
    <link rel="stylesheet" href="{{ asset('Admin/css/reset.css') }}">
    <style>
        .layui-form-label { padding: 9px 4px; width: auto; min-width: 70px; }
        .layui-input, .layui-textarea { width: 95%; }
        .image-upload-wrap { display: flex; align-items: center; gap: 10px; }
        .image-upload-wrap .preview-img { width: 60px; height: 60px; object-fit: cover; border: 1px solid #e6e6e6; border-radius: 4px; display: none; }
        .image-upload-wrap .preview-img.active { display: block; }
        .tox .tox-dialog { z-index: 10000 !important; }
        .tox .tox-dialog-wrap { z-index: 20000 !important; }
        .form-actions { margin-top: 20px; padding-top: 15px; border-top: 1px solid #e6e6e6; text-align: center; }
        .form-actions button { margin: 0 5px; }
    </style>
</head>
<body>
    <form class="layui-form" action="" style="padding: 10px;">
        <input type="hidden" id="id" name="id" value="">
        <input type="hidden" id="model_id" name="model_id" value="">

        <div class="layui-form-item" data-field-key="category_id" style="display:none;">
            <label class="layui-form-label">分类</label>
            <div class="layui-input-block">
                <select id="category_id" name="category_id" lay-verify="required" lay-reqText="请选择分类" lay-search="">
                    <option value="">请选择分类</option>
                </select>
            </div>
        </div>

        <!-- 公共字段占位区，由 field_config 动态排序填充 -->
        <div id="main-fields-area"></div>

        <!-- 扩展字段占位区 -->
        <div id="extension-fields"></div>

        <div class="form-actions">
            <button type="button" class="layui-btn layui-btn-primary layui-btn-sm" id="resetBtn">
                <i class="layui-icon layui-icon-refresh"></i> 清空
            </button>
            <button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit lay-filter="save">
                <i class="layui-icon layui-icon-ok"></i> 提交
            </button>
        </div>
    </form>

    <script src="{{ asset('CmsProUi/component/layui/layui.js') }}"></script>
    <script src="{{ asset('CmsProUi/component/pear/pear.js') }}"></script>
    <script>
        layui.use(['form', 'jquery', 'laydate', 'tinymce'], function() {
            var form = layui.form;
            var $ = layui.jquery;
            var laydate = layui.laydate;
            var tinymce = layui.tinymce;

            $.ajaxSetup({
                headers: {
                    'X-CSRF-TOKEN': '{{ csrf_token() }}'
                },
                statusCode: {
                    401: function() {
                        layer.msg('登录已过期，请重新登录', {icon: 2, time: 1500}, function() {
                            window.location.href = '/admin/login?redirect=' + encodeURIComponent(window.location.pathname + window.location.search);
                        });
                    }
                }
            });

            var editId = new URLSearchParams(window.location.search).get('id');
            var isEdit = !!editId;
            var contentData = null;
            var treeLoaded = false;
            var currentCategoryId = null;
            var editorInstance = null;
            var extensionData = {};
            var dynamicDateInstances = [];
            var dynamicEditorInstances = [];
            var loadedExtFields = [];
            var allExtFieldsMap = {};

            var urlParams = new URLSearchParams(window.location.search);
            var preCategoryId = urlParams.get('category_id');
            var preModelAlias = urlParams.get('model_alias');

            loadCategoryTree();
            loadFieldConfig();

            function loadCategoryTree() {
                $.ajax({
                    url: '/api/admin/content-categories/tree',
                    type: 'GET',
                    dataType: 'json',
                    success: function(res) {
                        if (res.code === 0 && res.data) {
                            var options = '';
                            function buildOptions(items, level) {
                                if (!items || !items.length) return;
                                items.forEach(function(item) {
                                    var prefix = '';
                                    for (var i = 0; i < level; i++) prefix += '├─ ';
                                    var hasModel = (item.model_alias || '') !== '';
                                    var disabledAttr = hasModel ? '' : ' disabled';
                                    options += '<option value="' + item.id + '" data-alias="' + (item.model_alias || '') + '"' + disabledAttr + '>' + prefix + item.name + '</option>';
                                    if (item.children && item.children.length) {
                                        buildOptions(item.children, level + 1);
                                    }
                                });
                            }
                            buildOptions(res.data, 0);
                            $('#category_id').html(options);
                            $('#category_id').off('change.categoryReload').on('change.categoryReload', function() {
                                var $opt = $(this).find('option:selected');
                                var alias = $opt.data('alias') || '';
                                var newCatId = $(this).val();
                                if (newCatId) {
                                    currentCategoryId = newCatId;
                                }
                                if (alias) {
                                    preModelAlias = alias;
                                    loadFieldConfig();
                                }
                            });
                            if (preCategoryId) {
                                $('#category_id').val(preCategoryId).trigger('change');
                            } else if (!isEdit) {
                                var $firstValid = $('#category_id option[data-alias]:not([value=""]):first');
                                if ($firstValid.length) {
                                    $firstValid.prop('selected', true);
                                    $firstValid.trigger('change');
                                }
                            }
                            treeLoaded = true;
                            if (!isEdit) {
                                form.render();
                            }
                        }
                    }
                });
            }

            function loadFieldConfig(explicitModelId) {
                var targetModelId = explicitModelId || new URLSearchParams(window.location.search).get('model_id');
                var targetModelAlias = preModelAlias || '';

                if (!targetModelId && !targetModelAlias) return;

                if (!targetModelId && targetModelAlias) {
                    $.ajax({
                        url: '/api/admin/content-models?alias=' + encodeURIComponent(targetModelAlias),
                        type: 'GET',
                        dataType: 'json',
                        async: false,
                        success: function(res) {
                            if (res.code === 0 && res.data && res.data.items && res.data.items.length > 0) {
                                targetModelId = res.data.items[0].id;
                            }
                        }
                    });
                }

                if (!targetModelId) return;

                $.ajax({
                    url: '/api/admin/content-models/' + targetModelId,
                    type: 'GET',
                    dataType: 'json',
                    success: function(modelRes) {
                        if (modelRes.code === 0 && modelRes.data) {
                            var model = modelRes.data;
                            $('#model_id').val(model.id);

                            loadAllExtensionFields(targetModelId, function() {
                                if (model.field_config && model.field_config.fields) {
                                    renderFormByFieldConfig(model.field_config.fields);
                                } else {
                                    renderDefaultMainFields();
                                }
                            });
                        }
                    }
                });
            }

            function loadAllExtensionFields(modelId, callback) {
                $.ajax({
                    url: '/api/admin/content-models/' + modelId + '/fields',
                    type: 'GET',
                    dataType: 'json',
                    success: function(res) {
                        allExtFieldsMap = {};
                        if (res.code === 0 && res.data && res.data.length > 0) {
                            for (var i = 0; i < res.data.length; i++) {
                                var f = res.data[i];
                                allExtFieldsMap[f.id] = f;
                            }
                        }
                        if (callback) callback();
                    },
                    error: function() {
                        allExtFieldsMap = {};
                        if (callback) callback();
                    }
                });
            }

            var defaultMainFields = [
                { key: 'title', label: '标题', required: true },
                { key: 'author', label: '作者', required: false },
                { key: 'source', label: '来源', required: false },
                { key: 'publish_at', label: '发布时间', required: false },
                { key: 'summary', label: '摘要', required: false },
                { key: 'image', label: '封面图', required: false },
                { key: 'content', label: '正文', required: false },
                { key: 'sort', label: '排序', required: false },
                { key: 'status', label: '状态', required: false }
            ];

            function getMainFieldHtml(key, label) {
                switch (key) {
                    case 'category_id':
                        return '';
                    case 'title':
                        return '<div class="layui-form-item" data-field-key="' + key + '">'
                            + '<label class="layui-form-label"><span style="color:#ff5722;">*</span> ' + label + '</label>'
                            + '<div class="layui-input-block"><input type="text" id="title" name="title" lay-verify="required" lay-reqText="标题不能为空" placeholder="请输入标题" class="layui-input" autocomplete="off"></div></div>';
                    case 'author':
                        return '<div class="layui-form-item" data-field-key="' + key + '">'
                            + '<label class="layui-form-label">' + label + '</label>'
                            + '<div class="layui-input-block"><input type="text" id="author" name="author" placeholder="作者（可选）" class="layui-input" autocomplete="off"></div></div>';
                    case 'source':
                        return '<div class="layui-form-item" data-field-key="' + key + '">'
                            + '<label class="layui-form-label">' + label + '</label>'
                            + '<div class="layui-input-block"><input type="text" id="source" name="source" placeholder="来源（可选）" class="layui-input" autocomplete="off"></div></div>';
                    case 'publish_at':
                    case 'published_at':
                        var pubNow = new Date();
                        var pubPad = function(n) { return n < 10 ? '0' + n : n; };
                        var pubDefault = pubNow.getFullYear() + '-' + pubPad(pubNow.getMonth() + 1) + '-' + pubPad(pubNow.getDate())
                            + ' ' + pubPad(pubNow.getHours()) + ':' + pubPad(pubNow.getMinutes()) + ':' + pubPad(pubNow.getSeconds());
                        return '<div class="layui-form-item" data-field-key="' + key + '">'
                            + '<label class="layui-form-label">' + label + '</label>'
                            + '<div class="layui-input-block"><input type="text" id="publish_at" name="publish_at" value="' + pubDefault + '" placeholder="选择发布时间" class="layui-input" autocomplete="off"></div></div>';
                    case 'summary':
                        return '<div class="layui-form-item" data-field-key="' + key + '">'
                            + '<label class="layui-form-label">' + label + '</label>'
                            + '<div class="layui-input-block"><textarea id="summary" name="summary" placeholder="内容摘要（可选）" class="layui-textarea" style="min-height:60px;"></textarea></div></div>';
                    case 'image':
                    case 'cover_image':
                        return '<div class="layui-form-item" data-field-key="' + key + '">'
                            + '<label class="layui-form-label">' + label + '</label>'
                            + '<div class="layui-input-block"><div class="image-upload-wrap">'
                            + '<input type="hidden" id="cover_image" name="image" value="">'
                            + '<img id="coverPreview" class="preview-img" src="" alt="">'
                            + '<button type="button" class="layui-btn layui-btn-sm" id="chooseCoverBtn"><i class="layui-icon layui-icon-upload"></i> 选择图片</button>'
                            + '<button type="button" class="layui-btn layui-btn-sm layui-btn-danger" id="removeCoverBtn" style="display:none;"><i class="layui-icon layui-icon-delete"></i> 移除</button>'
                            + '</div></div></div>';
                    case 'content':
                        return '<div class="layui-form-item" data-field-key="' + key + '">'
                            + '<label class="layui-form-label">' + label + '</label>'
                            + '<div class="layui-input-block"><textarea id="content" name="content" class="layui-textarea" style="min-height:300px;"></textarea></div></div>';
                    case 'sort':
                        return '<div class="layui-form-item" data-field-key="' + key + '">'
                            + '<label class="layui-form-label">' + label + '</label>'
                            + '<div class="layui-input-block"><input type="number" id="sort" name="sort" value="0" placeholder="数字越小越靠前" class="layui-input" autocomplete="off"></div></div>';
                    case 'status':
                        return '<div class="layui-form-item" data-field-key="' + key + '">'
                            + '<label class="layui-form-label">' + label + '</label>'
                            + '<div class="layui-input-block">'
                            + '<input type="radio" name="status" value="0" title="草稿" checked> '
                            + '<input type="radio" name="status" value="1" title="已发布"> '
                            + '<input type="radio" name="status" value="2" title="已下架">'
                            + '</div></div>';
                    default:
                        return '';
                }
            }

            function renderDefaultMainFields() {
                var html = '';
                defaultMainFields.forEach(function(f) {
                    html += getMainFieldHtml(f.key, f.label);
                });
                $('#main-fields-area').html(html);
                bindCoverEvents();
                initLaydate();
                form.render();
                initTinymce();
                if (isEdit && contentData) {
                    initFormData();
                }
            }

            function renderFormByFieldConfig(orderedFields) {
                var html = '';
                loadedExtFields = [];
                dynamicDateInstances = [];
                dynamicEditorInstances = [];

                orderedFields.forEach(function(f) {
                    if (f.type === 'main' && f.visible !== false) {
                        html += getMainFieldHtml(f.key, f.label);
                    } else if (f.type === 'extension' && f.visible !== false) {
                        var extId = f.extId || (f.key ? f.key.replace('ext_', '') : null);
                        if (extId && allExtFieldsMap[extId]) {
                            var field = allExtFieldsMap[extId];
                            var value = extensionData[field.field] || field.default_value || '';
                            html += renderFieldControl(field, value);
                            loadedExtFields.push('ext_' + field.field);
                        }
                    }
                });

                $('#main-fields-area').html(html);
                $('#extension-fields').empty();

                bindCoverEvents();
                initLaydate();

                if ($('#content').length > 0) {
                    initTinymce();
                } else {
                    setTimeout(function() {
                        if ($('#content').length > 0) initTinymce();
                    }, 200);
                }

                form.render();

                setTimeout(function() {
                    for (var d = 0; d < dynamicDateInstances.length; d++) {
                        var item = dynamicDateInstances[d];
                        laydate.render({ elem: '#' + item.id, type: item.type });
                    }
                    for (var e = 0; e < dynamicEditorInstances.length; e++) {
                        var edItem = dynamicEditorInstances[e];
                        tinymce.render({
                            elem: '#' + edItem.id,
                            height: 250,
                            images_upload_url: '/api/admin/attachments/upload'
                        });
                    }
                }, 100);

                if (isEdit && contentData) {
                    initFormData();
                }
            }

            function initLaydate() {
                if ($('#publish_at').length > 0) {
                    laydate.render({ elem: '#publish_at', type: 'datetime' });
                }
            }

            function bindCoverEvents() {
                $('#chooseCoverBtn').off('click.cover').on('click.cover', function() {
                    layer.open({
                        type: 2,
                        title: '选择封面图',
                        area: ['90%', '80%'],
                        success: function(layero, idx){
                            layer.full(idx);
                        },
                        content: '/admin/attachment?picker=1',
                        end: function() {
                            var selectedUrl = sessionStorage.getItem('selectedAttachmentUrl');
                            if (selectedUrl) {
                                $('#cover_image').val(selectedUrl);
                                $('#coverPreview').attr('src', selectedUrl).addClass('active');
                                $('#removeCoverBtn').show();
                                sessionStorage.removeItem('selectedAttachmentUrl');
                            }
                        }
                    });
                });
                $('#removeCoverBtn').off('click.removeCover').on('click.removeCover', function() {
                    $('#cover_image').val('');
                    $('#coverPreview').attr('src', '').removeClass('active');
                    $(this).hide();
                });
            }

            if (isEdit) {
                $.ajax({
                    url: '/api/admin/contents/' + editId,
                    type: 'GET',
                    dataType: 'json',
                    success: function(res) {
                        if (res.code === 0 && res.data) {
                            contentData = res.data;
                            var editCategoryId = contentData.category_id;

                            if (editCategoryId) {
                                preCategoryId = String(editCategoryId);
                                if (treeLoaded) {
                                    $('#category_id').val(preCategoryId).trigger('change');
                                }
                            }

                            // 内容数据加载完成后，若表单已渲染则立即回填；否则等渲染完成时回填
                            if ($('#title').length > 0) {
                                initFormData();
                            }
                        } else {
                            layer.msg(res.message || '数据加载失败', { icon: 2, time: 2000 });
                        }
                    },
                    error: function() {
                        layer.msg('请求失败', { icon: 2, time: 2000 });
                    }
                });
            } else {
                var now = new Date();
                var pad = function(n) { return n < 10 ? '0' + n : n; };
                var defaultTime = now.getFullYear() + '-' + pad(now.getMonth() + 1) + '-' + pad(now.getDate())
                    + ' ' + pad(now.getHours()) + ':' + pad(now.getMinutes()) + ':' + pad(now.getSeconds());
                form.render();
                setTimeout(function() {
                    $('#publish_at').val(defaultTime);
                    initLaydate();
                    initTinymce();
                }, 300);
            }

            function initFormData() {
                var d = contentData;
                $('#id').val(d.id);

                if (d.title) $('#title').val(d.title);
                if (d.summary) $('#summary').val(d.summary || '');
                if (d.author) $('#author').val(d.author || '');
                if (d.source) $('#source').val(d.source || '');
                if (d.publish_at) $('#publish_at').val(d.publish_at || '');
                if (d.sort !== undefined && d.sort !== null) $('#sort').val(d.sort);
                if (d.status) {
                    $('input[name="status"][value="' + d.status + '"]').prop('checked', true);
                }
                $('#cover_image').val(d.image || '');

                if (d.category_id) {
                    currentCategoryId = d.category_id;
                }

                if (d.image) {
                    $('#coverPreview').attr('src', d.image).addClass('active');
                    $('#removeCoverBtn').show();
                }

                form.render();

                if (d.content) {
                    $('#content').val(d.content);
                }

                initTinymce();

                if (d.extension && typeof d.extension === 'object') {
                    extensionData = d.extension;
                    $('form.layui-form').find('[name^="extension_"]').each(function() {
                        var input = $(this);
                        var rawName = input.attr('name').replace('extension_', '');
                        if (extensionData[rawName] !== undefined && extensionData[rawName] !== null) {
                            input.val(extensionData[rawName]);
                        }
                    });
                }
            }

            function initTinymce() {
                editorInstance = tinymce.render({
                    elem: '#content',
                    language: 'zh-cn',
                    height: 400,
                    plugins: 'code kityformula-editor quickbars print preview searchreplace autolink fullscreen image link media codesample table charmap hr advlist lists wordcount imagetools indent2em',
                    toolbar: 'code undo redo | kityformula-editor forecolor backcolor bold italic underline strikethrough | indent2em alignleft aligncenter alignright alignjustify outdent indent | link bullist numlist image table codesample | formatselect fontselect fontsizeselect fullscreen',
                    menubar: 'file edit insert format table',
                    resize: false,
                    elementpath: false,
                    branding: false,
                    images_upload_handler: function(blobInfo, success, failure) {
                        var formData = new FormData();
                        formData.append('files[]', blobInfo.blob(), blobInfo.filename());
                        $.ajax({
                            url: '/api/admin/attachments/upload',
                            type: 'POST',
                            data: formData,
                            processData: false,
                            contentType: false,
                            success: function(res) {
                                if (res.code === 0 && res.data && res.data.success && res.data.success.length > 0) {
                                    success(res.data.success[0].url);
                                } else {
                                    failure(res.message || '上传失败');
                                }
                            },
                            error: function() {
                                failure('上传请求失败');
                            }
                        });
                    },
                    file_picker_callback: function(callback, value, meta) {
                        console.log(meta.filetype);
                        if (meta.filetype === 'image' || meta.filetype === 'file') {
                            $('.tox.tox-silver-sink.tox-tinymce-aux').css('position', 'static');
                            layer.open({
                                type: 2,
                                title: meta.filetype === 'image' ? '选择图片' : '选择文件',
                                area: ['90%', '80%'],
                                success: function(layero, idx){
                                    layer.full(idx);
                                },
                                zIndex: 19999,
                                content: '/admin/attachment?picker=1',
                                end: function() {
                                    var selectedUrl = sessionStorage.getItem('selectedAttachmentUrl');
                                    if (selectedUrl) {
                                        callback(selectedUrl);
                                        sessionStorage.removeItem('selectedAttachmentUrl');
                                        $('.tox.tox-silver-sink.tox-tinymce-aux').css('position', 'relative');
                                    }else{
                                        $('.tox.tox-silver-sink.tox-tinymce-aux').css('position', 'relative');
                                    }
                                }
                            });
                        }
                    }
                });
            }

            form.on('select(category_id)', function(data) {
                var newCategoryId = data.value;
                if (newCategoryId && newCategoryId !== currentCategoryId) {
                    currentCategoryId = newCategoryId;
                    extensionData = {};
                } else if (!newCategoryId) {
                    currentCategoryId = null;
                }
            });

            function loadExtensionFields(categoryId) {
                $.ajax({
                    url: '/api/admin/content-models/' + $('#model_id').val() + '/fields',
                    type: 'GET',
                    dataType: 'json',
                    success: function(res) {
                        if (res.code === 0 && res.data && res.data.length > 0) {
                            var fields = res.data;
                            var visibleFields = [];
                            for (var i = 0; i < fields.length; i++) {
                                var f = fields[i];
                                var isLoaded = false;
                                for (var j = 0; j < loadedExtFields.length; j++) {
                                    if ('ext_' + f.id === loadedExtFields[j]) {
                                        isLoaded = true;
                                        break;
                                    }
                                }
                                if (loadedExtFields.length === 0 || isLoaded) {
                                    visibleFields.push(f);
                                }
                            }
                            if (visibleFields.length > 0) {
                                renderExtensionFields(visibleFields);
                            } else {
                                $('#extension-fields').empty();
                            }
                        } else {
                            $('#extension-fields').empty();
                        }
                    },
                    error: function() {
                        $('#extension-fields').empty();
                    }
                });
            }

            function renderExtensionFields(fields) {
                dynamicDateInstances = [];
                dynamicEditorInstances = [];

                var html = '<div style="margin-top:15px;padding-top:15px;border-top:1px dashed #e6e6e6;">';
                html += '<div style="font-size:14px;font-weight:600;color:#16b777;margin-bottom:12px;padding-left:10px;border-left:3px solid #16b777;">扩展字段</div>';

                for (var i = 0; i < fields.length; i++) {
                    var field = fields[i];
                    var value = extensionData[field.name] || field.default_value || '';
                    html += renderFieldControl(field, value);
                }

                html += '</div>';
                $('#extension-fields').html(html);
                form.render();

                setTimeout(function() {
                    for (var d = 0; d < dynamicDateInstances.length; d++) {
                        var item = dynamicDateInstances[d];
                        laydate.render({ elem: '#' + item.id, type: item.type });
                    }
                    for (var e = 0; e < dynamicEditorInstances.length; e++) {
                        var edItem = dynamicEditorInstances[e];
                        tinymce.render({
                            elem: '#' + edItem.id,
                            height: 250,
                            images_upload_url: '/api/admin/attachments/upload'
                        });
                    }
                }, 100);
            }

            function renderFieldControl(field, value) {
                var fieldName = 'extension_' + field.field;
                var html = '<div class="layui-form-item"><label class="layui-form-label">' + escapeHtml(field.name) + '</label>';
                html += '<div class="layui-input-block">';

                switch (field.form_type) {
                    case 'text':
                        html += '<input type="text" name="' + fieldName + '" value="' + escapeHtml(String(value)) + '" class="layui-input" placeholder="请输入' + escapeHtml(field.name) + '" autocomplete="off">';
                        break;
                    case 'textarea':
                        html += '<textarea name="' + fieldName + '" class="layui-textarea" placeholder="请输入' + escapeHtml(field.name) + '">' + escapeHtml(String(value)) + '</textarea>';
                        break;
                    case 'tinymce':
                        html += '<textarea id="ext_editor_' + field.name + '" name="' + fieldName + '" class="layui-textarea" style="min-height:250px;">' + escapeHtml(String(value)) + '</textarea>';
                        dynamicEditorInstances.push({ id: 'ext_editor_' + field.name });
                        break;
                    case 'select':
                        html += '<select name="' + fieldName + '">';
                        html += '<option value="">请选择</option>';
                        var opts = field.form_config && field.form_config.options ? field.form_config.options : [];
                        for (var o = 0; o < opts.length; o++) {
                            var opt = opts[o];
                            var optVal = typeof opt === 'object' ? opt.value : opt;
                            var optLabel = typeof opt === 'object' ? opt.label : opt;
                            var selected = String(optVal) === String(value) ? ' selected' : '';
                            html += '<option value="' + escapeHtml(String(optVal)) + '"' + selected + '>' + escapeHtml(String(optLabel)) + '</option>';
                        }
                        html += '</select>';
                        break;
                    case 'radio':
                        var radioOpts = field.form_config && field.form_config.options ? field.form_config.options : [];
                        for (var r = 0; r < radioOpts.length; r++) {
                            var rOpt = radioOpts[r];
                            var rVal = typeof rOpt === 'object' ? rOpt.value : rOpt;
                            var rLabel = typeof rOpt === 'object' ? rOpt.label : rOpt;
                            var rChecked = String(rVal) === String(value) ? ' checked' : '';
                            html += '<input type="radio" name="' + fieldName + '" value="' + escapeHtml(String(rVal)) + '" title="' + escapeHtml(String(rLabel)) + '"' + rChecked + '>';
                        }
                        break;
                    case 'checkbox':
                        var cbOpts = field.form_config && field.form_config.options ? field.form_config.options : [];
                        var cbValues = Array.isArray(value) ? value : (value ? String(value).split(',') : []);
                        for (var c = 0; c < cbOpts.length; c++) {
                            var cOpt = cbOpts[c];
                            var cVal = typeof cOpt === 'object' ? cOpt.value : cOpt;
                            var cLabel = typeof cOpt === 'object' ? cOpt.label : cOpt;
                            var cChecked = cbValues.indexOf(String(cVal)) !== -1 ? ' checked' : '';
                            html += '<input type="checkbox" name="' + fieldName + '" value="' + escapeHtml(String(cVal)) + '" title="' + escapeHtml(String(cLabel)) + '"' + cChecked + '>';
                        }
                        break;
                    case 'switch':
                        var swChecked = value == 1 || value === 'true' || value === '1' ? ' checked' : '';
                        html += '<input type="checkbox" name="' + fieldName + '" lay-skin="switch" lay-text="是|否"' + swChecked + '>';
                        break;
                    case 'date':
                        var dValue = value || '';
                        if (!dValue && !isEdit) {
                            var dNow = new Date();
                            var dPad = function(n) { return n < 10 ? '0' + n : n; };
                            dValue = dNow.getFullYear() + '-' + dPad(dNow.getMonth() + 1) + '-' + dPad(dNow.getDate());
                        }
                        html += '<input type="text" id="ext_date_' + field.name + '" name="' + fieldName + '" value="' + escapeHtml(String(dValue)) + '" class="layui-input" placeholder="选择日期" autocomplete="off">';
                        dynamicDateInstances.push({ id: 'ext_date_' + field.name, type: 'date' });
                        break;
                    case 'datetime':
                        var dtValue = value || '';
                        if (!dtValue && !isEdit) {
                            var dtNow = new Date();
                            var dtPad = function(n) { return n < 10 ? '0' + n : n; };
                            dtValue = dtNow.getFullYear() + '-' + dtPad(dtNow.getMonth() + 1) + '-' + dtPad(dtNow.getDate())
                                + ' ' + dtPad(dtNow.getHours()) + ':' + dtPad(dtNow.getMinutes()) + ':' + dtPad(dtNow.getSeconds());
                        }
                        html += '<input type="text" id="ext_datetime_' + field.name + '" name="' + fieldName + '" value="' + escapeHtml(String(dtValue)) + '" class="layui-input" placeholder="选择日期时间" autocomplete="off">';
                        dynamicDateInstances.push({ id: 'ext_datetime_' + field.name, type: 'datetime' });
                        break;
                    case 'image':
                        html += '<div class="image-upload-wrap">'
                            + '<input type="hidden" name="' + fieldName + '" value="' + escapeHtml(String(value)) + '" class="ext-image-input">'
                            + '<img class="preview-img ext-preview' + (value ? ' active' : '') + '" src="' + (value ? escapeHtml(String(value)) : '') + '" alt="">'
                            + '<button type="button" class="layui-btn layui-btn-sm ext-choose-btn"><i class="layui-icon layui-icon-upload"></i> 选择</button>'
                            + '<button type="button" class="layui-btn layui-btn-sm layui-btn-danger ext-remove-btn" style="' + (value ? '' : 'display:none;') + '"><i class="layui-icon layui-icon-delete"></i> 移除</button>'
                            + '</div>';
                        break;
                    case 'file':
                        html += '<div class="image-upload-wrap">'
                            + '<input type="hidden" name="' + fieldName + '" value="' + escapeHtml(String(value)) + '" class="ext-file-input">'
                            + '<button type="button" class="layui-btn layui-btn-sm ext-file-choose-btn"><i class="layui-icon layui-icon-upload"></i> 选择文件</button>'
                            + '<span class="ext-file-name">' + (value ? '已选择文件' : '') + '</span>'
                            + '</div>';
                        break;
                    case 'number':
                        html += '<input type="number" name="' + fieldName + '" value="' + escapeHtml(String(value)) + '" class="layui-input" placeholder="请输入' + escapeHtml(field.name) + '" autocomplete="off">';
                        break;
                    case 'color':
                        html += '<input type="color" name="' + fieldName + '" value="' + escapeHtml(String(value || '#000000')) + '" style="width:50px;height:38px;padding:2px;cursor:pointer;">';
                        break;
                    case 'tags':
                        html += '<input type="text" name="' + fieldName + '" value="' + escapeHtml(String(value)) + '" class="layui-input" placeholder="多个标签用逗号分隔" autocomplete="off">';
                        break;
                    default:
                        html += '<input type="text" name="' + fieldName + '" value="' + escapeHtml(String(value)) + '" class="layui-input" placeholder="请输入' + escapeHtml(field.name) + '" autocomplete="off">';
                }

                html += '</div></div>';
                return html;
            }

            function escapeHtml(str) {
                if (!str) return '';
                return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
            }

            $(document).on('click', '.ext-choose-btn', function() {
                var $wrap = $(this).closest('.image-upload-wrap');
                layer.open({
                    type: 2,
                    title: '选择图片',
                    area: ['90%', '80%'],
                    success: function(layero, idx){
                        layer.full(idx);
                    },
                    content: '/admin/attachment?picker=1',
                    end: function() {
                        var selectedUrl = sessionStorage.getItem('selectedAttachmentUrl');
                        if (selectedUrl) {
                            $wrap.find('.ext-image-input').val(selectedUrl);
                            $wrap.find('.ext-preview').attr('src', selectedUrl).addClass('active');
                            $wrap.find('.ext-remove-btn').show();
                            sessionStorage.removeItem('selectedAttachmentUrl');
                        }
                    }
                });
            });

            $(document).on('click', '.ext-remove-btn', function() {
                var $wrap = $(this).closest('.image-upload-wrap');
                $wrap.find('.ext-image-input').val('');
                $wrap.find('.ext-preview').attr('src', '').removeClass('active');
                $(this).hide();
            });

            $(document).on('click', '.ext-file-choose-btn', function() {
                var $wrap = $(this).closest('.image-upload-wrap');
                layer.open({
                    type: 2,
                    title: '选择文件',
                    area: ['90%', '80%'],
                    success: function(layero, idx){
                        layer.full(idx);
                    },
                    content: '/admin/attachment?picker=1',
                    end: function() {
                        var selectedUrl = sessionStorage.getItem('selectedAttachmentUrl');
                        if (selectedUrl) {
                            $wrap.find('.ext-file-input').val(selectedUrl);
                            $wrap.find('.ext-file-name').text('已选择文件');
                            sessionStorage.removeItem('selectedAttachmentUrl');
                        }
                    }
                });
            });

            $('#resetBtn').on('click', function() {
                $('form.layui-form')[0].reset();
                $('#publish_at').val('');
                $('#sort').val(0);
                $('input[name="status"][value="0"]').prop('checked', true);
                $('#coverPreview').attr('src', '').removeClass('active');
                $('#removeCoverBtn').hide();
                $('#extension-fields').empty();
                extensionData = {};
                layer.msg('已清空', { icon: 1, time: 800 });
            });

            form.on('submit(save)', function(data) {
                var formData = data.field;

                if (editorInstance) {
                    try {
                        formData.content = editorInstance.getContent();
                    } catch(e) {
                        formData.content = $('#content').val() || '';
                    }
                }

                var extension = {};
                var extCount = 0;
                $('form.layui-form').find('[name^="extension_"]').each(function() {
                    var input = $(this);
                    var rawName = input.attr('name').replace('extension_', '');
                    var val = input.val();

                    if (input.attr('type') === 'checkbox' && input.attr('lay-skin') === 'switch') {
                        val = input.prop('checked') ? 1 : 0;
                    } else if (input.attr('type') === 'checkbox') {
                        var checkedVals = [];
                        input.closest('.layui-form-item').find('input[type="checkbox"][name="extension_' + rawName + '"]:checked').each(function() {
                            checkedVals.push($(this).val());
                        });
                        val = checkedVals.join(',');
                    }

                    extension[rawName] = val;
                    extCount++;
                });

                formData.extension = extension;

                var url = isEdit ? '/api/admin/contents/' + editId : '/api/admin/contents';
                var method = isEdit ? 'PUT' : 'POST';

                $.ajax({
                    url: url,
                    type: method,
                    dataType: 'json',
                    contentType: 'application/json',
                    data: JSON.stringify(formData),
                    success: function(res) {
                        if (res.code === 0) {
                            layer.msg(isEdit ? '编辑成功' : '新增成功', { icon: 1, time: 1000 }, function() {
                                if (parent !== window && parent.layer && (parent.layui && parent.layui.table || parent.table)) {
                                    var index = parent.layer.getFrameIndex(window.name);
                                    parent.layer.close(index);
                                    var tbl = parent.layui ? parent.layui.table : parent.table;
                                    if (tbl) tbl.reload('content-table');
                                } else if (parent !== window && parent.layer) {
                                    var index = parent.layer.getFrameIndex(window.name);
                                    parent.layer.close(index);
                                    location.href = location.href;
                                } else {
                                    location.reload();
                                }
                            });
                        } else {
                            layer.msg(res.message || ('操作失败 code:' + res.code), { icon: 2, time: 2000 });
                        }
                    },
                    error: function(xhr, textStatus, errorThrown) {
                        if (xhr.status === 401) return;
                        var msg = '请求失败';
                        try { var errData = JSON.parse(xhr.responseText); if (errData.message) msg = errData.message; if (errData.data) msg += ' ' + JSON.stringify(errData.data); } catch(e) {}
                        layer.msg(msg, { icon: 2, time: 3000 });
                    }
                });
                return false;
            });
        });
    </script>
</body>
</html>
