<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <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>
        html, body {
            height: 100%;
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
        *, *::before, *::after {
            box-sizing: border-box;
        }
        .layui-form {
            height: 100%;
        }
        /* 内容区：总高度减去底部按钮栏高度，内容超出时自身滚动 */
        .layui-form > .layui-row {
            height: calc(100vh - 52px);
            overflow-y: auto;
            padding: 15px;
            margin: 0;
        }
        .layui-form-label {
            padding: 9px 4px;
            width: unset;
        }
        .layui-input, .layui-textarea {
            width: 98%;
        }
        /* 底部按钮栏：固定 52px 高度，始终贴底不参与滚动，按钮居右 */
        .bottom {
            height: 52px;
            background: #fff;
            border-top: 1px solid #e6e6e6;
            text-align: right;
        }
        .bottom .button-container {
            display: inline-block;
        }
        .bottom .button-container button {
            margin-left: 10px;
        }
    </style>
</head>

<body>
    <form class="layui-form" action="">
        <input type="hidden" id="id" name="id" value="">
        <div class="layui-row">
            <div class="layui-col-md12">
                <div class="layui-card-body layui-row">
                    <div class="layui-col-md12">
                        <div class="layui-form-item">
                            <label class="layui-form-label">角色</label>
                            <div class="layui-input-block">
                                <select id="role_id" name="role_id" lay-verify="required" lay-reqText="请选择角色" lay-search="">
                                    <option value="">请选择角色</option>
                                </select>
                            </div>
                        </div>
                        <div class="layui-form-item">
                            <label class="layui-form-label">用户名</label>
                            <div class="layui-input-block">
                                <input type="text" id="username" name="username" lay-verify="required" lay-reqText="用户名不能为空" placeholder="请输入用户名" class="layui-input" autocomplete="off">
                            </div>
                        </div>
                        <div class="layui-form-item" id="password-item">
                            <label class="layui-form-label">密码</label>
                            <div class="layui-input-block">
                                <input type="password" id="password" name="password" placeholder="请输入密码" class="layui-input" autocomplete="off">
                            </div>
                        </div>
                        <div class="layui-form-item">
                            <label class="layui-form-label">姓名</label>
                            <div class="layui-input-block">
                                <input type="text" id="name" name="name" placeholder="请输入姓名" class="layui-input" autocomplete="off">
                            </div>
                        </div>
                        <div class="layui-form-item">
                            <label class="layui-form-label">邮箱</label>
                            <div class="layui-input-block">
                                <input type="text" id="email" name="email" placeholder="请输入邮箱" class="layui-input" autocomplete="off">
                            </div>
                        </div>
                        <div class="layui-form-item">
                            <label class="layui-form-label">手机号</label>
                            <div class="layui-input-block">
                                <input type="text" id="phone" name="phone" placeholder="请输入手机号" class="layui-input" autocomplete="off">
                            </div>
                        </div>
                        <div class="layui-form-item">
                            <label class="layui-form-label">状态</label>
                            <div class="layui-input-block">
                                <select id="status" name="status">
                                    <option value="1">正常</option>
                                    <option value="0">禁用</option>
                                </select>
                            </div>
                        </div>
                        <!-- 扩展字段区域，由JS动态渲染 -->
                        <div id="ext-fields-container"></div>
                    </div>
                </div>
            </div>
        </div>
        <div class="bottom">
            <div class="button-container">
                <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>
                <button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">
                    <i class="layui-icon layui-icon-refresh"></i> 清空
                </button>
            </div>
        </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', 'formSelects'], function() {
            var form = layui.form;
            var $ = layui.jquery;
            var formSelects = layui.formSelects;

            $.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 extFieldsDef = []; // 扩展字段定义缓存

            if (isEdit) {
                $('#password-item').find('input').removeAttr('lay-verify');
                $('#password-item').find('.layui-form-label').append('<span style="color:#999;font-size:12px;">(留空则不修改)</span>');
            } else {
                $('#password').attr('lay-verify', 'required');
                $('#password').attr('lay-reqText', '密码不能为空');
            }

            // 暂存扩展字段值，用于协调 loadExtFields 与 loadUserData 的异步顺序
            // 当 loadUserData 先返回但 extFieldsDef 尚未加载完成时，先暂存；等 loadExtFields 完成后使用
            var pendingExtValues = null;

            // 加载扩展字段定义并渲染
            function loadExtFields() {
                $.ajax({
                    url: '/api/admin/admin-user-ext-fields',
                    type: 'GET', dataType: 'json',
                    success: function(res) {
                        if (res.code === 0 && res.data) {
                            extFieldsDef = res.data.filter(function(f) { return f.status === 1 || f.status === '1'; });
                            // 编辑模式下，等用户数据就绪后再渲染，避免先渲染空值导致下拉框选中失败
                            if (isEdit && !pendingExtValues) {
                                return;
                            }
                            renderExtFields(pendingExtValues || {});
                            pendingExtValues = null;
                        }
                    }
                });
            }

            // 渲染版本号，用于避免重复渲染时的 AJAX 竞态
            var renderVersion = 0;

            // 根据字段定义渲染表单项（先预加载数据源，再统一渲染，确保 selected 属性在初始HTML中就正确设置）
            function renderExtFields(values) {
                renderVersion++;
                var currentVersion = renderVersion;
                // 收集需要动态拉取选项的字段
                var sourceFields = [];
                for (var i = 0; i < extFieldsDef.length; i++) {
                    var f = extFieldsDef[i];
                    if (f.field_type === 'select') {
                        var opts = f.field_options || [];
                        var isSource = opts && typeof opts === 'object' && opts.source;
                        if (isSource) {
                            sourceFields.push({
                                name: f.field_name,
                                source: opts.source,
                                value: values[f.field_name] || '',
                                multiple: opts.multiple === true
                            });
                        }
                    }
                }
                // 预加载所有数据源，加载完成后统一渲染
                var sourceDataMap = {};
                if (sourceFields.length > 0) {
                    var deferreds = sourceFields.map(function(item) {
                        return $.ajax({
                            url: item.source.url, type: 'GET', dataType: 'json'
                        }).then(function(res) {
                            if (res.code === 0 && res.data) {
                                sourceDataMap[item.name] = {
                                    list: Array.isArray(res.data) ? res.data : (res.data.items || []),
                                    source: item.source,
                                    value: item.value,
                                    multiple: item.multiple
                                };
                            }
                        });
                    });
                    $.when.apply($, deferreds).always(function() {
                        if (currentVersion !== renderVersion) return;
                        doRenderExtFields(values, sourceDataMap);
                    });
                } else {
                    doRenderExtFields(values, sourceDataMap);
                }
            }

            // 构建完整HTML并渲染（数据源已预加载，selected 属性在初始HTML中即设置）
            function doRenderExtFields(values, sourceDataMap) {
                var html = '';
                for (var i = 0; i < extFieldsDef.length; i++) {
                    var f = extFieldsDef[i];
                    var val = values[f.field_name] || '';
                    html += '<div class="layui-form-item">';
                    html += '<label class="layui-form-label">' + f.field_label + '</label>';
                    html += '<div class="layui-input-block">';
                    if (f.field_type === 'select') {
                        var opts = f.field_options || [];
                        var isSource = opts && typeof opts === 'object' && opts.source;
                        var isMultiple = opts && typeof opts === 'object' && opts.multiple === true;
                        var sourceData = isSource ? sourceDataMap[f.field_name] : null;
                        if (isMultiple) {
                            if (isSource && sourceData) {
                                // 多选动态数据源：已预加载，直接构建完整选项
                                html += '<select name="ext_' + f.field_name + '" xm-select="ext_' + f.field_name + '" xm-select-search>';
                                html += '<option value=""></option>';
                                for (var k = 0; k < sourceData.list.length; k++) {
                                    var optVal = sourceData.list[k][sourceData.source.value_key];
                                    var optLabel = sourceData.list[k][sourceData.source.label_key];
                                    var isSelected = (Array.isArray(val) && val.indexOf(String(optVal)) !== -1);
                                    html += '<option value="' + optVal + '"' + (isSelected ? ' selected' : '') + '>' + optLabel + '</option>';
                                }
                                html += '</select>';
                            } else if (isSource) {
                                // 数据源加载失败，渲染空select
                                html += '<select name="ext_' + f.field_name + '" xm-select="ext_' + f.field_name + '" xm-select-search>';
                                html += '<option value="">加载失败</option>';
                                html += '</select>';
                            } else {
                                // 静态选项
                                html += '<select name="ext_' + f.field_name + '" xm-select="ext_' + f.field_name + '" xm-select-search>';
                                var optList = opts.options || opts;
                                for (var j = 0; j < optList.length; j++) {
                                    var selectedAttr = (Array.isArray(val) && val.indexOf(String(optList[j].value)) !== -1) ? ' selected' : '';
                                    html += '<option value="' + optList[j].value + '"' + selectedAttr + '>' + optList[j].label + '</option>';
                                }
                                html += '</select>';
                            }
                        } else {
                            html += '<select name="ext_' + f.field_name + '"><option value="">请选择</option>';
                            if (isSource && sourceData) {
                                // 单选动态数据源：已预加载，直接构建完整选项（含selected）
                                for (var k = 0; k < sourceData.list.length; k++) {
                                    var optVal = sourceData.list[k][sourceData.source.value_key];
                                    var optLabel = sourceData.list[k][sourceData.source.label_key];
                                    var sel = String(optVal) === String(val) ? ' selected' : '';
                                    html += '<option value="' + optVal + '"' + sel + '>' + optLabel + '</option>';
                                }
                            } else if (isSource) {
                                // 数据源加载失败，仅保留默认选项
                            } else {
                                // 静态选项
                                for (var j = 0; j < opts.length; j++) {
                                    var sel = opts[j].value === val ? ' selected' : '';
                                    html += '<option value="' + opts[j].value + '"' + sel + '>' + opts[j].label + '</option>';
                                }
                            }
                            html += '</select>';
                        }
                    } else if (f.field_type === 'textarea') {
                        html += '<textarea name="ext_' + f.field_name + '" placeholder="请输入' + f.field_label + '" class="layui-textarea">' + val + '</textarea>';
                    } else if (f.field_type === 'switch') {
                        var chk = val === '1' || val === 1 ? ' checked' : '';
                        html += '<input type="checkbox" name="ext_' + f.field_name + '" lay-skin="switch" lay-text="是|否" value="1"' + chk + '>';
                    } else if (f.field_type === 'date') {
                        html += '<input type="text" name="ext_' + f.field_name + '" id="ext_date_' + f.field_name + '" placeholder="请选择' + f.field_label + '" class="layui-input" value="' + val + '">';
                    } else if (f.field_type === 'number') {
                        html += '<input type="number" name="ext_' + f.field_name + '" placeholder="请输入' + f.field_label + '" class="layui-input" value="' + val + '" autocomplete="off">';
                    } else {
                        html += '<input type="text" name="ext_' + f.field_name + '" placeholder="请输入' + f.field_label + '" class="layui-input" value="' + val + '" autocomplete="off">';
                    }
                    html += '</div></div>';
                }
                $('#ext-fields-container').html(html);
                // 渲染日期选择器
                for (var i = 0; i < extFieldsDef.length; i++) {
                    if (extFieldsDef[i].field_type === 'date') {
                        layui.laydate.render({ elem: '#ext_date_' + extFieldsDef[i].field_name });
                    }
                }
                form.render();
                // 渲染所有 xm-select 多选组件（数据源已预加载，选项已内嵌在HTML中）
                var xmSelectFields = extFieldsDef.filter(function(f) {
                    return f.field_type === 'select' && f.field_options && f.field_options.multiple === true;
                });
                xmSelectFields.forEach(function(f) {
                    var xmSelectId = 'ext_' + f.field_name;
                    formSelects.render(xmSelectId, { isSearch: true });
                });
            }

            loadExtFields();

            $.ajax({
                url: '/api/admin/roles/all',
                type: 'GET',
                dataType: 'json',
                success: function(res) {
                    if (res.code === 0 && res.data) {
                        // 兼容新旧返回结构：新结构为 {items, is_super_privileged}，旧结构为数组
                        var list = Array.isArray(res.data) ? res.data : (res.data.items || []);

                        // 递归构建树形 option（使用 ├─ └─ │ 缩进前缀模拟树形层级）
                        function buildRoleTree(items, parentId, prefix) {
                            var html = '';
                            var children = items.filter(function(item) {
                                return (item.parent_id || 0) == parentId;
                            });
                            for (var i = 0; i < children.length; i++) {
                                var item = children[i];
                                var isLast = (i === children.length - 1);
                                // 顶级角色不加前缀，子角色按层级加缩进
                                var treePrefix = parentId == 0 ? '' : (prefix + (isLast ? '└─ ' : '├─ '));
                                html += '<option value="' + item.id + '">' + treePrefix + item.name + '</option>';
                                html += buildRoleTree(items, item.id, prefix + (isLast ? '   ' : '│  '));
                            }
                            return html;
                        }

                        var options = '<option value="">请选择角色</option>' + buildRoleTree(list, 0, '');
                        $('#role_id').html(options);

                        if (isEdit) {
                            loadUserData();
                        }

                        form.render('select');
                    }
                }
            });

            function loadUserData() {
                $.ajax({
                    url: '/api/admin/users/' + editId,
                    type: 'GET',
                    dataType: 'json',
                    success: function(res) {
                        if (res.code === 0 && res.data) {
                            var d = res.data;
                            $('#id').val(d.id);
                            $('#role_id').val(d.roles && d.roles.length > 0 ? d.roles[0].id : '');
                            $('#username').val(d.username);
                            $('#name').val(d.name);
                            $('#email').val(d.email);
                            $('#phone').val(d.phone);
                            $('#status').val(d.status);
                            form.render();
                            // 回填扩展字段
                            if (d.ext_fields) {
                                // 若字段定义已加载完成，直接渲染；否则暂存等 loadExtFields 完成后渲染
                                if (extFieldsDef.length > 0) {
                                    renderExtFields(d.ext_fields);
                                } else {
                                    pendingExtValues = d.ext_fields;
                                }
                            }
                        }
                    }
                });
            }

            form.on('submit(save)', function(data) {
                var url = isEdit ? '/api/admin/users/' + editId : '/api/admin/users';
                var method = isEdit ? 'PUT' : 'POST';

                if (isEdit && !data.field.password) {
                    delete data.field.password;
                }

                // 收集扩展字段数据
                var extFields = {};
                for (var i = 0; i < extFieldsDef.length; i++) {
                    var f = extFieldsDef[i];
                    var fname = f.field_name;
                    var key = 'ext_' + fname;
                    var opts = f.field_options || {};
                    var isMultipleSelect = (f.field_type === 'select' && typeof opts === 'object' && opts.multiple === true);
                    if (isMultipleSelect) {
                        // 多选 select：从 xm-select 获取选中值（'val' 返回纯值数组，避免拿到对象数组）
                        var xmSelectId = 'ext_' + fname;
                        extFields[fname] = formSelects.value(xmSelectId, 'val').map(function(v){ return String(v); });
                    } else if (f.field_type === 'switch') {
                        extFields[fname] = data.field[key] ? '1' : '0';
                        delete data.field[key];
                    } else if (data.field[key] !== undefined) {
                        extFields[fname] = data.field[key];
                        delete data.field[key];
                    }
                }
                data.field.ext_fields = extFields;

                $.ajax({
                    url: url,
                    type: method,
                    dataType: 'json',
                    contentType: 'application/json',
                    data: JSON.stringify(data.field),
                    success: function(res) {
                        if (res.code === 0) {
                            layer.msg(isEdit ? '编辑成功' : '新增成功', { icon: 1, time: 1000 }, function() {
                            var index = parent.layer.getFrameIndex(window.name);
                            parent.layer.close(index);
                            parent.layui.table.reload('user-table');
                        });
                        } else {
                            // 业务错误：优先展示后端返回的 message
                            // 若 data 中包含字段级错误列表，则拼接展示
                            var errMsg = res.message || '操作失败';
                            if (res.data && typeof res.data === 'object') {
                                var fieldErrors = [];
                                for (var field in res.data) {
                                    if (Array.isArray(res.data[field])) {
                                        fieldErrors = fieldErrors.concat(res.data[field]);
                                    } else if (typeof res.data[field] === 'string') {
                                        fieldErrors.push(res.data[field]);
                                    }
                                }
                                if (fieldErrors.length > 0) {
                                    errMsg = fieldErrors.join('；');
                                }
                            }
                            layer.msg(errMsg, { icon: 2, time: 3000 });
                        }
                    },
                    error: function(xhr) {
                        // HTTP 错误（4xx/5xx）：尝试解析响应体中的 JSON 错误信息
                        var errMsg = '请求失败';
                        if (xhr.responseJSON) {
                            var res = xhr.responseJSON;
                            // 优先使用 message 字段
                            if (res.message) {
                                errMsg = res.message;
                            }
                            // 拼接 data 中的字段级错误（如 422 校验错误）
                            if (res.data && typeof res.data === 'object') {
                                var fieldErrors = [];
                                for (var field in res.data) {
                                    if (Array.isArray(res.data[field])) {
                                        fieldErrors = fieldErrors.concat(res.data[field]);
                                    } else if (typeof res.data[field] === 'string') {
                                        fieldErrors.push(res.data[field]);
                                    }
                                }
                                if (fieldErrors.length > 0) {
                                    errMsg = fieldErrors.join('；');
                                }
                            }
                        } else if (xhr.status === 0) {
                            errMsg = '网络连接失败，请检查网络';
                        } else if (xhr.status >= 500) {
                            errMsg = '服务器内部错误（' + xhr.status + '）';
                        }
                        layer.msg(errMsg, { icon: 2, time: 3000 });
                    }
                });
                return false;
            });
        });
    </script>
</body>
</html>
