feat: 完成用户管理、角色管理、菜单管理、部门管理

This commit is contained in:
橙子
2024-09-02 23:26:41 +08:00
parent bc83362b35
commit e886614641
17 changed files with 230 additions and 326 deletions

View File

@@ -5,14 +5,11 @@ namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Dept
/// </summary> /// </summary>
public class DeptCreateInputVo public class DeptCreateInputVo
{ {
public Guid Id { get; set; }
public DateTime CreationTime { get; set; } = DateTime.Now;
public Guid? CreatorId { get; set; }
public bool State { get; set; } public bool State { get; set; }
public string DeptName { get; set; } = string.Empty; public string DeptName { get; set; }
public string DeptCode { get; set; } = string.Empty; public string DeptCode { get; set; }
public string? Leader { get; set; } public string? Leader { get; set; }
public Guid ParentId { get; set; } public Guid? ParentId { get; set; }=Guid.Empty;
public string? Remark { get; set; } public string? Remark { get; set; }
} }
} }

View File

@@ -2,14 +2,11 @@ namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Dept
{ {
public class DeptUpdateInputVo public class DeptUpdateInputVo
{ {
public Guid Id { get; set; }
public DateTime CreationTime { get; set; } = DateTime.Now;
public Guid? CreatorId { get; set; }
public bool State { get; set; } public bool State { get; set; }
public string DeptName { get; set; } = string.Empty; public string DeptName { get; set; } = string.Empty;
public string DeptCode { get; set; } = string.Empty; public string DeptCode { get; set; } = string.Empty;
public string? Leader { get; set; } public string? Leader { get; set; }
public Guid ParentId { get; set; } public Guid? ParentId { get; set; }=Guid.Empty;
public string? Remark { get; set; } public string? Remark { get; set; }
} }
} }

View File

@@ -7,22 +7,22 @@ export const getList = (data?: object) => {
}; };
/** 查询部门详细 */ /** 查询部门详细 */
export const getDept = id => { export const getPost = id => {
return http.request<Result>("get", `/dept/${id}`, {}); return http.request<Result>("get", `/dept/${id}`, {});
}; };
/** 新增部门 */ /** 新增部门 */
export const addDept = data => { export const addPost = data => {
return http.request<Result>("post", `/dept`, { data }); return http.request<Result>("post", `/dept`, { data });
}; };
/** 修改部门 */ /** 修改部门 */
export const updateDept = (id, data) => { export const updatePost = (id, data) => {
return http.request<Result>("put", `/dept/${id}`, { data }); return http.request<Result>("put", `/dept/${id}`, { data });
}; };
/** 删除部门 */ /** 删除部门 */
export const delDept = id => { export const delPost = id => {
return http.request<Result>("delete", `/dept`, { params: { id } }); return http.request<Result>("delete", `/dept`, { params: { id } });
}; };

View File

@@ -243,7 +243,10 @@ getCode();
<template v-slot:append> <template v-slot:append>
<img <img
:src="codeUrl" :src="codeUrl"
class="login-code-img" width="120"
height="40"
style="width: 120px; height: 40px"
class="cursor-pointer"
alt="" alt=""
@click="getCode" @click="getCode"
/> />

View File

