218 lines
5.1 KiB
Vue
218 lines
5.1 KiB
Vue
<template>
|
|
<el-dialog
|
|
v-model="visible"
|
|
:title="isEdit ? '编辑角色' : '添加角色'"
|
|
width="600px"
|
|
@close="handleClose"
|
|
>
|
|
<el-form :model="form" :rules="rules" ref="formRef" label-width="100px">
|
|
<el-form-item label="角色名称" prop="name">
|
|
<el-input
|
|
v-model="form.name"
|
|
placeholder="请输入角色名称"
|
|
maxlength="50"
|
|
show-word-limit
|
|
/>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="状态" prop="status">
|
|
<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="权限设置" prop="rights">
|
|
<el-tree
|
|
ref="treeRef"
|
|
:data="menuTree"
|
|
show-checkbox
|
|
node-key="id"
|
|
:props="{ children: 'children', label: 'title' }"
|
|
:default-checked-keys="form.rights"
|
|
style="width: 100%; border: 1px solid var(--el-border-color); border-radius: 4px; padding: 10px; max-height: 400px; overflow-y: auto;"
|
|
/>
|
|
</el-form-item>
|
|
</el-form>
|
|
|
|
<template #footer>
|
|
<el-button @click="handleClose">取消</el-button>
|
|
<el-button type="primary" @click="handleSubmit" :loading="submitting">
|
|
确定
|
|
</el-button>
|
|
</template>
|
|
</el-dialog>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, watch, nextTick } from "vue";
|
|
import { ElMessage } from "element-plus";
|
|
import { createRole, updateRole } from "@/api/role";
|
|
import { getAllMenus } from "@/api/menu";
|
|
|
|
interface Props {
|
|
modelValue: boolean;
|
|
role?: any;
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
modelValue: false,
|
|
role: null,
|
|
});
|
|
|
|
const emit = defineEmits(["update:modelValue", "success"]);
|
|
|
|
const visible = ref(false);
|
|
const isEdit = ref(false);
|
|
const submitting = ref(false);
|
|
const formRef = ref();
|
|
const treeRef = ref();
|
|
const menuTree = ref<any[]>([]);
|
|
|
|
const form = ref({
|
|
name: "",
|
|
status: 1,
|
|
rights: [] as number[],
|
|
});
|
|
|
|
const rules = {
|
|
name: [
|
|
{ required: true, message: "请输入角色名称", trigger: "blur" },
|
|
{ min: 2, max: 50, message: "角色名称长度在 2 到 50 个字符", trigger: "blur" },
|
|
],
|
|
status: [{ required: true, message: "请选择状态", trigger: "change" }],
|
|
};
|
|
|
|
// 监听 modelValue
|
|
watch(
|
|
() => props.modelValue,
|
|
(val) => {
|
|
visible.value = val;
|
|
if (val) {
|
|
loadMenus();
|
|
if (props.role) {
|
|
isEdit.value = true;
|
|
form.value = {
|
|
name: props.role.name,
|
|
status: props.role.status,
|
|
rights: parseRights(props.role.rights),
|
|
};
|
|
// 等待树加载完成后设置选中状态
|
|
nextTick(() => {
|
|
if (treeRef.value) {
|
|
treeRef.value.setCheckedKeys(form.value.rights);
|
|
}
|
|
});
|
|
} else {
|
|
isEdit.value = false;
|
|
resetForm();
|
|
}
|
|
}
|
|
}
|
|
);
|
|
|
|
// 监听 visible
|
|
watch(visible, (val) => {
|
|
emit("update:modelValue", val);
|
|
});
|
|
|
|
// 解析权限字符串
|
|
const parseRights = (rights: any): number[] => {
|
|
if (!rights) return [];
|
|
if (Array.isArray(rights)) return rights;
|
|
if (typeof rights === "string") {
|
|
try {
|
|
const parsed = JSON.parse(rights);
|
|
return Array.isArray(parsed) ? parsed : [];
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
return [];
|
|
};
|
|
|
|
// 加载菜单树
|
|
const loadMenus = async () => {
|
|
try {
|
|
const res = await getAllMenus();
|
|
if (res.code === 200) {
|
|
menuTree.value = res.data || [];
|
|
}
|
|
} catch (error) {
|
|
console.error("加载菜单失败:", error);
|
|
ElMessage.error("加载菜单失败");
|
|
}
|
|
};
|
|
|
|
// 重置表单
|
|
const resetForm = () => {
|
|
form.value = {
|
|
name: "",
|
|
status: 1,
|
|
rights: [],
|
|
};
|
|
if (formRef.value) {
|
|
formRef.value.clearValidate();
|
|
}
|
|
if (treeRef.value) {
|
|
treeRef.value.setCheckedKeys([]);
|
|
}
|
|
};
|
|
|
|
// 关闭对话框
|
|
const handleClose = () => {
|
|
visible.value = false;
|
|
resetForm();
|
|
};
|
|
|
|
// 提交表单
|
|
const handleSubmit = async () => {
|
|
if (!formRef.value) return;
|
|
|
|
try {
|
|
await formRef.value.validate();
|
|
|
|
// 获取选中的菜单ID
|
|
const checkedKeys = treeRef.value.getCheckedKeys();
|
|
const halfCheckedKeys = treeRef.value.getHalfCheckedKeys();
|
|
const allCheckedKeys = [...checkedKeys, ...halfCheckedKeys];
|
|
|
|
const submitData = {
|
|
name: form.value.name,
|
|
status: form.value.status,
|
|
rights: allCheckedKeys,
|
|
};
|
|
|
|
submitting.value = true;
|
|
|
|
let res;
|
|
if (isEdit.value && props.role) {
|
|
res = await updateRole(props.role.id, submitData);
|
|
} else {
|
|
res = await createRole(submitData);
|
|
}
|
|
|
|
if (res.code === 200) {
|
|
ElMessage.success(isEdit.value ? "更新成功" : "创建成功");
|
|
emit("success");
|
|
handleClose();
|
|
} else {
|
|
ElMessage.error(res.msg || "操作失败");
|
|
}
|
|
} catch (error: any) {
|
|
if (error !== false) {
|
|
// 不是表单验证错误
|
|
ElMessage.error(error.message || "操作失败");
|
|
}
|
|
} finally {
|
|
submitting.value = false;
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
:deep(.el-tree) {
|
|
background-color: var(--el-bg-color);
|
|
}
|
|
</style>
|