<template>
    <el-main>
        <el-card shadow="never">
            <template #header>
                <div class="header-row">
                    <span>身份列表</span>
                    <el-button type="primary" @click="openCreate">添加身份</el-button>
                </div>
            </template>

            <el-table v-loading="loading" :data="list">
                <el-table-column prop="id" label="ID" width="80" />
                <el-table-column prop="role_name" label="身份名称" min-width="160" show-overflow-tooltip>
                    <template #default="{ row }">
                        {{ row.role_name ?? row.name ?? "-" }}
                    </template>
                </el-table-column>
                <el-table-column label="状态" width="120">
                    <template #default="{ row }">
                        <el-switch
                            :model-value="Number(row.status)"
                            :active-value="1"
                            :inactive-value="0"
                            inline-prompt
                            active-text="启用"
                            inactive-text="停用"
                            active-color="#13ce66"
                            inactive-color="#ff4949"
                            @change="(val) => changeStatus(row, val)"
                        />
                    </template>
                </el-table-column>
                <el-table-column label="操作" width="200" fixed="right">
                    <template #default="{ row }">
                        <div class="table-row-actions">
                            <el-button type="primary" size="small" @click="openEdit(row)">编辑</el-button>
                            <el-button type="danger" size="small" plain @click="removeRow(row)">删除</el-button>
                        </div>
                    </template>
                </el-table-column>
            </el-table>
        </el-card>

        <el-dialog v-model="dialogVisible" :title="dialogTitle" width="560px" destroy-on-close @closed="onDialogClosed">
            <el-form ref="formRef" :model="form" :rules="rules" label-width="90px">
                <el-form-item label="名称" prop="role_name">
                    <el-input v-model="form.role_name" clearable maxlength="60" placeholder="身份名称" />
                </el-form-item>
                <el-form-item label="状态">
                    <el-radio-group v-model="form.status">
                        <el-radio :label="1">启用</el-radio>
                        <el-radio :label="0">停用</el-radio>
                    </el-radio-group>
                </el-form-item>
                <el-form-item label="菜单权限">
                    <el-scrollbar max-height="360px">
                        <el-tree
                            v-if="dialogVisible"
                            :key="treeKey"
                            ref="treeRef"
                            :data="menuTree"
                            :props="treeProps"
                            show-checkbox
                            check-strictly
                            node-key="id"
                            default-expand-all
                            class="perm-tree"
                        />
                        <div v-if="!menuTree.length" class="tree-empty">暂无菜单数据</div>
                    </el-scrollbar>
                </el-form-item>
            </el-form>
            <template #footer>
                <el-button @click="dialogVisible = false">取消</el-button>
                <el-button type="primary" :loading="saving" @click="submitForm">保存</el-button>
            </template>
        </el-dialog>
    </el-main>
</template>

<script>
/** 必选且不可取消勾选的菜单权限 id */
const LOCKED_RULE_IDS = new Set(["1", "3"]);