@@ -7,14 +7,16 @@ import { usePublicHooks } from "../hooks";
const props = withDefaults(defineProps<FormProps>(), { const props = withDefaults(defineProps<FormProps>(), {
formInline: () => ({ formInline: () => ({
id: "",
deptCode: "",
higherDeptOptions: [], higherDeptOptions: [],
parentId: 0, parentId: "00000000-0000-0000-0000-000000000000",
name: "", deptName: "",
principal: "", leader: "",
phone: "", phone: "",
email: "", email: "",
sort: 0, orderNum: 0,
status: 1, state: true,
remark: "" remark: ""
}) })
}); });
@@ -46,7 +48,7 @@ defineExpose({ getRef });
:options="newFormInline.higherDeptOptions" :options="newFormInline.higherDeptOptions"
:props="{ :props="{
value: 'id', value: 'id',
label: 'name', label: 'deptName',
emitPath: false, emitPath: false,
checkStrictly: true checkStrictly: true
}" }"
@@ -55,7 +57,7 @@ defineExpose({ getRef });
placeholder="请选择上级部门" placeholder="请选择上级部门"
> >
<template #default="{ node, data }"> <template #default="{ node, data }">
<span>{{ data.name }}</span> <span>{{ data.deptName }}</span>
<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span> <span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
</template> </template>
</el-cascader> </el-cascader>
@@ -63,18 +65,29 @@ defineExpose({ getRef });
</re-col> </re-col>
<re-col :value="12" :xs="24" :sm="24"> <re-col :value="12" :xs="24" :sm="24">
<el-form-item label="部门名称" prop="name"> <el-form-item label="部门名称" prop="deptName">
<el-input <el-input
v-model="newFormInline.name" v-model="newFormInline.deptName"
clearable clearable
placeholder="请输入部门名称" placeholder="请输入部门名称"
/> />
</el-form-item> </el-form-item>
</re-col> </re-col>
<re-col :value="12" :xs="24" :sm="24">
<el-form-item label="部门编码" prop="deptCode">
<el-input
v-model="newFormInline.deptCode"
clearable
placeholder="请输入部门编码"
/>
</el-form-item>
</re-col>
<re-col :value="12" :xs="24" :sm="24"> <re-col :value="12" :xs="24" :sm="24">
<el-form-item label="部门负责人"> <el-form-item label="部门负责人">
<el-input <el-input
v-model="newFormInline.principal" v-model="newFormInline.leader"
clearable clearable
placeholder="请输入部门负责人" placeholder="请输入部门负责人"
/> />
@@ -103,7 +116,7 @@ defineExpose({ getRef });
<re-col :value="12" :xs="24" :sm="24"> <re-col :value="12" :xs="24" :sm="24">
<el-form-item label="排序"> <el-form-item label="排序">
<el-input-number <el-input-number
v-model="newFormInline.sort" v-model="newFormInline.orderNum"
class="!w-full" class="!w-full"
:min="0" :min="0"
:max="9999" :max="9999"
@@ -114,10 +127,10 @@ defineExpose({ getRef });
<re-col :value="12" :xs="24" :sm="24"> <re-col :value="12" :xs="24" :sm="24">
<el-form-item label="部门状态"> <el-form-item label="部门状态">
<el-switch <el-switch
v-model="newFormInline.status" v-model="newFormInline.state"
inline-prompt inline-prompt
:active-value="1" :active-value="true"
:inactive-value="0" :inactive-value="false"
active-text="启用" active-text="启用"
inactive-text="停用" inactive-text="停用"
:style="switchStyle" :style="switchStyle"

View File