export default {
    name: "PermissionRoleList",
    data() {
        return {
            loading: false,
            saving: false,
            list: [],
            dialogVisible: false,
            dialogTitle: "添加身份",
            treeKey: 0,
            menuTree: [],
            form: this.getDefaultForm(),
            rules: {
                role_name: [{ required: true, message: "请输入身份名称", trigger: "blur" }],
            },
            treeProps: {
                children: "children",
                label: "permLabel",
                disabled: "disabled",
            },
        };
    },
    created() {
        this.getList();
    },
    methods: {
        getDefaultForm() {
            return { id: "", role_name: "", status: 1 };
        },
        normalizeMenuTree(nodes) {
            if (!Array.isArray(nodes)) return [];
            return nodes.map((node) => {
                const meta = node.meta && typeof node.meta === "object" ? node.meta : null;
                const rawId = node.id ?? node.menu_id ?? node.value ?? meta?.id;
                const id = rawId != null && rawId !== "" ? String(rawId) : rawId;
                const label =
                    (meta && (meta.title || meta.name)) ||
                    node.title ||
                    node.name ||
                    node.menu_name ||
                    node.label ||
                    node.pathname ||
                    node.path_name ||
                    (id != null ? `节点 ${id}` : "未命名");
                const raw = node.children ?? node.child ?? node.subs ?? node.son ?? node.nodes;
                const children = Array.isArray(raw) && raw.length ? this.normalizeMenuTree(raw) : [];
                const locked = id != null && LOCKED_RULE_IDS.has(String(id));
                return {
                    ...node,
                    id,
                    permLabel: label,
                    disabled: locked,
                    children: children.length ? children : undefined,
                };
            });
        },
        /** 后端可能直接返回数组（与 menu/list 一致），或包在 menus / authList / data 等字段中 */
        pickMenuTree(payload) {
            if (Array.isArray(payload)) return payload;
            if (!payload || typeof payload !== "object") return [];
            const d = payload;
            const buckets = [
                d.menus,
                d.menu,
                d.menuList,
                d.menu_list,
                d.authList,
                d.authorize,
                Array.isArray(d.data) ? d.data : null,
                d.ruleList,
                d.tree,
                d.nodes,
                d.routers,
                d.routes,
                d.list,
            ];
            for (let i = 0; i < buckets.length; i++) {
                const b = buckets[i];
                if (Array.isArray(b)) return b;
            }
            return [];
        },
        parseRulesKeys(rules) {
            if (Array.isArray(rules)) return rules.map((x) => String(x));
            if (typeof rules === "string" && rules.trim()) {
                return rules
                    .split(/[,|]/)
                    .map((s) => s.trim())
                    .filter(Boolean);
            }
            return [];
        },
        mergeRoleInfo(data) {
            const d = data || {};
            const role = d.role || d.info || {};
            return {
                id: role.id != null ? role.id : d.id,
                role_name: role.role_name ?? role.name ?? d.role_name ?? "",
                status: role.status != null ? Number(role.status) : d.status != null ? Number(d.status) : 1,
                rules: role.rules ?? d.rules ?? d.rule ?? "",
            };
        },
        apiOk(res) {
            return res && (res.code === 1 || res.code === 200);
        },
        async getList() {
            this.loading = true;
            try {
                const res = await this.$API.role.list.get({});
                if (!this.apiOk(res)) {
                    this.$message.error(res.msg || "获取身份列表失败");
                    return;
                }
                const data = res.data ?? {};
                const raw = Array.isArray(data) ? data : data.list || data.data || data.roles || [];
                this.list = raw;
            } finally {
                this.loading = false;
            }
        },
        collectRules() {
            const tree = this.$refs.treeRef;
            if (!tree) return [...LOCKED_RULE_IDS];
            const checked = tree.getCheckedKeys(false);
            const half = tree.getHalfCheckedKeys();
            const picked = [...new Set([...checked, ...half].map(String))];
            return this.ensureLockedRules(picked);
        },
        /** 提交与编辑回填时都必须包含必选 id */
        ensureLockedRules(keys) {
            const set = new Set(keys.map(String));
            LOCKED_RULE_IDS.forEach((id) => set.add(id));
            return [...set];
        },
        async openCreate() {
            this.dialogTitle = "添加身份";
            this.form = this.getDefaultForm();
            this.treeKey += 1;
            this.dialogVisible = true;
            try {
                const res = await this.$API.role.create.get();
                if (!this.apiOk(res)) {
                    this.$message.error(res.msg || "获取菜单失败");
                    this.menuTree = [];
                    return;
                }
                const d = res.data || {};
                this.menuTree = this.normalizeMenuTree(this.pickMenuTree(d));
                await this.$nextTick();
                /** 新建：默认仅勾选 1、3，且这两项禁止取消 */
                this.$refs.treeRef?.setCheckedKeys([...LOCKED_RULE_IDS]);
            } catch (e) {
                this.menuTree = [];
            }
            this.$nextTick(() => this.$refs.formRef?.clearValidate());
        },
        async openEdit(row) {
            const id = row.id;
            if (id == null) {
                this.$message.error("缺少身份 ID");
                return;
            }
            this.dialogTitle = "编辑身份";
            this.treeKey += 1;
            this.dialogVisible = true;
            try {
                const res = await this.$API.role.edit.get(id);
                if (!this.apiOk(res)) {
                    this.$message.error(res.msg || "获取身份详情失败");
                    this.menuTree = [];
                    return;
                }
                const d = res.data || {};
                this.menuTree = this.normalizeMenuTree(this.pickMenuTree(d));
                const merged = this.mergeRoleInfo(d);
                this.form = {
                    id: merged.id != null ? String(merged.id) : "",
                    role_name: merged.role_name,
                    status: merged.status,
                };
                await this.$nextTick();
                const keys = this.ensureLockedRules(this.parseRulesKeys(merged.rules));
                this.$refs.treeRef?.setCheckedKeys(keys);
            } catch (e) {
                this.menuTree = [];
            }
            this.$nextTick(() => this.$refs.formRef?.clearValidate());
        },
        onDialogClosed() {
            this.menuTree = [];
            this.form = this.getDefaultForm();
        },
        submitForm() {
            this.$refs.formRef.validate(async (valid) => {
                if (!valid) return false;
                this.saving = true;
                try {
                    const payload = {
                        role_name: this.form.role_name,
                        status: String(this.form.status ?? 1),
                        rules: this.collectRules(),
                    };
                    if (this.form.id != null && String(this.form.id) !== "") {
                        payload.id = String(this.form.id);
                    }
                    const res = await this.$API.role.save.post(payload);
                    if (!this.apiOk(res)) {
                        this.$message.error(res.msg || "保存失败");
                        return false;
                    }
                    this.$message.success(res.msg || "保存成功");
                    this.dialogVisible = false;
                    this.getList();
                } finally {
                    this.saving = false;
                }
            });
        },
        async removeRow(row) {
            const confirm = await this.$confirm("确认删除该身份吗？", "提示", {
                type: "warning",
                confirmButtonText: "删除",
                confirmButtonClass: "el-button--danger",
            }).catch(() => {});
            if (confirm !== "confirm") return;
            const res = await this.$API.role.del.delete(row.id);
            if (!this.apiOk(res)) {
                this.$message.error(res.msg || "删除失败");
                return;
            }
            this.$message.success(res.msg || "删除成功");
            this.getList();
        },
        async changeStatus(row, status) {
            const res = await this.$API.role.setStatus.get(row.id, status);
            if (!this.apiOk(res)) {
                this.$message.error(res.msg || "状态更新失败");
                this.getList();
                return;
            }
            this.$message.success(res.msg || "状态更新成功");
            row.status = status;
        },
    },
};
</script>

<style scoped>
.header-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
}
.perm-tree {
    width: 100%;
    padding: 6px 0;
}
.tree-empty {
    color: var(--el-text-color-secondary);
    font-size: 13px;
    padding: 12px 0;
}
</style>