@@ -38,21 +38,21 @@ const {
> >
<el-form-item label="部门名称:" prop="name"> <el-form-item label="部门名称:" prop="name">
<el-input <el-input
v-model="form.name" v-model="form.deptName"
placeholder="请输入部门名称" placeholder="请输入部门名称"
clearable clearable
class="!w-[180px]" class="!w-[180px]"
/> />
</el-form-item> </el-form-item>
<el-form-item label="状态:" prop="status"> <el-form-item label="状态:" prop="state">
<el-select <el-select
v-model="form.status" v-model="form.state"
placeholder="请选择状态" placeholder="请选择状态"
clearable clearable
class="!w-[180px]" class="!w-[180px]"
> >
<el-option label="启用" :value="1" /> <el-option label="启用" :value="true" />
<el-option label="停用" :value="0" /> <el-option label="停用" :value="false" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
@@ -71,7 +71,7 @@ const {
</el-form> </el-form>
<PureTableBar <PureTableBar
title="部门管理(仅演示,操作后不生效)" title="部门管理"
:columns="columns" :columns="columns"
:tableRef="tableRef?.getTableRef()" :tableRef="tableRef?.getTableRef()"
@refresh="onSearch" @refresh="onSearch"
@@ -127,7 +127,7 @@ const {
新增 新增
</el-button> </el-button>
<el-popconfirm <el-popconfirm
:title="`是否确认删除部门名称为${row.name}的这条数据`" :title="`是否确认删除部门名称为${row.deptName}的这条数据`"
@confirm="handleDelete(row)" @confirm="handleDelete(row)"
> >
<template #reference> <template #reference>

View File

@@ -2,17 +2,17 @@ import dayjs from "dayjs";
import editForm from "../form.vue"; import editForm from "../form.vue";
import { handleTree } from "@/utils/tree"; import { handleTree } from "@/utils/tree";
import { message } from "@/utils/message"; import { message } from "@/utils/message";
import { getDeptList } from "@/api/system";
import { usePublicHooks } from "../../hooks"; import { usePublicHooks } from "../../hooks";
import { addDialog } from "@/components/ReDialog"; import { addDialog } from "@/components/ReDialog";
import { reactive, ref, onMounted, h } from "vue"; import { reactive, ref, onMounted, h } from "vue";
import type { FormItemProps } from "../utils/types"; import type { FormItemProps } from "../utils/types";
import { cloneDeep, isAllEmpty, deviceDetection } from "@pureadmin/utils"; import { cloneDeep, isAllEmpty, deviceDetection } from "@pureadmin/utils";
import { addDept, delDept, getDeptList, updateDept } from "@/api/system/dept";
export function useDept() { export function useDept() {
const form = reactive({ const form = reactive({
name: "", deptName: "",
status: null state: true
}); });
const formRef = ref(); const formRef = ref();
@@ -23,31 +23,31 @@ export function useDept() {
const columns: TableColumnList = [ const columns: TableColumnList = [
{ {
label: "部门名称", label: "部门名称",
prop: "name", prop: "deptName",
width: 180, width: 180,
align: "left" align: "left"
}, },
{ {
label: "排序", label: "排序",
prop: "sort", prop: "orderNum",
minWidth: 70 minWidth: 70
}, },
{ {
label: "状态", label: "状态",
prop: "status", prop: "state",
minWidth: 100, minWidth: 100,
cellRenderer: ({ row, props }) => ( cellRenderer: ({ row, props }) => (
<el-tag size={props.size} style={tagStyle.value(row.status)}> <el-tag size={props.size} style={tagStyle.value(row.state)}>
{row.status === 1 ? "启用" : "停用"} {row.state === true ? "启用" : "停用"}
</el-tag> </el-tag>
) )
}, },
{ {
label: "创建时间", label: "创建时间",
minWidth: 200, minWidth: 200,
prop: "createTime", prop: "creationTime",
formatter: ({ createTime }) => formatter: ({ creationTime }) =>
dayjs(createTime).format("YYYY-MM-DD HH:mm:ss") dayjs(creationTime).format("YYYY-MM-DD HH:mm:ss")
}, },
{ {
label: "备注", label: "备注",
@@ -74,20 +74,18 @@ export function useDept() {
async function onSearch() { async function onSearch() {
loading.value = true; loading.value = true;
const { data } = await getDeptList(); // 这里是返回一维数组结构前端自行处理成树结构返回格式要求唯一id加父节点parentIdparentId取父节点id const data = (await getDeptList()).data.items; // 这里是返回一维数组结构前端自行处理成树结构返回格式要求唯一id加父节点parentIdparentId取父节点id
let newData = data; let newData = data;
if (!isAllEmpty(form.name)) { if (!isAllEmpty(form.deptName)) {
// 前端搜索部门名称 // 前端搜索部门名称
newData = newData.filter(item => item.name.includes(form.name)); newData = newData.filter(item => item.name.includes(form.deptName));
} }
if (!isAllEmpty(form.status)) { if (!isAllEmpty(form.state)) {
// 前端搜索状态 // 前端搜索状态
newData = newData.filter(item => item.status === form.status); newData = newData.filter(item => item.state === form.state);
} }
dataList.value = handleTree(newData); // 处理成树结构 dataList.value = handleTree(newData); // 处理成树结构
setTimeout(() => { loading.value = false;
loading.value = false;
}, 500);
} }
function formatHigherDeptOptions(treeList) { function formatHigherDeptOptions(treeList) {
@@ -107,15 +105,17 @@ export function useDept() {
title: `${title}部门`, title: `${title}部门`,
props: { props: {
formInline: { formInline: {
id: row?.id ?? "",
higherDeptOptions: formatHigherDeptOptions(cloneDeep(dataList.value)), higherDeptOptions: formatHigherDeptOptions(cloneDeep(dataList.value)),
parentId: row?.parentId ?? 0, parentId: row?.parentId ?? "00000000-0000-0000-0000-000000000000",
name: row?.name ?? "", deptName: row?.deptName ?? "",
principal: row?.principal ?? "", leader: row?.leader ?? "",
phone: row?.phone ?? "", phone: row?.phone ?? "",
email: row?.email ?? "", email: row?.email ?? "",
sort: row?.sort ?? 0, orderNum: row?.orderNum ?? 0,
status: row?.status ?? 1, state: row?.state ?? true,
remark: row?.remark ?? "" remark: row?.remark ?? "",
deptCode: row?.deptCode ?? ""
} }
}, },
width: "40%", width: "40%",
@@ -128,21 +128,22 @@ export function useDept() {
const FormRef = formRef.value.getRef(); const FormRef = formRef.value.getRef();
const curData = options.props.formInline as FormItemProps; const curData = options.props.formInline as FormItemProps;
function chores() { function chores() {
message(`${title}了部门名称为${curData.name}的这条数据`, { message(`${title}了部门名称为${curData.deptName}的这条数据`, {
type: "success" type: "success"
}); });
done(); // 关闭弹框 done(); // 关闭弹框
onSearch(); // 刷新表格数据 onSearch(); // 刷新表格数据
} }
FormRef.validate(valid => { FormRef.validate(async valid => {
if (valid) { if (valid) {
console.log("curData", curData);
// 表单规则校验通过 // 表单规则校验通过
if (title === "新增") { if (title === "新增") {
// 实际开发先调用新增接口,再进行下面操作 // 实际开发先调用新增接口,再进行下面操作
await addDept(curData);
chores(); chores();
} else { } else {
// 实际开发先调用修改接口,再进行下面操作 // 实际开发先调用修改接口,再进行下面操作
await updateDept(row.id, curData);
chores(); chores();
} }
} }
@@ -151,8 +152,9 @@ export function useDept() {
}); });
} }
function handleDelete(row) { async function handleDelete(row) {
message(`您删除了部门名称为${row.name}的这条数据`, { type: "success" }); await delDept([row.id]);
message(`您删除了部门名称为${row.deptName}的这条数据`, { type: "success" });
onSearch(); onSearch();
} }

View File

@@ -4,7 +4,8 @@ import { isPhone, isEmail } from "@pureadmin/utils";
/** 自定义表单规则校验 */ /** 自定义表单规则校验 */
export const formRules = reactive(<FormRules>{ export const formRules = reactive(<FormRules>{
name: [{ required: true, message: "部门名称为必填项", trigger: "blur" }], deptName: [{ required: true, message: "部门名称为必填项", trigger: "blur" }],
deptCode: [{ required: true, message: "部门编码为必填项", trigger: "blur" }],
phone: [ phone: [
{ {
validator: (rule, value, callback) => { validator: (rule, value, callback) => {

View File

@@ -1,13 +1,15 @@
interface FormItemProps { interface FormItemProps {
id: string;
higherDeptOptions: Record<string, unknown>[]; higherDeptOptions: Record<string, unknown>[];
parentId: number; parentId: string;
name: string; deptName: string;
principal: string; leader: string;
phone: string | number; phone: string | number;
email: string; email: string;
sort: number; orderNum: number;
status: number; state: boolean;
remark: string; remark: string;
deptCode: string;
} }
interface FormProps { interface FormProps {
formInline: FormItemProps; formInline: FormItemProps;

View File

@@ -14,33 +14,25 @@ import {
keepAliveOptions, keepAliveOptions,
hiddenTagOptions, hiddenTagOptions,
showParentOptions, showParentOptions,
frameLoadingOptions frameLoadingOptions,
isLinkOptions,
stateOptions
} from "./utils/enums"; } from "./utils/enums";
const props = withDefaults(defineProps<FormProps>(), { const props = withDefaults(defineProps<FormProps>(), {
formInline: () => ({ formInline: () => ({
menuType: 0, menuType: 0,
higherMenuOptions: [], higherMenuOptions: [],
parentId: 0, parentId: "00000000-0000-0000-0000-000000000000",
menuName: "", menuName: "",
name: "",
router: "", router: "",
component: "", component: "",
orderNum: 99, orderNum: 0,
redirect: "",
icon: "", icon: "",
extraIcon: "",
enterTransition: "",
leaveTransition: "",
activePath: "",
permissionCode: "", permissionCode: "",
frameSrc: "",
frameLoading: true,
keepAlive: false,
hiddenTag: false,
fixedTag: false,
isShow: true, isShow: true,
showParent: false isLink: false,
state: true
}) })
}); });
@@ -67,6 +59,7 @@ defineExpose({ getRef });
<Segmented <Segmented
v-model="newFormInline.menuType" v-model="newFormInline.menuType"
:options="menuTypeOptions" :options="menuTypeOptions"
@change="changeSegmented"
/> />
</el-form-item> </el-form-item>
</re-col> </re-col>
@@ -79,7 +72,7 @@ defineExpose({ getRef });
:options="newFormInline.higherMenuOptions" :options="newFormInline.higherMenuOptions"
:props="{ :props="{
value: 'id', value: 'id',
label: 'title', label: 'menuName',
emitPath: false, emitPath: false,
checkStrictly: true checkStrictly: true
}" }"
@@ -94,9 +87,18 @@ defineExpose({ getRef });
</el-cascader> </el-cascader>
</el-form-item> </el-form-item>
</re-col> </re-col>
<re-col
v-show="newFormInline.menuType !== 2"
:value="24"
:xs="24"
:sm="24"
>
<el-form-item label="菜单图标">
<IconSelect v-model="newFormInline.icon" class="w-full" />
</el-form-item>
</re-col>
<re-col :value="12" :xs="24" :sm="24"> <re-col :value="12" :xs="24" :sm="24">
<el-form-item label="菜单名称" prop="title"> <el-form-item label="菜单名称" prop="menuName">
<el-input <el-input
v-model="newFormInline.menuName" v-model="newFormInline.menuName"
clearable clearable
@@ -104,27 +106,40 @@ defineExpose({ getRef });
/> />
</el-form-item> </el-form-item>
</re-col> </re-col>
<re-col v-if="newFormInline.menuType !== 3" :value="12" :xs="24" :sm="24">
<el-form-item label="路由名称" prop="name"> <re-col :value="12" :xs="24" :sm="24">
<el-input <el-form-item label="菜单排序" prop="orderNum">
v-model="newFormInline.name" <el-input-number
clearable v-model="newFormInline.orderNum"
placeholder="请输入路由名称" class="!w-full"
:min="1"
:max="9999"
controls-position="right"
/> />
</el-form-item> </el-form-item>
</re-col> </re-col>
<re-col v-if="newFormInline.menuType !== 3" :value="12" :xs="24" :sm="24"> <re-col
<el-form-item label="路由路径" prop="router"> v-show="newFormInline.menuType !== 2"
<el-input :value="12"
v-model="newFormInline.router" :xs="24"
clearable :sm="24"
placeholder="请输入路由路径" >
<el-form-item label="是否为外链">
<Segmented
:modelValue="newFormInline.isLink ? false : true"
:options="isLinkOptions"
@change="
({ option: { value } }) => {
newFormInline.isLink = value;
}
"
/> />
</el-form-item> </el-form-item>
</re-col> </re-col>
<re-col <re-col
v-show="newFormInline.menuType === 0" v-show="newFormInline.menuType === 1"
:value="12" :value="12"
:xs="24" :xs="24"
:sm="24" :sm="24"
@@ -137,94 +152,21 @@ defineExpose({ getRef });
/> />
</el-form-item> </el-form-item>
</re-col> </re-col>
<re-col v-if="newFormInline.menuType !== 2" :value="12" :xs="24" :sm="24">
<re-col :value="12" :xs="24" :sm="24"> <el-form-item label="路由路径" prop="router">
<el-form-item label="菜单排序">
<el-input-number
v-model="newFormInline.rank"
class="!w-full"
:min="1"
:max="9999"
controls-position="right"
/>
</el-form-item>
</re-col>
<re-col
v-show="newFormInline.menuType === 0"
:value="12"
:xs="24"
:sm="24"
>
<el-form-item label="路由重定向">
<el-input <el-input
v-model="newFormInline.redirect" v-model="newFormInline.router"
clearable clearable
placeholder="请输入默认跳转地址" placeholder="请输入路由路径"
/> />
</el-form-item> </el-form-item>
</re-col> </re-col>
<re-col <re-col v-if="newFormInline.menuType !== 0" :value="12" :xs="24" :sm="24">
v-show="newFormInline.menuType !== 3"
:value="12"
:xs="24"
:sm="24"
>
<el-form-item label="菜单图标">
<IconSelect v-model="newFormInline.icon" class="w-full" />
</el-form-item>
</re-col>
<re-col
v-show="newFormInline.menuType !== 3"
:value="12"
:xs="24"
:sm="24"
>
<el-form-item label="右侧图标">
<el-input
v-model="newFormInline.extraIcon"
clearable
placeholder="菜单名称右侧的额外图标"
/>
</el-form-item>
</re-col>
<re-col v-show="newFormInline.menuType < 2" :value="12" :xs="24" :sm="24">
<el-form-item label="进场动画">
<ReAnimateSelector
v-model="newFormInline.enterTransition"
placeholder="请选择页面进场加载动画"
/>
</el-form-item>
</re-col>
<re-col v-show="newFormInline.menuType < 2" :value="12" :xs="24" :sm="24">
<el-form-item label="离场动画">
<ReAnimateSelector
v-model="newFormInline.leaveTransition"
placeholder="请选择页面离场加载动画"
/>
</el-form-item>
</re-col>
<re-col
v-show="newFormInline.menuType === 0"
:value="12"
:xs="24"
:sm="24"
>
<el-form-item label="菜单激活">
<el-input
v-model="newFormInline.activePath"
clearable
placeholder="请输入需要激活的菜单"
/>
</el-form-item>
</re-col>
<re-col v-if="newFormInline.menuType === 3" :value="12" :xs="24" :sm="24">
<!-- 按钮级别权限设置 --> <!-- 按钮级别权限设置 -->
<el-form-item label="权限标识" prop="orderNum"> <el-form-item label="权限标识" prop="permissionCode">
<el-input <el-input
v-model="newFormInline.orderNum" v-model="newFormInline.permissionCode"
clearable clearable
placeholder="请输入权限标识" placeholder="请输入权限标识"
/> />
@@ -232,41 +174,12 @@ defineExpose({ getRef });
</re-col> </re-col>
<re-col <re-col
v-show="newFormInline.menuType === 1" v-show="newFormInline.menuType !== 'Component'"
:value="12" :value="12"
:xs="24" :xs="24"
:sm="24" :sm="24"
> >
<!-- iframe --> <el-form-item label="是否显示">
<el-form-item label="链接地址">
<el-input
v-model="newFormInline.frameSrc"
clearable
placeholder="请输入 iframe 链接地址"
/>
</el-form-item>
</re-col>
<re-col v-if="newFormInline.menuType === 1" :value="12" :xs="24" :sm="24">
<el-form-item label="加载动画">
<Segmented
:modelValue="newFormInline.frameLoading ? 0 : 1"
:options="frameLoadingOptions"
@change="
({ option: { value } }) => {
newFormInline.frameLoading = value;
}
"
/>
</el-form-item>
</re-col>
<re-col
v-show="newFormInline.menuType !== 3"
:value="12"
:xs="24"
:sm="24"
>
<el-form-item label="菜单">
<Segmented <Segmented
:modelValue="newFormInline.isShow ? false : true" :modelValue="newFormInline.isShow ? false : true"
:options="showLinkOptions" :options="showLinkOptions"
@@ -278,60 +191,14 @@ defineExpose({ getRef });
/> />
</el-form-item> </el-form-item>
</re-col> </re-col>
<re-col <re-col :value="12" :xs="24" :sm="24">
v-show="newFormInline.menuType !== 3" <el-form-item label="是否启用">
:value="12"
:xs="24"
:sm="24"
>
<el-form-item label="父级菜单">
<Segmented <Segmented
:modelValue="newFormInline.showParent ? 0 : 1" :modelValue="newFormInline.state ? false : true"
:options="showParentOptions" :options="stateOptions"
@change=" @change="
({ option: { value } }) => { ({ option: { value } }) => {
newFormInline.showParent = value; newFormInline.state = value;
}
"
/>
</el-form-item>
</re-col>
<re-col v-show="newFormInline.menuType < 2" :value="12" :xs="24" :sm="24">
<el-form-item label="缓存页面">
<Segmented
:modelValue="newFormInline.keepAlive ? 0 : 1"
:options="keepAliveOptions"
@change="
({ option: { value } }) => {
newFormInline.keepAlive = value;
}
"
/>
</el-form-item>
</re-col>
<re-col v-show="newFormInline.menuType < 2" :value="12" :xs="24" :sm="24">
<el-form-item label="标签页">
<Segmented
:modelValue="newFormInline.hiddenTag ? 1 : 0"
:options="hiddenTagOptions"
@change="
({ option: { value } }) => {
newFormInline.hiddenTag = value;
}
"
/>
</el-form-item>
</re-col>
<re-col v-show="newFormInline.menuType < 2" :value="12" :xs="24" :sm="24">
<el-form-item label="固定标签页">
<Segmented
:modelValue="newFormInline.fixedTag ? 0 : 1"
:options="fixedTagOptions"
@change="
({ option: { value } }) => {
newFormInline.fixedTag = value;
} }
" "
/> />

View File

@@ -61,7 +61,7 @@ const {
</el-form> </el-form>
<PureTableBar <PureTableBar
title="菜单管理(仅演示,操作后不生效)" title="菜单管理"
:columns="columns" :columns="columns"
:isExpandAll="false" :isExpandAll="false"
:tableRef="tableRef?.getTableRef()" :tableRef="tableRef?.getTableRef()"
@@ -118,7 +118,7 @@ const {
新增 新增
</el-button> </el-button>
<el-popconfirm <el-popconfirm
:title="`是否确认删除菜单名称为${transformI18n(row.title)}的这条数据${row?.children?.length > 0 ? '。注意下级菜单也会一并删除,请谨慎操作' : ''}`" :title="`是否确认删除菜单名称为${transformI18n(row.menuName)}的这条数据${row?.children?.length > 0 ? '。注意下级菜单也会一并删除,请谨慎操作' : ''}`"
@confirm="handleDelete(row)" @confirm="handleDelete(row)"
> >
<template #reference> <template #reference>

View File

@@ -2,23 +2,42 @@ import type { OptionsType } from "@/components/ReSegmented";
const menuTypeOptions: Array<OptionsType> = [ const menuTypeOptions: Array<OptionsType> = [
{ {
label: "菜单", label: "目录",
value: 0 value: "Catalogue"
}, },
{ {
label: "iframe", label: "菜单",
value: 1 value: "Menu"
},
{
label: "组件",
value: "Component"
}
];
const stateOptions: Array<OptionsType> = [
{
label: "启用",
tip: "启用菜单",
value: true
},
{
label: "禁用",
tip: "禁用菜单",
value: false
}
];
const isLinkOptions: Array<OptionsType> = [
{
label: "非外链",
tip: "使用本地路由",
value: false
}, },
{ {
label: "外链", label: "外链",
value: 2 tip: "链接到其他地址",
}, value: true
{
label: "按钮",
value: 3
} }
]; ];
const showLinkOptions: Array<OptionsType> = [ const showLinkOptions: Array<OptionsType> = [
{ {
label: "显示", label: "显示",
@@ -104,5 +123,7 @@ export {
keepAliveOptions, keepAliveOptions,
hiddenTagOptions, hiddenTagOptions,
showParentOptions, showParentOptions,
frameLoadingOptions frameLoadingOptions,
isLinkOptions,
stateOptions
}; };

View File

@@ -1,13 +1,14 @@
import editForm from "../form.vue"; import editForm from "../form.vue";
import { handleTree } from "@/utils/tree"; import { handleTree } from "@/utils/tree";
import { message } from "@/utils/message"; import { message } from "@/utils/message";
import { getListMenu } from "@/api/system/menu"; import { addMenu, delMenu, getListMenu, updateMenu } from "@/api/system/menu";
import { transformI18n } from "@/plugins/i18n"; import { transformI18n } from "@/plugins/i18n";
import { addDialog } from "@/components/ReDialog"; import { addDialog } from "@/components/ReDialog";
import { reactive, ref, onMounted, h } from "vue"; import { reactive, ref, onMounted, h } from "vue";
import type { FormItemProps } from "../utils/types"; import type { FormItemProps } from "../utils/types";
import { useRenderIcon } from "@/components/ReIcon/src/hooks"; import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import { cloneDeep, isAllEmpty, deviceDetection } from "@pureadmin/utils"; import { cloneDeep, isAllEmpty, deviceDetection } from "@pureadmin/utils";
import { menuTypeOptions } from "@/views/system/menu/utils/enums";
export function useMenu() { export function useMenu() {
const form = reactive({ const form = reactive({
@@ -18,16 +19,14 @@ export function useMenu() {
const dataList = ref([]); const dataList = ref([]);
const loading = ref(true); const loading = ref(true);
const getMenuType = (type, text = false) => { const getMenuType = (type: string, text = false) => {
switch (type) { switch (type) {
case 0: case "Catalogue":
return text ? "菜单" : "primary"; return text ? "目录" : "primary";
case 1: case "Menu":
return text ? "iframe" : "warning"; return text ? "菜单" : "warning";
case 2: case "Component":
return text ? "外链" : "danger"; return text ? "组件" : "info";
case 3:
return text ? "按钮" : "info";
} }
}; };
@@ -129,33 +128,33 @@ export function useMenu() {
return newTreeList; return newTreeList;
} }
function openDialog(title = "新增", row?: FormItemProps) { async function openDialog(title = "新增", row?: FormItemProps) {
// let data: any = null;
// if (title == "修改") {
// data = await getMenu(row.id);
// }
addDialog({ addDialog({
title: `${title}菜单`, title: `${title}菜单`,
props: { props: {
formInline: { formInline: {
menuType: row?.menuType ?? 0, menuName: row?.menuName ?? "",
menuType:
row?.menuType == undefined
? 0
: menuTypeOptions.findIndex(
option => option.value === row?.menuType
),
higherMenuOptions: formatHigherMenuOptions(cloneDeep(dataList.value)), higherMenuOptions: formatHigherMenuOptions(cloneDeep(dataList.value)),
id: row?.id ?? "00000000-0000-0000-0000-000000000000",
parentId: row?.parentId ?? 0, parentId: row?.parentId ?? 0,
title: row?.menuName ?? "",
name: row?.name ?? "",
router: row?.router ?? "", router: row?.router ?? "",
component: row?.component ?? "", component: row?.component ?? "",
orderNum: row?.orderNum ?? 99, orderNum: row?.orderNum ?? 0,
redirect: row?.redirect ?? "",
icon: row?.icon ?? "", icon: row?.icon ?? "",
extraIcon: row?.extraIcon ?? "",
enterTransition: row?.enterTransition ?? "",
leaveTransition: row?.leaveTransition ?? "",
activePath: row?.activePath ?? "",
permissionCode: row?.permissionCode ?? "", permissionCode: row?.permissionCode ?? "",
frameSrc: row?.frameSrc ?? "",
frameLoading: row?.frameLoading ?? true,
keepAlive: row?.keepAlive ?? false,
hiddenTag: row?.hiddenTag ?? false,
fixedTag: row?.fixedTag ?? false,
showLink: row?.isShow ?? true, showLink: row?.isShow ?? true,
showParent: row?.showParent ?? false isLink: row?.isLink ?? false,
state: row?.state ?? true
} }
}, },
width: "45%", width: "45%",
@@ -177,15 +176,16 @@ export function useMenu() {
done(); // 关闭弹框 done(); // 关闭弹框
onSearch(); // 刷新表格数据 onSearch(); // 刷新表格数据
} }
FormRef.validate(valid => { FormRef.validate(async valid => {
if (valid) { if (valid) {
console.log("curData", curData);
// 表单规则校验通过 // 表单规则校验通过
if (title === "新增") { if (title === "新增") {
// 实际开发先调用新增接口,再进行下面操作 // 实际开发先调用新增接口,再进行下面操作
await addMenu(curData);
chores(); chores();
} else { } else {
// 实际开发先调用修改接口,再进行下面操作 // 实际开发先调用修改接口,再进行下面操作
await updateMenu(row.id, curData);
chores(); chores();
} }
} }
@@ -194,8 +194,9 @@ export function useMenu() {
}); });
} }
function handleDelete(row) { async function handleDelete(row) {
message(`您删除了菜单名称为${transformI18n(row.title)}的这条数据`, { await delMenu([row.id]);
message(`您删除了菜单名称为${transformI18n(row.menuName)}的这条数据`, {
type: "success" type: "success"
}); });
onSearch(); onSearch();

View File

@@ -6,6 +6,7 @@ export const formRules = reactive(<FormRules>{
menuName: [{ required: true, message: "菜单名称为必填项", trigger: "blur" }], menuName: [{ required: true, message: "菜单名称为必填项", trigger: "blur" }],
name: [{ required: true, message: "路由名称为必填项", trigger: "blur" }], name: [{ required: true, message: "路由名称为必填项", trigger: "blur" }],
router: [{ required: true, message: "路由路径为必填项", trigger: "blur" }], router: [{ required: true, message: "路由路径为必填项", trigger: "blur" }],
orderNum: [{ required: true, message: "菜单排序为必填项", trigger: "blur" }],
permissionCode: [ permissionCode: [
{ required: true, message: "权限标识为必填项", trigger: "blur" } { required: true, message: "权限标识为必填项", trigger: "blur" }
] ]

View File

@@ -1,27 +1,18 @@
interface FormItemProps { interface FormItemProps {
/** 菜单类型0代表菜单、1代表iframe、2代表外链、3代表按钮*/ /** 菜单类型0目录、1代表菜单、2代表组件*/
menuType: number; id?: string;
menuType: number | string;
higherMenuOptions: Record<string, unknown>[]; higherMenuOptions: Record<string, unknown>[];
parentId: number; parentId: string;
menuName: string; menuName: string;
name: string;
router: string; router: string;
component: string; component: string;
orderNum: number; orderNum: number;
redirect: string;
icon: string; icon: string;
extraIcon: string;
enterTransition: string;
leaveTransition: string;
activePath: string;
permissionCode: string; permissionCode: string;
frameSrc: string;
frameLoading: boolean;
keepAlive: boolean;
hiddenTag: boolean;
fixedTag: boolean;
isShow: boolean; isShow: boolean;
showParent: boolean; isLink: boolean;
state: boolean;
} }
interface FormProps { interface FormProps {
formInline: FormItemProps; formInline: FormItemProps;

View File

@@ -5,6 +5,7 @@ import { FormProps } from "./utils/types";
const props = withDefaults(defineProps<FormProps>(), { const props = withDefaults(defineProps<FormProps>(), {
formInline: () => ({ formInline: () => ({
id: "",
roleName: "", roleName: "",
roleCode: "", roleCode: "",
remark: "", remark: "",

View File

@@ -21,7 +21,16 @@ import {
} from "@/api/system/role"; } from "@/api/system/role";
import { getMenuOption } from "@/api/system/menu"; import { getMenuOption } from "@/api/system/menu";
import {type Ref, reactive, ref, onMounted, h, toRaw, watch, nextTick} from "vue"; import {
type Ref,
reactive,
ref,
onMounted,
h,
toRaw,
watch,
nextTick
} from "vue";
export function useRole(treeRef: Ref) { export function useRole(treeRef: Ref) {
const form = reactive({ const form = reactive({
@@ -44,7 +53,6 @@ export function useRole(treeRef: Ref) {
const isExpandAll = ref(false); const isExpandAll = ref(false);
const isSelectAll = ref(false); const isSelectAll = ref(false);
const { switchStyle } = usePublicHooks(); const { switchStyle } = usePublicHooks();
let currentRoleData: any = {};
const treeProps = { const treeProps = {
value: "id", value: "id",
label: "menuName", label: "menuName",
@@ -246,7 +254,6 @@ export function useRole(treeRef: Ref) {
nextTick(async () => { nextTick(async () => {
treeRef.value.setCheckedKeys(curRow.value.menuIds); treeRef.value.setCheckedKeys(curRow.value.menuIds);
}); });
} else { } else {
curRow.value = null; curRow.value = null;
isShow.value = false; isShow.value = false;