mirror of
				https://github.com/pure-admin/pure-admin-thin.git
				synced 2025-11-04 17:44:48 +08:00 
			
		
		
		
	perf: 系统管理
This commit is contained in:
		
							parent
							
								
									7443ac3ac4
								
							
						
					
					
						commit
						9bac6333fb
					
				@ -38,6 +38,7 @@ menus:
 | 
				
			|||||||
  hsRole: Role Manage
 | 
					  hsRole: Role Manage
 | 
				
			||||||
  hsSystemMenu: Menu Manage
 | 
					  hsSystemMenu: Menu Manage
 | 
				
			||||||
  hsDept: Dept Manage
 | 
					  hsDept: Dept Manage
 | 
				
			||||||
 | 
					  hsJob: Job Manage
 | 
				
			||||||
  hssysMonitor: System Monitor
 | 
					  hssysMonitor: System Monitor
 | 
				
			||||||
  hsOnlineUser: Online User
 | 
					  hsOnlineUser: Online User
 | 
				
			||||||
  hsLoginLog: Login Log
 | 
					  hsLoginLog: Login Log
 | 
				
			||||||
 | 
				
			|||||||
@ -35,9 +35,10 @@ menus:
 | 
				
			|||||||
  hsAbout: 关于
 | 
					  hsAbout: 关于
 | 
				
			||||||
  hssysManagement: 系统管理
 | 
					  hssysManagement: 系统管理
 | 
				
			||||||
  hsUser: 用户管理
 | 
					  hsUser: 用户管理
 | 
				
			||||||
  hsRole: 角色管理
 | 
					  hsRole: 权限管理
 | 
				
			||||||
  hsSystemMenu: 菜单管理
 | 
					  hsSystemMenu: 菜单管理
 | 
				
			||||||
  hsDept: 部门管理
 | 
					  hsDept: 部门管理
 | 
				
			||||||
 | 
					  hsJob: 角色管理
 | 
				
			||||||
  hssysMonitor: 系统监控
 | 
					  hssysMonitor: 系统监控
 | 
				
			||||||
  hsOnlineUser: 在线用户
 | 
					  hsOnlineUser: 在线用户
 | 
				
			||||||
  hsLoginLog: 登录日志
 | 
					  hsLoginLog: 登录日志
 | 
				
			||||||
 | 
				
			|||||||
@ -51,6 +51,15 @@ const systemManagementRouter = {
 | 
				
			|||||||
        title: "menus.hsDept",
 | 
					        title: "menus.hsDept",
 | 
				
			||||||
        roles: ["admin"]
 | 
					        roles: ["admin"]
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      path: "/system/job/index",
 | 
				
			||||||
 | 
					      name: "SystemJob",
 | 
				
			||||||
 | 
					      meta: {
 | 
				
			||||||
 | 
					        icon: "ri:account-circle-fill",
 | 
				
			||||||
 | 
					        title: "menus.hsDept",
 | 
				
			||||||
 | 
					        roles: ["admin"]
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  ]
 | 
					  ]
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										73
									
								
								src/api/system/dept.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								src/api/system/dept.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,73 @@
 | 
				
			|||||||
 | 
					import { http } from "@/utils/http";
 | 
				
			||||||
 | 
					import { PageQuery, type ApiAbstract } from "@/utils/http/ApiAbstract";
 | 
				
			||||||
 | 
					import { baseUrlApi } from "../utils";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class Dept {
 | 
				
			||||||
 | 
					  createBy: string;
 | 
				
			||||||
 | 
					  createTime: Date;
 | 
				
			||||||
 | 
					  deptSort: number;
 | 
				
			||||||
 | 
					  enabled: boolean;
 | 
				
			||||||
 | 
					  hasChildren: boolean;
 | 
				
			||||||
 | 
					  id: number;
 | 
				
			||||||
 | 
					  pid: number;
 | 
				
			||||||
 | 
					  status: number;
 | 
				
			||||||
 | 
					  label: string;
 | 
				
			||||||
 | 
					  leaf: boolean;
 | 
				
			||||||
 | 
					  name: string;
 | 
				
			||||||
 | 
					  subCount: number;
 | 
				
			||||||
 | 
					  updateBy: string;
 | 
				
			||||||
 | 
					  updateTime: Date;
 | 
				
			||||||
 | 
					  menus: any[];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export class DeptQueryCriteria extends PageQuery {
 | 
				
			||||||
 | 
					  name: string;
 | 
				
			||||||
 | 
					  enabled: boolean;
 | 
				
			||||||
 | 
					  pid: number;
 | 
				
			||||||
 | 
					  pidIsNull: boolean;
 | 
				
			||||||
 | 
					  createTime: Array<Date>;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getDepts = (params: DeptQueryCriteria | any) => {
 | 
				
			||||||
 | 
					  return http.request<ApiAbstract<Dept>>("get", baseUrlApi("dept"), {
 | 
				
			||||||
 | 
					    params
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export const getDeptTree = (params?: DeptQueryCriteria | any) => {
 | 
				
			||||||
 | 
					  return http.request<ApiAbstract<Dept>>("get", baseUrlApi("dept/treeAll"), {
 | 
				
			||||||
 | 
					    params
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getDeptSuperior = (ids: Number[]) => {
 | 
				
			||||||
 | 
					  const data = ids.length || ids.length === 0 ? ids : Array.of(ids);
 | 
				
			||||||
 | 
					  return http.request<ApiAbstract<Dept>>("post", baseUrlApi("dept/superior"), {
 | 
				
			||||||
 | 
					    data
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const add = (data: Partial<Dept>) => {
 | 
				
			||||||
 | 
					  return http.request<ApiAbstract<Dept>>("post", baseUrlApi("dept"), {
 | 
				
			||||||
 | 
					    data
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const del = (ids: number[] | any) => {
 | 
				
			||||||
 | 
					  return http.request("delete", baseUrlApi("dept"), {
 | 
				
			||||||
 | 
					    data: ids
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export const edit = (data: Partial<Dept>) => {
 | 
				
			||||||
 | 
					  return http.request<ApiAbstract<Dept>>("put", baseUrlApi("dept"), {
 | 
				
			||||||
 | 
					    data
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export const download = (data: Partial<DeptQueryCriteria>) => {
 | 
				
			||||||
 | 
					  return http.request<Blob>(
 | 
				
			||||||
 | 
					    "get",
 | 
				
			||||||
 | 
					    baseUrlApi("dept/download"),
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      data
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { responseType: "blob" }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										64
									
								
								src/api/system/job.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								src/api/system/job.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,64 @@
 | 
				
			|||||||
 | 
					import { http } from "@/utils/http";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  type ApiAbstract,
 | 
				
			||||||
 | 
					  type Page,
 | 
				
			||||||
 | 
					  PageQuery,
 | 
				
			||||||
 | 
					  VersionEntity
 | 
				
			||||||
 | 
					} from "@/utils/http/ApiAbstract";
 | 
				
			||||||
 | 
					import { baseUrlApi } from "../utils";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class Job extends VersionEntity {
 | 
				
			||||||
 | 
					  id: number;
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 岗位名称
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  name: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 岗位排序
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  jobSort: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 是否启用
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  enabled: boolean;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export class JobQueryCriteria extends PageQuery {
 | 
				
			||||||
 | 
					  name: string;
 | 
				
			||||||
 | 
					  enabled: boolean;
 | 
				
			||||||
 | 
					  createTime: Date[];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const get = (params?: number | any) => {
 | 
				
			||||||
 | 
					  return http.request<ApiAbstract<Page<Job>>>("get", baseUrlApi("job"), {
 | 
				
			||||||
 | 
					    params
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const add = (data: Partial<Job>) => {
 | 
				
			||||||
 | 
					  return http.request("post", baseUrlApi("job"), {
 | 
				
			||||||
 | 
					    data
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const del = (ids: number[] | any) => {
 | 
				
			||||||
 | 
					  return http.request("delete", baseUrlApi("job"), {
 | 
				
			||||||
 | 
					    data: ids
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export const edit = (data: Partial<Job>) => {
 | 
				
			||||||
 | 
					  return http.request("put", baseUrlApi("job"), {
 | 
				
			||||||
 | 
					    data
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export const download = (data: Partial<JobQueryCriteria>) => {
 | 
				
			||||||
 | 
					  return http.request<Blob>(
 | 
				
			||||||
 | 
					    "get",
 | 
				
			||||||
 | 
					    baseUrlApi("job/download"),
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      data
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { responseType: "blob" }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										78
									
								
								src/api/system/menu.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/api/system/menu.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,78 @@
 | 
				
			|||||||
 | 
					import { http } from "@/utils/http";
 | 
				
			||||||
 | 
					import { PageQuery, type ApiAbstract } from "@/utils/http/ApiAbstract";
 | 
				
			||||||
 | 
					import { baseUrlApi } from "../utils";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class Menu {
 | 
				
			||||||
 | 
					  id: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  children: Menu[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  type: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  permission: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  title: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  menuSort: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  path: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  component: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  pid: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  subCount: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  iframe: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  cache: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  hidden: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  componentName: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  icon: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export class MenuQueryCriteria extends PageQuery {
 | 
				
			||||||
 | 
					  blurry: string;
 | 
				
			||||||
 | 
					  pid: number;
 | 
				
			||||||
 | 
					  createTime: Date[];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export const menuTree = (ids: number[]) => {
 | 
				
			||||||
 | 
					  return http.request<ApiAbstract<Menu>>("post", baseUrlApi("menus/tree"), {
 | 
				
			||||||
 | 
					    data: ids
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const get = (params: number | any) => {
 | 
				
			||||||
 | 
					  return http.request<ApiAbstract<Menu>>("get", baseUrlApi("menus"), {
 | 
				
			||||||
 | 
					    params
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const add = (data: Partial<Menu>) => {
 | 
				
			||||||
 | 
					  return http.request("post", baseUrlApi("menus"), {
 | 
				
			||||||
 | 
					    data
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const del = (ids: number[] | any) => {
 | 
				
			||||||
 | 
					  return http.request("delete", baseUrlApi("menus"), {
 | 
				
			||||||
 | 
					    data: ids
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export const edit = (data: Partial<Menu>) => {
 | 
				
			||||||
 | 
					  return http.request<ApiAbstract<Menu>>("put", baseUrlApi("menus"), {
 | 
				
			||||||
 | 
					    data
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export const download = (data: Partial<MenuQueryCriteria>) => {
 | 
				
			||||||
 | 
					  return http.request<Blob>(
 | 
				
			||||||
 | 
					    "get",
 | 
				
			||||||
 | 
					    baseUrlApi("menus/download"),
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      data
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { responseType: "blob" }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										90
									
								
								src/api/system/role.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								src/api/system/role.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,90 @@
 | 
				
			|||||||
 | 
					import { http } from "@/utils/http";
 | 
				
			||||||
 | 
					import { type ApiAbstract, PageQuery } from "@/utils/http/ApiAbstract";
 | 
				
			||||||
 | 
					import { baseUrlApi } from "../utils";
 | 
				
			||||||
 | 
					import type { Dept } from "./dept";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class Role {
 | 
				
			||||||
 | 
					  id: number;
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 用户
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  users: any;
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 菜单
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  menus: any;
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 部门
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  depts: Dept[] | any[];
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 名称
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  name: string;
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 数据权限,全部 、 本级 、 自定义
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  dataScope: string;
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 级别,数值越小,级别越大
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  level: number;
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 描述
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  description: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export class RoleQueryCriteria extends PageQuery {
 | 
				
			||||||
 | 
					  blurry: string;
 | 
				
			||||||
 | 
					  createTime: Date[];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export const getAll = (data: Partial<RoleQueryCriteria>) => {
 | 
				
			||||||
 | 
					  return http.request<Role[]>("get", baseUrlApi("roles/all"), {
 | 
				
			||||||
 | 
					    data
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const get = (params?: number | any) => {
 | 
				
			||||||
 | 
					  return http.request<ApiAbstract<Role>>("get", baseUrlApi("roles"), {
 | 
				
			||||||
 | 
					    params
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getLevel = () => {
 | 
				
			||||||
 | 
					  return http.request("get", baseUrlApi("roles/level"));
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const editMenu = data => {
 | 
				
			||||||
 | 
					  return http.request("put", baseUrlApi("roles/menu"), { data });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export const add = (data: Partial<Role>) => {
 | 
				
			||||||
 | 
					  return http.request("post", baseUrlApi("roles"), {
 | 
				
			||||||
 | 
					    data
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const del = (ids: number[] | any) => {
 | 
				
			||||||
 | 
					  return http.request("delete", baseUrlApi("roles"), {
 | 
				
			||||||
 | 
					    data: ids
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export const edit = (data: Partial<Role>) => {
 | 
				
			||||||
 | 
					  return http.request<ApiAbstract<Role>>("put", baseUrlApi("roles"), {
 | 
				
			||||||
 | 
					    data
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export const menus = (data: Partial<Dept>) => {
 | 
				
			||||||
 | 
					  return http.request("put", baseUrlApi("roles/menu"), {
 | 
				
			||||||
 | 
					    data
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export const download = (data: Partial<RoleQueryCriteria>) => {
 | 
				
			||||||
 | 
					  return http.request<Blob>(
 | 
				
			||||||
 | 
					    "get",
 | 
				
			||||||
 | 
					    baseUrlApi("roles/download"),
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      data
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { responseType: "blob" }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										158
									
								
								src/api/system/user.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								src/api/system/user.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,158 @@
 | 
				
			|||||||
 | 
					import { http } from "@/utils/http";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  type ApiAbstract,
 | 
				
			||||||
 | 
					  PageQuery,
 | 
				
			||||||
 | 
					  VersionEntity
 | 
				
			||||||
 | 
					} from "@/utils/http/ApiAbstract";
 | 
				
			||||||
 | 
					import { baseUrlApi } from "../utils";
 | 
				
			||||||
 | 
					import type { Role } from "./role";
 | 
				
			||||||
 | 
					import type { Job } from "./job";
 | 
				
			||||||
 | 
					import type { Dept } from "./dept";
 | 
				
			||||||
 | 
					import { encrypt } from "@/utils/rsaEncrypt";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class User extends VersionEntity {
 | 
				
			||||||
 | 
					  id: number;
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 用户角色
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  roles: Role[];
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 用户岗位
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  jobs: Job[];
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 用户部门
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  dept: Dept;
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 用户名称
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  username: string;
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 用户昵称
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  nickName: string;
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 邮箱
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  email: string;
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 电话号码
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  phone: string;
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 用户性别
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  gender: string;
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 头像真实名称
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  avatarName: string;
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 头像存储的路径
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  avatarPath: string;
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 密码
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  password: string;
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 是否启用
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  enabled: string;
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 是否为admin账号
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  isAdmin: boolean;
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 最后修改密码的时间
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  pwdResetTime: Date;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export class UserQueryCriteria extends PageQuery {
 | 
				
			||||||
 | 
					  name: string;
 | 
				
			||||||
 | 
					  deptId: number;
 | 
				
			||||||
 | 
					  deptIds: number[];
 | 
				
			||||||
 | 
					  enabled: boolean;
 | 
				
			||||||
 | 
					  createTime: Date[];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const get = (params: number | any) => {
 | 
				
			||||||
 | 
					  return http.request<ApiAbstract<User>>("get", baseUrlApi("users"), {
 | 
				
			||||||
 | 
					    params
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const add = (data: Partial<User>) => {
 | 
				
			||||||
 | 
					  return http.request("post", baseUrlApi("users"), {
 | 
				
			||||||
 | 
					    data
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const del = (ids: number[] | any) => {
 | 
				
			||||||
 | 
					  return http.request("delete", baseUrlApi("users"), {
 | 
				
			||||||
 | 
					    data: ids
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export const edit = (data: Partial<User>) => {
 | 
				
			||||||
 | 
					  return http.request("put", baseUrlApi("users"), {
 | 
				
			||||||
 | 
					    data
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export const download = (data: Partial<UserQueryCriteria>) => {
 | 
				
			||||||
 | 
					  return http.request<Blob>(
 | 
				
			||||||
 | 
					    "get",
 | 
				
			||||||
 | 
					    baseUrlApi("users/download"),
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      data
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { responseType: "blob" }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const updateAvatarByid = ({ id, avatar }) => {
 | 
				
			||||||
 | 
					  const formData = new FormData();
 | 
				
			||||||
 | 
					  formData.append("avatar", avatar, "avatar.jpg");
 | 
				
			||||||
 | 
					  return http.request("post", baseUrlApi("/users/updateAvatar/" + id), {
 | 
				
			||||||
 | 
					    data: formData,
 | 
				
			||||||
 | 
					    // 请求超时时间
 | 
				
			||||||
 | 
					    timeout: 60000,
 | 
				
			||||||
 | 
					    headers: {
 | 
				
			||||||
 | 
					      "Content-Type": "multipart/form-data",
 | 
				
			||||||
 | 
					      filename: "avatar.png"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function updatePass({ oldPass, newPass }) {
 | 
				
			||||||
 | 
					  const data = {
 | 
				
			||||||
 | 
					    oldPass: encrypt(oldPass),
 | 
				
			||||||
 | 
					    newPass: encrypt(newPass)
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  return http.request("post", baseUrlApi("users/updatePass"), {
 | 
				
			||||||
 | 
					    data
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function resetEmail(data) {
 | 
				
			||||||
 | 
					  return http.request("post", baseUrlApi("/code/resetEmail?email=" + data));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function updateEmail(form) {
 | 
				
			||||||
 | 
					  const data = {
 | 
				
			||||||
 | 
					    password: encrypt(form.pass),
 | 
				
			||||||
 | 
					    email: form.email
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  return http.request("post", baseUrlApi("users/updateEmail/" + form.code), {
 | 
				
			||||||
 | 
					    data
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export function editUser(data) {
 | 
				
			||||||
 | 
					  return http.request("put", baseUrlApi("users/center"), {
 | 
				
			||||||
 | 
					    data
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function getLog() {
 | 
				
			||||||
 | 
					  return http.request("get", baseUrlApi("logs/user"));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										53
									
								
								src/views/components/date-picker.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/views/components/date-picker.vue
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					<script setup lang="tsx">
 | 
				
			||||||
 | 
					import { ref } from "vue";
 | 
				
			||||||
 | 
					const props = defineProps({
 | 
				
			||||||
 | 
					  createTime: {
 | 
				
			||||||
 | 
					    type: String,
 | 
				
			||||||
 | 
					    default: ""
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const createTime = ref(props.createTime);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const shortcuts = [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    text: "最近1周",
 | 
				
			||||||
 | 
					    value: () => {
 | 
				
			||||||
 | 
					      const end = new Date();
 | 
				
			||||||
 | 
					      const start = new Date();
 | 
				
			||||||
 | 
					      start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
 | 
				
			||||||
 | 
					      return [start, end];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    text: "最近1个月",
 | 
				
			||||||
 | 
					    value: () => {
 | 
				
			||||||
 | 
					      const end = new Date();
 | 
				
			||||||
 | 
					      const start = new Date();
 | 
				
			||||||
 | 
					      start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
 | 
				
			||||||
 | 
					      return [start, end];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    text: "最近3个月",
 | 
				
			||||||
 | 
					    value: () => {
 | 
				
			||||||
 | 
					      const end = new Date();
 | 
				
			||||||
 | 
					      const start = new Date();
 | 
				
			||||||
 | 
					      start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
 | 
				
			||||||
 | 
					      return [start, end];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <el-date-picker
 | 
				
			||||||
 | 
					    v-model="createTime"
 | 
				
			||||||
 | 
					    type="datetimerange"
 | 
				
			||||||
 | 
					    :shortcuts="shortcuts"
 | 
				
			||||||
 | 
					    range-separator="-"
 | 
				
			||||||
 | 
					    start-placeholder="开始时间"
 | 
				
			||||||
 | 
					    end-placeholder="结束时间"
 | 
				
			||||||
 | 
					    value-format="YYYY-MM-DD h:m:s"
 | 
				
			||||||
 | 
					  />
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
@ -58,7 +58,7 @@ const { locale, translationCh, translationEn } = useTranslationLang();
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const ruleForm = reactive({
 | 
					const ruleForm = reactive({
 | 
				
			||||||
  username: "admin",
 | 
					  username: "admin",
 | 
				
			||||||
  password: "admin123",
 | 
					  password: "123456",
 | 
				
			||||||
  verifyCode: ""
 | 
					  verifyCode: ""
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import { ref } from "vue";
 | 
					import { ref, onMounted } from "vue";
 | 
				
			||||||
import ReCol from "@/components/ReCol";
 | 
					import ReCol from "@/components/ReCol";
 | 
				
			||||||
import { formRules } from "./utils/rule";
 | 
					import { formRules } from "./utils/rule";
 | 
				
			||||||
import { FormProps } from "./utils/types";
 | 
					import { FormProps } from "./utils/types";
 | 
				
			||||||
@ -8,13 +8,17 @@ import { usePublicHooks } from "../hooks";
 | 
				
			|||||||
const props = withDefaults(defineProps<FormProps>(), {
 | 
					const props = withDefaults(defineProps<FormProps>(), {
 | 
				
			||||||
  formInline: () => ({
 | 
					  formInline: () => ({
 | 
				
			||||||
    higherDeptOptions: [],
 | 
					    higherDeptOptions: [],
 | 
				
			||||||
 | 
					    higherDeptOptions2: {},
 | 
				
			||||||
    parentId: 0,
 | 
					    parentId: 0,
 | 
				
			||||||
 | 
					    id: 0,
 | 
				
			||||||
 | 
					    pid: 0,
 | 
				
			||||||
 | 
					    deptSort: 0,
 | 
				
			||||||
 | 
					    enabled: false,
 | 
				
			||||||
    name: "",
 | 
					    name: "",
 | 
				
			||||||
    principal: "",
 | 
					    principal: "",
 | 
				
			||||||
    phone: "",
 | 
					    phone: "",
 | 
				
			||||||
    email: "",
 | 
					    email: "",
 | 
				
			||||||
    sort: 0,
 | 
					    sort: 0,
 | 
				
			||||||
    status: 1,
 | 
					 | 
				
			||||||
    remark: ""
 | 
					    remark: ""
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
@ -26,7 +30,9 @@ const newFormInline = ref(props.formInline);
 | 
				
			|||||||
function getRef() {
 | 
					function getRef() {
 | 
				
			||||||
  return ruleFormRef.value;
 | 
					  return ruleFormRef.value;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					onMounted(() => {
 | 
				
			||||||
 | 
					  // 在这里编写页面加载后要执行的代码
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
defineExpose({ getRef });
 | 
					defineExpose({ getRef });
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -41,22 +47,16 @@ defineExpose({ getRef });
 | 
				
			|||||||
      <re-col>
 | 
					      <re-col>
 | 
				
			||||||
        <el-form-item label="上级部门">
 | 
					        <el-form-item label="上级部门">
 | 
				
			||||||
          <el-cascader
 | 
					          <el-cascader
 | 
				
			||||||
            v-model="newFormInline.parentId"
 | 
					            v-model="newFormInline.pid"
 | 
				
			||||||
            class="w-full"
 | 
					            class="w-full"
 | 
				
			||||||
            :options="newFormInline.higherDeptOptions"
 | 
					            :props="newFormInline.higherDeptOptions2"
 | 
				
			||||||
            :props="{
 | 
					 | 
				
			||||||
              value: 'id',
 | 
					 | 
				
			||||||
              label: 'name',
 | 
					 | 
				
			||||||
              emitPath: false,
 | 
					 | 
				
			||||||
              checkStrictly: true
 | 
					 | 
				
			||||||
            }"
 | 
					 | 
				
			||||||
            clearable
 | 
					            clearable
 | 
				
			||||||
            filterable
 | 
					            filterable
 | 
				
			||||||
            placeholder="请选择上级部门"
 | 
					            placeholder="请选择上级部门"
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            <template #default="{ node, data }">
 | 
					            <template #default="{ node, data }">
 | 
				
			||||||
              <span>{{ data.name }}</span>
 | 
					              <span>{{ data.label }}</span>
 | 
				
			||||||
              <span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
 | 
					              <span v-if="!node.isLeaf"> ({{ data.subCount }}) </span>
 | 
				
			||||||
            </template>
 | 
					            </template>
 | 
				
			||||||
          </el-cascader>
 | 
					          </el-cascader>
 | 
				
			||||||
        </el-form-item>
 | 
					        </el-form-item>
 | 
				
			||||||
@ -103,8 +103,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.deptSort"
 | 
				
			||||||
            class="!w-full"
 | 
					 | 
				
			||||||
            :min="0"
 | 
					            :min="0"
 | 
				
			||||||
            :max="9999"
 | 
					            :max="9999"
 | 
				
			||||||
            controls-position="right"
 | 
					            controls-position="right"
 | 
				
			||||||
@ -114,10 +113,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.enabled"
 | 
				
			||||||
            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"
 | 
				
			||||||
 | 
				
			|||||||
@ -3,28 +3,94 @@ import { ref } from "vue";
 | 
				
			|||||||
import { useDept } from "./utils/hook";
 | 
					import { useDept } from "./utils/hook";
 | 
				
			||||||
import { PureTableBar } from "@/components/RePureTableBar";
 | 
					import { PureTableBar } from "@/components/RePureTableBar";
 | 
				
			||||||
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 | 
					import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 | 
				
			||||||
 | 
					import datePicker from "@/views/components/date-picker.vue";
 | 
				
			||||||
 | 
					import * as Dept from "@/api/system/dept";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import Delete from "@iconify-icons/ep/delete";
 | 
					import Delete from "@iconify-icons/ep/delete";
 | 
				
			||||||
import EditPen from "@iconify-icons/ep/edit-pen";
 | 
					import EditPen from "@iconify-icons/ep/edit-pen";
 | 
				
			||||||
import Refresh from "@iconify-icons/ep/refresh";
 | 
					import Refresh from "@iconify-icons/ep/refresh";
 | 
				
			||||||
import AddFill from "@iconify-icons/ri/add-circle-line";
 | 
					import AddFill from "@iconify-icons/ri/add-circle-line";
 | 
				
			||||||
 | 
					import { message } from "@/utils/message";
 | 
				
			||||||
 | 
					import { ElMessageBox } from "element-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
defineOptions({
 | 
					defineOptions({
 | 
				
			||||||
  name: "SystemDept"
 | 
					  name: "Dept"
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const handleSelectionChange = val => {
 | 
				
			||||||
 | 
					  multipleSelection.value = val;
 | 
				
			||||||
 | 
					  if (val != null && val.length > 0) {
 | 
				
			||||||
 | 
					    value2.value = false;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    value2.value = true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function deleteAll() {
 | 
				
			||||||
 | 
					  ElMessageBox.confirm(
 | 
				
			||||||
 | 
					    `确认要<strong>删除所选的</strong><strong style='color:var(--el-color-primary)'>${multipleSelection.value.length}</strong>个部门吗?`,
 | 
				
			||||||
 | 
					    "系统提示",
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      confirmButtonText: "确定",
 | 
				
			||||||
 | 
					      cancelButtonText: "取消",
 | 
				
			||||||
 | 
					      type: "warning",
 | 
				
			||||||
 | 
					      dangerouslyUseHTMLString: true,
 | 
				
			||||||
 | 
					      draggable: true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					    .then(() => {
 | 
				
			||||||
 | 
					      Dept.del(multipleSelection.value.map(dept => dept.id));
 | 
				
			||||||
 | 
					      message("已删除所选的部门", {
 | 
				
			||||||
 | 
					        type: "success"
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      onSearch();
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .catch(() => {
 | 
				
			||||||
 | 
					      onSearch();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					const load = (
 | 
				
			||||||
 | 
					  row: Partial<Dept.Dept>,
 | 
				
			||||||
 | 
					  treeNode: unknown,
 | 
				
			||||||
 | 
					  resolve: (date: Partial<Dept.Dept>[]) => void
 | 
				
			||||||
 | 
					) => {
 | 
				
			||||||
 | 
					  let queryDept = { pid: row?.id };
 | 
				
			||||||
 | 
					  if (!row?.id) {
 | 
				
			||||||
 | 
					    queryDept = null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  Dept.getDepts(queryDept).then(contentData => {
 | 
				
			||||||
 | 
					    // 调用' resolve '回调以返回子节点数据并指示加载完成。
 | 
				
			||||||
 | 
					    resolve(contentData.data.content);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					const exportClick = async () => {
 | 
				
			||||||
 | 
					  const response: Blob = await Dept.download(null);
 | 
				
			||||||
 | 
					  const a = document.createElement("a");
 | 
				
			||||||
 | 
					  const url = window.URL.createObjectURL(response); // 创建媒体流 url ,详细了解可自己查 URL.createObjectURL(推荐 MDN )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  a.href = url;
 | 
				
			||||||
 | 
					  a.style.display = "none";
 | 
				
			||||||
 | 
					  document.body.appendChild(a);
 | 
				
			||||||
 | 
					  a.click();
 | 
				
			||||||
 | 
					  a.parentNode.removeChild(a);
 | 
				
			||||||
 | 
					  window.URL.revokeObjectURL(url); // 删除创建的媒体流 url 对象
 | 
				
			||||||
 | 
					  message("导出成功", {
 | 
				
			||||||
 | 
					    type: "success"
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
const formRef = ref();
 | 
					const formRef = ref();
 | 
				
			||||||
const tableRef = ref();
 | 
					const tableRef = ref();
 | 
				
			||||||
 | 
					const value2 = ref(true);
 | 
				
			||||||
const {
 | 
					const {
 | 
				
			||||||
  form,
 | 
					  form,
 | 
				
			||||||
  loading,
 | 
					  loading,
 | 
				
			||||||
  columns,
 | 
					  columns,
 | 
				
			||||||
  dataList,
 | 
					  dataList,
 | 
				
			||||||
 | 
					  multipleSelection,
 | 
				
			||||||
  onSearch,
 | 
					  onSearch,
 | 
				
			||||||
  resetForm,
 | 
					  resetForm,
 | 
				
			||||||
  openDialog,
 | 
					  openDialog,
 | 
				
			||||||
  handleDelete,
 | 
					  handleDelete
 | 
				
			||||||
  handleSelectionChange
 | 
					 | 
				
			||||||
} = useDept();
 | 
					} = useDept();
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -41,24 +107,27 @@ const {
 | 
				
			|||||||
          v-model="form.name"
 | 
					          v-model="form.name"
 | 
				
			||||||
          placeholder="请输入部门名称"
 | 
					          placeholder="请输入部门名称"
 | 
				
			||||||
          clearable
 | 
					          clearable
 | 
				
			||||||
          class="!w-[180px]"
 | 
					          class="!w-[200px]"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </el-form-item>
 | 
					      </el-form-item>
 | 
				
			||||||
      <el-form-item label="状态:" prop="status">
 | 
					      <el-form-item label="状态:" prop="status">
 | 
				
			||||||
        <el-select
 | 
					        <el-select
 | 
				
			||||||
          v-model="form.status"
 | 
					          v-model="form.enabled"
 | 
				
			||||||
          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 label="" prop="createTime">
 | 
				
			||||||
 | 
					        <datePicker v-model="form.createTime" />
 | 
				
			||||||
 | 
					      </el-form-item>
 | 
				
			||||||
      <el-form-item>
 | 
					      <el-form-item>
 | 
				
			||||||
        <el-button
 | 
					        <el-button
 | 
				
			||||||
          type="primary"
 | 
					          type="primary"
 | 
				
			||||||
          :icon="useRenderIcon('ri:search-line')"
 | 
					          :icon="useRenderIcon('search')"
 | 
				
			||||||
          :loading="loading"
 | 
					          :loading="loading"
 | 
				
			||||||
          @click="onSearch"
 | 
					          @click="onSearch"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
@ -71,12 +140,12 @@ const {
 | 
				
			|||||||
    </el-form>
 | 
					    </el-form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <PureTableBar
 | 
					    <PureTableBar
 | 
				
			||||||
      title="部门管理(仅演示,操作后不生效)"
 | 
					      title="部门列表"
 | 
				
			||||||
      :columns="columns"
 | 
					      :columns="columns"
 | 
				
			||||||
      :tableRef="tableRef?.getTableRef()"
 | 
					      :tableRef="tableRef?.getTableRef()"
 | 
				
			||||||
      @refresh="onSearch"
 | 
					      @refresh="onSearch"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <template #buttons>
 | 
					      <template #add>
 | 
				
			||||||
        <el-button
 | 
					        <el-button
 | 
				
			||||||
          type="primary"
 | 
					          type="primary"
 | 
				
			||||||
          :icon="useRenderIcon(AddFill)"
 | 
					          :icon="useRenderIcon(AddFill)"
 | 
				
			||||||
@ -85,11 +154,30 @@ const {
 | 
				
			|||||||
          新增部门
 | 
					          新增部门
 | 
				
			||||||
        </el-button>
 | 
					        </el-button>
 | 
				
			||||||
      </template>
 | 
					      </template>
 | 
				
			||||||
 | 
					      <template #delete>
 | 
				
			||||||
 | 
					        <el-button
 | 
				
			||||||
 | 
					          type="danger"
 | 
				
			||||||
 | 
					          :disabled="value2"
 | 
				
			||||||
 | 
					          :icon="useRenderIcon(Delete)"
 | 
				
			||||||
 | 
					          @click="deleteAll()"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          删除部门
 | 
				
			||||||
 | 
					        </el-button>
 | 
				
			||||||
 | 
					      </template>
 | 
				
			||||||
 | 
					      <template #export>
 | 
				
			||||||
 | 
					        <el-button
 | 
				
			||||||
 | 
					          type="success"
 | 
				
			||||||
 | 
					          :icon="useRenderIcon('solar:upload-bold')"
 | 
				
			||||||
 | 
					          @click="exportClick()"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          导出数据
 | 
				
			||||||
 | 
					        </el-button>
 | 
				
			||||||
 | 
					      </template>
 | 
				
			||||||
      <template v-slot="{ size, dynamicColumns }">
 | 
					      <template v-slot="{ size, dynamicColumns }">
 | 
				
			||||||
        <pure-table
 | 
					        <pure-table
 | 
				
			||||||
          ref="tableRef"
 | 
					          ref="tableRef"
 | 
				
			||||||
          adaptive
 | 
					          adaptive
 | 
				
			||||||
          :adaptiveConfig="{ offsetBottom: 45 }"
 | 
					          :adaptiveConfig="{ offsetBottom: 32 }"
 | 
				
			||||||
          align-whole="center"
 | 
					          align-whole="center"
 | 
				
			||||||
          row-key="id"
 | 
					          row-key="id"
 | 
				
			||||||
          showOverflowTooltip
 | 
					          showOverflowTooltip
 | 
				
			||||||
@ -97,12 +185,14 @@ const {
 | 
				
			|||||||
          default-expand-all
 | 
					          default-expand-all
 | 
				
			||||||
          :loading="loading"
 | 
					          :loading="loading"
 | 
				
			||||||
          :size="size"
 | 
					          :size="size"
 | 
				
			||||||
          :data="dataList"
 | 
					 | 
				
			||||||
          :columns="dynamicColumns"
 | 
					          :columns="dynamicColumns"
 | 
				
			||||||
 | 
					          :data="dataList"
 | 
				
			||||||
          :header-cell-style="{
 | 
					          :header-cell-style="{
 | 
				
			||||||
            background: 'var(--el-fill-color-light)',
 | 
					            background: 'var(--el-fill-color-light)',
 | 
				
			||||||
            color: 'var(--el-text-color-primary)'
 | 
					            color: 'var(--el-text-color-primary)'
 | 
				
			||||||
          }"
 | 
					          }"
 | 
				
			||||||
 | 
					          lazy
 | 
				
			||||||
 | 
					          :load="load"
 | 
				
			||||||
          @selection-change="handleSelectionChange"
 | 
					          @selection-change="handleSelectionChange"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <template #operation="{ row }">
 | 
					          <template #operation="{ row }">
 | 
				
			||||||
@ -112,19 +202,9 @@ const {
 | 
				
			|||||||
              type="primary"
 | 
					              type="primary"
 | 
				
			||||||
              :size="size"
 | 
					              :size="size"
 | 
				
			||||||
              :icon="useRenderIcon(EditPen)"
 | 
					              :icon="useRenderIcon(EditPen)"
 | 
				
			||||||
              @click="openDialog('修改', row)"
 | 
					              @click="openDialog('编辑', row)"
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
              修改
 | 
					              编辑
 | 
				
			||||||
            </el-button>
 | 
					 | 
				
			||||||
            <el-button
 | 
					 | 
				
			||||||
              class="reset-margin"
 | 
					 | 
				
			||||||
              link
 | 
					 | 
				
			||||||
              type="primary"
 | 
					 | 
				
			||||||
              :size="size"
 | 
					 | 
				
			||||||
              :icon="useRenderIcon(AddFill)"
 | 
					 | 
				
			||||||
              @click="openDialog('新增', { parentId: row.id } as any)"
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
              新增
 | 
					 | 
				
			||||||
            </el-button>
 | 
					            </el-button>
 | 
				
			||||||
            <el-popconfirm
 | 
					            <el-popconfirm
 | 
				
			||||||
              :title="`是否确认删除部门名称为${row.name}的这条数据`"
 | 
					              :title="`是否确认删除部门名称为${row.name}的这条数据`"
 | 
				
			||||||
@ -150,14 +230,6 @@ const {
 | 
				
			|||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss" scoped>
 | 
					<style lang="scss" scoped>
 | 
				
			||||||
:deep(.el-table__inner-wrapper::before) {
 | 
					 | 
				
			||||||
  height: 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.main-content {
 | 
					 | 
				
			||||||
  margin: 24px 24px 0 !important;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.search-form {
 | 
					.search-form {
 | 
				
			||||||
  :deep(.el-form-item) {
 | 
					  :deep(.el-form-item) {
 | 
				
			||||||
    margin-bottom: 12px;
 | 
					    margin-bottom: 12px;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,26 +1,41 @@
 | 
				
			|||||||
import dayjs from "dayjs";
 | 
					import dayjs from "dayjs";
 | 
				
			||||||
import editForm from "../form.vue";
 | 
					import editForm from "../form.vue";
 | 
				
			||||||
import { handleTree } from "@/utils/tree";
 | 
					 | 
				
			||||||
import { message } from "@/utils/message";
 | 
					import { message } from "@/utils/message";
 | 
				
			||||||
import { getDeptList } from "@/api/system";
 | 
					import * as Dept from "@/api/system/dept";
 | 
				
			||||||
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 } from "@pureadmin/utils";
 | 
					import { cloneDeep, isAllEmpty } from "@pureadmin/utils";
 | 
				
			||||||
 | 
					import { usePublicHooks } from "../../hooks";
 | 
				
			||||||
 | 
					import { ElMessageBox, type CascaderProps } from "element-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function useDept() {
 | 
					export function useDept() {
 | 
				
			||||||
  const form = reactive({
 | 
					  const form = reactive({
 | 
				
			||||||
    name: "",
 | 
					    name: "",
 | 
				
			||||||
    status: null
 | 
					    enabled: null,
 | 
				
			||||||
 | 
					    createTime: ""
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const formRef = ref();
 | 
					  const formRef = ref();
 | 
				
			||||||
  const dataList = ref([]);
 | 
					  const dataList = reactive([]);
 | 
				
			||||||
  const loading = ref(true);
 | 
					  const loading = ref(true);
 | 
				
			||||||
  const { tagStyle } = usePublicHooks();
 | 
					  const multipleSelection = ref([]);
 | 
				
			||||||
 | 
					  const switchLoadMap = ref({});
 | 
				
			||||||
 | 
					  const { switchStyle } = usePublicHooks();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** 表格索引 */
 | 
				
			||||||
 | 
					  const indexMethod = (index: number) => {
 | 
				
			||||||
 | 
					    return index + 1;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const columns: TableColumnList = [
 | 
					  const columns: TableColumnList = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      type: "selection"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      type: "index",
 | 
				
			||||||
 | 
					      index: indexMethod
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      label: "部门名称",
 | 
					      label: "部门名称",
 | 
				
			||||||
      prop: "name",
 | 
					      prop: "name",
 | 
				
			||||||
@ -29,17 +44,26 @@ export function useDept() {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      label: "排序",
 | 
					      label: "排序",
 | 
				
			||||||
      prop: "sort",
 | 
					      prop: "deptSort",
 | 
				
			||||||
      minWidth: 70
 | 
					      minWidth: 70
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      label: "状态",
 | 
					      label: "状态",
 | 
				
			||||||
      prop: "status",
 | 
					      prop: "enabled",
 | 
				
			||||||
      minWidth: 100,
 | 
					      minWidth: 100,
 | 
				
			||||||
      cellRenderer: ({ row, props }) => (
 | 
					      cellRenderer: scope => (
 | 
				
			||||||
        <el-tag size={props.size} style={tagStyle.value(row.status)}>
 | 
					        <el-switch
 | 
				
			||||||
          {row.status === 1 ? "启用" : "停用"}
 | 
					          v-model={scope.row.enabled}
 | 
				
			||||||
        </el-tag>
 | 
					          size={scope.props.size === "small" ? "small" : "default"}
 | 
				
			||||||
 | 
					          loading={switchLoadMap.value[scope.row.index]?.loading}
 | 
				
			||||||
 | 
					          style={switchStyle.value}
 | 
				
			||||||
 | 
					          inline-prompt
 | 
				
			||||||
 | 
					          active-value={true}
 | 
				
			||||||
 | 
					          inactive-value={false}
 | 
				
			||||||
 | 
					          active-text="启用"
 | 
				
			||||||
 | 
					          inactive-text="停用"
 | 
				
			||||||
 | 
					          onChange={() => onChange(scope as any)}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@ -57,15 +81,11 @@ export function useDept() {
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
      label: "操作",
 | 
					      label: "操作",
 | 
				
			||||||
      fixed: "right",
 | 
					      fixed: "right",
 | 
				
			||||||
      width: 210,
 | 
					      width: 160,
 | 
				
			||||||
      slot: "operation"
 | 
					      slot: "operation"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  ];
 | 
					  ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  function handleSelectionChange(val) {
 | 
					 | 
				
			||||||
    console.log("handleSelectionChange", val);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  function resetForm(formEl) {
 | 
					  function resetForm(formEl) {
 | 
				
			||||||
    if (!formEl) return;
 | 
					    if (!formEl) return;
 | 
				
			||||||
    formEl.resetFields();
 | 
					    formEl.resetFields();
 | 
				
			||||||
@ -74,17 +94,24 @@ export function useDept() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  async function onSearch() {
 | 
					  async function onSearch() {
 | 
				
			||||||
    loading.value = true;
 | 
					    loading.value = true;
 | 
				
			||||||
    const { data } = await getDeptList(); // 这里是返回一维数组结构,前端自行处理成树结构,返回格式要求:唯一id加父节点parentId,parentId取父节点id
 | 
					    const queryType = new Dept.DeptQueryCriteria();
 | 
				
			||||||
    let newData = data;
 | 
					
 | 
				
			||||||
    if (!isAllEmpty(form.name)) {
 | 
					    if (!isAllEmpty(form.name)) {
 | 
				
			||||||
      // 前端搜索部门名称
 | 
					      queryType.name = form.name;
 | 
				
			||||||
      newData = newData.filter(item => item.name.includes(form.name));
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (!isAllEmpty(form.status)) {
 | 
					    if (!isAllEmpty(form.enabled)) {
 | 
				
			||||||
      // 前端搜索状态
 | 
					      queryType.enabled = form.enabled;
 | 
				
			||||||
      newData = newData.filter(item => item.status === form.status);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    dataList.value = handleTree(newData); // 处理成树结构
 | 
					    if (!isAllEmpty(form.createTime)) {
 | 
				
			||||||
 | 
					      queryType.createTime = form.createTime;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const depts = (await Dept.getDepts(queryType)).data; // 这里是返回一维数组结构,前端自行处理成树结构,返回格式要求:唯一id加父节点parentId,parentId取父节点id
 | 
				
			||||||
 | 
					    let newData = depts.content;
 | 
				
			||||||
 | 
					    //dataList.value = handleTree2(newData); // 处理成树结构
 | 
				
			||||||
 | 
					    dataList.splice(0, dataList.length); // 清空数组
 | 
				
			||||||
 | 
					    newData.forEach(x => {
 | 
				
			||||||
 | 
					      dataList.push(x);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
    setTimeout(() => {
 | 
					    setTimeout(() => {
 | 
				
			||||||
      loading.value = false;
 | 
					      loading.value = false;
 | 
				
			||||||
    }, 500);
 | 
					    }, 500);
 | 
				
			||||||
@ -95,26 +122,51 @@ export function useDept() {
 | 
				
			|||||||
    if (!treeList || !treeList.length) return;
 | 
					    if (!treeList || !treeList.length) return;
 | 
				
			||||||
    const newTreeList = [];
 | 
					    const newTreeList = [];
 | 
				
			||||||
    for (let i = 0; i < treeList.length; i++) {
 | 
					    for (let i = 0; i < treeList.length; i++) {
 | 
				
			||||||
      treeList[i].disabled = treeList[i].status === 0 ? true : false;
 | 
					      treeList[i].disabled = treeList[i].enabled;
 | 
				
			||||||
      formatHigherDeptOptions(treeList[i].children);
 | 
					      formatHigherDeptOptions(treeList[i].children);
 | 
				
			||||||
      newTreeList.push(treeList[i]);
 | 
					      newTreeList.push(treeList[i]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return newTreeList;
 | 
					    return newTreeList;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  const higherDeptOptions2: CascaderProps = {
 | 
				
			||||||
 | 
					    lazy: true,
 | 
				
			||||||
 | 
					    checkStrictly: true,
 | 
				
			||||||
 | 
					    lazyLoad(node, resolve) {
 | 
				
			||||||
 | 
					      setTimeout(() => {
 | 
				
			||||||
 | 
					        let queryDept = { pid: node?.data?.value };
 | 
				
			||||||
 | 
					        if (!node.data) {
 | 
				
			||||||
 | 
					          queryDept = null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Dept.getDepts(queryDept).then(contentData => {
 | 
				
			||||||
 | 
					          const nodes = contentData.data.content.map(item => ({
 | 
				
			||||||
 | 
					            value: item.id,
 | 
				
			||||||
 | 
					            label: item.name,
 | 
				
			||||||
 | 
					            subCount: item.subCount,
 | 
				
			||||||
 | 
					            leaf: item.subCount === 0
 | 
				
			||||||
 | 
					          }));
 | 
				
			||||||
 | 
					          // 调用' resolve '回调以返回子节点数据并指示加载完成。
 | 
				
			||||||
 | 
					          resolve(nodes);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }, 1000);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
  function openDialog(title = "新增", row?: FormItemProps) {
 | 
					  function openDialog(title = "新增", row?: FormItemProps) {
 | 
				
			||||||
    addDialog({
 | 
					    addDialog({
 | 
				
			||||||
      title: `${title}部门`,
 | 
					      title: `${title}部门`,
 | 
				
			||||||
      props: {
 | 
					      props: {
 | 
				
			||||||
        formInline: {
 | 
					        formInline: {
 | 
				
			||||||
          higherDeptOptions: formatHigherDeptOptions(cloneDeep(dataList.value)),
 | 
					          higherDeptOptions: formatHigherDeptOptions(cloneDeep(dataList)),
 | 
				
			||||||
 | 
					          higherDeptOptions2: higherDeptOptions2,
 | 
				
			||||||
          parentId: row?.parentId ?? 0,
 | 
					          parentId: row?.parentId ?? 0,
 | 
				
			||||||
 | 
					          id: row?.id ?? 0,
 | 
				
			||||||
 | 
					          pid: row?.pid ?? 0,
 | 
				
			||||||
          name: row?.name ?? "",
 | 
					          name: row?.name ?? "",
 | 
				
			||||||
 | 
					          deptSort: row?.deptSort ?? 0,
 | 
				
			||||||
          principal: row?.principal ?? "",
 | 
					          principal: row?.principal ?? "",
 | 
				
			||||||
          phone: row?.phone ?? "",
 | 
					          phone: row?.phone ?? "",
 | 
				
			||||||
          email: row?.email ?? "",
 | 
					          email: row?.email ?? "",
 | 
				
			||||||
          sort: row?.sort ?? 0,
 | 
					          sort: row?.sort ?? 0,
 | 
				
			||||||
          status: row?.status ?? 1,
 | 
					          enabled: row?.enabled ?? false,
 | 
				
			||||||
          remark: row?.remark ?? ""
 | 
					          remark: row?.remark ?? ""
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
@ -135,13 +187,27 @@ export function useDept() {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        FormRef.validate(valid => {
 | 
					        FormRef.validate(valid => {
 | 
				
			||||||
          if (valid) {
 | 
					          if (valid) {
 | 
				
			||||||
            console.log("curData", curData);
 | 
					 | 
				
			||||||
            // 表单规则校验通过
 | 
					            // 表单规则校验通过
 | 
				
			||||||
            if (title === "新增") {
 | 
					            if (title === "新增") {
 | 
				
			||||||
              // 实际开发先调用新增接口,再进行下面操作
 | 
					              // 实际开发先调用新增接口,再进行下面操作
 | 
				
			||||||
 | 
					              Dept.add({
 | 
				
			||||||
 | 
					                name: curData.name,
 | 
				
			||||||
 | 
					                pid: curData.pid === 0 ? null : curData.pid[0],
 | 
				
			||||||
 | 
					                deptSort: curData.deptSort,
 | 
				
			||||||
 | 
					                enabled: curData.enabled
 | 
				
			||||||
 | 
					              });
 | 
				
			||||||
 | 
					              chores();
 | 
				
			||||||
 | 
					            } else if (title === "修改") {
 | 
				
			||||||
 | 
					              Dept.edit({
 | 
				
			||||||
 | 
					                id: curData.id,
 | 
				
			||||||
 | 
					                name: curData.name,
 | 
				
			||||||
 | 
					                pid: curData.pid === 0 ? null : curData.pid,
 | 
				
			||||||
 | 
					                deptSort: curData.deptSort,
 | 
				
			||||||
 | 
					                enabled: curData.enabled
 | 
				
			||||||
 | 
					              });
 | 
				
			||||||
 | 
					              // 实际开发先调用编辑接口,再进行下面操作
 | 
				
			||||||
              chores();
 | 
					              chores();
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
              // 实际开发先调用修改接口,再进行下面操作
 | 
					 | 
				
			||||||
              chores();
 | 
					              chores();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
@ -151,10 +217,60 @@ export function useDept() {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  function handleDelete(row) {
 | 
					  function handleDelete(row) {
 | 
				
			||||||
    message(`您删除了部门名称为${row.name}的这条数据`, { type: "success" });
 | 
					    Dept.del([row.id]).then(() => {
 | 
				
			||||||
 | 
					      message(`您删除了部门名称为${row.name}的这条数据`, { type: "success" });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
    onSearch();
 | 
					    onSearch();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function onChange({ row, index }) {
 | 
				
			||||||
 | 
					    ElMessageBox.confirm(
 | 
				
			||||||
 | 
					      `确认要<strong>${
 | 
				
			||||||
 | 
					        !row.enabled ? "停用" : "启用"
 | 
				
			||||||
 | 
					      }</strong><strong style='color:var(--el-color-primary)'>${
 | 
				
			||||||
 | 
					        row.name
 | 
				
			||||||
 | 
					      }</strong>用户吗?`,
 | 
				
			||||||
 | 
					      "系统提示",
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        confirmButtonText: "确定",
 | 
				
			||||||
 | 
					        cancelButtonText: "取消",
 | 
				
			||||||
 | 
					        type: "warning",
 | 
				
			||||||
 | 
					        dangerouslyUseHTMLString: true,
 | 
				
			||||||
 | 
					        draggable: true
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					      .then(() => {
 | 
				
			||||||
 | 
					        switchLoadMap.value[index] = Object.assign(
 | 
				
			||||||
 | 
					          {},
 | 
				
			||||||
 | 
					          switchLoadMap.value[index],
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            loading: true
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        setTimeout(() => {
 | 
				
			||||||
 | 
					          switchLoadMap.value[index] = Object.assign(
 | 
				
			||||||
 | 
					            {},
 | 
				
			||||||
 | 
					            switchLoadMap.value[index],
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              loading: false
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					          Dept.edit({
 | 
				
			||||||
 | 
					            id: row.id,
 | 
				
			||||||
 | 
					            name: row.name,
 | 
				
			||||||
 | 
					            pid: row.pid === 0 ? null : row.pid,
 | 
				
			||||||
 | 
					            deptSort: row.deptSort,
 | 
				
			||||||
 | 
					            enabled: row.enabled
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          message("已成功修改部门状态", {
 | 
				
			||||||
 | 
					            type: "success"
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }, 300);
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      .catch(() => {
 | 
				
			||||||
 | 
					        row.enabled ? (row.enabled = false) : (row.enabled = true);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  onMounted(() => {
 | 
					  onMounted(() => {
 | 
				
			||||||
    onSearch();
 | 
					    onSearch();
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
@ -164,14 +280,14 @@ export function useDept() {
 | 
				
			|||||||
    loading,
 | 
					    loading,
 | 
				
			||||||
    columns,
 | 
					    columns,
 | 
				
			||||||
    dataList,
 | 
					    dataList,
 | 
				
			||||||
 | 
					    multipleSelection,
 | 
				
			||||||
    /** 搜索 */
 | 
					    /** 搜索 */
 | 
				
			||||||
    onSearch,
 | 
					    onSearch,
 | 
				
			||||||
    /** 重置 */
 | 
					    /** 重置 */
 | 
				
			||||||
    resetForm,
 | 
					    resetForm,
 | 
				
			||||||
    /** 新增、修改部门 */
 | 
					    /** 新增、编辑部门 */
 | 
				
			||||||
    openDialog,
 | 
					    openDialog,
 | 
				
			||||||
    /** 删除部门 */
 | 
					    /** 删除部门 */
 | 
				
			||||||
    handleDelete,
 | 
					    handleDelete
 | 
				
			||||||
    handleSelectionChange
 | 
					 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,12 +1,17 @@
 | 
				
			|||||||
 | 
					import type { CascaderProps } from "element-plus";
 | 
				
			||||||
interface FormItemProps {
 | 
					interface FormItemProps {
 | 
				
			||||||
  higherDeptOptions: Record<string, unknown>[];
 | 
					  higherDeptOptions: Record<string, unknown>[];
 | 
				
			||||||
 | 
					  higherDeptOptions2: CascaderProps;
 | 
				
			||||||
  parentId: number;
 | 
					  parentId: number;
 | 
				
			||||||
 | 
					  id: number;
 | 
				
			||||||
 | 
					  pid: number;
 | 
				
			||||||
 | 
					  deptSort: number;
 | 
				
			||||||
  name: string;
 | 
					  name: string;
 | 
				
			||||||
  principal: string;
 | 
					  principal: string;
 | 
				
			||||||
  phone: string | number;
 | 
					  phone: string | number;
 | 
				
			||||||
  email: string;
 | 
					  email: string;
 | 
				
			||||||
  sort: number;
 | 
					  sort: number;
 | 
				
			||||||
  status: number;
 | 
					  enabled: boolean;
 | 
				
			||||||
  remark: string;
 | 
					  remark: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
interface FormProps {
 | 
					interface FormProps {
 | 
				
			||||||
 | 
				
			|||||||
@ -13,8 +13,8 @@ export function usePublicHooks() {
 | 
				
			|||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const tagStyle = computed(() => {
 | 
					  const tagStyle = computed(() => {
 | 
				
			||||||
    return (status: number) => {
 | 
					    return (enabled: boolean) => {
 | 
				
			||||||
      return status === 1
 | 
					      return enabled
 | 
				
			||||||
        ? {
 | 
					        ? {
 | 
				
			||||||
            "--el-tag-text-color": isDark.value ? "#6abe39" : "#389e0d",
 | 
					            "--el-tag-text-color": isDark.value ? "#6abe39" : "#389e0d",
 | 
				
			||||||
            "--el-tag-bg-color": isDark.value ? "#172412" : "#f6ffed",
 | 
					            "--el-tag-bg-color": isDark.value ? "#172412" : "#f6ffed",
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										80
									
								
								src/views/system/job/form.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								src/views/system/job/form.vue
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,80 @@
 | 
				
			|||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import { ref, onMounted } from "vue";
 | 
				
			||||||
 | 
					import ReCol from "@/components/ReCol";
 | 
				
			||||||
 | 
					import { formRules } from "./utils/rule";
 | 
				
			||||||
 | 
					import { FormProps } from "./utils/types";
 | 
				
			||||||
 | 
					import { usePublicHooks } from "../hooks";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const props = withDefaults(defineProps<FormProps>(), {
 | 
				
			||||||
 | 
					  formInline: () => ({
 | 
				
			||||||
 | 
					    higherDeptOptions: [],
 | 
				
			||||||
 | 
					    jobSort: 0,
 | 
				
			||||||
 | 
					    id: 0,
 | 
				
			||||||
 | 
					    deptSort: 0,
 | 
				
			||||||
 | 
					    enabled: false,
 | 
				
			||||||
 | 
					    name: "",
 | 
				
			||||||
 | 
					    principal: "",
 | 
				
			||||||
 | 
					    phone: "",
 | 
				
			||||||
 | 
					    email: "",
 | 
				
			||||||
 | 
					    version: 0,
 | 
				
			||||||
 | 
					    sort: 0,
 | 
				
			||||||
 | 
					    remark: ""
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ruleFormRef = ref();
 | 
				
			||||||
 | 
					const { switchStyle } = usePublicHooks();
 | 
				
			||||||
 | 
					const newFormInline = ref(props.formInline);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function getRef() {
 | 
				
			||||||
 | 
					  return ruleFormRef.value;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					onMounted(() => {
 | 
				
			||||||
 | 
					  // 在这里编写页面加载后要执行的代码
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					defineExpose({ getRef });
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <el-form
 | 
				
			||||||
 | 
					    ref="ruleFormRef"
 | 
				
			||||||
 | 
					    :model="newFormInline"
 | 
				
			||||||
 | 
					    :rules="formRules"
 | 
				
			||||||
 | 
					    label-width="82px"
 | 
				
			||||||
 | 
					  >
 | 
				
			||||||
 | 
					    <el-row :gutter="30">
 | 
				
			||||||
 | 
					      <re-col :value="12" :xs="24" :sm="24">
 | 
				
			||||||
 | 
					        <el-form-item label="岗位名称" prop="name">
 | 
				
			||||||
 | 
					          <el-input
 | 
				
			||||||
 | 
					            v-model="newFormInline.name"
 | 
				
			||||||
 | 
					            clearable
 | 
				
			||||||
 | 
					            placeholder="请输入岗位名称"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </el-form-item>
 | 
				
			||||||
 | 
					      </re-col>
 | 
				
			||||||
 | 
					      <re-col :value="12" :xs="24" :sm="24">
 | 
				
			||||||
 | 
					        <el-form-item label="排序">
 | 
				
			||||||
 | 
					          <el-input-number
 | 
				
			||||||
 | 
					            v-model="newFormInline.jobSort"
 | 
				
			||||||
 | 
					            :min="0"
 | 
				
			||||||
 | 
					            :max="9999"
 | 
				
			||||||
 | 
					            controls-position="right"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </el-form-item>
 | 
				
			||||||
 | 
					      </re-col>
 | 
				
			||||||
 | 
					      <re-col :value="12" :xs="24" :sm="24">
 | 
				
			||||||
 | 
					        <el-form-item label="岗位状态">
 | 
				
			||||||
 | 
					          <el-switch
 | 
				
			||||||
 | 
					            v-model="newFormInline.enabled"
 | 
				
			||||||
 | 
					            inline-prompt
 | 
				
			||||||
 | 
					            :active-value="true"
 | 
				
			||||||
 | 
					            :inactive-value="false"
 | 
				
			||||||
 | 
					            active-text="启用"
 | 
				
			||||||
 | 
					            inactive-text="停用"
 | 
				
			||||||
 | 
					            :style="switchStyle"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </el-form-item>
 | 
				
			||||||
 | 
					      </re-col>
 | 
				
			||||||
 | 
					    </el-row>
 | 
				
			||||||
 | 
					  </el-form>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
							
								
								
									
										229
									
								
								src/views/system/job/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										229
									
								
								src/views/system/job/index.vue
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,229 @@
 | 
				
			|||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import { ref } from "vue";
 | 
				
			||||||
 | 
					import { useDept } from "./utils/hook";
 | 
				
			||||||
 | 
					import { PureTableBar } from "@/components/RePureTableBar";
 | 
				
			||||||
 | 
					import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 | 
				
			||||||
 | 
					import datePicker from "@/views/components/date-picker.vue";
 | 
				
			||||||
 | 
					import * as Job from "@/api/system/job";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Delete from "@iconify-icons/ep/delete";
 | 
				
			||||||
 | 
					import EditPen from "@iconify-icons/ep/edit-pen";
 | 
				
			||||||
 | 
					import Refresh from "@iconify-icons/ep/refresh";
 | 
				
			||||||
 | 
					import AddFill from "@iconify-icons/ri/add-circle-line";
 | 
				
			||||||
 | 
					import { message } from "@/utils/message";
 | 
				
			||||||
 | 
					import { ElMessageBox } from "element-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defineOptions({
 | 
				
			||||||
 | 
					  name: "Dept"
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const handleSelectionChange = val => {
 | 
				
			||||||
 | 
					  multipleSelection.value = val;
 | 
				
			||||||
 | 
					  if (val != null && val.length > 0) {
 | 
				
			||||||
 | 
					    value2.value = false;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    value2.value = true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function deleteAll() {
 | 
				
			||||||
 | 
					  ElMessageBox.confirm(
 | 
				
			||||||
 | 
					    `确认要<strong>删除所选的</strong><strong style='color:var(--el-color-primary)'>${multipleSelection.value.length}</strong>个岗位吗?`,
 | 
				
			||||||
 | 
					    "系统提示",
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      confirmButtonText: "确定",
 | 
				
			||||||
 | 
					      cancelButtonText: "取消",
 | 
				
			||||||
 | 
					      type: "warning",
 | 
				
			||||||
 | 
					      dangerouslyUseHTMLString: true,
 | 
				
			||||||
 | 
					      draggable: true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					    .then(() => {
 | 
				
			||||||
 | 
					      Job.del(multipleSelection.value.map(dept => dept.id)).then(() => {
 | 
				
			||||||
 | 
					        message("已删除所选的岗位", {
 | 
				
			||||||
 | 
					          type: "success"
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        onSearch();
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .catch(() => {
 | 
				
			||||||
 | 
					      onSearch();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					const exportClick = async () => {
 | 
				
			||||||
 | 
					  const response: Blob = await Job.download(null);
 | 
				
			||||||
 | 
					  const a = document.createElement("a");
 | 
				
			||||||
 | 
					  const url = window.URL.createObjectURL(response); // 创建媒体流 url ,详细了解可自己查 URL.createObjectURL(推荐 MDN )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  a.href = url;
 | 
				
			||||||
 | 
					  a.style.display = "none";
 | 
				
			||||||
 | 
					  document.body.appendChild(a);
 | 
				
			||||||
 | 
					  a.click();
 | 
				
			||||||
 | 
					  a.parentNode.removeChild(a);
 | 
				
			||||||
 | 
					  window.URL.revokeObjectURL(url); // 删除创建的媒体流 url 对象
 | 
				
			||||||
 | 
					  message("导出成功", {
 | 
				
			||||||
 | 
					    type: "success"
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					const formRef = ref();
 | 
				
			||||||
 | 
					const tableRef = ref();
 | 
				
			||||||
 | 
					const value2 = ref(true);
 | 
				
			||||||
 | 
					const {
 | 
				
			||||||
 | 
					  form,
 | 
				
			||||||
 | 
					  loading,
 | 
				
			||||||
 | 
					  columns,
 | 
				
			||||||
 | 
					  dataList,
 | 
				
			||||||
 | 
					  multipleSelection,
 | 
				
			||||||
 | 
					  pagination,
 | 
				
			||||||
 | 
					  onSearch,
 | 
				
			||||||
 | 
					  resetForm,
 | 
				
			||||||
 | 
					  openDialog,
 | 
				
			||||||
 | 
					  handleDelete,
 | 
				
			||||||
 | 
					  handleSizeChange,
 | 
				
			||||||
 | 
					  handleCurrentChange
 | 
				
			||||||
 | 
					} = useDept();
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div class="main">
 | 
				
			||||||
 | 
					    <el-form
 | 
				
			||||||
 | 
					      ref="formRef"
 | 
				
			||||||
 | 
					      :inline="true"
 | 
				
			||||||
 | 
					      :model="form"
 | 
				
			||||||
 | 
					      class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px]"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <el-form-item label="岗位名称:" prop="name">
 | 
				
			||||||
 | 
					        <el-input
 | 
				
			||||||
 | 
					          v-model="form.name"
 | 
				
			||||||
 | 
					          placeholder="请输入岗位名称"
 | 
				
			||||||
 | 
					          clearable
 | 
				
			||||||
 | 
					          class="!w-[200px]"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					      </el-form-item>
 | 
				
			||||||
 | 
					      <el-form-item label="状态:" prop="status">
 | 
				
			||||||
 | 
					        <el-select
 | 
				
			||||||
 | 
					          v-model="form.enabled"
 | 
				
			||||||
 | 
					          placeholder="请选择状态"
 | 
				
			||||||
 | 
					          clearable
 | 
				
			||||||
 | 
					          class="!w-[180px]"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <el-option label="启用" :value="true" />
 | 
				
			||||||
 | 
					          <el-option label="停用" :value="false" />
 | 
				
			||||||
 | 
					        </el-select>
 | 
				
			||||||
 | 
					      </el-form-item>
 | 
				
			||||||
 | 
					      <el-form-item label="" prop="createTime">
 | 
				
			||||||
 | 
					        <datePicker v-model="form.createTime" />
 | 
				
			||||||
 | 
					      </el-form-item>
 | 
				
			||||||
 | 
					      <el-form-item>
 | 
				
			||||||
 | 
					        <el-button
 | 
				
			||||||
 | 
					          type="primary"
 | 
				
			||||||
 | 
					          :icon="useRenderIcon('search')"
 | 
				
			||||||
 | 
					          :loading="loading"
 | 
				
			||||||
 | 
					          @click="onSearch"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          搜索
 | 
				
			||||||
 | 
					        </el-button>
 | 
				
			||||||
 | 
					        <el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)">
 | 
				
			||||||
 | 
					          重置
 | 
				
			||||||
 | 
					        </el-button>
 | 
				
			||||||
 | 
					      </el-form-item>
 | 
				
			||||||
 | 
					    </el-form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <PureTableBar
 | 
				
			||||||
 | 
					      title="岗位列表"
 | 
				
			||||||
 | 
					      :columns="columns"
 | 
				
			||||||
 | 
					      :tableRef="tableRef?.getTableRef()"
 | 
				
			||||||
 | 
					      @refresh="onSearch"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <template #add>
 | 
				
			||||||
 | 
					        <el-button
 | 
				
			||||||
 | 
					          type="primary"
 | 
				
			||||||
 | 
					          :icon="useRenderIcon(AddFill)"
 | 
				
			||||||
 | 
					          @click="openDialog()"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          新增岗位
 | 
				
			||||||
 | 
					        </el-button>
 | 
				
			||||||
 | 
					      </template>
 | 
				
			||||||
 | 
					      <template #delete>
 | 
				
			||||||
 | 
					        <el-button
 | 
				
			||||||
 | 
					          type="danger"
 | 
				
			||||||
 | 
					          :disabled="value2"
 | 
				
			||||||
 | 
					          :icon="useRenderIcon(Delete)"
 | 
				
			||||||
 | 
					          @click="deleteAll()"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          删除岗位
 | 
				
			||||||
 | 
					        </el-button>
 | 
				
			||||||
 | 
					      </template>
 | 
				
			||||||
 | 
					      <template #export>
 | 
				
			||||||
 | 
					        <el-button
 | 
				
			||||||
 | 
					          type="success"
 | 
				
			||||||
 | 
					          :icon="useRenderIcon('solar:upload-bold')"
 | 
				
			||||||
 | 
					          @click="exportClick()"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          导出数据
 | 
				
			||||||
 | 
					        </el-button>
 | 
				
			||||||
 | 
					      </template>
 | 
				
			||||||
 | 
					      <template v-slot="{ size, dynamicColumns }">
 | 
				
			||||||
 | 
					        <pure-table
 | 
				
			||||||
 | 
					          adaptive
 | 
				
			||||||
 | 
					          :adaptiveConfig="{ offsetBottom: 32 }"
 | 
				
			||||||
 | 
					          align-whole="center"
 | 
				
			||||||
 | 
					          row-key="id"
 | 
				
			||||||
 | 
					          showOverflowTooltip
 | 
				
			||||||
 | 
					          table-layout="auto"
 | 
				
			||||||
 | 
					          default-expand-all
 | 
				
			||||||
 | 
					          :loading="loading"
 | 
				
			||||||
 | 
					          :size="size"
 | 
				
			||||||
 | 
					          :columns="dynamicColumns"
 | 
				
			||||||
 | 
					          :data="dataList"
 | 
				
			||||||
 | 
					          :pagination="pagination"
 | 
				
			||||||
 | 
					          :paginationSmall="size === 'small' ? true : false"
 | 
				
			||||||
 | 
					          :header-cell-style="{
 | 
				
			||||||
 | 
					            background: 'var(--el-fill-color-light)',
 | 
				
			||||||
 | 
					            color: 'var(--el-text-color-primary)'
 | 
				
			||||||
 | 
					          }"
 | 
				
			||||||
 | 
					          @selection-change="handleSelectionChange"
 | 
				
			||||||
 | 
					          @page-size-change="handleSizeChange"
 | 
				
			||||||
 | 
					          @page-current-change="handleCurrentChange"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <template #operation="{ row }">
 | 
				
			||||||
 | 
					            <el-button
 | 
				
			||||||
 | 
					              class="reset-margin"
 | 
				
			||||||
 | 
					              link
 | 
				
			||||||
 | 
					              type="primary"
 | 
				
			||||||
 | 
					              :size="size"
 | 
				
			||||||
 | 
					              :icon="useRenderIcon(EditPen)"
 | 
				
			||||||
 | 
					              @click="openDialog('编辑', row)"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              编辑
 | 
				
			||||||
 | 
					            </el-button>
 | 
				
			||||||
 | 
					            <el-popconfirm
 | 
				
			||||||
 | 
					              :title="`是否确认删除岗位名称为${row.name}的这条数据`"
 | 
				
			||||||
 | 
					              @confirm="handleDelete(row)"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <template #reference>
 | 
				
			||||||
 | 
					                <el-button
 | 
				
			||||||
 | 
					                  class="reset-margin"
 | 
				
			||||||
 | 
					                  link
 | 
				
			||||||
 | 
					                  type="primary"
 | 
				
			||||||
 | 
					                  :size="size"
 | 
				
			||||||
 | 
					                  :icon="useRenderIcon(Delete)"
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  删除
 | 
				
			||||||
 | 
					                </el-button>
 | 
				
			||||||
 | 
					              </template>
 | 
				
			||||||
 | 
					            </el-popconfirm>
 | 
				
			||||||
 | 
					          </template>
 | 
				
			||||||
 | 
					        </pure-table>
 | 
				
			||||||
 | 
					      </template>
 | 
				
			||||||
 | 
					    </PureTableBar>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style lang="scss" scoped>
 | 
				
			||||||
 | 
					.search-form {
 | 
				
			||||||
 | 
					  :deep(.el-form-item) {
 | 
				
			||||||
 | 
					    margin-bottom: 12px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										271
									
								
								src/views/system/job/utils/hook.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										271
									
								
								src/views/system/job/utils/hook.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,271 @@
 | 
				
			|||||||
 | 
					import dayjs from "dayjs";
 | 
				
			||||||
 | 
					import editForm from "../form.vue";
 | 
				
			||||||
 | 
					import { message } from "@/utils/message";
 | 
				
			||||||
 | 
					import * as Job from "@/api/system/job";
 | 
				
			||||||
 | 
					import { addDialog } from "@/components/ReDialog";
 | 
				
			||||||
 | 
					import type { PaginationProps } from "@pureadmin/table";
 | 
				
			||||||
 | 
					import { reactive, ref, onMounted, h } from "vue";
 | 
				
			||||||
 | 
					import type { FormItemProps } from "../utils/types";
 | 
				
			||||||
 | 
					import { cloneDeep, isAllEmpty } from "@pureadmin/utils";
 | 
				
			||||||
 | 
					import { usePublicHooks } from "../../hooks";
 | 
				
			||||||
 | 
					import { ElMessageBox } from "element-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function useDept() {
 | 
				
			||||||
 | 
					  const form = reactive({
 | 
				
			||||||
 | 
					    name: "",
 | 
				
			||||||
 | 
					    enabled: null,
 | 
				
			||||||
 | 
					    createTime: ""
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const formRef = ref();
 | 
				
			||||||
 | 
					  const dataList = reactive([]);
 | 
				
			||||||
 | 
					  const loading = ref(true);
 | 
				
			||||||
 | 
					  const multipleSelection = ref([]);
 | 
				
			||||||
 | 
					  const switchLoadMap = ref({});
 | 
				
			||||||
 | 
					  const { switchStyle } = usePublicHooks();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** 分页配置 */
 | 
				
			||||||
 | 
					  const pagination = reactive<PaginationProps>({
 | 
				
			||||||
 | 
					    total: 10,
 | 
				
			||||||
 | 
					    pageSize: 2,
 | 
				
			||||||
 | 
					    pageSizes: [10, 20, 50],
 | 
				
			||||||
 | 
					    currentPage: 1,
 | 
				
			||||||
 | 
					    align: "left",
 | 
				
			||||||
 | 
					    background: true
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  /** 表格索引 */
 | 
				
			||||||
 | 
					  const indexMethod = (index: number) => {
 | 
				
			||||||
 | 
					    return index + 1;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const columns: TableColumnList = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      type: "selection"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      type: "index",
 | 
				
			||||||
 | 
					      index: indexMethod
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: "岗位名称",
 | 
				
			||||||
 | 
					      prop: "name",
 | 
				
			||||||
 | 
					      width: 180,
 | 
				
			||||||
 | 
					      align: "left"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: "排序",
 | 
				
			||||||
 | 
					      prop: "jobSort",
 | 
				
			||||||
 | 
					      minWidth: 70
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: "状态",
 | 
				
			||||||
 | 
					      prop: "enabled",
 | 
				
			||||||
 | 
					      minWidth: 100,
 | 
				
			||||||
 | 
					      cellRenderer: scope => (
 | 
				
			||||||
 | 
					        <el-switch
 | 
				
			||||||
 | 
					          v-model={scope.row.enabled}
 | 
				
			||||||
 | 
					          size={scope.props.size === "small" ? "small" : "default"}
 | 
				
			||||||
 | 
					          loading={switchLoadMap.value[scope.row.index]?.loading}
 | 
				
			||||||
 | 
					          style={switchStyle.value}
 | 
				
			||||||
 | 
					          inline-prompt
 | 
				
			||||||
 | 
					          active-value={true}
 | 
				
			||||||
 | 
					          inactive-value={false}
 | 
				
			||||||
 | 
					          active-text="启用"
 | 
				
			||||||
 | 
					          inactive-text="停用"
 | 
				
			||||||
 | 
					          onChange={() => onChange(scope as any)}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: "创建时间",
 | 
				
			||||||
 | 
					      minWidth: 200,
 | 
				
			||||||
 | 
					      prop: "createTime",
 | 
				
			||||||
 | 
					      formatter: ({ createTime }) =>
 | 
				
			||||||
 | 
					        dayjs(createTime).format("YYYY-MM-DD HH:mm:ss")
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: "操作",
 | 
				
			||||||
 | 
					      fixed: "right",
 | 
				
			||||||
 | 
					      width: 160,
 | 
				
			||||||
 | 
					      slot: "operation"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function resetForm(formEl) {
 | 
				
			||||||
 | 
					    if (!formEl) return;
 | 
				
			||||||
 | 
					    formEl.resetFields();
 | 
				
			||||||
 | 
					    onSearch();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async function onSearch() {
 | 
				
			||||||
 | 
					    loading.value = true;
 | 
				
			||||||
 | 
					    const queryType = new Job.JobQueryCriteria();
 | 
				
			||||||
 | 
					    if (!isAllEmpty(form.name)) {
 | 
				
			||||||
 | 
					      queryType.name = form.name;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (!isAllEmpty(form.enabled)) {
 | 
				
			||||||
 | 
					      queryType.enabled = form.enabled;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (!isAllEmpty(form.createTime)) {
 | 
				
			||||||
 | 
					      queryType.createTime = form.createTime;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    queryType.page = pagination.currentPage - 1;
 | 
				
			||||||
 | 
					    queryType.size = pagination.pageSize;
 | 
				
			||||||
 | 
					    const depts = (await Job.get(queryType)).data;
 | 
				
			||||||
 | 
					    pagination.total = depts.totalElements;
 | 
				
			||||||
 | 
					    let newData = depts.content;
 | 
				
			||||||
 | 
					    dataList.splice(0, dataList.length); // 清空数组
 | 
				
			||||||
 | 
					    newData.forEach(x => {
 | 
				
			||||||
 | 
					      dataList.push(x);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    setTimeout(() => {
 | 
				
			||||||
 | 
					      loading.value = false;
 | 
				
			||||||
 | 
					    }, 500);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function openDialog(title = "新增", row?: FormItemProps) {
 | 
				
			||||||
 | 
					    addDialog({
 | 
				
			||||||
 | 
					      title: `${title}岗位`,
 | 
				
			||||||
 | 
					      props: {
 | 
				
			||||||
 | 
					        formInline: {
 | 
				
			||||||
 | 
					          higherDeptOptions: cloneDeep(dataList),
 | 
				
			||||||
 | 
					          id: row?.id ?? 0,
 | 
				
			||||||
 | 
					          name: row?.name ?? "",
 | 
				
			||||||
 | 
					          jobSort: row?.jobSort ?? 0,
 | 
				
			||||||
 | 
					          principal: row?.principal ?? "",
 | 
				
			||||||
 | 
					          phone: row?.phone ?? "",
 | 
				
			||||||
 | 
					          email: row?.email ?? "",
 | 
				
			||||||
 | 
					          sort: row?.sort ?? 0,
 | 
				
			||||||
 | 
					          version: row?.version ?? 0,
 | 
				
			||||||
 | 
					          enabled: row?.enabled ?? false,
 | 
				
			||||||
 | 
					          remark: row?.remark ?? ""
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      width: "40%",
 | 
				
			||||||
 | 
					      draggable: true,
 | 
				
			||||||
 | 
					      fullscreenIcon: true,
 | 
				
			||||||
 | 
					      closeOnClickModal: false,
 | 
				
			||||||
 | 
					      contentRenderer: () => h(editForm, { ref: formRef }),
 | 
				
			||||||
 | 
					      beforeSure: (done, { options }) => {
 | 
				
			||||||
 | 
					        const FormRef = formRef.value.getRef();
 | 
				
			||||||
 | 
					        const curData = options.props.formInline as FormItemProps;
 | 
				
			||||||
 | 
					        function chores() {
 | 
				
			||||||
 | 
					          message(`您${title}了岗位名称为${curData.name}的这条数据`, {
 | 
				
			||||||
 | 
					            type: "success"
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          done(); // 关闭弹框
 | 
				
			||||||
 | 
					          onSearch(); // 刷新表格数据
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        FormRef.validate(valid => {
 | 
				
			||||||
 | 
					          if (valid) {
 | 
				
			||||||
 | 
					            // 表单规则校验通过
 | 
				
			||||||
 | 
					            if (title === "新增") {
 | 
				
			||||||
 | 
					              // 实际开发先调用新增接口,再进行下面操作
 | 
				
			||||||
 | 
					              Job.add({
 | 
				
			||||||
 | 
					                name: curData.name,
 | 
				
			||||||
 | 
					                enabled: curData.enabled,
 | 
				
			||||||
 | 
					                version: curData.version,
 | 
				
			||||||
 | 
					                jobSort: curData.jobSort
 | 
				
			||||||
 | 
					              }).finally(() => chores());
 | 
				
			||||||
 | 
					            } else if (title === "编辑") {
 | 
				
			||||||
 | 
					              Job.edit({
 | 
				
			||||||
 | 
					                id: curData.id,
 | 
				
			||||||
 | 
					                name: curData.name,
 | 
				
			||||||
 | 
					                enabled: curData.enabled,
 | 
				
			||||||
 | 
					                version: curData.version,
 | 
				
			||||||
 | 
					                jobSort: curData.jobSort
 | 
				
			||||||
 | 
					              }).finally(() => chores());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function handleDelete(row) {
 | 
				
			||||||
 | 
					    Job.del([row.id]).then(() => {
 | 
				
			||||||
 | 
					      message(`您删除了岗位名称为${row.name}的这条数据`, { type: "success" });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    onSearch();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function onChange({ row, index }) {
 | 
				
			||||||
 | 
					    ElMessageBox.confirm(
 | 
				
			||||||
 | 
					      `确认要<strong>${
 | 
				
			||||||
 | 
					        !row.enabled ? "停用" : "启用"
 | 
				
			||||||
 | 
					      }</strong><strong style='color:var(--el-color-primary)'>${
 | 
				
			||||||
 | 
					        row.name
 | 
				
			||||||
 | 
					      }</strong>用户吗?`,
 | 
				
			||||||
 | 
					      "系统提示",
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        confirmButtonText: "确定",
 | 
				
			||||||
 | 
					        cancelButtonText: "取消",
 | 
				
			||||||
 | 
					        type: "warning",
 | 
				
			||||||
 | 
					        dangerouslyUseHTMLString: true,
 | 
				
			||||||
 | 
					        draggable: true
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					      .then(() => {
 | 
				
			||||||
 | 
					        switchLoadMap.value[index] = Object.assign(
 | 
				
			||||||
 | 
					          {},
 | 
				
			||||||
 | 
					          switchLoadMap.value[index],
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            loading: true
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        setTimeout(() => {
 | 
				
			||||||
 | 
					          switchLoadMap.value[index] = Object.assign(
 | 
				
			||||||
 | 
					            {},
 | 
				
			||||||
 | 
					            switchLoadMap.value[index],
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              loading: false
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					          Job.edit({
 | 
				
			||||||
 | 
					            id: row.id,
 | 
				
			||||||
 | 
					            name: row.name,
 | 
				
			||||||
 | 
					            enabled: row.enabled,
 | 
				
			||||||
 | 
					            version: row.version,
 | 
				
			||||||
 | 
					            jobSort: row.jobSort
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          message("已成功修改岗位状态", {
 | 
				
			||||||
 | 
					            type: "success"
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }, 300);
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      .catch(() => {
 | 
				
			||||||
 | 
					        row.enabled ? (row.enabled = false) : (row.enabled = true);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  function handleSizeChange(val: number) {
 | 
				
			||||||
 | 
					    pagination.pageSize = val;
 | 
				
			||||||
 | 
					    onSearch();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function handleCurrentChange(val: number) {
 | 
				
			||||||
 | 
					    pagination.currentPage = val;
 | 
				
			||||||
 | 
					    onSearch();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  onMounted(() => {
 | 
				
			||||||
 | 
					    onSearch();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    form,
 | 
				
			||||||
 | 
					    loading,
 | 
				
			||||||
 | 
					    columns,
 | 
				
			||||||
 | 
					    dataList,
 | 
				
			||||||
 | 
					    multipleSelection,
 | 
				
			||||||
 | 
					    pagination,
 | 
				
			||||||
 | 
					    /** 搜索 */
 | 
				
			||||||
 | 
					    onSearch,
 | 
				
			||||||
 | 
					    /** 重置 */
 | 
				
			||||||
 | 
					    resetForm,
 | 
				
			||||||
 | 
					    /** 新增、编辑岗位 */
 | 
				
			||||||
 | 
					    openDialog,
 | 
				
			||||||
 | 
					    /** 删除岗位 */
 | 
				
			||||||
 | 
					    handleDelete,
 | 
				
			||||||
 | 
					    handleSizeChange,
 | 
				
			||||||
 | 
					    handleCurrentChange
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										8
									
								
								src/views/system/job/utils/rule.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/views/system/job/utils/rule.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					import { reactive } from "vue";
 | 
				
			||||||
 | 
					import type { FormRules } from "element-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 自定义表单规则校验 */
 | 
				
			||||||
 | 
					export const formRules = reactive(<FormRules>{
 | 
				
			||||||
 | 
					  name: [{ required: true, message: "岗位名称为必填项", trigger: "blur" }],
 | 
				
			||||||
 | 
					  jobSort: [{ required: true, message: "岗位排序为必填项", trigger: "blur" }]
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										19
									
								
								src/views/system/job/utils/types.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/views/system/job/utils/types.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					interface FormItemProps {
 | 
				
			||||||
 | 
					  higherDeptOptions: Record<string, unknown>[];
 | 
				
			||||||
 | 
					  parentId?: number;
 | 
				
			||||||
 | 
					  id: number;
 | 
				
			||||||
 | 
					  jobSort: number;
 | 
				
			||||||
 | 
					  name: string;
 | 
				
			||||||
 | 
					  principal: string;
 | 
				
			||||||
 | 
					  phone: string | number;
 | 
				
			||||||
 | 
					  email: string;
 | 
				
			||||||
 | 
					  sort: number;
 | 
				
			||||||
 | 
					  version: number;
 | 
				
			||||||
 | 
					  enabled: boolean;
 | 
				
			||||||
 | 
					  remark: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					interface FormProps {
 | 
				
			||||||
 | 
					  formInline: FormItemProps;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type { FormItemProps, FormProps };
 | 
				
			||||||
@ -1,26 +0,0 @@
 | 
				
			|||||||
<!-- 初版,持续完善中 -->
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## 字段含义
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
| 字段              | 说明                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
 | 
					 | 
				
			||||||
| :---------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
 | 
					 | 
				
			||||||
| `menuType`        | 菜单类型(`0`代表菜单、`1`代表`iframe`、`2`代表外链、`3`代表按钮)                                                                                                                                                                                                                                                                                                                                                                                               |
 | 
					 | 
				
			||||||
| `parentId`        |                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
 | 
					 | 
				
			||||||
| `title`           | 菜单名称(兼容国际化、非国际化,如果用国际化的写法就必须在根目录的`locales`文件夹下对应添加)                                                                                                                                                                                                                                                                                                                                                                    |
 | 
					 | 
				
			||||||
| `name`            | 路由名称(必须唯一并且和当前路由`component`字段对应的页面里用`defineOptions`包起来的`name`保持一致)                                                                                                                                                                                                                                                                                                                                                             |
 | 
					 | 
				
			||||||
| `path`            | 路由路径                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
 | 
					 | 
				
			||||||
| `component`       | 组件路径(传`component`组件路径,那么`path`可以随便写,如果不传,`component`组件路径会跟`path`保持一致)                                                                                                                                                                                                                                                                                                                                                         |
 | 
					 | 
				
			||||||
| `rank`            | 菜单排序(平台规定只有`home`路由的`rank`才能为`0`,所以后端在返回`rank`的时候需要从非`0`开始 [点击查看更多](https://yiming_chang.gitee.io/pure-admin-doc/pages/routerMenu/#%E8%8F%9C%E5%8D%95%E6%8E%92%E5%BA%8F-rank))                                                                                                                                                                                                                                          |
 | 
					 | 
				
			||||||
| `redirect`        | 路由重定向                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
 | 
					 | 
				
			||||||
| `icon`            | 菜单图标                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
 | 
					 | 
				
			||||||
| `extraIcon`       | 右侧图标                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
 | 
					 | 
				
			||||||
| `enterTransition` | 进场动画(页面加载动画)                                                                                                                                                                                                                                                                                                                                                                                                                                         |
 | 
					 | 
				
			||||||
| `leaveTransition` | 离场动画(页面加载动画)                                                                                                                                                                                                                                                                                                                                                                                                                                         |
 | 
					 | 
				
			||||||
| `activePath`      | 菜单激活(将某个菜单激活,主要用于通过`query`或`params`传参的路由,当它们通过配置`showLink: false`后不在菜单中显示,就不会有任何菜单高亮,而通过设置`activePath`指定激活菜单即可获得高亮,`activePath`为指定激活菜单的`path`)                                                                                                                                                                                                                                   |
 | 
					 | 
				
			||||||
| `auths`           | 权限标识(按钮级别权限设置)                                                                                                                                                                                                                                                                                                                                                                                                                                     |
 | 
					 | 
				
			||||||
| `frameSrc`        | 链接地址(需要内嵌的`iframe`链接地址)                                                                                                                                                                                                                                                                                                                                                                                                                           |
 | 
					 | 
				
			||||||
| `frameLoading`    | 加载动画(内嵌的`iframe`页面是否开启首次加载动画)                                                                                                                                                                                                                                                                                                                                                                                                               |
 | 
					 | 
				
			||||||
| `keepAlive`       | 缓存页面(是否缓存该路由页面,开启后会保存该页面的整体状态,刷新后会清空状态)                                                                                                                                                                                                                                                                                                                                                                                   |
 | 
					 | 
				
			||||||
| `hiddenTag`       | 标签页(当前菜单名称或自定义信息禁止添加到标签页)                                                                                                                                                                                                                                                                                                                                                                                                               |
 | 
					 | 
				
			||||||
| `showLink`        | 菜单(是否显示该菜单)                                                                                                                                                                                                                                                                                                                                                                                                                                           |
 | 
					 | 
				
			||||||
| `showParent`      | 父级菜单(是否显示父级菜单 [点击查看更多](https://yiming_chang.gitee.io/pure-admin-doc/pages/routerMenu/#%E7%AC%AC%E4%B8%80%E7%A7%8D-%E8%AF%A5%E6%A8%A1%E5%BC%8F%E9%92%88%E5%AF%B9%E7%88%B6%E7%BA%A7%E8%8F%9C%E5%8D%95%E4%B8%8B%E5%8F%AA%E6%9C%89%E4%B8%80%E4%B8%AA%E5%AD%90%E8%8F%9C%E5%8D%95%E7%9A%84%E6%83%85%E5%86%B5-%E5%9C%A8%E5%AD%90%E8%8F%9C%E5%8D%95%E7%9A%84-meta-%E5%B1%9E%E6%80%A7%E4%B8%AD%E5%8A%A0%E4%B8%8A-showparent-true-%E5%8D%B3%E5%8F%AF)) |
 | 
					 | 
				
			||||||
@ -1,326 +0,0 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					 | 
				
			||||||
import { ref } from "vue";
 | 
					 | 
				
			||||||
import ReCol from "@/components/ReCol";
 | 
					 | 
				
			||||||
import { formRules } from "./utils/rule";
 | 
					 | 
				
			||||||
import { FormProps } from "./utils/types";
 | 
					 | 
				
			||||||
import { transformI18n } from "@/plugins/i18n";
 | 
					 | 
				
			||||||
import { IconSelect } from "@/components/ReIcon";
 | 
					 | 
				
			||||||
import Segmented from "@/components/ReSegmented";
 | 
					 | 
				
			||||||
import ReAnimateSelector from "@/components/ReAnimateSelector";
 | 
					 | 
				
			||||||
import {
 | 
					 | 
				
			||||||
  menuTypeOptions,
 | 
					 | 
				
			||||||
  showLinkOptions,
 | 
					 | 
				
			||||||
  keepAliveOptions,
 | 
					 | 
				
			||||||
  hiddenTagOptions,
 | 
					 | 
				
			||||||
  showParentOptions,
 | 
					 | 
				
			||||||
  frameLoadingOptions
 | 
					 | 
				
			||||||
} from "./utils/enums";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const props = withDefaults(defineProps<FormProps>(), {
 | 
					 | 
				
			||||||
  formInline: () => ({
 | 
					 | 
				
			||||||
    menuType: 0,
 | 
					 | 
				
			||||||
    higherMenuOptions: [],
 | 
					 | 
				
			||||||
    parentId: 0,
 | 
					 | 
				
			||||||
    title: "",
 | 
					 | 
				
			||||||
    name: "",
 | 
					 | 
				
			||||||
    path: "",
 | 
					 | 
				
			||||||
    component: "",
 | 
					 | 
				
			||||||
    rank: 99,
 | 
					 | 
				
			||||||
    redirect: " ",
 | 
					 | 
				
			||||||
    icon: "",
 | 
					 | 
				
			||||||
    extraIcon: "",
 | 
					 | 
				
			||||||
    enterTransition: "",
 | 
					 | 
				
			||||||
    leaveTransition: "",
 | 
					 | 
				
			||||||
    activePath: "",
 | 
					 | 
				
			||||||
    auths: "",
 | 
					 | 
				
			||||||
    frameSrc: "",
 | 
					 | 
				
			||||||
    frameLoading: true,
 | 
					 | 
				
			||||||
    keepAlive: false,
 | 
					 | 
				
			||||||
    hiddenTag: false,
 | 
					 | 
				
			||||||
    showLink: true,
 | 
					 | 
				
			||||||
    showParent: false
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const ruleFormRef = ref();
 | 
					 | 
				
			||||||
const newFormInline = ref(props.formInline);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function getRef() {
 | 
					 | 
				
			||||||
  return ruleFormRef.value;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
defineExpose({ getRef });
 | 
					 | 
				
			||||||
</script>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<template>
 | 
					 | 
				
			||||||
  <el-form
 | 
					 | 
				
			||||||
    ref="ruleFormRef"
 | 
					 | 
				
			||||||
    :model="newFormInline"
 | 
					 | 
				
			||||||
    :rules="formRules"
 | 
					 | 
				
			||||||
    label-width="82px"
 | 
					 | 
				
			||||||
  >
 | 
					 | 
				
			||||||
    <el-row :gutter="30">
 | 
					 | 
				
			||||||
      <re-col>
 | 
					 | 
				
			||||||
        <el-form-item label="菜单类型">
 | 
					 | 
				
			||||||
          <Segmented
 | 
					 | 
				
			||||||
            v-model="newFormInline.menuType"
 | 
					 | 
				
			||||||
            :options="menuTypeOptions"
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
        </el-form-item>
 | 
					 | 
				
			||||||
      </re-col>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      <re-col>
 | 
					 | 
				
			||||||
        <el-form-item label="上级菜单">
 | 
					 | 
				
			||||||
          <el-cascader
 | 
					 | 
				
			||||||
            v-model="newFormInline.parentId"
 | 
					 | 
				
			||||||
            class="w-full"
 | 
					 | 
				
			||||||
            :options="newFormInline.higherMenuOptions"
 | 
					 | 
				
			||||||
            :props="{
 | 
					 | 
				
			||||||
              value: 'id',
 | 
					 | 
				
			||||||
              label: 'title',
 | 
					 | 
				
			||||||
              emitPath: false,
 | 
					 | 
				
			||||||
              checkStrictly: true
 | 
					 | 
				
			||||||
            }"
 | 
					 | 
				
			||||||
            clearable
 | 
					 | 
				
			||||||
            filterable
 | 
					 | 
				
			||||||
            placeholder="请选择上级菜单"
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            <template #default="{ node, data }">
 | 
					 | 
				
			||||||
              <span>{{ transformI18n(data.title) }}</span>
 | 
					 | 
				
			||||||
              <span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
 | 
					 | 
				
			||||||
            </template>
 | 
					 | 
				
			||||||
          </el-cascader>
 | 
					 | 
				
			||||||
        </el-form-item>
 | 
					 | 
				
			||||||
      </re-col>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      <re-col :value="12" :xs="24" :sm="24">
 | 
					 | 
				
			||||||
        <el-form-item label="菜单名称" prop="title">
 | 
					 | 
				
			||||||
          <el-input
 | 
					 | 
				
			||||||
            v-model="newFormInline.title"
 | 
					 | 
				
			||||||
            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="name">
 | 
					 | 
				
			||||||
          <el-input
 | 
					 | 
				
			||||||
            v-model="newFormInline.name"
 | 
					 | 
				
			||||||
            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="path">
 | 
					 | 
				
			||||||
          <el-input
 | 
					 | 
				
			||||||
            v-model="newFormInline.path"
 | 
					 | 
				
			||||||
            clearable
 | 
					 | 
				
			||||||
            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.component"
 | 
					 | 
				
			||||||
            clearable
 | 
					 | 
				
			||||||
            placeholder="请输入组件路径"
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
        </el-form-item>
 | 
					 | 
				
			||||||
      </re-col>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      <re-col :value="12" :xs="24" :sm="24">
 | 
					 | 
				
			||||||
        <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
 | 
					 | 
				
			||||||
            v-model="newFormInline.redirect"
 | 
					 | 
				
			||||||
            clearable
 | 
					 | 
				
			||||||
            placeholder="请输入默认跳转地址"
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
        </el-form-item>
 | 
					 | 
				
			||||||
      </re-col>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      <re-col
 | 
					 | 
				
			||||||
        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="auths">
 | 
					 | 
				
			||||||
          <el-input
 | 
					 | 
				
			||||||
            v-model="newFormInline.auths"
 | 
					 | 
				
			||||||
            clearable
 | 
					 | 
				
			||||||
            placeholder="请输入权限标识"
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
        </el-form-item>
 | 
					 | 
				
			||||||
      </re-col>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      <re-col
 | 
					 | 
				
			||||||
        v-show="newFormInline.menuType === 1"
 | 
					 | 
				
			||||||
        :value="12"
 | 
					 | 
				
			||||||
        :xs="24"
 | 
					 | 
				
			||||||
        :sm="24"
 | 
					 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        <!-- iframe -->
 | 
					 | 
				
			||||||
        <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 < 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 !== 3"
 | 
					 | 
				
			||||||
        :value="12"
 | 
					 | 
				
			||||||
        :xs="24"
 | 
					 | 
				
			||||||
        :sm="24"
 | 
					 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        <el-form-item label="菜单">
 | 
					 | 
				
			||||||
          <Segmented
 | 
					 | 
				
			||||||
            :modelValue="newFormInline.showLink ? 0 : 1"
 | 
					 | 
				
			||||||
            :options="showLinkOptions"
 | 
					 | 
				
			||||||
            @change="
 | 
					 | 
				
			||||||
              ({ option: { value } }) => {
 | 
					 | 
				
			||||||
                newFormInline.showLink = value;
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            "
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
        </el-form-item>
 | 
					 | 
				
			||||||
      </re-col>
 | 
					 | 
				
			||||||
      <re-col
 | 
					 | 
				
			||||||
        v-show="newFormInline.menuType !== 3"
 | 
					 | 
				
			||||||
        :value="8"
 | 
					 | 
				
			||||||
        :xs="24"
 | 
					 | 
				
			||||||
        :sm="24"
 | 
					 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        <el-form-item label="父级菜单">
 | 
					 | 
				
			||||||
          <Segmented
 | 
					 | 
				
			||||||
            :modelValue="newFormInline.showParent ? 0 : 1"
 | 
					 | 
				
			||||||
            :options="showParentOptions"
 | 
					 | 
				
			||||||
            @change="
 | 
					 | 
				
			||||||
              ({ option: { value } }) => {
 | 
					 | 
				
			||||||
                newFormInline.showParent = value;
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            "
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
        </el-form-item>
 | 
					 | 
				
			||||||
      </re-col>
 | 
					 | 
				
			||||||
    </el-row>
 | 
					 | 
				
			||||||
  </el-form>
 | 
					 | 
				
			||||||
</template>
 | 
					 | 
				
			||||||
@ -1,157 +0,0 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					 | 
				
			||||||
import { ref } from "vue";
 | 
					 | 
				
			||||||
import { useMenu } from "./utils/hook";
 | 
					 | 
				
			||||||
import { transformI18n } from "@/plugins/i18n";
 | 
					 | 
				
			||||||
import { PureTableBar } from "@/components/RePureTableBar";
 | 
					 | 
				
			||||||
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import Delete from "@iconify-icons/ep/delete";
 | 
					 | 
				
			||||||
import EditPen from "@iconify-icons/ep/edit-pen";
 | 
					 | 
				
			||||||
import Refresh from "@iconify-icons/ep/refresh";
 | 
					 | 
				
			||||||
import AddFill from "@iconify-icons/ri/add-circle-line";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
defineOptions({
 | 
					 | 
				
			||||||
  name: "SystemMenu"
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const formRef = ref();
 | 
					 | 
				
			||||||
const tableRef = ref();
 | 
					 | 
				
			||||||
const {
 | 
					 | 
				
			||||||
  form,
 | 
					 | 
				
			||||||
  loading,
 | 
					 | 
				
			||||||
  columns,
 | 
					 | 
				
			||||||
  dataList,
 | 
					 | 
				
			||||||
  onSearch,
 | 
					 | 
				
			||||||
  resetForm,
 | 
					 | 
				
			||||||
  openDialog,
 | 
					 | 
				
			||||||
  handleDelete,
 | 
					 | 
				
			||||||
  handleSelectionChange
 | 
					 | 
				
			||||||
} = useMenu();
 | 
					 | 
				
			||||||
</script>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<template>
 | 
					 | 
				
			||||||
  <div class="main">
 | 
					 | 
				
			||||||
    <el-form
 | 
					 | 
				
			||||||
      ref="formRef"
 | 
					 | 
				
			||||||
      :inline="true"
 | 
					 | 
				
			||||||
      :model="form"
 | 
					 | 
				
			||||||
      class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px]"
 | 
					 | 
				
			||||||
    >
 | 
					 | 
				
			||||||
      <el-form-item label="菜单名称:" prop="title">
 | 
					 | 
				
			||||||
        <el-input
 | 
					 | 
				
			||||||
          v-model="form.title"
 | 
					 | 
				
			||||||
          placeholder="请输入菜单名称"
 | 
					 | 
				
			||||||
          clearable
 | 
					 | 
				
			||||||
          class="!w-[180px]"
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
      </el-form-item>
 | 
					 | 
				
			||||||
      <el-form-item>
 | 
					 | 
				
			||||||
        <el-button
 | 
					 | 
				
			||||||
          type="primary"
 | 
					 | 
				
			||||||
          :icon="useRenderIcon('ri:search-line')"
 | 
					 | 
				
			||||||
          :loading="loading"
 | 
					 | 
				
			||||||
          @click="onSearch"
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          搜索
 | 
					 | 
				
			||||||
        </el-button>
 | 
					 | 
				
			||||||
        <el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)">
 | 
					 | 
				
			||||||
          重置
 | 
					 | 
				
			||||||
        </el-button>
 | 
					 | 
				
			||||||
      </el-form-item>
 | 
					 | 
				
			||||||
    </el-form>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <PureTableBar
 | 
					 | 
				
			||||||
      title="菜单管理(初版,持续完善中)"
 | 
					 | 
				
			||||||
      :columns="columns"
 | 
					 | 
				
			||||||
      :isExpandAll="false"
 | 
					 | 
				
			||||||
      :tableRef="tableRef?.getTableRef()"
 | 
					 | 
				
			||||||
      @refresh="onSearch"
 | 
					 | 
				
			||||||
    >
 | 
					 | 
				
			||||||
      <template #buttons>
 | 
					 | 
				
			||||||
        <el-button
 | 
					 | 
				
			||||||
          type="primary"
 | 
					 | 
				
			||||||
          :icon="useRenderIcon(AddFill)"
 | 
					 | 
				
			||||||
          @click="openDialog()"
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          新增菜单
 | 
					 | 
				
			||||||
        </el-button>
 | 
					 | 
				
			||||||
      </template>
 | 
					 | 
				
			||||||
      <template v-slot="{ size, dynamicColumns }">
 | 
					 | 
				
			||||||
        <pure-table
 | 
					 | 
				
			||||||
          ref="tableRef"
 | 
					 | 
				
			||||||
          adaptive
 | 
					 | 
				
			||||||
          :adaptiveConfig="{ offsetBottom: 45 }"
 | 
					 | 
				
			||||||
          align-whole="center"
 | 
					 | 
				
			||||||
          row-key="id"
 | 
					 | 
				
			||||||
          showOverflowTooltip
 | 
					 | 
				
			||||||
          table-layout="auto"
 | 
					 | 
				
			||||||
          :loading="loading"
 | 
					 | 
				
			||||||
          :size="size"
 | 
					 | 
				
			||||||
          :data="dataList"
 | 
					 | 
				
			||||||
          :columns="dynamicColumns"
 | 
					 | 
				
			||||||
          :header-cell-style="{
 | 
					 | 
				
			||||||
            background: 'var(--el-fill-color-light)',
 | 
					 | 
				
			||||||
            color: 'var(--el-text-color-primary)'
 | 
					 | 
				
			||||||
          }"
 | 
					 | 
				
			||||||
          @selection-change="handleSelectionChange"
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          <template #operation="{ row }">
 | 
					 | 
				
			||||||
            <el-button
 | 
					 | 
				
			||||||
              class="reset-margin"
 | 
					 | 
				
			||||||
              link
 | 
					 | 
				
			||||||
              type="primary"
 | 
					 | 
				
			||||||
              :size="size"
 | 
					 | 
				
			||||||
              :icon="useRenderIcon(EditPen)"
 | 
					 | 
				
			||||||
              @click="openDialog('修改', row)"
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
              修改
 | 
					 | 
				
			||||||
            </el-button>
 | 
					 | 
				
			||||||
            <el-button
 | 
					 | 
				
			||||||
              v-show="row.menuType !== 3"
 | 
					 | 
				
			||||||
              class="reset-margin"
 | 
					 | 
				
			||||||
              link
 | 
					 | 
				
			||||||
              type="primary"
 | 
					 | 
				
			||||||
              :size="size"
 | 
					 | 
				
			||||||
              :icon="useRenderIcon(AddFill)"
 | 
					 | 
				
			||||||
              @click="openDialog('新增', { parentId: row.id } as any)"
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
              新增
 | 
					 | 
				
			||||||
            </el-button>
 | 
					 | 
				
			||||||
            <el-popconfirm
 | 
					 | 
				
			||||||
              :title="`是否确认删除菜单名称为${transformI18n(row.title)}的这条数据${row?.children?.length > 0 ? '。注意下级菜单也会一并删除,请谨慎操作' : ''}`"
 | 
					 | 
				
			||||||
              @confirm="handleDelete(row)"
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
              <template #reference>
 | 
					 | 
				
			||||||
                <el-button
 | 
					 | 
				
			||||||
                  class="reset-margin"
 | 
					 | 
				
			||||||
                  link
 | 
					 | 
				
			||||||
                  type="primary"
 | 
					 | 
				
			||||||
                  :size="size"
 | 
					 | 
				
			||||||
                  :icon="useRenderIcon(Delete)"
 | 
					 | 
				
			||||||
                >
 | 
					 | 
				
			||||||
                  删除
 | 
					 | 
				
			||||||
                </el-button>
 | 
					 | 
				
			||||||
              </template>
 | 
					 | 
				
			||||||
            </el-popconfirm>
 | 
					 | 
				
			||||||
          </template>
 | 
					 | 
				
			||||||
        </pure-table>
 | 
					 | 
				
			||||||
      </template>
 | 
					 | 
				
			||||||
    </PureTableBar>
 | 
					 | 
				
			||||||
  </div>
 | 
					 | 
				
			||||||
</template>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<style lang="scss" scoped>
 | 
					 | 
				
			||||||
:deep(.el-table__inner-wrapper::before) {
 | 
					 | 
				
			||||||
  height: 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.main-content {
 | 
					 | 
				
			||||||
  margin: 24px 24px 0 !important;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.search-form {
 | 
					 | 
				
			||||||
  :deep(.el-form-item) {
 | 
					 | 
				
			||||||
    margin-bottom: 12px;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
</style>
 | 
					 | 
				
			||||||
@ -1,94 +0,0 @@
 | 
				
			|||||||
import type { OptionsType } from "@/components/ReSegmented";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const menuTypeOptions: Array<OptionsType> = [
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    label: "菜单",
 | 
					 | 
				
			||||||
    value: 0
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    label: "iframe",
 | 
					 | 
				
			||||||
    value: 1
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    label: "外链",
 | 
					 | 
				
			||||||
    value: 2
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    label: "按钮",
 | 
					 | 
				
			||||||
    value: 3
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const showLinkOptions: Array<OptionsType> = [
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    label: "显示",
 | 
					 | 
				
			||||||
    tip: "会在菜单中显示",
 | 
					 | 
				
			||||||
    value: true
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    label: "隐藏",
 | 
					 | 
				
			||||||
    tip: "不会在菜单中显示",
 | 
					 | 
				
			||||||
    value: false
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const keepAliveOptions: Array<OptionsType> = [
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    label: "缓存",
 | 
					 | 
				
			||||||
    tip: "会保存该页面的整体状态,刷新后会清空状态",
 | 
					 | 
				
			||||||
    value: true
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    label: "不缓存",
 | 
					 | 
				
			||||||
    tip: "不会保存该页面的整体状态",
 | 
					 | 
				
			||||||
    value: false
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const hiddenTagOptions: Array<OptionsType> = [
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    label: "允许",
 | 
					 | 
				
			||||||
    tip: "当前菜单名称或自定义信息允许添加到标签页",
 | 
					 | 
				
			||||||
    value: false
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    label: "禁止",
 | 
					 | 
				
			||||||
    tip: "当前菜单名称或自定义信息禁止添加到标签页",
 | 
					 | 
				
			||||||
    value: true
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const showParentOptions: Array<OptionsType> = [
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    label: "显示",
 | 
					 | 
				
			||||||
    tip: "会显示父级菜单",
 | 
					 | 
				
			||||||
    value: true
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    label: "隐藏",
 | 
					 | 
				
			||||||
    tip: "不会显示父级菜单",
 | 
					 | 
				
			||||||
    value: false
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const frameLoadingOptions: Array<OptionsType> = [
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    label: "开启",
 | 
					 | 
				
			||||||
    tip: "有首次加载动画",
 | 
					 | 
				
			||||||
    value: true
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    label: "关闭",
 | 
					 | 
				
			||||||
    tip: "无首次加载动画",
 | 
					 | 
				
			||||||
    value: false
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export {
 | 
					 | 
				
			||||||
  menuTypeOptions,
 | 
					 | 
				
			||||||
  showLinkOptions,
 | 
					 | 
				
			||||||
  keepAliveOptions,
 | 
					 | 
				
			||||||
  hiddenTagOptions,
 | 
					 | 
				
			||||||
  showParentOptions,
 | 
					 | 
				
			||||||
  frameLoadingOptions
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@ -1,223 +0,0 @@
 | 
				
			|||||||
import editForm from "../form.vue";
 | 
					 | 
				
			||||||
import { handleTree } from "@/utils/tree";
 | 
					 | 
				
			||||||
import { message } from "@/utils/message";
 | 
					 | 
				
			||||||
import { getMenuList } from "@/api/system";
 | 
					 | 
				
			||||||
import { transformI18n } from "@/plugins/i18n";
 | 
					 | 
				
			||||||
import { addDialog } from "@/components/ReDialog";
 | 
					 | 
				
			||||||
import { reactive, ref, onMounted, h } from "vue";
 | 
					 | 
				
			||||||
import type { FormItemProps } from "../utils/types";
 | 
					 | 
				
			||||||
import { cloneDeep, isAllEmpty } from "@pureadmin/utils";
 | 
					 | 
				
			||||||
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function useMenu() {
 | 
					 | 
				
			||||||
  const form = reactive({
 | 
					 | 
				
			||||||
    title: ""
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const formRef = ref();
 | 
					 | 
				
			||||||
  const dataList = ref([]);
 | 
					 | 
				
			||||||
  const loading = ref(true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const getMenuType = (type, text = false) => {
 | 
					 | 
				
			||||||
    switch (type) {
 | 
					 | 
				
			||||||
      case 0:
 | 
					 | 
				
			||||||
        return text ? "菜单" : "primary";
 | 
					 | 
				
			||||||
      case 1:
 | 
					 | 
				
			||||||
        return text ? "iframe" : "warning";
 | 
					 | 
				
			||||||
      case 2:
 | 
					 | 
				
			||||||
        return text ? "外链" : "danger";
 | 
					 | 
				
			||||||
      case 3:
 | 
					 | 
				
			||||||
        return text ? "按钮" : "info";
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const columns: TableColumnList = [
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      label: "菜单名称",
 | 
					 | 
				
			||||||
      prop: "title",
 | 
					 | 
				
			||||||
      align: "left",
 | 
					 | 
				
			||||||
      cellRenderer: ({ row }) => (
 | 
					 | 
				
			||||||
        <>
 | 
					 | 
				
			||||||
          <span class="inline-block mr-1">
 | 
					 | 
				
			||||||
            {h(useRenderIcon(row.icon), {
 | 
					 | 
				
			||||||
              style: { paddingTop: "1px" }
 | 
					 | 
				
			||||||
            })}
 | 
					 | 
				
			||||||
          </span>
 | 
					 | 
				
			||||||
          <span>{transformI18n(row.title)}</span>
 | 
					 | 
				
			||||||
        </>
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      label: "菜单类型",
 | 
					 | 
				
			||||||
      prop: "menuType",
 | 
					 | 
				
			||||||
      width: 100,
 | 
					 | 
				
			||||||
      cellRenderer: ({ row, props }) => (
 | 
					 | 
				
			||||||
        <el-tag
 | 
					 | 
				
			||||||
          size={props.size}
 | 
					 | 
				
			||||||
          type={getMenuType(row.menuType)}
 | 
					 | 
				
			||||||
          effect="plain"
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          {getMenuType(row.menuType, true)}
 | 
					 | 
				
			||||||
        </el-tag>
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      label: "路由路径",
 | 
					 | 
				
			||||||
      prop: "path"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      label: "组件路径",
 | 
					 | 
				
			||||||
      prop: "component",
 | 
					 | 
				
			||||||
      formatter: ({ path, component }) =>
 | 
					 | 
				
			||||||
        isAllEmpty(component) ? path : component
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      label: "权限标识",
 | 
					 | 
				
			||||||
      prop: "auths"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      label: "排序",
 | 
					 | 
				
			||||||
      prop: "rank",
 | 
					 | 
				
			||||||
      width: 100
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      label: "隐藏",
 | 
					 | 
				
			||||||
      prop: "showLink",
 | 
					 | 
				
			||||||
      formatter: ({ showLink }) => (showLink ? "否" : "是"),
 | 
					 | 
				
			||||||
      width: 100
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      label: "操作",
 | 
					 | 
				
			||||||
      fixed: "right",
 | 
					 | 
				
			||||||
      width: 210,
 | 
					 | 
				
			||||||
      slot: "operation"
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  ];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  function handleSelectionChange(val) {
 | 
					 | 
				
			||||||
    console.log("handleSelectionChange", val);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  function resetForm(formEl) {
 | 
					 | 
				
			||||||
    if (!formEl) return;
 | 
					 | 
				
			||||||
    formEl.resetFields();
 | 
					 | 
				
			||||||
    onSearch();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  async function onSearch() {
 | 
					 | 
				
			||||||
    loading.value = true;
 | 
					 | 
				
			||||||
    const { data } = await getMenuList(); // 这里是返回一维数组结构,前端自行处理成树结构,返回格式要求:唯一id加父节点parentId,parentId取父节点id
 | 
					 | 
				
			||||||
    let newData = data;
 | 
					 | 
				
			||||||
    if (!isAllEmpty(form.title)) {
 | 
					 | 
				
			||||||
      // 前端搜索菜单名称
 | 
					 | 
				
			||||||
      newData = newData.filter(item =>
 | 
					 | 
				
			||||||
        transformI18n(item.title).includes(form.title)
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    dataList.value = handleTree(newData); // 处理成树结构
 | 
					 | 
				
			||||||
    setTimeout(() => {
 | 
					 | 
				
			||||||
      loading.value = false;
 | 
					 | 
				
			||||||
    }, 500);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  function formatHigherMenuOptions(treeList) {
 | 
					 | 
				
			||||||
    if (!treeList || !treeList.length) return;
 | 
					 | 
				
			||||||
    const newTreeList = [];
 | 
					 | 
				
			||||||
    for (let i = 0; i < treeList.length; i++) {
 | 
					 | 
				
			||||||
      treeList[i].title = transformI18n(treeList[i].title);
 | 
					 | 
				
			||||||
      formatHigherMenuOptions(treeList[i].children);
 | 
					 | 
				
			||||||
      newTreeList.push(treeList[i]);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return newTreeList;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  function openDialog(title = "新增", row?: FormItemProps) {
 | 
					 | 
				
			||||||
    addDialog({
 | 
					 | 
				
			||||||
      title: `${title}菜单`,
 | 
					 | 
				
			||||||
      props: {
 | 
					 | 
				
			||||||
        formInline: {
 | 
					 | 
				
			||||||
          menuType: row?.menuType ?? 0,
 | 
					 | 
				
			||||||
          higherMenuOptions: formatHigherMenuOptions(cloneDeep(dataList.value)),
 | 
					 | 
				
			||||||
          parentId: row?.parentId ?? 0,
 | 
					 | 
				
			||||||
          title: row?.title ?? "",
 | 
					 | 
				
			||||||
          name: row?.name ?? "",
 | 
					 | 
				
			||||||
          path: row?.path ?? "",
 | 
					 | 
				
			||||||
          component: row?.component ?? "",
 | 
					 | 
				
			||||||
          rank: row?.rank ?? 99,
 | 
					 | 
				
			||||||
          redirect: row?.redirect ?? "",
 | 
					 | 
				
			||||||
          icon: row?.icon ?? "",
 | 
					 | 
				
			||||||
          extraIcon: row?.extraIcon ?? "",
 | 
					 | 
				
			||||||
          enterTransition: row?.enterTransition ?? "",
 | 
					 | 
				
			||||||
          leaveTransition: row?.leaveTransition ?? "",
 | 
					 | 
				
			||||||
          activePath: row?.activePath ?? "",
 | 
					 | 
				
			||||||
          auths: row?.auths ?? "",
 | 
					 | 
				
			||||||
          frameSrc: row?.frameSrc ?? "",
 | 
					 | 
				
			||||||
          frameLoading: row?.frameLoading ?? true,
 | 
					 | 
				
			||||||
          keepAlive: row?.keepAlive ?? false,
 | 
					 | 
				
			||||||
          hiddenTag: row?.hiddenTag ?? false,
 | 
					 | 
				
			||||||
          showLink: row?.showLink ?? true,
 | 
					 | 
				
			||||||
          showParent: row?.showParent ?? false
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      width: "45%",
 | 
					 | 
				
			||||||
      draggable: true,
 | 
					 | 
				
			||||||
      fullscreenIcon: true,
 | 
					 | 
				
			||||||
      closeOnClickModal: false,
 | 
					 | 
				
			||||||
      contentRenderer: () => h(editForm, { ref: formRef }),
 | 
					 | 
				
			||||||
      beforeSure: (done, { options }) => {
 | 
					 | 
				
			||||||
        const FormRef = formRef.value.getRef();
 | 
					 | 
				
			||||||
        const curData = options.props.formInline as FormItemProps;
 | 
					 | 
				
			||||||
        function chores() {
 | 
					 | 
				
			||||||
          message(
 | 
					 | 
				
			||||||
            `您${title}了菜单名称为${transformI18n(curData.title)}的这条数据`,
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
              type: "success"
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          );
 | 
					 | 
				
			||||||
          done(); // 关闭弹框
 | 
					 | 
				
			||||||
          onSearch(); // 刷新表格数据
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        FormRef.validate(valid => {
 | 
					 | 
				
			||||||
          if (valid) {
 | 
					 | 
				
			||||||
            console.log("curData", curData);
 | 
					 | 
				
			||||||
            // 表单规则校验通过
 | 
					 | 
				
			||||||
            if (title === "新增") {
 | 
					 | 
				
			||||||
              // 实际开发先调用新增接口,再进行下面操作
 | 
					 | 
				
			||||||
              chores();
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
              // 实际开发先调用修改接口,再进行下面操作
 | 
					 | 
				
			||||||
              chores();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  function handleDelete(row) {
 | 
					 | 
				
			||||||
    message(`您删除了菜单名称为${transformI18n(row.title)}的这条数据`, {
 | 
					 | 
				
			||||||
      type: "success"
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    onSearch();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  onMounted(() => {
 | 
					 | 
				
			||||||
    onSearch();
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return {
 | 
					 | 
				
			||||||
    form,
 | 
					 | 
				
			||||||
    loading,
 | 
					 | 
				
			||||||
    columns,
 | 
					 | 
				
			||||||
    dataList,
 | 
					 | 
				
			||||||
    /** 搜索 */
 | 
					 | 
				
			||||||
    onSearch,
 | 
					 | 
				
			||||||
    /** 重置 */
 | 
					 | 
				
			||||||
    resetForm,
 | 
					 | 
				
			||||||
    /** 新增、修改菜单 */
 | 
					 | 
				
			||||||
    openDialog,
 | 
					 | 
				
			||||||
    /** 删除菜单 */
 | 
					 | 
				
			||||||
    handleDelete,
 | 
					 | 
				
			||||||
    handleSelectionChange
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,10 +0,0 @@
 | 
				
			|||||||
import { reactive } from "vue";
 | 
					 | 
				
			||||||
import type { FormRules } from "element-plus";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/** 自定义表单规则校验 */
 | 
					 | 
				
			||||||
export const formRules = reactive(<FormRules>{
 | 
					 | 
				
			||||||
  title: [{ required: true, message: "菜单名称为必填项", trigger: "blur" }],
 | 
					 | 
				
			||||||
  name: [{ required: true, message: "路由名称为必填项", trigger: "blur" }],
 | 
					 | 
				
			||||||
  path: [{ required: true, message: "路由路径为必填项", trigger: "blur" }],
 | 
					 | 
				
			||||||
  auths: [{ required: true, message: "权限标识为必填项", trigger: "blur" }]
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
@ -1,29 +0,0 @@
 | 
				
			|||||||
interface FormItemProps {
 | 
					 | 
				
			||||||
  /** 菜单类型(0代表菜单、1代表iframe、2代表外链、3代表按钮)*/
 | 
					 | 
				
			||||||
  menuType: number;
 | 
					 | 
				
			||||||
  higherMenuOptions: Record<string, unknown>[];
 | 
					 | 
				
			||||||
  parentId: number;
 | 
					 | 
				
			||||||
  title: string;
 | 
					 | 
				
			||||||
  name: string;
 | 
					 | 
				
			||||||
  path: string;
 | 
					 | 
				
			||||||
  component: string;
 | 
					 | 
				
			||||||
  rank: number;
 | 
					 | 
				
			||||||
  redirect: string;
 | 
					 | 
				
			||||||
  icon: string;
 | 
					 | 
				
			||||||
  extraIcon: string;
 | 
					 | 
				
			||||||
  enterTransition: string;
 | 
					 | 
				
			||||||
  leaveTransition: string;
 | 
					 | 
				
			||||||
  activePath: string;
 | 
					 | 
				
			||||||
  auths: string;
 | 
					 | 
				
			||||||
  frameSrc: string;
 | 
					 | 
				
			||||||
  frameLoading: boolean;
 | 
					 | 
				
			||||||
  keepAlive: boolean;
 | 
					 | 
				
			||||||
  hiddenTag: boolean;
 | 
					 | 
				
			||||||
  showLink: boolean;
 | 
					 | 
				
			||||||
  showParent: boolean;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
interface FormProps {
 | 
					 | 
				
			||||||
  formInline: FormItemProps;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export type { FormItemProps, FormProps };
 | 
					 | 
				
			||||||
@ -5,15 +5,23 @@ import { FormProps } from "./utils/types";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const props = withDefaults(defineProps<FormProps>(), {
 | 
					const props = withDefaults(defineProps<FormProps>(), {
 | 
				
			||||||
  formInline: () => ({
 | 
					  formInline: () => ({
 | 
				
			||||||
 | 
					    id: 0,
 | 
				
			||||||
    name: "",
 | 
					    name: "",
 | 
				
			||||||
    code: "",
 | 
					    description: "",
 | 
				
			||||||
    remark: ""
 | 
					    dataScope: "全部",
 | 
				
			||||||
 | 
					    level: 0,
 | 
				
			||||||
 | 
					    depts: [],
 | 
				
			||||||
 | 
					    deptIds: []
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					 | 
				
			||||||
const ruleFormRef = ref();
 | 
					const ruleFormRef = ref();
 | 
				
			||||||
const newFormInline = ref(props.formInline);
 | 
					const newFormInline = ref(props.formInline);
 | 
				
			||||||
 | 
					const props1 = {
 | 
				
			||||||
 | 
					  multiple: true,
 | 
				
			||||||
 | 
					  value: "id",
 | 
				
			||||||
 | 
					  label: "name",
 | 
				
			||||||
 | 
					  checkStrictly: true
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
function getRef() {
 | 
					function getRef() {
 | 
				
			||||||
  return ruleFormRef.value;
 | 
					  return ruleFormRef.value;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -28,28 +36,68 @@ defineExpose({ getRef });
 | 
				
			|||||||
    :rules="formRules"
 | 
					    :rules="formRules"
 | 
				
			||||||
    label-width="82px"
 | 
					    label-width="82px"
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <el-form-item label="角色名称" prop="name">
 | 
					    <el-row>
 | 
				
			||||||
      <el-input
 | 
					      <el-col>
 | 
				
			||||||
        v-model="newFormInline.name"
 | 
					        <el-form-item label="角色名称" prop="name">
 | 
				
			||||||
        clearable
 | 
					          <el-input
 | 
				
			||||||
        placeholder="请输入角色名称"
 | 
					            v-model="newFormInline.name"
 | 
				
			||||||
      />
 | 
					            clearable
 | 
				
			||||||
    </el-form-item>
 | 
					            placeholder="请输入角色名称"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
    <el-form-item label="角色标识" prop="code">
 | 
					        </el-form-item>
 | 
				
			||||||
      <el-input
 | 
					      </el-col>
 | 
				
			||||||
        v-model="newFormInline.code"
 | 
					      <el-col :span="12">
 | 
				
			||||||
        clearable
 | 
					        <el-form-item label="角色级别" prop="level">
 | 
				
			||||||
        placeholder="请输入角色标识"
 | 
					          <el-input-number
 | 
				
			||||||
      />
 | 
					            v-model="newFormInline.level"
 | 
				
			||||||
    </el-form-item>
 | 
					            clearable
 | 
				
			||||||
 | 
					            :min="0"
 | 
				
			||||||
    <el-form-item label="备注">
 | 
					            placeholder="请输入角色级别"
 | 
				
			||||||
      <el-input
 | 
					          />
 | 
				
			||||||
        v-model="newFormInline.remark"
 | 
					        </el-form-item>
 | 
				
			||||||
        placeholder="请输入备注信息"
 | 
					      </el-col>
 | 
				
			||||||
        type="textarea"
 | 
					      <el-col :span="12">
 | 
				
			||||||
      />
 | 
					        <el-form-item label="数据范围" prop="dataScope">
 | 
				
			||||||
    </el-form-item>
 | 
					          <el-select
 | 
				
			||||||
 | 
					            v-model="newFormInline.dataScope"
 | 
				
			||||||
 | 
					            filterable
 | 
				
			||||||
 | 
					            placeholder="请选择数据范围"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <el-option key="全部" value="全部" label="全部" default />
 | 
				
			||||||
 | 
					            <el-option key="本级" value="本级" label="本级" />
 | 
				
			||||||
 | 
					            <el-option key="自定义" value="自定义" label="自定义" />
 | 
				
			||||||
 | 
					          </el-select>
 | 
				
			||||||
 | 
					        </el-form-item>
 | 
				
			||||||
 | 
					      </el-col>
 | 
				
			||||||
 | 
					      <el-col v-show="newFormInline.dataScope === '自定义'">
 | 
				
			||||||
 | 
					        <el-form-item label="数据权限" prop="deptIds">
 | 
				
			||||||
 | 
					          <el-cascader
 | 
				
			||||||
 | 
					            v-model="newFormInline.deptIds"
 | 
				
			||||||
 | 
					            placeholder="请选择部门"
 | 
				
			||||||
 | 
					            clearable
 | 
				
			||||||
 | 
					            filterable
 | 
				
			||||||
 | 
					            :props="props1"
 | 
				
			||||||
 | 
					            :show-all-levels="false"
 | 
				
			||||||
 | 
					            :options="newFormInline.depts"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <template #default="{ node, data }">
 | 
				
			||||||
 | 
					              <span>{{ data.name }}</span>
 | 
				
			||||||
 | 
					              <span v-if="!node.isLeaf && data.children?.length > 0">
 | 
				
			||||||
 | 
					                ({{ data.children?.length }})
 | 
				
			||||||
 | 
					              </span>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					          </el-cascader>
 | 
				
			||||||
 | 
					        </el-form-item>
 | 
				
			||||||
 | 
					      </el-col>
 | 
				
			||||||
 | 
					      <el-col>
 | 
				
			||||||
 | 
					        <el-form-item label="备注">
 | 
				
			||||||
 | 
					          <el-input
 | 
				
			||||||
 | 
					            v-model="newFormInline.description"
 | 
				
			||||||
 | 
					            placeholder="请输入备注信息"
 | 
				
			||||||
 | 
					            type="textarea"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </el-form-item>
 | 
				
			||||||
 | 
					      </el-col>
 | 
				
			||||||
 | 
					    </el-row>
 | 
				
			||||||
  </el-form>
 | 
					  </el-form>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,180 +1,183 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import { ref } from "vue";
 | 
					import { ref } from "vue";
 | 
				
			||||||
import { useRole } from "./utils/hook";
 | 
					import { useRole } from "./utils/hook";
 | 
				
			||||||
 | 
					import tree from "./tree.vue";
 | 
				
			||||||
import { PureTableBar } from "@/components/RePureTableBar";
 | 
					import { PureTableBar } from "@/components/RePureTableBar";
 | 
				
			||||||
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 | 
					import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 | 
				
			||||||
 | 
					import * as Role from "@/api/system/role";
 | 
				
			||||||
 | 
					import { message } from "@/utils/message";
 | 
				
			||||||
 | 
					import datePicker from "@/views/components/date-picker.vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// import Database from "@iconify-icons/ri/database-2-line";
 | 
				
			||||||
 | 
					// import More from "@iconify-icons/ep/more-filled";
 | 
				
			||||||
import Delete from "@iconify-icons/ep/delete";
 | 
					import Delete from "@iconify-icons/ep/delete";
 | 
				
			||||||
import Edit from "@iconify-icons/ep/edit";
 | 
					import EditPen from "@iconify-icons/ep/edit-pen";
 | 
				
			||||||
import Refresh from "@iconify-icons/ep/refresh";
 | 
					import Refresh from "@iconify-icons/ep/refresh";
 | 
				
			||||||
import AddFill from "@iconify-icons/ri/add-circle-line";
 | 
					import AddFill from "@iconify-icons/ri/add-circle-line";
 | 
				
			||||||
import Download from "@iconify-icons/ep/download";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
defineOptions({
 | 
					defineOptions({
 | 
				
			||||||
  name: "SystemRole"
 | 
					  name: "Role"
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const exportClick = async () => {
 | 
				
			||||||
 | 
					  const response: Blob = await Role.download(null);
 | 
				
			||||||
 | 
					  const a = document.createElement("a");
 | 
				
			||||||
 | 
					  const url = window.URL.createObjectURL(response); // 创建媒体流 url ,详细了解可自己查 URL.createObjectURL(推荐 MDN )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  a.href = url;
 | 
				
			||||||
 | 
					  a.style.display = "none";
 | 
				
			||||||
 | 
					  document.body.appendChild(a);
 | 
				
			||||||
 | 
					  a.click();
 | 
				
			||||||
 | 
					  a.parentNode.removeChild(a);
 | 
				
			||||||
 | 
					  window.URL.revokeObjectURL(url); // 删除创建的媒体流 url 对象
 | 
				
			||||||
 | 
					  message("导出成功", {
 | 
				
			||||||
 | 
					    type: "success"
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					const treeRef = ref();
 | 
				
			||||||
const formRef = ref();
 | 
					const formRef = ref();
 | 
				
			||||||
 | 
					const tableRef = ref();
 | 
				
			||||||
const {
 | 
					const {
 | 
				
			||||||
  form,
 | 
					  form,
 | 
				
			||||||
  loading,
 | 
					  loading,
 | 
				
			||||||
  columns,
 | 
					  columns,
 | 
				
			||||||
  dataList,
 | 
					  dataList,
 | 
				
			||||||
  pagination,
 | 
					  pagination,
 | 
				
			||||||
  disabledDelete,
 | 
					  treeData,
 | 
				
			||||||
  disabledEdit,
 | 
					  treeLoading,
 | 
				
			||||||
  disabledEditFrom,
 | 
					  currentRow,
 | 
				
			||||||
 | 
					  deptId,
 | 
				
			||||||
 | 
					  // buttonClass,
 | 
				
			||||||
 | 
					  onTreeSelect,
 | 
				
			||||||
 | 
					  // buttonClass,
 | 
				
			||||||
  onSearch,
 | 
					  onSearch,
 | 
				
			||||||
  resetForm,
 | 
					  resetForm,
 | 
				
			||||||
  openDialog,
 | 
					  openDialog,
 | 
				
			||||||
  handleDelete,
 | 
					  handleDelete,
 | 
				
			||||||
 | 
					  // handleDatabase,
 | 
				
			||||||
  handleSizeChange,
 | 
					  handleSizeChange,
 | 
				
			||||||
  handleCurrentChange,
 | 
					  handleCurrentChange,
 | 
				
			||||||
  handleSelectionChange
 | 
					  handleCurrentChange1
 | 
				
			||||||
} = useRole();
 | 
					} = useRole(tableRef, treeRef);
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div class="main">
 | 
					  <div class="flex justify-between">
 | 
				
			||||||
    <!-- 搜索状态栏 -->
 | 
					    <div class="w-[calc(90%-180px)]">
 | 
				
			||||||
    <el-form
 | 
					      <el-form
 | 
				
			||||||
      ref="formRef"
 | 
					        ref="formRef"
 | 
				
			||||||
      :inline="true"
 | 
					        :inline="true"
 | 
				
			||||||
      :model="form"
 | 
					        :model="form"
 | 
				
			||||||
      class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px]"
 | 
					        class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px]"
 | 
				
			||||||
    >
 | 
					      >
 | 
				
			||||||
      <el-form-item label="角色名称:" prop="name">
 | 
					        <el-form-item label="角色名称:" prop="blurry">
 | 
				
			||||||
        <el-input
 | 
					          <el-input
 | 
				
			||||||
          v-model="form.name"
 | 
					            v-model="form.blurry"
 | 
				
			||||||
          placeholder="请输入角色名称"
 | 
					            placeholder="请输入角色名称"
 | 
				
			||||||
          clearable
 | 
					            clearable
 | 
				
			||||||
          class="!w-[180px]"
 | 
					            class="!w-[200px]"
 | 
				
			||||||
        />
 | 
					          />
 | 
				
			||||||
      </el-form-item>
 | 
					        </el-form-item>
 | 
				
			||||||
      <el-form-item label="状态:" prop="status">
 | 
					        <el-form-item label="" prop="createTime">
 | 
				
			||||||
        <el-select
 | 
					          <datePicker v-model="form.createTime" />
 | 
				
			||||||
          v-model="form.status"
 | 
					        </el-form-item>
 | 
				
			||||||
          placeholder="请选择状态"
 | 
					        <el-form-item>
 | 
				
			||||||
          clearable
 | 
					          <el-button
 | 
				
			||||||
          class="!w-[180px]"
 | 
					            type="primary"
 | 
				
			||||||
        >
 | 
					            :icon="useRenderIcon('search')"
 | 
				
			||||||
          <el-option label="已启用" value="1" />
 | 
					            :loading="loading"
 | 
				
			||||||
          <el-option label="已停用" value="0" />
 | 
					            @click="onSearch"
 | 
				
			||||||
        </el-select>
 | 
					          >
 | 
				
			||||||
      </el-form-item>
 | 
					            搜索
 | 
				
			||||||
      <el-form-item>
 | 
					          </el-button>
 | 
				
			||||||
        <el-button
 | 
					          <el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)">
 | 
				
			||||||
          type="primary"
 | 
					            重置
 | 
				
			||||||
          :icon="useRenderIcon('ri:search-line')"
 | 
					          </el-button>
 | 
				
			||||||
          :loading="loading"
 | 
					        </el-form-item>
 | 
				
			||||||
          @click="onSearch"
 | 
					      </el-form>
 | 
				
			||||||
        >
 | 
					
 | 
				
			||||||
          搜索
 | 
					      <PureTableBar title="角色列表" :columns="columns" @refresh="onSearch">
 | 
				
			||||||
        </el-button>
 | 
					        <template #add>
 | 
				
			||||||
        <el-button
 | 
					          <el-button
 | 
				
			||||||
          type="info"
 | 
					            type="primary"
 | 
				
			||||||
          :icon="useRenderIcon(Refresh)"
 | 
					            :icon="useRenderIcon(AddFill)"
 | 
				
			||||||
          @click="resetForm(formRef)"
 | 
					            @click="openDialog()"
 | 
				
			||||||
        >
 | 
					          >
 | 
				
			||||||
          重置
 | 
					            新增角色
 | 
				
			||||||
        </el-button>
 | 
					          </el-button>
 | 
				
			||||||
      </el-form-item>
 | 
					        </template>
 | 
				
			||||||
    </el-form>
 | 
					        <template #export>
 | 
				
			||||||
    <!-- 表格 -->
 | 
					          <el-button
 | 
				
			||||||
    <PureTableBar
 | 
					            type="success"
 | 
				
			||||||
      title="角色管理(仅演示,操作后不生效)"
 | 
					            :icon="useRenderIcon('solar:upload-bold')"
 | 
				
			||||||
      :columns="columns"
 | 
					            @click="exportClick()"
 | 
				
			||||||
      @refresh="onSearch"
 | 
					          >
 | 
				
			||||||
    >
 | 
					            导出数据
 | 
				
			||||||
      <!-- 表头按钮 -->
 | 
					          </el-button>
 | 
				
			||||||
      <template #buttons>
 | 
					        </template>
 | 
				
			||||||
        <el-button
 | 
					        <template v-slot="{ size, dynamicColumns }">
 | 
				
			||||||
          type="success"
 | 
					          <pure-table
 | 
				
			||||||
          :icon="useRenderIcon(AddFill)"
 | 
					            ref="tableRef"
 | 
				
			||||||
          @click="openDialog()"
 | 
					            align-whole="center"
 | 
				
			||||||
        >
 | 
					            showOverflowTooltip
 | 
				
			||||||
          新增
 | 
					            adaptive
 | 
				
			||||||
        </el-button>
 | 
					            table-layout="auto"
 | 
				
			||||||
        <el-button
 | 
					            :loading="loading"
 | 
				
			||||||
          type="primary"
 | 
					            :size="size"
 | 
				
			||||||
          :icon="useRenderIcon(Edit)"
 | 
					            :data="dataList"
 | 
				
			||||||
          :disabled="disabledEdit"
 | 
					            :columns="dynamicColumns"
 | 
				
			||||||
          @click="openDialog('修改', disabledEditFrom)"
 | 
					            :pagination="pagination"
 | 
				
			||||||
        >
 | 
					            :paginationSmall="size === 'small' ? true : false"
 | 
				
			||||||
          修改
 | 
					            :header-cell-style="{
 | 
				
			||||||
        </el-button>
 | 
					              background: 'var(--el-fill-color-light)',
 | 
				
			||||||
        <el-button
 | 
					              color: 'var(--el-text-color-primary)'
 | 
				
			||||||
          type="danger"
 | 
					            }"
 | 
				
			||||||
          :icon="useRenderIcon(Delete)"
 | 
					            highlight-current-row
 | 
				
			||||||
          :disabled="disabledDelete"
 | 
					            @selection-change="handleCurrentChange"
 | 
				
			||||||
          @click="openDialog()"
 | 
					            @page-size-change="handleSizeChange"
 | 
				
			||||||
        >
 | 
					            @page-current-change="handleCurrentChange"
 | 
				
			||||||
          删除
 | 
					            @current-change="handleCurrentChange1"
 | 
				
			||||||
        </el-button>
 | 
					          >
 | 
				
			||||||
        <el-button
 | 
					            <template #operation="{ row }">
 | 
				
			||||||
          type="warning"
 | 
					              <el-button
 | 
				
			||||||
          :icon="useRenderIcon(Download)"
 | 
					                class="reset-margin"
 | 
				
			||||||
          @click="openDialog()"
 | 
					                link
 | 
				
			||||||
        >
 | 
					                type="primary"
 | 
				
			||||||
          导出
 | 
					                :size="size"
 | 
				
			||||||
        </el-button>
 | 
					                :icon="useRenderIcon(EditPen)"
 | 
				
			||||||
      </template>
 | 
					                @click="openDialog('编辑', row)"
 | 
				
			||||||
      <!-- 表格内容 -->
 | 
					              >
 | 
				
			||||||
      <template v-slot="{ size, dynamicColumns }">
 | 
					                修改
 | 
				
			||||||
        <pure-table
 | 
					              </el-button>
 | 
				
			||||||
          align-whole="center"
 | 
					              <el-popconfirm
 | 
				
			||||||
          showOverflowTooltip
 | 
					                :title="`是否确认删除角色名称为${row.name}的这条数据`"
 | 
				
			||||||
          table-layout="auto"
 | 
					                @confirm="handleDelete(row)"
 | 
				
			||||||
          :loading="loading"
 | 
					              >
 | 
				
			||||||
          :size="size"
 | 
					                <template #reference>
 | 
				
			||||||
          adaptive
 | 
					                  <el-button
 | 
				
			||||||
          stripe
 | 
					                    class="reset-margin"
 | 
				
			||||||
          :adaptiveConfig="{ offsetBottom: 108 }"
 | 
					                    link
 | 
				
			||||||
          :data="dataList"
 | 
					                    type="primary"
 | 
				
			||||||
          row-key="id"
 | 
					                    :size="size"
 | 
				
			||||||
          :columns="dynamicColumns"
 | 
					                    :icon="useRenderIcon(Delete)"
 | 
				
			||||||
          :pagination="pagination"
 | 
					                  >
 | 
				
			||||||
          :paginationSmall="size === 'small' ? true : false"
 | 
					                    删除
 | 
				
			||||||
          :header-cell-style="{
 | 
					                  </el-button>
 | 
				
			||||||
            background: 'var(--el-fill-color-light)',
 | 
					                </template>
 | 
				
			||||||
            color: 'var(--el-text-color-primary)'
 | 
					              </el-popconfirm>
 | 
				
			||||||
          }"
 | 
					            </template>
 | 
				
			||||||
          @selection-change="handleSelectionChange"
 | 
					          </pure-table>
 | 
				
			||||||
          @page-size-change="handleSizeChange"
 | 
					        </template>
 | 
				
			||||||
          @page-current-change="handleCurrentChange"
 | 
					      </PureTableBar>
 | 
				
			||||||
        >
 | 
					    </div>
 | 
				
			||||||
          <!-- 表格数据操作按钮 -->
 | 
					    <tree
 | 
				
			||||||
          <template #operation="{ row }">
 | 
					      v-model:currentRow="currentRow"
 | 
				
			||||||
            <el-button
 | 
					      v-model:deptId="deptId"
 | 
				
			||||||
              class="reset-margin"
 | 
					      class="min-w-[300px] mr-2"
 | 
				
			||||||
              link
 | 
					      :treeData="treeData"
 | 
				
			||||||
              type="primary"
 | 
					      :treeLoading="treeLoading"
 | 
				
			||||||
              :size="size"
 | 
					      @tree-select="onTreeSelect"
 | 
				
			||||||
              :icon="useRenderIcon(Edit)"
 | 
					    />
 | 
				
			||||||
              @click="openDialog('修改', row)"
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
              修改
 | 
					 | 
				
			||||||
            </el-button>
 | 
					 | 
				
			||||||
            <el-popconfirm
 | 
					 | 
				
			||||||
              :title="`是否确认删除角色名称为${row.name}的这条数据`"
 | 
					 | 
				
			||||||
              @confirm="handleDelete(row)"
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
              <template #reference>
 | 
					 | 
				
			||||||
                <el-button
 | 
					 | 
				
			||||||
                  class="reset-margin"
 | 
					 | 
				
			||||||
                  link
 | 
					 | 
				
			||||||
                  type="danger"
 | 
					 | 
				
			||||||
                  :size="size"
 | 
					 | 
				
			||||||
                  :icon="useRenderIcon(Delete)"
 | 
					 | 
				
			||||||
                >
 | 
					 | 
				
			||||||
                  删除
 | 
					 | 
				
			||||||
                </el-button>
 | 
					 | 
				
			||||||
              </template>
 | 
					 | 
				
			||||||
            </el-popconfirm>
 | 
					 | 
				
			||||||
          </template>
 | 
					 | 
				
			||||||
        </pure-table>
 | 
					 | 
				
			||||||
      </template>
 | 
					 | 
				
			||||||
    </PureTableBar>
 | 
					 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -183,10 +186,6 @@ const {
 | 
				
			|||||||
  margin: 0;
 | 
					  margin: 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.main-content {
 | 
					 | 
				
			||||||
  margin: 24px 24px 0 !important;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.search-form {
 | 
					.search-form {
 | 
				
			||||||
  :deep(.el-form-item) {
 | 
					  :deep(.el-form-item) {
 | 
				
			||||||
    margin-bottom: 12px;
 | 
					    margin-bottom: 12px;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										213
									
								
								src/views/system/role/tree.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								src/views/system/role/tree.vue
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,213 @@
 | 
				
			|||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import { ref, computed, watch, defineModel, getCurrentInstance } from "vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Dept from "@iconify-icons/ri/git-branch-line";
 | 
				
			||||||
 | 
					// import Reset from "@iconify-icons/ri/restart-line";
 | 
				
			||||||
 | 
					import More2Fill from "@iconify-icons/ri/more-2-fill";
 | 
				
			||||||
 | 
					import OfficeBuilding from "@iconify-icons/ep/office-building";
 | 
				
			||||||
 | 
					import LocationCompany from "@iconify-icons/ep/add-location";
 | 
				
			||||||
 | 
					import { TreeKey } from "element-plus/es/components/tree/src/tree.type.mjs";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface Tree {
 | 
				
			||||||
 | 
					  id: number;
 | 
				
			||||||
 | 
					  label: string;
 | 
				
			||||||
 | 
					  highlight?: boolean;
 | 
				
			||||||
 | 
					  children?: Tree[];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const props = defineProps({
 | 
				
			||||||
 | 
					  treeLoading: Boolean,
 | 
				
			||||||
 | 
					  treeData: Array
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					const currentRow = defineModel<TreeKey[]>("currentRow");
 | 
				
			||||||
 | 
					const deptId = defineModel<Number>("deptId");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const emit = defineEmits(["tree-select"]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const treeRef = ref();
 | 
				
			||||||
 | 
					const treeRef2 = ref();
 | 
				
			||||||
 | 
					const isExpand = ref(true);
 | 
				
			||||||
 | 
					const searchValue = ref("");
 | 
				
			||||||
 | 
					const highlightMap = ref({});
 | 
				
			||||||
 | 
					const { proxy } = getCurrentInstance();
 | 
				
			||||||
 | 
					const defaultProps = {
 | 
				
			||||||
 | 
					  children: "children",
 | 
				
			||||||
 | 
					  label: "label"
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					const buttonClass = computed(() => {
 | 
				
			||||||
 | 
					  return [
 | 
				
			||||||
 | 
					    "!h-[20px]",
 | 
				
			||||||
 | 
					    "reset-margin",
 | 
				
			||||||
 | 
					    "!text-gray-500",
 | 
				
			||||||
 | 
					    "dark:!text-white",
 | 
				
			||||||
 | 
					    "dark:hover:!text-primary"
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const filterNode = (value: string, data: Tree) => {
 | 
				
			||||||
 | 
					  if (!value) return true;
 | 
				
			||||||
 | 
					  return data.label.includes(value);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function toggleRowExpansionAll(status) {
 | 
				
			||||||
 | 
					  isExpand.value = status;
 | 
				
			||||||
 | 
					  const nodes = (proxy.$refs["treeRef"] as any).store._getAllNodes();
 | 
				
			||||||
 | 
					  for (let i = 0; i < nodes.length; i++) {
 | 
				
			||||||
 | 
					    nodes[i].expanded = status;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/** 重置部门树状态(选中状态、搜索框值、树初始化) */
 | 
				
			||||||
 | 
					function onTreeReset() {
 | 
				
			||||||
 | 
					  highlightMap.value = {};
 | 
				
			||||||
 | 
					  searchValue.value = "";
 | 
				
			||||||
 | 
					  toggleRowExpansionAll(true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function testClick() {
 | 
				
			||||||
 | 
					  emit("tree-select", { id: deptId, menuIds: treeRef.value.getCheckedKeys() });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					watch(searchValue, val => {
 | 
				
			||||||
 | 
					  treeRef.value!.filter(val);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defineExpose({ onTreeReset });
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div
 | 
				
			||||||
 | 
					    v-loading="props.treeLoading"
 | 
				
			||||||
 | 
					    class="h-full bg-bg_color overflow-auto"
 | 
				
			||||||
 | 
					    :style="{ minHeight: `calc(100vh - 133px)` }"
 | 
				
			||||||
 | 
					  >
 | 
				
			||||||
 | 
					    <div class="flex items-center h-[34px]">
 | 
				
			||||||
 | 
					      <el-row :gutter="24">
 | 
				
			||||||
 | 
					        <el-col :span="16"
 | 
				
			||||||
 | 
					          ><div class="grid-content ep-bg-purple" />
 | 
				
			||||||
 | 
					          菜单分配</el-col
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					        <el-col :span="6"
 | 
				
			||||||
 | 
					          ><div class="grid-content ep-bg-purple" />
 | 
				
			||||||
 | 
					          <el-button type="primary" @click="testClick">✔保存</el-button>
 | 
				
			||||||
 | 
					        </el-col>
 | 
				
			||||||
 | 
					      </el-row>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="flex items-center h-[34px]">
 | 
				
			||||||
 | 
					      <el-input
 | 
				
			||||||
 | 
					        v-model="searchValue"
 | 
				
			||||||
 | 
					        class="ml-2"
 | 
				
			||||||
 | 
					        size="small"
 | 
				
			||||||
 | 
					        placeholder="请输入部门名称"
 | 
				
			||||||
 | 
					        clearable
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <template #suffix>
 | 
				
			||||||
 | 
					          <el-icon v-show="searchValue.length === 0" class="el-input__icon">
 | 
				
			||||||
 | 
					            <IconifyIconOffline icon="search" />
 | 
				
			||||||
 | 
					          </el-icon>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					      </el-input>
 | 
				
			||||||
 | 
					      <el-dropdown :hide-on-click="false">
 | 
				
			||||||
 | 
					        <IconifyIconOffline
 | 
				
			||||||
 | 
					          class="w-[28px] cursor-pointer"
 | 
				
			||||||
 | 
					          width="18px"
 | 
				
			||||||
 | 
					          :icon="More2Fill"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					        <template #dropdown>
 | 
				
			||||||
 | 
					          <el-dropdown-menu>
 | 
				
			||||||
 | 
					            <el-dropdown-item>
 | 
				
			||||||
 | 
					              <el-button
 | 
				
			||||||
 | 
					                :class="buttonClass"
 | 
				
			||||||
 | 
					                link
 | 
				
			||||||
 | 
					                type="primary"
 | 
				
			||||||
 | 
					                @click="toggleRowExpansionAll(isExpand ? false : true)"
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                {{ isExpand ? "折叠全部" : "展开全部" }}
 | 
				
			||||||
 | 
					              </el-button>
 | 
				
			||||||
 | 
					            </el-dropdown-item>
 | 
				
			||||||
 | 
					            <el-dropdown-item>
 | 
				
			||||||
 | 
					              <el-button
 | 
				
			||||||
 | 
					                :class="buttonClass"
 | 
				
			||||||
 | 
					                link
 | 
				
			||||||
 | 
					                type="primary"
 | 
				
			||||||
 | 
					                @click="onTreeReset"
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                全选
 | 
				
			||||||
 | 
					              </el-button>
 | 
				
			||||||
 | 
					            </el-dropdown-item>
 | 
				
			||||||
 | 
					            <el-dropdown-item>
 | 
				
			||||||
 | 
					              <el-button
 | 
				
			||||||
 | 
					                :class="buttonClass"
 | 
				
			||||||
 | 
					                link
 | 
				
			||||||
 | 
					                type="primary"
 | 
				
			||||||
 | 
					                @click="onTreeReset"
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                取消全选
 | 
				
			||||||
 | 
					              </el-button>
 | 
				
			||||||
 | 
					            </el-dropdown-item>
 | 
				
			||||||
 | 
					          </el-dropdown-menu>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					      </el-dropdown>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <el-divider />
 | 
				
			||||||
 | 
					    <el-tree
 | 
				
			||||||
 | 
					      ref="treeRef"
 | 
				
			||||||
 | 
					      node-key="id"
 | 
				
			||||||
 | 
					      size="small"
 | 
				
			||||||
 | 
					      show-checkbox
 | 
				
			||||||
 | 
					      :data="treeData"
 | 
				
			||||||
 | 
					      :props="defaultProps"
 | 
				
			||||||
 | 
					      :default-checked-keys="currentRow"
 | 
				
			||||||
 | 
					      :current-node-key="treeRef2"
 | 
				
			||||||
 | 
					      :expand-on-click-node="false"
 | 
				
			||||||
 | 
					      :filter-node-method="filterNode"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <template #default="{ node, data }">
 | 
				
			||||||
 | 
					        <span
 | 
				
			||||||
 | 
					          :class="[
 | 
				
			||||||
 | 
					            'pl-1',
 | 
				
			||||||
 | 
					            'pr-1',
 | 
				
			||||||
 | 
					            'rounded',
 | 
				
			||||||
 | 
					            'flex',
 | 
				
			||||||
 | 
					            'items-center',
 | 
				
			||||||
 | 
					            'select-none',
 | 
				
			||||||
 | 
					            'hover:text-primary',
 | 
				
			||||||
 | 
					            searchValue.trim().length > 0 &&
 | 
				
			||||||
 | 
					              node.label.includes(searchValue) &&
 | 
				
			||||||
 | 
					              'text-red-500',
 | 
				
			||||||
 | 
					            highlightMap[node.id]?.highlight ? 'dark:text-primary' : ''
 | 
				
			||||||
 | 
					          ]"
 | 
				
			||||||
 | 
					          :style="{
 | 
				
			||||||
 | 
					            color: highlightMap[node.id]?.highlight
 | 
				
			||||||
 | 
					              ? 'var(--el-color-primary)'
 | 
				
			||||||
 | 
					              : '',
 | 
				
			||||||
 | 
					            background: highlightMap[node.id]?.highlight
 | 
				
			||||||
 | 
					              ? 'var(--el-color-primary-light-7)'
 | 
				
			||||||
 | 
					              : 'transparent'
 | 
				
			||||||
 | 
					          }"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <IconifyIconOffline
 | 
				
			||||||
 | 
					            :icon="
 | 
				
			||||||
 | 
					              data.type === 1
 | 
				
			||||||
 | 
					                ? OfficeBuilding
 | 
				
			||||||
 | 
					                : data.type === 2
 | 
				
			||||||
 | 
					                  ? LocationCompany
 | 
				
			||||||
 | 
					                  : Dept
 | 
				
			||||||
 | 
					            "
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					          {{ node.label }}
 | 
				
			||||||
 | 
					        </span>
 | 
				
			||||||
 | 
					      </template>
 | 
				
			||||||
 | 
					    </el-tree>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style lang="scss" scoped>
 | 
				
			||||||
 | 
					:deep(.el-divider) {
 | 
				
			||||||
 | 
					  margin: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					:deep(.el-tree) {
 | 
				
			||||||
 | 
					  --el-tree-node-hover-bg-color: transparent;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
@ -1,68 +1,61 @@
 | 
				
			|||||||
import dayjs from "dayjs";
 | 
					import dayjs from "dayjs";
 | 
				
			||||||
import editForm from "../form.vue";
 | 
					import editForm from "../form.vue";
 | 
				
			||||||
import { message } from "@/utils/message";
 | 
					import { message } from "@/utils/message";
 | 
				
			||||||
import { getRoleList } from "@/api/system";
 | 
					import * as Role from "@/api/system/role";
 | 
				
			||||||
import { ElMessageBox } from "element-plus";
 | 
					 | 
				
			||||||
import { usePublicHooks } from "../../hooks";
 | 
					 | 
				
			||||||
import { addDialog } from "@/components/ReDialog";
 | 
					import { addDialog } from "@/components/ReDialog";
 | 
				
			||||||
import type { FormItemProps } from "../utils/types";
 | 
					import type { FormItemProps } from "../utils/types";
 | 
				
			||||||
import type { PaginationProps } from "@pureadmin/table";
 | 
					import type { PaginationProps } from "@pureadmin/table";
 | 
				
			||||||
import { reactive, ref, onMounted, h, toRaw } from "vue";
 | 
					import { reactive, ref, onMounted, h, toRaw, type Ref } from "vue";
 | 
				
			||||||
 | 
					import { handleTree } from "@/utils/tree";
 | 
				
			||||||
 | 
					import * as Dept from "@/api/system/dept";
 | 
				
			||||||
 | 
					import * as Menu from "@/api/system/menu";
 | 
				
			||||||
 | 
					import { cloneDeep } from "@pureadmin/utils";
 | 
				
			||||||
 | 
					import type { ApiAbstract } from "@/utils/http/ApiAbstract";
 | 
				
			||||||
 | 
					//import { cloneDeep } from "@pureadmin/utils";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function useRole() {
 | 
					export function useRole(tableRef?: Ref, treeRef?: Ref) {
 | 
				
			||||||
 | 
					  const deptList = ref();
 | 
				
			||||||
 | 
					  console.log(tableRef, treeRef);
 | 
				
			||||||
  const form = reactive({
 | 
					  const form = reactive({
 | 
				
			||||||
    name: "",
 | 
					    blurry: "",
 | 
				
			||||||
    code: "",
 | 
					    createTime: "",
 | 
				
			||||||
    status: ""
 | 
					    size: 10,
 | 
				
			||||||
 | 
					    page: 0
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  const formRef = ref();
 | 
					  const formRef = ref();
 | 
				
			||||||
  const dataList = ref([]);
 | 
					  const dataList = ref([]);
 | 
				
			||||||
  const loading = ref(true);
 | 
					  const loading = ref(true);
 | 
				
			||||||
  const switchLoadMap = ref({});
 | 
					  const treeData = ref([]);
 | 
				
			||||||
  const { switchStyle } = usePublicHooks();
 | 
					  const treeLoading = ref(true);
 | 
				
			||||||
 | 
					  const currentRow = ref([]);
 | 
				
			||||||
 | 
					  const deptId = ref<Number>();
 | 
				
			||||||
 | 
					  const nenus = ref<ApiAbstract<Menu.Menu>>();
 | 
				
			||||||
  const pagination = reactive<PaginationProps>({
 | 
					  const pagination = reactive<PaginationProps>({
 | 
				
			||||||
    total: 0,
 | 
					    total: 0,
 | 
				
			||||||
    pageSize: 10,
 | 
					    pageSize: 10,
 | 
				
			||||||
    currentPage: 1,
 | 
					    currentPage: 1,
 | 
				
			||||||
 | 
					    pageSizes: [10, 20, 50, 100],
 | 
				
			||||||
    background: true
 | 
					    background: true
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  const columns: TableColumnList = [
 | 
					  const columns: TableColumnList = [
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      label: "角色编号",
 | 
					 | 
				
			||||||
      prop: "id",
 | 
					 | 
				
			||||||
      minWidth: 100
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      label: "角色名称",
 | 
					      label: "角色名称",
 | 
				
			||||||
      prop: "name",
 | 
					      prop: "name",
 | 
				
			||||||
      minWidth: 120
 | 
					      minWidth: 120
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      label: "角色标识",
 | 
					      label: "数据权限",
 | 
				
			||||||
      prop: "code",
 | 
					      prop: "dataScope",
 | 
				
			||||||
      minWidth: 150
 | 
					      minWidth: 150
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      label: "状态",
 | 
					      label: "角色级别",
 | 
				
			||||||
      minWidth: 130,
 | 
					      prop: "level",
 | 
				
			||||||
      cellRenderer: scope => (
 | 
					      minWidth: 150
 | 
				
			||||||
        <el-switch
 | 
					 | 
				
			||||||
          size={scope.props.size === "small" ? "small" : "default"}
 | 
					 | 
				
			||||||
          loading={switchLoadMap.value[scope.index]?.loading}
 | 
					 | 
				
			||||||
          v-model={scope.row.status}
 | 
					 | 
				
			||||||
          active-value={1}
 | 
					 | 
				
			||||||
          inactive-value={0}
 | 
					 | 
				
			||||||
          active-text="已启用"
 | 
					 | 
				
			||||||
          inactive-text="已停用"
 | 
					 | 
				
			||||||
          inline-prompt
 | 
					 | 
				
			||||||
          style={switchStyle.value}
 | 
					 | 
				
			||||||
          onChange={() => onChange(scope as any)}
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      label: "备注",
 | 
					      label: "描述",
 | 
				
			||||||
      prop: "remark",
 | 
					      prop: "description",
 | 
				
			||||||
      minWidth: 150
 | 
					      minWidth: 150
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@ -89,72 +82,37 @@ export function useRole() {
 | 
				
			|||||||
  //   ];
 | 
					  //   ];
 | 
				
			||||||
  // });
 | 
					  // });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  function onChange({ row, index }) {
 | 
					 | 
				
			||||||
    ElMessageBox.confirm(
 | 
					 | 
				
			||||||
      `确认要<strong>${
 | 
					 | 
				
			||||||
        row.status === 0 ? "停用" : "启用"
 | 
					 | 
				
			||||||
      }</strong><strong style='color:var(--el-color-primary)'>${
 | 
					 | 
				
			||||||
        row.name
 | 
					 | 
				
			||||||
      }</strong>吗?`,
 | 
					 | 
				
			||||||
      "系统提示",
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        confirmButtonText: "确定",
 | 
					 | 
				
			||||||
        cancelButtonText: "取消",
 | 
					 | 
				
			||||||
        type: "warning",
 | 
					 | 
				
			||||||
        dangerouslyUseHTMLString: true,
 | 
					 | 
				
			||||||
        draggable: true
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
      .then(() => {
 | 
					 | 
				
			||||||
        switchLoadMap.value[index] = Object.assign(
 | 
					 | 
				
			||||||
          {},
 | 
					 | 
				
			||||||
          switchLoadMap.value[index],
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            loading: true
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        setTimeout(() => {
 | 
					 | 
				
			||||||
          switchLoadMap.value[index] = Object.assign(
 | 
					 | 
				
			||||||
            {},
 | 
					 | 
				
			||||||
            switchLoadMap.value[index],
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
              loading: false
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          );
 | 
					 | 
				
			||||||
          message(`已${row.status === 0 ? "停用" : "启用"}${row.name}`, {
 | 
					 | 
				
			||||||
            type: "success"
 | 
					 | 
				
			||||||
          });
 | 
					 | 
				
			||||||
        }, 300);
 | 
					 | 
				
			||||||
      })
 | 
					 | 
				
			||||||
      .catch(() => {
 | 
					 | 
				
			||||||
        row.status === 0 ? (row.status = 1) : (row.status = 0);
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  function handleDelete(row) {
 | 
					  function handleDelete(row) {
 | 
				
			||||||
    message(`您删除了角色名称为${row.name}的这条数据`, { type: "success" });
 | 
					    message(`您删除了角色名称为${row.name}的这条数据`, { type: "success" });
 | 
				
			||||||
    onSearch();
 | 
					    Role.del([row.id]).finally(() => onSearch());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  function handleSizeChange(val: number) {
 | 
					  function handleSizeChange(val: number) {
 | 
				
			||||||
    console.log(`${val} items per page`);
 | 
					    form.size = val - 1;
 | 
				
			||||||
 | 
					    onSearch();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  function handleCurrentChange(val: number) {
 | 
					  function handleCurrentChange(val: number) {
 | 
				
			||||||
    console.log(`current page: ${val}`);
 | 
					    form.page = val - 1;
 | 
				
			||||||
 | 
					    onSearch();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  function handleCurrentChange1(value: Dept.Dept) {
 | 
				
			||||||
  function handleSelectionChange(val) {
 | 
					    deptId.value = value?.id;
 | 
				
			||||||
    console.log("handleSelectionChange", val);
 | 
					    const { data } = nenus.value;
 | 
				
			||||||
 | 
					    treeData.value = cloneDeep(handleTree(data, "id", "pid"));
 | 
				
			||||||
 | 
					    currentRow.value = value?.menus?.map(item => item.id) ?? [-1];
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async function onSearch() {
 | 
					  async function onSearch() {
 | 
				
			||||||
 | 
					    getDeptTree();
 | 
				
			||||||
    loading.value = true;
 | 
					    loading.value = true;
 | 
				
			||||||
    const { data } = await getRoleList(toRaw(form));
 | 
					    const { data } = await Role.get(
 | 
				
			||||||
    dataList.value = data.list;
 | 
					      Object.entries(toRaw(form))
 | 
				
			||||||
    pagination.total = data.total;
 | 
					        .filter(([_, value]) => value !== null && value !== "")
 | 
				
			||||||
    pagination.pageSize = data.pageSize;
 | 
					        .reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {})
 | 
				
			||||||
    pagination.currentPage = data.currentPage;
 | 
					    );
 | 
				
			||||||
 | 
					    dataList.value = data.content;
 | 
				
			||||||
 | 
					    pagination.total = data.totalElements;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    setTimeout(() => {
 | 
					    setTimeout(() => {
 | 
				
			||||||
      loading.value = false;
 | 
					      loading.value = false;
 | 
				
			||||||
@ -172,9 +130,14 @@ export function useRole() {
 | 
				
			|||||||
      title: `${title}角色`,
 | 
					      title: `${title}角色`,
 | 
				
			||||||
      props: {
 | 
					      props: {
 | 
				
			||||||
        formInline: {
 | 
					        formInline: {
 | 
				
			||||||
 | 
					          id: row?.id ?? 0,
 | 
				
			||||||
          name: row?.name ?? "",
 | 
					          name: row?.name ?? "",
 | 
				
			||||||
          code: row?.code ?? "",
 | 
					          description: row?.description ?? "",
 | 
				
			||||||
          remark: row?.remark ?? ""
 | 
					          level: row?.level ?? 0,
 | 
				
			||||||
 | 
					          dataScope: row?.dataScope ?? "全部",
 | 
				
			||||||
 | 
					          dataIds: row?.deptIds ?? [],
 | 
				
			||||||
 | 
					          deptIds: row?.depts.map(person => person.id) ?? [],
 | 
				
			||||||
 | 
					          depts: cloneDeep(deptList.value)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      width: "40%",
 | 
					      width: "40%",
 | 
				
			||||||
@ -194,14 +157,24 @@ export function useRole() {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        FormRef.validate(valid => {
 | 
					        FormRef.validate(valid => {
 | 
				
			||||||
          if (valid) {
 | 
					          if (valid) {
 | 
				
			||||||
            console.log("curData", curData);
 | 
					 | 
				
			||||||
            // 表单规则校验通过
 | 
					            // 表单规则校验通过
 | 
				
			||||||
            if (title === "新增") {
 | 
					            if (title === "新增") {
 | 
				
			||||||
              // 实际开发先调用新增接口,再进行下面操作
 | 
					              const obj = {
 | 
				
			||||||
              chores();
 | 
					                ...curData,
 | 
				
			||||||
            } else {
 | 
					                depts: curData.deptIds.map(person => ({
 | 
				
			||||||
              // 实际开发先调用修改接口,再进行下面操作
 | 
					                  id: Object.values(person)[Object.values(person).length - 1]
 | 
				
			||||||
              chores();
 | 
					                }))
 | 
				
			||||||
 | 
					              }; // 复制对象
 | 
				
			||||||
 | 
					              delete obj.id; // 删除指定字段
 | 
				
			||||||
 | 
					              Role.add(obj).finally(() => chores());
 | 
				
			||||||
 | 
					            } else if (title === "编辑") {
 | 
				
			||||||
 | 
					              const roleOne = {
 | 
				
			||||||
 | 
					                ...curData,
 | 
				
			||||||
 | 
					                depts: curData.deptIds.map(person => ({
 | 
				
			||||||
 | 
					                  id: Object.values(person)[Object.values(person).length - 1]
 | 
				
			||||||
 | 
					                }))
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              Role.edit(roleOne).finally(() => chores());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
@ -209,15 +182,35 @@ export function useRole() {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** 菜单权限 */
 | 
					  function getDeptTree() {
 | 
				
			||||||
  function handleMenu() {
 | 
					    Dept.getDeptTree([]).then(data => {
 | 
				
			||||||
    message("等菜单管理页面开发后完善");
 | 
					      if (data.status) {
 | 
				
			||||||
 | 
					        deptList.value = handleTree(data.data, "id", "pid");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  function onTreeSelect({ id, menuIds }) {
 | 
				
			||||||
  /** 数据权限 可自行开发 */
 | 
					    if (
 | 
				
			||||||
  // function handleDatabase() {}
 | 
					      id.value !== null &&
 | 
				
			||||||
 | 
					      id.value !== undefined &&
 | 
				
			||||||
  onMounted(() => {
 | 
					      id.value === deptId.value
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					      Role.menus({
 | 
				
			||||||
 | 
					        id: id.value,
 | 
				
			||||||
 | 
					        menus: menuIds.map(person => ({
 | 
				
			||||||
 | 
					          id: person
 | 
				
			||||||
 | 
					        }))
 | 
				
			||||||
 | 
					      }).then(() => {
 | 
				
			||||||
 | 
					        onSearch();
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  onMounted(async () => {
 | 
				
			||||||
 | 
					    // 归属部门
 | 
				
			||||||
 | 
					    nenus.value = await Menu.menuTree([]);
 | 
				
			||||||
 | 
					    const { data } = nenus.value;
 | 
				
			||||||
 | 
					    treeData.value = cloneDeep(handleTree(data, "id", "pid"));
 | 
				
			||||||
 | 
					    treeLoading.value = false;
 | 
				
			||||||
    onSearch();
 | 
					    onSearch();
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -226,18 +219,21 @@ export function useRole() {
 | 
				
			|||||||
    loading,
 | 
					    loading,
 | 
				
			||||||
    columns,
 | 
					    columns,
 | 
				
			||||||
    dataList,
 | 
					    dataList,
 | 
				
			||||||
 | 
					    deptList,
 | 
				
			||||||
    pagination,
 | 
					    pagination,
 | 
				
			||||||
 | 
					    treeData,
 | 
				
			||||||
 | 
					    treeLoading,
 | 
				
			||||||
 | 
					    currentRow,
 | 
				
			||||||
 | 
					    deptId,
 | 
				
			||||||
    // buttonClass,
 | 
					    // buttonClass,
 | 
				
			||||||
    switchStyle,
 | 
					    onTreeSelect,
 | 
				
			||||||
    onChange,
 | 
					 | 
				
			||||||
    onSearch,
 | 
					    onSearch,
 | 
				
			||||||
    resetForm,
 | 
					    resetForm,
 | 
				
			||||||
    openDialog,
 | 
					    openDialog,
 | 
				
			||||||
    handleMenu,
 | 
					 | 
				
			||||||
    handleDelete,
 | 
					    handleDelete,
 | 
				
			||||||
    // handleDatabase,
 | 
					    // handleDatabase,
 | 
				
			||||||
    handleSizeChange,
 | 
					    handleSizeChange,
 | 
				
			||||||
    handleCurrentChange,
 | 
					    handleCurrentChange,
 | 
				
			||||||
    handleSelectionChange
 | 
					    handleCurrentChange1
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -4,5 +4,19 @@ import type { FormRules } from "element-plus";
 | 
				
			|||||||
/** 自定义表单规则校验 */
 | 
					/** 自定义表单规则校验 */
 | 
				
			||||||
export const formRules = reactive(<FormRules>{
 | 
					export const formRules = reactive(<FormRules>{
 | 
				
			||||||
  name: [{ required: true, message: "角色名称为必填项", trigger: "blur" }],
 | 
					  name: [{ required: true, message: "角色名称为必填项", trigger: "blur" }],
 | 
				
			||||||
  code: [{ required: true, message: "角色标识为必填项", trigger: "blur" }]
 | 
					  code: [{ required: true, message: "角色标识为必填项", trigger: "blur" }],
 | 
				
			||||||
 | 
					  deptIds: [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      required: true,
 | 
				
			||||||
 | 
					      validator: (rule, value, callback) => {
 | 
				
			||||||
 | 
					        if (value === "" || value.lenght < 1) {
 | 
				
			||||||
 | 
					          callback(new Error("手机号为必填项"));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          callback();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      trigger: "blur"
 | 
				
			||||||
 | 
					      // trigger: "click" // 如果想在点击确定按钮时触发这个校验,trigger 设置成 click 即可
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
				
			|||||||
@ -1,12 +1,18 @@
 | 
				
			|||||||
// 虽然字段很少 但是抽离出来 后续有扩展字段需求就很方便了
 | 
					// 虽然字段很少 但是抽离出来 后续有扩展字段需求就很方便了
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface FormItemProps {
 | 
					interface FormItemProps {
 | 
				
			||||||
 | 
					  id: number;
 | 
				
			||||||
  /** 角色名称 */
 | 
					  /** 角色名称 */
 | 
				
			||||||
  name: string;
 | 
					  name: string;
 | 
				
			||||||
  /** 角色编号 */
 | 
					  /** 角色编号 */
 | 
				
			||||||
  code: string;
 | 
					  level: number;
 | 
				
			||||||
 | 
					  /** 数据范围 */
 | 
				
			||||||
 | 
					  dataScope: string;
 | 
				
			||||||
  /** 备注 */
 | 
					  /** 备注 */
 | 
				
			||||||
  remark: string;
 | 
					  description: string;
 | 
				
			||||||
 | 
					  /** 备注 */
 | 
				
			||||||
 | 
					  depts: any[];
 | 
				
			||||||
 | 
					  deptIds: number[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
interface FormProps {
 | 
					interface FormProps {
 | 
				
			||||||
  formInline: FormItemProps;
 | 
					  formInline: FormItemProps;
 | 
				
			||||||
 | 
				
			|||||||
@ -9,15 +9,20 @@ const props = withDefaults(defineProps<FormProps>(), {
 | 
				
			|||||||
  formInline: () => ({
 | 
					  formInline: () => ({
 | 
				
			||||||
    title: "新增",
 | 
					    title: "新增",
 | 
				
			||||||
    higherDeptOptions: [],
 | 
					    higherDeptOptions: [],
 | 
				
			||||||
 | 
					    id: null,
 | 
				
			||||||
    parentId: 0,
 | 
					    parentId: 0,
 | 
				
			||||||
    nickname: "",
 | 
					    nickName: "",
 | 
				
			||||||
    username: "",
 | 
					    username: "",
 | 
				
			||||||
    password: "",
 | 
					    password: "",
 | 
				
			||||||
    phone: "",
 | 
					    phone: "",
 | 
				
			||||||
    email: "",
 | 
					    email: "",
 | 
				
			||||||
    sex: "",
 | 
					    gender: "男",
 | 
				
			||||||
    status: 1,
 | 
					    enabled: false,
 | 
				
			||||||
    remark: ""
 | 
					    remark: "",
 | 
				
			||||||
 | 
					    roleOptionsId: [],
 | 
				
			||||||
 | 
					    roleOptions: [],
 | 
				
			||||||
 | 
					    jobOptionsId: [],
 | 
				
			||||||
 | 
					    jobOptions: []
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -51,9 +56,9 @@ defineExpose({ getRef });
 | 
				
			|||||||
  >
 | 
					  >
 | 
				
			||||||
    <el-row :gutter="30">
 | 
					    <el-row :gutter="30">
 | 
				
			||||||
      <re-col :value="12" :xs="24" :sm="24">
 | 
					      <re-col :value="12" :xs="24" :sm="24">
 | 
				
			||||||
        <el-form-item label="用户昵称" prop="nickname">
 | 
					        <el-form-item label="用户昵称" prop="nickName">
 | 
				
			||||||
          <el-input
 | 
					          <el-input
 | 
				
			||||||
            v-model="newFormInline.nickname"
 | 
					            v-model="newFormInline.nickName"
 | 
				
			||||||
            clearable
 | 
					            clearable
 | 
				
			||||||
            placeholder="请输入用户昵称"
 | 
					            placeholder="请输入用户昵称"
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
@ -104,24 +109,20 @@ 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="用户性别">
 | 
					        <el-form-item label="用户性别">
 | 
				
			||||||
          <el-select
 | 
					          <el-radio-group v-model="newFormInline.gender">
 | 
				
			||||||
            v-model="newFormInline.sex"
 | 
					            <el-radio
 | 
				
			||||||
            placeholder="请选择用户性别"
 | 
					 | 
				
			||||||
            class="w-full"
 | 
					 | 
				
			||||||
            clearable
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            <el-option
 | 
					 | 
				
			||||||
              v-for="(item, index) in sexOptions"
 | 
					              v-for="(item, index) in sexOptions"
 | 
				
			||||||
              :key="index"
 | 
					              :key="index"
 | 
				
			||||||
              :label="item.label"
 | 
					              :label="item.label"
 | 
				
			||||||
              :value="item.value"
 | 
					              :value="item.value"
 | 
				
			||||||
 | 
					              border
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
          </el-select>
 | 
					          </el-radio-group>
 | 
				
			||||||
        </el-form-item>
 | 
					        </el-form-item>
 | 
				
			||||||
      </re-col>
 | 
					      </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="归属部门" prop="parentId">
 | 
				
			||||||
          <el-cascader
 | 
					          <el-cascader
 | 
				
			||||||
            v-model="newFormInline.parentId"
 | 
					            v-model="newFormInline.parentId"
 | 
				
			||||||
            class="w-full"
 | 
					            class="w-full"
 | 
				
			||||||
@ -143,25 +144,59 @@ defineExpose({ getRef });
 | 
				
			|||||||
          </el-cascader>
 | 
					          </el-cascader>
 | 
				
			||||||
        </el-form-item>
 | 
					        </el-form-item>
 | 
				
			||||||
      </re-col>
 | 
					      </re-col>
 | 
				
			||||||
      <re-col
 | 
					      <re-col :value="12" :xs="24" :sm="24">
 | 
				
			||||||
        v-if="newFormInline.title === '新增'"
 | 
					 | 
				
			||||||
        :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.enabled"
 | 
				
			||||||
            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"
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
        </el-form-item>
 | 
					        </el-form-item>
 | 
				
			||||||
      </re-col>
 | 
					      </re-col>
 | 
				
			||||||
 | 
					      <re-col :value="12" :xs="24" :sm="24">
 | 
				
			||||||
 | 
					        <el-form-item label="角色" prop="roleOptionsId">
 | 
				
			||||||
 | 
					          <el-select
 | 
				
			||||||
 | 
					            v-model="newFormInline.roleOptionsId"
 | 
				
			||||||
 | 
					            placeholder="请选择"
 | 
				
			||||||
 | 
					            class="w-full"
 | 
				
			||||||
 | 
					            clearable
 | 
				
			||||||
 | 
					            multiple
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <el-option
 | 
				
			||||||
 | 
					              v-for="(item, index) in newFormInline.roleOptions"
 | 
				
			||||||
 | 
					              :key="index"
 | 
				
			||||||
 | 
					              :value="item.id"
 | 
				
			||||||
 | 
					              :label="item.name"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              {{ item.name }}
 | 
				
			||||||
 | 
					            </el-option>
 | 
				
			||||||
 | 
					          </el-select>
 | 
				
			||||||
 | 
					        </el-form-item>
 | 
				
			||||||
 | 
					      </re-col>
 | 
				
			||||||
 | 
					      <re-col :value="12" :xs="24" :sm="24">
 | 
				
			||||||
 | 
					        <el-form-item label="岗位" prop="jobOptionsId">
 | 
				
			||||||
 | 
					          <el-select
 | 
				
			||||||
 | 
					            v-model="newFormInline.jobOptionsId"
 | 
				
			||||||
 | 
					            placeholder="请选择"
 | 
				
			||||||
 | 
					            class="w-full"
 | 
				
			||||||
 | 
					            clearable
 | 
				
			||||||
 | 
					            multiple
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <el-option
 | 
				
			||||||
 | 
					              v-for="(item, index) in newFormInline.jobOptions"
 | 
				
			||||||
 | 
					              :key="index"
 | 
				
			||||||
 | 
					              :value="item.id"
 | 
				
			||||||
 | 
					              :label="item.name"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              {{ item.name }}
 | 
				
			||||||
 | 
					            </el-option>
 | 
				
			||||||
 | 
					          </el-select>
 | 
				
			||||||
 | 
					        </el-form-item>
 | 
				
			||||||
 | 
					      </re-col>
 | 
				
			||||||
      <re-col>
 | 
					      <re-col>
 | 
				
			||||||
        <el-form-item label="备注">
 | 
					        <el-form-item label="备注">
 | 
				
			||||||
          <el-input
 | 
					          <el-input
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,7 @@ import { RoleFormProps } from "../utils/types";
 | 
				
			|||||||
const props = withDefaults(defineProps<RoleFormProps>(), {
 | 
					const props = withDefaults(defineProps<RoleFormProps>(), {
 | 
				
			||||||
  formInline: () => ({
 | 
					  formInline: () => ({
 | 
				
			||||||
    username: "",
 | 
					    username: "",
 | 
				
			||||||
    nickname: "",
 | 
					    nickName: "",
 | 
				
			||||||
    roleOptions: [],
 | 
					    roleOptions: [],
 | 
				
			||||||
    ids: []
 | 
					    ids: []
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
@ -18,14 +18,14 @@ const newFormInline = ref(props.formInline);
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <el-form :model="newFormInline">
 | 
					  <el-form :model="newFormInline">
 | 
				
			||||||
    <el-row :gutter="30">
 | 
					    <el-row :gutter="30">
 | 
				
			||||||
      <!-- <re-col>
 | 
					 | 
				
			||||||
        <el-form-item label="用户名称" prop="username">
 | 
					 | 
				
			||||||
          <el-input disabled v-model="newFormInline.username" />
 | 
					 | 
				
			||||||
        </el-form-item>
 | 
					 | 
				
			||||||
      </re-col> -->
 | 
					 | 
				
			||||||
      <re-col>
 | 
					      <re-col>
 | 
				
			||||||
        <el-form-item label="用户昵称" prop="nickname">
 | 
					        <el-form-item label="用户名称" prop="username">
 | 
				
			||||||
          <el-input v-model="newFormInline.nickname" disabled />
 | 
					          <el-input v-model="newFormInline.username" disabled />
 | 
				
			||||||
 | 
					        </el-form-item>
 | 
				
			||||||
 | 
					      </re-col>
 | 
				
			||||||
 | 
					      <re-col>
 | 
				
			||||||
 | 
					        <el-form-item label="用户昵称" prop="nickName">
 | 
				
			||||||
 | 
					          <el-input v-model="newFormInline.nickName" disabled />
 | 
				
			||||||
        </el-form-item>
 | 
					        </el-form-item>
 | 
				
			||||||
      </re-col>
 | 
					      </re-col>
 | 
				
			||||||
      <re-col>
 | 
					      <re-col>
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,7 @@ import tree from "./tree.vue";
 | 
				
			|||||||
import { useUser } from "./utils/hook";
 | 
					import { useUser } from "./utils/hook";
 | 
				
			||||||
import { PureTableBar } from "@/components/RePureTableBar";
 | 
					import { PureTableBar } from "@/components/RePureTableBar";
 | 
				
			||||||
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 | 
					import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 | 
				
			||||||
 | 
					import datePicker from "@/views/components/date-picker.vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import Upload from "@iconify-icons/ri/upload-line";
 | 
					import Upload from "@iconify-icons/ri/upload-line";
 | 
				
			||||||
import Role from "@iconify-icons/ri/admin-line";
 | 
					import Role from "@iconify-icons/ri/admin-line";
 | 
				
			||||||
@ -15,7 +16,7 @@ import Refresh from "@iconify-icons/ep/refresh";
 | 
				
			|||||||
import AddFill from "@iconify-icons/ri/add-circle-line";
 | 
					import AddFill from "@iconify-icons/ri/add-circle-line";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
defineOptions({
 | 
					defineOptions({
 | 
				
			||||||
  name: "SystemUser"
 | 
					  name: "User"
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const treeRef = ref();
 | 
					const treeRef = ref();
 | 
				
			||||||
@ -68,34 +69,29 @@ const {
 | 
				
			|||||||
        <el-form-item label="用户名称:" prop="username">
 | 
					        <el-form-item label="用户名称:" prop="username">
 | 
				
			||||||
          <el-input
 | 
					          <el-input
 | 
				
			||||||
            v-model="form.username"
 | 
					            v-model="form.username"
 | 
				
			||||||
            placeholder="请输入用户名称"
 | 
					            placeholder="请输入用户名或邮箱"
 | 
				
			||||||
            clearable
 | 
					            clearable
 | 
				
			||||||
            class="!w-[180px]"
 | 
					            class="!w-[160px]"
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
        </el-form-item>
 | 
					        </el-form-item>
 | 
				
			||||||
        <el-form-item label="手机号码:" prop="phone">
 | 
					        <el-form-item label="" prop="createTime">
 | 
				
			||||||
          <el-input
 | 
					          <datePicker v-model="form.createTime" />
 | 
				
			||||||
            v-model="form.phone"
 | 
					 | 
				
			||||||
            placeholder="请输入手机号码"
 | 
					 | 
				
			||||||
            clearable
 | 
					 | 
				
			||||||
            class="!w-[180px]"
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
        </el-form-item>
 | 
					        </el-form-item>
 | 
				
			||||||
        <el-form-item label="状态:" prop="status">
 | 
					        <el-form-item label="状态:" prop="status">
 | 
				
			||||||
          <el-select
 | 
					          <el-select
 | 
				
			||||||
            v-model="form.status"
 | 
					            v-model="form.status"
 | 
				
			||||||
            placeholder="请选择"
 | 
					            placeholder="请选择"
 | 
				
			||||||
            clearable
 | 
					            clearable
 | 
				
			||||||
            class="!w-[180px]"
 | 
					            class="!w-[160px]"
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            <el-option label="已开启" value="1" />
 | 
					            <el-option label="激活" value="1" />
 | 
				
			||||||
            <el-option label="已关闭" value="0" />
 | 
					            <el-option label="锁定" value="0" />
 | 
				
			||||||
          </el-select>
 | 
					          </el-select>
 | 
				
			||||||
        </el-form-item>
 | 
					        </el-form-item>
 | 
				
			||||||
        <el-form-item>
 | 
					        <el-form-item>
 | 
				
			||||||
          <el-button
 | 
					          <el-button
 | 
				
			||||||
            type="primary"
 | 
					            type="primary"
 | 
				
			||||||
            :icon="useRenderIcon('ri:search-line')"
 | 
					            :icon="useRenderIcon('search')"
 | 
				
			||||||
            :loading="loading"
 | 
					            :loading="loading"
 | 
				
			||||||
            @click="onSearch"
 | 
					            @click="onSearch"
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
@ -107,12 +103,8 @@ const {
 | 
				
			|||||||
        </el-form-item>
 | 
					        </el-form-item>
 | 
				
			||||||
      </el-form>
 | 
					      </el-form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <PureTableBar
 | 
					      <PureTableBar title="用户管理" :columns="columns" @refresh="onSearch">
 | 
				
			||||||
        title="用户管理(仅演示,操作后不生效)"
 | 
					        <template #add>
 | 
				
			||||||
        :columns="columns"
 | 
					 | 
				
			||||||
        @refresh="onSearch"
 | 
					 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        <template #buttons>
 | 
					 | 
				
			||||||
          <el-button
 | 
					          <el-button
 | 
				
			||||||
            type="primary"
 | 
					            type="primary"
 | 
				
			||||||
            :icon="useRenderIcon(AddFill)"
 | 
					            :icon="useRenderIcon(AddFill)"
 | 
				
			||||||
@ -121,6 +113,25 @@ const {
 | 
				
			|||||||
            新增用户
 | 
					            新增用户
 | 
				
			||||||
          </el-button>
 | 
					          </el-button>
 | 
				
			||||||
        </template>
 | 
					        </template>
 | 
				
			||||||
 | 
					        <template #export>
 | 
				
			||||||
 | 
					          <el-button
 | 
				
			||||||
 | 
					            type="success"
 | 
				
			||||||
 | 
					            :icon="useRenderIcon('solar:upload-bold')"
 | 
				
			||||||
 | 
					            @click="openDialog()"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            导出数据
 | 
				
			||||||
 | 
					          </el-button>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					        <template #reset>
 | 
				
			||||||
 | 
					          <el-button
 | 
				
			||||||
 | 
					            type="danger"
 | 
				
			||||||
 | 
					            disabled
 | 
				
			||||||
 | 
					            :icon="useRenderIcon(Refresh)"
 | 
				
			||||||
 | 
					            @click="openDialog()"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            重置密码
 | 
				
			||||||
 | 
					          </el-button>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
        <template v-slot="{ size, dynamicColumns }">
 | 
					        <template v-slot="{ size, dynamicColumns }">
 | 
				
			||||||
          <div
 | 
					          <div
 | 
				
			||||||
            v-if="selectedNum > 0"
 | 
					            v-if="selectedNum > 0"
 | 
				
			||||||
@ -150,7 +161,6 @@ const {
 | 
				
			|||||||
            ref="tableRef"
 | 
					            ref="tableRef"
 | 
				
			||||||
            row-key="id"
 | 
					            row-key="id"
 | 
				
			||||||
            adaptive
 | 
					            adaptive
 | 
				
			||||||
            :adaptiveConfig="{ offsetBottom: 108 }"
 | 
					 | 
				
			||||||
            align-whole="center"
 | 
					            align-whole="center"
 | 
				
			||||||
            table-layout="auto"
 | 
					            table-layout="auto"
 | 
				
			||||||
            :loading="loading"
 | 
					            :loading="loading"
 | 
				
			||||||
@ -174,7 +184,7 @@ const {
 | 
				
			|||||||
                type="primary"
 | 
					                type="primary"
 | 
				
			||||||
                :size="size"
 | 
					                :size="size"
 | 
				
			||||||
                :icon="useRenderIcon(EditPen)"
 | 
					                :icon="useRenderIcon(EditPen)"
 | 
				
			||||||
                @click="openDialog('修改', row)"
 | 
					                @click="openDialog('编辑', row)"
 | 
				
			||||||
              >
 | 
					              >
 | 
				
			||||||
                修改
 | 
					                修改
 | 
				
			||||||
              </el-button>
 | 
					              </el-button>
 | 
				
			||||||
@ -261,10 +271,6 @@ const {
 | 
				
			|||||||
  outline: none;
 | 
					  outline: none;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.main-content {
 | 
					 | 
				
			||||||
  margin: 24px 24px 0 !important;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.search-form {
 | 
					.search-form {
 | 
				
			||||||
  :deep(.el-form-item) {
 | 
					  :deep(.el-form-item) {
 | 
				
			||||||
    margin-bottom: 12px;
 | 
					    margin-bottom: 12px;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										241
									
								
								src/views/system/user/info.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										241
									
								
								src/views/system/user/info.vue
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,241 @@
 | 
				
			|||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import { ref, reactive } from "vue";
 | 
				
			||||||
 | 
					import type { TabsPaneContext } from "element-plus";
 | 
				
			||||||
 | 
					import { useUser } from "./utils/info";
 | 
				
			||||||
 | 
					import { isPhone } from "@pureadmin/utils";
 | 
				
			||||||
 | 
					import type { FormInstance } from "element-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Check from "@iconify-icons/ep/avatar";
 | 
				
			||||||
 | 
					import SignIn from "@iconify-icons/ri/login-box-line";
 | 
				
			||||||
 | 
					import NodeTree from "@iconify-icons/ri/node-tree";
 | 
				
			||||||
 | 
					import Phone from "@iconify-icons/ep/iphone";
 | 
				
			||||||
 | 
					import Mail from "@iconify-icons/ri/mail-fill";
 | 
				
			||||||
 | 
					import Secure from "@iconify-icons/ri/secure-payment-fill";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const activeName = ref("first");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const handleClick = (tab: TabsPaneContext, event: Event) => {
 | 
				
			||||||
 | 
					  console.log("tab", tab.paneName);
 | 
				
			||||||
 | 
					  console.log("event", event);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const treeRef = ref();
 | 
				
			||||||
 | 
					const tableRef = ref();
 | 
				
			||||||
 | 
					const ruleFormRef = ref<FormInstance>();
 | 
				
			||||||
 | 
					const {
 | 
				
			||||||
 | 
					  userInfo,
 | 
				
			||||||
 | 
					  handleUpload,
 | 
				
			||||||
 | 
					  handleReset,
 | 
				
			||||||
 | 
					  handleResetEmail,
 | 
				
			||||||
 | 
					  submitEditUser
 | 
				
			||||||
 | 
					} = useUser(tableRef, treeRef);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const user = reactive(userInfo.value.user);
 | 
				
			||||||
 | 
					defineOptions({
 | 
				
			||||||
 | 
					  name: "UserInfo"
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div class="justify-between">
 | 
				
			||||||
 | 
					    <el-row :gutter="30">
 | 
				
			||||||
 | 
					      <el-col :xs="8" :sm="6" :md="4" :lg="6" :xl="5">
 | 
				
			||||||
 | 
					        <div class="grid-content">
 | 
				
			||||||
 | 
					          <el-card class="box-card">
 | 
				
			||||||
 | 
					            <template #header>
 | 
				
			||||||
 | 
					              <div class="card-header">
 | 
				
			||||||
 | 
					                <span>个人信息</span>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					            <div class="el-upload">
 | 
				
			||||||
 | 
					              <el-avatar
 | 
				
			||||||
 | 
					                :size="80"
 | 
				
			||||||
 | 
					                src="https://empty"
 | 
				
			||||||
 | 
					                @click="handleUpload(userInfo.user)"
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <img :src="'/avatar/' + userInfo.user.avatarName" />
 | 
				
			||||||
 | 
					              </el-avatar>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <ul class="user-info">
 | 
				
			||||||
 | 
					              <li>
 | 
				
			||||||
 | 
					                <div style="height: 100%">
 | 
				
			||||||
 | 
					                  <IconifyIconOffline class="check-zh" :icon="SignIn" />
 | 
				
			||||||
 | 
					                  登录账号
 | 
				
			||||||
 | 
					                  <div class="user-right">{{ userInfo.user.username }}</div>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					              </li>
 | 
				
			||||||
 | 
					              <li>
 | 
				
			||||||
 | 
					                <IconifyIconOffline class="check-zh" :icon="Check" />
 | 
				
			||||||
 | 
					                用户昵称
 | 
				
			||||||
 | 
					                <div class="user-right">{{ userInfo.user.nickName }}</div>
 | 
				
			||||||
 | 
					              </li>
 | 
				
			||||||
 | 
					              <li>
 | 
				
			||||||
 | 
					                <IconifyIconOffline class="check-zh" :icon="NodeTree" />
 | 
				
			||||||
 | 
					                所属部门
 | 
				
			||||||
 | 
					                <div class="user-right">{{ userInfo.user.dept.name }}</div>
 | 
				
			||||||
 | 
					              </li>
 | 
				
			||||||
 | 
					              <li>
 | 
				
			||||||
 | 
					                <IconifyIconOffline class="check-zh" :icon="Phone" />
 | 
				
			||||||
 | 
					                手机号码
 | 
				
			||||||
 | 
					                <div class="user-right">{{ userInfo.user.phone }}</div>
 | 
				
			||||||
 | 
					              </li>
 | 
				
			||||||
 | 
					              <li>
 | 
				
			||||||
 | 
					                <IconifyIconOffline class="check-zh" :icon="Mail" />
 | 
				
			||||||
 | 
					                用户邮箱
 | 
				
			||||||
 | 
					                <div class="user-right">{{ userInfo.user.email }}</div>
 | 
				
			||||||
 | 
					              </li>
 | 
				
			||||||
 | 
					              <li>
 | 
				
			||||||
 | 
					                <IconifyIconOffline class="check-zh" :icon="Secure" />
 | 
				
			||||||
 | 
					                安全设置
 | 
				
			||||||
 | 
					                <div class="user-right">
 | 
				
			||||||
 | 
					                  <a @click="handleReset">修改密码 </a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  <a @click="handleResetEmail"> 修改邮箱</a>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					              </li>
 | 
				
			||||||
 | 
					            </ul>
 | 
				
			||||||
 | 
					          </el-card>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </el-col>
 | 
				
			||||||
 | 
					      <el-col :xs="8" :sm="6" :md="8" :lg="18" :xl="11"
 | 
				
			||||||
 | 
					        ><div class="grid-content">
 | 
				
			||||||
 | 
					          <el-tabs
 | 
				
			||||||
 | 
					            v-model="activeName"
 | 
				
			||||||
 | 
					            class="demo-tabs grid-content"
 | 
				
			||||||
 | 
					            @tab-click="handleClick"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <el-tab-pane label="用户资料" name="first">
 | 
				
			||||||
 | 
					              <el-form
 | 
				
			||||||
 | 
					                ref="ruleFormRef"
 | 
				
			||||||
 | 
					                :model="user"
 | 
				
			||||||
 | 
					                style="margin-top: 10px"
 | 
				
			||||||
 | 
					                size="small"
 | 
				
			||||||
 | 
					                label-width="65px"
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <el-form-item
 | 
				
			||||||
 | 
					                  label="昵称"
 | 
				
			||||||
 | 
					                  prop="nickName"
 | 
				
			||||||
 | 
					                  :rules="[
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                      required: true,
 | 
				
			||||||
 | 
					                      message: '昵称为必填项',
 | 
				
			||||||
 | 
					                      trigger: 'blur'
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                      min: 3,
 | 
				
			||||||
 | 
					                      max: 12,
 | 
				
			||||||
 | 
					                      message: 'Length should be 4 to 12',
 | 
				
			||||||
 | 
					                      trigger: 'blur'
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                  ]"
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  <el-input
 | 
				
			||||||
 | 
					                    v-model="user.nickName"
 | 
				
			||||||
 | 
					                    clearable
 | 
				
			||||||
 | 
					                    style="width: 35%"
 | 
				
			||||||
 | 
					                  />
 | 
				
			||||||
 | 
					                  <span style=" margin-left: 10px;color: #e6a23c"
 | 
				
			||||||
 | 
					                    >⚠️用户昵称不作为登录使用</span
 | 
				
			||||||
 | 
					                  >
 | 
				
			||||||
 | 
					                </el-form-item>
 | 
				
			||||||
 | 
					                <el-form-item
 | 
				
			||||||
 | 
					                  label="手机号"
 | 
				
			||||||
 | 
					                  prop="phone"
 | 
				
			||||||
 | 
					                  :rules="[
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                      required: true,
 | 
				
			||||||
 | 
					                      message: '手机号为必填项',
 | 
				
			||||||
 | 
					                      trigger: 'blur'
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                      required: true,
 | 
				
			||||||
 | 
					                      validator: (rule, value, callback) => {
 | 
				
			||||||
 | 
					                        if (value === '') {
 | 
				
			||||||
 | 
					                          callback(new Error('手机号为必填项'));
 | 
				
			||||||
 | 
					                        } else if (!isPhone(value)) {
 | 
				
			||||||
 | 
					                          callback(new Error('请输入正确的手机号码格式'));
 | 
				
			||||||
 | 
					                        } else {
 | 
				
			||||||
 | 
					                          callback();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                      },
 | 
				
			||||||
 | 
					                      trigger: 'blur'
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                  ]"
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  <el-input v-model="user.phone" clearable style="width: 35%" />
 | 
				
			||||||
 | 
					                  <span style=" margin-left: 10px;color: #e6a23c"
 | 
				
			||||||
 | 
					                    >⚠️手机号码不能重复</span
 | 
				
			||||||
 | 
					                  >
 | 
				
			||||||
 | 
					                </el-form-item>
 | 
				
			||||||
 | 
					                <el-form-item label="性别" prop="gender">
 | 
				
			||||||
 | 
					                  <el-radio-group v-model="user.gender" style="width: 178px">
 | 
				
			||||||
 | 
					                    <el-radio label="男" value="男">男</el-radio>
 | 
				
			||||||
 | 
					                    <el-radio label="女" value="女">女</el-radio>
 | 
				
			||||||
 | 
					                  </el-radio-group>
 | 
				
			||||||
 | 
					                </el-form-item>
 | 
				
			||||||
 | 
					                <el-form-item>
 | 
				
			||||||
 | 
					                  <el-button
 | 
				
			||||||
 | 
					                    type="primary"
 | 
				
			||||||
 | 
					                    @click="submitEditUser(ruleFormRef, user)"
 | 
				
			||||||
 | 
					                    >保存配置</el-button
 | 
				
			||||||
 | 
					                  >
 | 
				
			||||||
 | 
					                </el-form-item>
 | 
				
			||||||
 | 
					              </el-form>
 | 
				
			||||||
 | 
					            </el-tab-pane>
 | 
				
			||||||
 | 
					            <el-tab-pane label="操作日志" name="second">操作日志</el-tab-pane>
 | 
				
			||||||
 | 
					          </el-tabs>
 | 
				
			||||||
 | 
					        </div></el-col
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					    </el-row>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style>
 | 
				
			||||||
 | 
					.el-col {
 | 
				
			||||||
 | 
					  border-radius: 4px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.grid-content {
 | 
				
			||||||
 | 
					  min-height: 36px;
 | 
				
			||||||
 | 
					  border-radius: 4px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.demo-tabs > .el-tabs__content {
 | 
				
			||||||
 | 
					  padding: 32px;
 | 
				
			||||||
 | 
					  font-size: 32px;
 | 
				
			||||||
 | 
					  font-weight: 600;
 | 
				
			||||||
 | 
					  color: #6b778c;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.el-upload {
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					  outline: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.user-info {
 | 
				
			||||||
 | 
					  padding-left: 0;
 | 
				
			||||||
 | 
					  list-style: none;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  li {
 | 
				
			||||||
 | 
					    padding: 11px 0;
 | 
				
			||||||
 | 
					    font-size: 13px;
 | 
				
			||||||
 | 
					    border-bottom: 1px solid #f0f3f4;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .user-right {
 | 
				
			||||||
 | 
					    float: right;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    a {
 | 
				
			||||||
 | 
					      color: #317ef3;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.check-zh {
 | 
				
			||||||
 | 
					  display: unset;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
@ -1 +1 @@
 | 
				
			|||||||
<svg width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M22 4V2H2v2h9v14.17l-5.5-5.5-1.42 1.41L12 22l7.92-7.92-1.42-1.41-5.5 5.5V4z"/></svg>
 | 
					<svg width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M22 4V2H2v2h9v14.17l-5.5-5.5-1.42 1.41L12 22l7.92-7.92-1.42-1.41-5.5 5.5V4h9Z"/></svg>
 | 
				
			||||||
| 
		 Before Width: | Height: | Size: 161 B After Width: | Height: | Size: 163 B  | 
@ -1 +1 @@
 | 
				
			|||||||
<svg width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M4 2H2v20h2v-9h14.17l-5.5 5.5 1.41 1.42L22 12l-7.92-7.92-1.41 1.42 5.5 5.5H4z"/></svg>
 | 
					<svg width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M4 2H2v20h2v-9h14.17l-5.5 5.5l1.41 1.42L22 12l-7.92-7.92l-1.41 1.42l5.5 5.5H4V2Z"/></svg>
 | 
				
			||||||
| 
		 Before Width: | Height: | Size: 163 B After Width: | Height: | Size: 166 B  | 
@ -96,7 +96,7 @@ defineExpose({ onTreeReset });
 | 
				
			|||||||
  <div
 | 
					  <div
 | 
				
			||||||
    v-loading="props.treeLoading"
 | 
					    v-loading="props.treeLoading"
 | 
				
			||||||
    class="h-full bg-bg_color overflow-auto"
 | 
					    class="h-full bg-bg_color overflow-auto"
 | 
				
			||||||
    :style="{ minHeight: `calc(100vh - 145px)` }"
 | 
					    :style="{ minHeight: `calc(100vh - 133px)` }"
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <div class="flex items-center h-[34px]">
 | 
					    <div class="flex items-center h-[34px]">
 | 
				
			||||||
      <el-input
 | 
					      <el-input
 | 
				
			||||||
@ -110,7 +110,7 @@ defineExpose({ onTreeReset });
 | 
				
			|||||||
          <el-icon class="el-input__icon">
 | 
					          <el-icon class="el-input__icon">
 | 
				
			||||||
            <IconifyIconOffline
 | 
					            <IconifyIconOffline
 | 
				
			||||||
              v-show="searchValue.length === 0"
 | 
					              v-show="searchValue.length === 0"
 | 
				
			||||||
              icon="ri:search-line"
 | 
					              icon="search"
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
          </el-icon>
 | 
					          </el-icon>
 | 
				
			||||||
        </template>
 | 
					        </template>
 | 
				
			||||||
 | 
				
			|||||||
@ -10,7 +10,6 @@ const props = defineProps({
 | 
				
			|||||||
const emit = defineEmits(["cropper"]);
 | 
					const emit = defineEmits(["cropper"]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const infos = ref();
 | 
					const infos = ref();
 | 
				
			||||||
const popoverRef = ref();
 | 
					 | 
				
			||||||
const refCropper = ref();
 | 
					const refCropper = ref();
 | 
				
			||||||
const showPopover = ref(false);
 | 
					const showPopover = ref(false);
 | 
				
			||||||
const cropperImg = ref<string>("");
 | 
					const cropperImg = ref<string>("");
 | 
				
			||||||
@ -20,22 +19,11 @@ function onCropper({ base64, blob, info }) {
 | 
				
			|||||||
  cropperImg.value = base64;
 | 
					  cropperImg.value = base64;
 | 
				
			||||||
  emit("cropper", { base64, blob, info });
 | 
					  emit("cropper", { base64, blob, info });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
function hidePopover() {
 | 
					 | 
				
			||||||
  popoverRef.value.hide();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
defineExpose({ hidePopover });
 | 
					 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div v-loading="!showPopover" element-loading-background="transparent">
 | 
					  <div v-loading="!showPopover" element-loading-background="transparent">
 | 
				
			||||||
    <el-popover
 | 
					    <el-popover :visible="showPopover" placement="right-end" width="18vw">
 | 
				
			||||||
      ref="popoverRef"
 | 
					 | 
				
			||||||
      :visible="showPopover"
 | 
					 | 
				
			||||||
      placement="right"
 | 
					 | 
				
			||||||
      width="18vw"
 | 
					 | 
				
			||||||
    >
 | 
					 | 
				
			||||||
      <template #reference>
 | 
					      <template #reference>
 | 
				
			||||||
        <div class="w-[18vw]">
 | 
					        <div class="w-[18vw]">
 | 
				
			||||||
          <ReCropper
 | 
					          <ReCropper
 | 
				
			||||||
 | 
				
			|||||||
@ -10,13 +10,17 @@ import { usePublicHooks } from "../../hooks";
 | 
				
			|||||||
import { addDialog } from "@/components/ReDialog";
 | 
					import { addDialog } from "@/components/ReDialog";
 | 
				
			||||||
import type { PaginationProps } from "@pureadmin/table";
 | 
					import type { PaginationProps } from "@pureadmin/table";
 | 
				
			||||||
import type { FormItemProps, RoleFormItemProps } from "../utils/types";
 | 
					import type { FormItemProps, RoleFormItemProps } from "../utils/types";
 | 
				
			||||||
import { hideTextAtIndex, getKeyList, isAllEmpty } from "@pureadmin/utils";
 | 
					 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  getRoleIds,
 | 
					  hideTextAtIndex,
 | 
				
			||||||
  getDeptList,
 | 
					  getKeyList,
 | 
				
			||||||
  getUserList,
 | 
					  isAllEmpty,
 | 
				
			||||||
  getAllRoleList
 | 
					  cloneDeep
 | 
				
			||||||
} from "@/api/system";
 | 
					} from "@pureadmin/utils";
 | 
				
			||||||
 | 
					import { baseUrlAvatar } from "@/api/utils";
 | 
				
			||||||
 | 
					import * as User from "@/api/system/user";
 | 
				
			||||||
 | 
					import * as Dept from "@/api/system/dept";
 | 
				
			||||||
 | 
					import * as Job from "@/api/system/job";
 | 
				
			||||||
 | 
					import * as Role from "@/api/system/role";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  ElForm,
 | 
					  ElForm,
 | 
				
			||||||
  ElInput,
 | 
					  ElInput,
 | 
				
			||||||
@ -24,22 +28,14 @@ import {
 | 
				
			|||||||
  ElProgress,
 | 
					  ElProgress,
 | 
				
			||||||
  ElMessageBox
 | 
					  ElMessageBox
 | 
				
			||||||
} from "element-plus";
 | 
					} from "element-plus";
 | 
				
			||||||
import {
 | 
					import { type Ref, h, ref, watch, computed, reactive, onMounted } from "vue";
 | 
				
			||||||
  type Ref,
 | 
					 | 
				
			||||||
  h,
 | 
					 | 
				
			||||||
  ref,
 | 
					 | 
				
			||||||
  toRaw,
 | 
					 | 
				
			||||||
  watch,
 | 
					 | 
				
			||||||
  computed,
 | 
					 | 
				
			||||||
  reactive,
 | 
					 | 
				
			||||||
  onMounted
 | 
					 | 
				
			||||||
} from "vue";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function useUser(tableRef: Ref, treeRef: Ref) {
 | 
					export function useUser(tableRef: Ref, treeRef: Ref) {
 | 
				
			||||||
  const form = reactive({
 | 
					  const form = reactive({
 | 
				
			||||||
    // 左侧部门树的id
 | 
					    // 左侧部门树的id
 | 
				
			||||||
    deptId: "",
 | 
					    deptId: "",
 | 
				
			||||||
    username: "",
 | 
					    username: "",
 | 
				
			||||||
 | 
					    createTime: "",
 | 
				
			||||||
    phone: "",
 | 
					    phone: "",
 | 
				
			||||||
    status: ""
 | 
					    status: ""
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
@ -55,10 +51,13 @@ export function useUser(tableRef: Ref, treeRef: Ref) {
 | 
				
			|||||||
  const treeData = ref([]);
 | 
					  const treeData = ref([]);
 | 
				
			||||||
  const treeLoading = ref(true);
 | 
					  const treeLoading = ref(true);
 | 
				
			||||||
  const selectedNum = ref(0);
 | 
					  const selectedNum = ref(0);
 | 
				
			||||||
 | 
					  /** 分页配置 */
 | 
				
			||||||
  const pagination = reactive<PaginationProps>({
 | 
					  const pagination = reactive<PaginationProps>({
 | 
				
			||||||
    total: 0,
 | 
					    total: 0,
 | 
				
			||||||
    pageSize: 10,
 | 
					    pageSize: 10,
 | 
				
			||||||
 | 
					    pageSizes: [10, 15, 20],
 | 
				
			||||||
    currentPage: 1,
 | 
					    currentPage: 1,
 | 
				
			||||||
 | 
					    align: "left",
 | 
				
			||||||
    background: true
 | 
					    background: true
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  const columns: TableColumnList = [
 | 
					  const columns: TableColumnList = [
 | 
				
			||||||
@ -75,15 +74,21 @@ export function useUser(tableRef: Ref, treeRef: Ref) {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      label: "用户头像",
 | 
					      label: "用户头像",
 | 
				
			||||||
      prop: "avatar",
 | 
					      prop: "avatarName",
 | 
				
			||||||
      cellRenderer: ({ row }) => (
 | 
					      cellRenderer: ({ row }) => (
 | 
				
			||||||
        <el-image
 | 
					        <el-image
 | 
				
			||||||
          fit="cover"
 | 
					          fit="cover"
 | 
				
			||||||
          preview-teleported={true}
 | 
					          preview-teleported={true}
 | 
				
			||||||
          src={row.avatar}
 | 
					          src={baseUrlAvatar(row.avatarName)}
 | 
				
			||||||
          preview-src-list={Array.of(row.avatar)}
 | 
					          preview-src-list={Array.of(baseUrlAvatar(row.avatarName))}
 | 
				
			||||||
          class="w-[24px] h-[24px] rounded-full align-middle"
 | 
					          class="w-[24px] h-[24px] rounded-full align-middle"
 | 
				
			||||||
        />
 | 
					        >
 | 
				
			||||||
 | 
					          {{
 | 
				
			||||||
 | 
					            error: () => (
 | 
				
			||||||
 | 
					              <el-image src="https://element-plus.org/images/element-plus-logo.svg" />
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					          }}
 | 
				
			||||||
 | 
					        </el-image>
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
      width: 90
 | 
					      width: 90
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
@ -94,20 +99,20 @@ export function useUser(tableRef: Ref, treeRef: Ref) {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      label: "用户昵称",
 | 
					      label: "用户昵称",
 | 
				
			||||||
      prop: "nickname",
 | 
					      prop: "nickName",
 | 
				
			||||||
      minWidth: 130
 | 
					      minWidth: 130
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      label: "性别",
 | 
					      label: "性别",
 | 
				
			||||||
      prop: "sex",
 | 
					      prop: "gender",
 | 
				
			||||||
      minWidth: 90,
 | 
					      minWidth: 90,
 | 
				
			||||||
      cellRenderer: ({ row, props }) => (
 | 
					      cellRenderer: ({ row, props }) => (
 | 
				
			||||||
        <el-tag
 | 
					        <el-tag
 | 
				
			||||||
          size={props.size}
 | 
					          size={props.size}
 | 
				
			||||||
          type={row.sex === 1 ? "danger" : null}
 | 
					          type={row.sex === 1 ? "danger" : "success"}
 | 
				
			||||||
          effect="plain"
 | 
					          effect="plain"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          {row.sex === 1 ? "女" : "男"}
 | 
					          {row.gender}
 | 
				
			||||||
        </el-tag>
 | 
					        </el-tag>
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
@ -122,19 +127,24 @@ export function useUser(tableRef: Ref, treeRef: Ref) {
 | 
				
			|||||||
      minWidth: 90,
 | 
					      minWidth: 90,
 | 
				
			||||||
      formatter: ({ phone }) => hideTextAtIndex(phone, { start: 3, end: 6 })
 | 
					      formatter: ({ phone }) => hideTextAtIndex(phone, { start: 3, end: 6 })
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: "邮箱",
 | 
				
			||||||
 | 
					      prop: "email",
 | 
				
			||||||
 | 
					      minWidth: 90
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      label: "状态",
 | 
					      label: "状态",
 | 
				
			||||||
      prop: "status",
 | 
					      prop: "enabled",
 | 
				
			||||||
      minWidth: 90,
 | 
					      minWidth: 90,
 | 
				
			||||||
      cellRenderer: scope => (
 | 
					      cellRenderer: scope => (
 | 
				
			||||||
        <el-switch
 | 
					        <el-switch
 | 
				
			||||||
          size={scope.props.size === "small" ? "small" : "default"}
 | 
					          size={scope.props.size === "small" ? "small" : "default"}
 | 
				
			||||||
          loading={switchLoadMap.value[scope.index]?.loading}
 | 
					          loading={switchLoadMap.value[scope.index]?.loading}
 | 
				
			||||||
          v-model={scope.row.status}
 | 
					          v-model={scope.row.enabled}
 | 
				
			||||||
          active-value={1}
 | 
					          active-value={true}
 | 
				
			||||||
          inactive-value={0}
 | 
					          inactive-value={false}
 | 
				
			||||||
          active-text="已启用"
 | 
					          active-text="激活"
 | 
				
			||||||
          inactive-text="已停用"
 | 
					          inactive-text="锁定"
 | 
				
			||||||
          inline-prompt
 | 
					          inline-prompt
 | 
				
			||||||
          style={switchStyle.value}
 | 
					          style={switchStyle.value}
 | 
				
			||||||
          onChange={() => onChange(scope as any)}
 | 
					          onChange={() => onChange(scope as any)}
 | 
				
			||||||
@ -164,6 +174,7 @@ export function useUser(tableRef: Ref, treeRef: Ref) {
 | 
				
			|||||||
      "dark:hover:!text-primary"
 | 
					      "dark:hover:!text-primary"
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // 重置的新密码
 | 
					  // 重置的新密码
 | 
				
			||||||
  const pwdForm = reactive({
 | 
					  const pwdForm = reactive({
 | 
				
			||||||
    newPwd: ""
 | 
					    newPwd: ""
 | 
				
			||||||
@ -178,11 +189,12 @@ export function useUser(tableRef: Ref, treeRef: Ref) {
 | 
				
			|||||||
  // 当前密码强度(0-4)
 | 
					  // 当前密码强度(0-4)
 | 
				
			||||||
  const curScore = ref();
 | 
					  const curScore = ref();
 | 
				
			||||||
  const roleOptions = ref([]);
 | 
					  const roleOptions = ref([]);
 | 
				
			||||||
 | 
					  const jobOptions = ref([]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  function onChange({ row, index }) {
 | 
					  function onChange({ row, index }) {
 | 
				
			||||||
    ElMessageBox.confirm(
 | 
					    ElMessageBox.confirm(
 | 
				
			||||||
      `确认要<strong>${
 | 
					      `确认要<strong>${
 | 
				
			||||||
        row.status === 0 ? "停用" : "启用"
 | 
					        row.enabled ? "激活" : "锁定"
 | 
				
			||||||
      }</strong><strong style='color:var(--el-color-primary)'>${
 | 
					      }</strong><strong style='color:var(--el-color-primary)'>${
 | 
				
			||||||
        row.username
 | 
					        row.username
 | 
				
			||||||
      }</strong>用户吗?`,
 | 
					      }</strong>用户吗?`,
 | 
				
			||||||
@ -203,7 +215,7 @@ export function useUser(tableRef: Ref, treeRef: Ref) {
 | 
				
			|||||||
            loading: true
 | 
					            loading: true
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        setTimeout(() => {
 | 
					        User.edit(row).finally(() => {
 | 
				
			||||||
          switchLoadMap.value[index] = Object.assign(
 | 
					          switchLoadMap.value[index] = Object.assign(
 | 
				
			||||||
            {},
 | 
					            {},
 | 
				
			||||||
            switchLoadMap.value[index],
 | 
					            switchLoadMap.value[index],
 | 
				
			||||||
@ -214,7 +226,8 @@ export function useUser(tableRef: Ref, treeRef: Ref) {
 | 
				
			|||||||
          message("已成功修改用户状态", {
 | 
					          message("已成功修改用户状态", {
 | 
				
			||||||
            type: "success"
 | 
					            type: "success"
 | 
				
			||||||
          });
 | 
					          });
 | 
				
			||||||
        }, 300);
 | 
					          onSearch();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      .catch(() => {
 | 
					      .catch(() => {
 | 
				
			||||||
        row.status === 0 ? (row.status = 1) : (row.status = 0);
 | 
					        row.status === 0 ? (row.status = 1) : (row.status = 0);
 | 
				
			||||||
@ -226,8 +239,10 @@ export function useUser(tableRef: Ref, treeRef: Ref) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  function handleDelete(row) {
 | 
					  function handleDelete(row) {
 | 
				
			||||||
    message(`您删除了用户编号为${row.id}的这条数据`, { type: "success" });
 | 
					    User.del([row.id]).then(() => {
 | 
				
			||||||
    onSearch();
 | 
					      message(`您删除了用户编号为${row.id}的这条数据!`, { type: "success" });
 | 
				
			||||||
 | 
					      onSearch();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  function handleSizeChange(val: number) {
 | 
					  function handleSizeChange(val: number) {
 | 
				
			||||||
@ -256,25 +271,42 @@ export function useUser(tableRef: Ref, treeRef: Ref) {
 | 
				
			|||||||
  function onbatchDel() {
 | 
					  function onbatchDel() {
 | 
				
			||||||
    // 返回当前选中的行
 | 
					    // 返回当前选中的行
 | 
				
			||||||
    const curSelected = tableRef.value.getTableRef().getSelectionRows();
 | 
					    const curSelected = tableRef.value.getTableRef().getSelectionRows();
 | 
				
			||||||
    // 接下来根据实际业务,通过选中行的某项数据,比如下面的id,调用接口进行批量删除
 | 
					    User.del(getKeyList(curSelected, "id")).then(() => {
 | 
				
			||||||
    message(`已删除用户编号为 ${getKeyList(curSelected, "id")} 的数据`, {
 | 
					      // 接下来根据实际业务,通过选中行的某项数据,比如下面的id,调用接口进行批量删除
 | 
				
			||||||
      type: "success"
 | 
					      message(`已删除用户编号为 ${getKeyList(curSelected, "id")} 的数据`, {
 | 
				
			||||||
 | 
					        type: "success"
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      tableRef.value.getTableRef().clearSelection();
 | 
				
			||||||
 | 
					      onSearch();
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    tableRef.value.getTableRef().clearSelection();
 | 
					 | 
				
			||||||
    onSearch();
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async function onSearch() {
 | 
					  async function onSearch() {
 | 
				
			||||||
    loading.value = true;
 | 
					    loading.value = true;
 | 
				
			||||||
    const { data } = await getUserList(toRaw(form));
 | 
					    const queryType = new User.UserQueryCriteria();
 | 
				
			||||||
    dataList.value = data.list;
 | 
					    if (!isAllEmpty(form.username)) {
 | 
				
			||||||
    pagination.total = data.total;
 | 
					      queryType.name = form.username;
 | 
				
			||||||
    pagination.pageSize = data.pageSize;
 | 
					    }
 | 
				
			||||||
    pagination.currentPage = data.currentPage;
 | 
					    if (
 | 
				
			||||||
 | 
					      form.deptId !== null &&
 | 
				
			||||||
    setTimeout(() => {
 | 
					      form.deptId !== "0" &&
 | 
				
			||||||
      loading.value = false;
 | 
					      form.deptId !== "" &&
 | 
				
			||||||
    }, 500);
 | 
					      form.deptId !== " "
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					      queryType.deptId = Number(form.deptId);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    queryType.page = pagination.currentPage - 1;
 | 
				
			||||||
 | 
					    queryType.size = pagination.pageSize;
 | 
				
			||||||
 | 
					    User.get(queryType)
 | 
				
			||||||
 | 
					      .then(data => {
 | 
				
			||||||
 | 
					        data.data.content.forEach(userFor => {
 | 
				
			||||||
 | 
					          userFor["roleOptionsId"] = userFor.roles.map(x => x.id);
 | 
				
			||||||
 | 
					          userFor["jobOptionsId"] = userFor.jobs.map(x => x.id);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        dataList.value = data.data.content;
 | 
				
			||||||
 | 
					        pagination.total = data.data.totalElements;
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      .finally(() => (loading.value = false));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const resetForm = formEl => {
 | 
					  const resetForm = formEl => {
 | 
				
			||||||
@ -309,15 +341,20 @@ export function useUser(tableRef: Ref, treeRef: Ref) {
 | 
				
			|||||||
        formInline: {
 | 
					        formInline: {
 | 
				
			||||||
          title,
 | 
					          title,
 | 
				
			||||||
          higherDeptOptions: formatHigherDeptOptions(higherDeptOptions.value),
 | 
					          higherDeptOptions: formatHigherDeptOptions(higherDeptOptions.value),
 | 
				
			||||||
 | 
					          id: row?.id,
 | 
				
			||||||
          parentId: row?.dept.id ?? 0,
 | 
					          parentId: row?.dept.id ?? 0,
 | 
				
			||||||
          nickname: row?.nickname ?? "",
 | 
					          nickName: row?.nickName ?? "",
 | 
				
			||||||
          username: row?.username ?? "",
 | 
					          username: row?.nickName ?? "",
 | 
				
			||||||
          password: row?.password ?? "",
 | 
					          password: row?.password ?? "",
 | 
				
			||||||
          phone: row?.phone ?? "",
 | 
					          phone: row?.phone ?? "",
 | 
				
			||||||
          email: row?.email ?? "",
 | 
					          email: row?.email ?? "",
 | 
				
			||||||
          sex: row?.sex ?? "",
 | 
					          gender: row?.gender ?? "男",
 | 
				
			||||||
          status: row?.status ?? 1,
 | 
					          enabled: row?.enabled ?? 1,
 | 
				
			||||||
          remark: row?.remark ?? ""
 | 
					          remark: row?.remark ?? "",
 | 
				
			||||||
 | 
					          jobOptionsId: row?.jobOptionsId ?? [],
 | 
				
			||||||
 | 
					          roleOptionsId: row?.roleOptionsId ?? [],
 | 
				
			||||||
 | 
					          roleOptions: roleOptions?.value ?? [],
 | 
				
			||||||
 | 
					          jobOptions: jobOptions?.value ?? []
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      width: "46%",
 | 
					      width: "46%",
 | 
				
			||||||
@ -329,7 +366,7 @@ export function useUser(tableRef: Ref, treeRef: Ref) {
 | 
				
			|||||||
        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.username}的这条数据`, {
 | 
					          message(`您${title}了用户名称为${curData.nickName}的这条数据`, {
 | 
				
			||||||
            type: "success"
 | 
					            type: "success"
 | 
				
			||||||
          });
 | 
					          });
 | 
				
			||||||
          done(); // 关闭弹框
 | 
					          done(); // 关闭弹框
 | 
				
			||||||
@ -337,14 +374,30 @@ export function useUser(tableRef: Ref, treeRef: Ref) {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        FormRef.validate(valid => {
 | 
					        FormRef.validate(valid => {
 | 
				
			||||||
          if (valid) {
 | 
					          if (valid) {
 | 
				
			||||||
            console.log("curData", curData);
 | 
					            const userClone = cloneDeep(curData);
 | 
				
			||||||
 | 
					            userClone["dept"] = { id: userClone.parentId };
 | 
				
			||||||
 | 
					            userClone["roles"] = userClone.roleOptionsId.map(x => ({
 | 
				
			||||||
 | 
					              id: x
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            userClone["jobs"] = userClone.jobOptionsId.map(x => ({
 | 
				
			||||||
 | 
					              id: x
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            delete userClone.title;
 | 
				
			||||||
 | 
					            delete userClone.higherDeptOptions;
 | 
				
			||||||
 | 
					            delete userClone.parentId;
 | 
				
			||||||
 | 
					            delete userClone.roleOptions;
 | 
				
			||||||
 | 
					            delete userClone.jobOptions;
 | 
				
			||||||
 | 
					            delete userClone.roleOptionsId;
 | 
				
			||||||
 | 
					            delete userClone.jobOptionsId;
 | 
				
			||||||
            // 表单规则校验通过
 | 
					            // 表单规则校验通过
 | 
				
			||||||
            if (title === "新增") {
 | 
					            if (title === "新增") {
 | 
				
			||||||
              // 实际开发先调用新增接口,再进行下面操作
 | 
					              User.add(userClone);
 | 
				
			||||||
              chores();
 | 
					              chores();
 | 
				
			||||||
 | 
					              console.log("curData", userClone);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
              // 实际开发先调用修改接口,再进行下面操作
 | 
					              User.edit(userClone).finally(() => {
 | 
				
			||||||
              chores();
 | 
					                chores();
 | 
				
			||||||
 | 
					              });
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
@ -352,7 +405,6 @@ export function useUser(tableRef: Ref, treeRef: Ref) {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const cropRef = ref();
 | 
					 | 
				
			||||||
  /** 上传头像 */
 | 
					  /** 上传头像 */
 | 
				
			||||||
  function handleUpload(row) {
 | 
					  function handleUpload(row) {
 | 
				
			||||||
    addDialog({
 | 
					    addDialog({
 | 
				
			||||||
@ -362,17 +414,15 @@ export function useUser(tableRef: Ref, treeRef: Ref) {
 | 
				
			|||||||
      closeOnClickModal: false,
 | 
					      closeOnClickModal: false,
 | 
				
			||||||
      contentRenderer: () =>
 | 
					      contentRenderer: () =>
 | 
				
			||||||
        h(croppingUpload, {
 | 
					        h(croppingUpload, {
 | 
				
			||||||
          ref: cropRef,
 | 
					          imgSrc: baseUrlAvatar(row.avatarName),
 | 
				
			||||||
          imgSrc: row.avatar,
 | 
					 | 
				
			||||||
          onCropper: info => (avatarInfo.value = info)
 | 
					          onCropper: info => (avatarInfo.value = info)
 | 
				
			||||||
        }),
 | 
					        }),
 | 
				
			||||||
      beforeSure: done => {
 | 
					      beforeSure: done => {
 | 
				
			||||||
        console.log("裁剪后的图片信息:", avatarInfo.value);
 | 
					        User.updateAvatarByid({ id: row.id, avatar: avatarInfo.value.blob });
 | 
				
			||||||
        // 根据实际业务使用avatarInfo.value和row里的某些字段去调用上传头像接口即可
 | 
					        // 根据实际业务使用avatarInfo.value和row里的某些字段去调用上传头像接口即可
 | 
				
			||||||
        done(); // 关闭弹框
 | 
					        done(); // 关闭弹框
 | 
				
			||||||
        onSearch(); // 刷新表格数据
 | 
					        onSearch(); // 刷新表格数据
 | 
				
			||||||
      },
 | 
					      }
 | 
				
			||||||
      closeCallBack: () => cropRef.value.hidePopover()
 | 
					 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -445,7 +495,6 @@ export function useUser(tableRef: Ref, treeRef: Ref) {
 | 
				
			|||||||
            message(`已成功重置 ${row.username} 用户的密码`, {
 | 
					            message(`已成功重置 ${row.username} 用户的密码`, {
 | 
				
			||||||
              type: "success"
 | 
					              type: "success"
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
            console.log(pwdForm.newPwd);
 | 
					 | 
				
			||||||
            // 根据实际业务使用pwdForm.newPwd和row里的某些字段去调用重置用户密码接口即可
 | 
					            // 根据实际业务使用pwdForm.newPwd和row里的某些字段去调用重置用户密码接口即可
 | 
				
			||||||
            done(); // 关闭弹框
 | 
					            done(); // 关闭弹框
 | 
				
			||||||
            onSearch(); // 刷新表格数据
 | 
					            onSearch(); // 刷新表格数据
 | 
				
			||||||
@ -457,14 +506,15 @@ export function useUser(tableRef: Ref, treeRef: Ref) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /** 分配角色 */
 | 
					  /** 分配角色 */
 | 
				
			||||||
  async function handleRole(row) {
 | 
					  async function handleRole(row) {
 | 
				
			||||||
 | 
					    const roleIds = row.roles.map(x => x.id);
 | 
				
			||||||
    // 选中的角色列表
 | 
					    // 选中的角色列表
 | 
				
			||||||
    const ids = (await getRoleIds({ userId: row.id })).data ?? [];
 | 
					    const ids = roleIds ?? [];
 | 
				
			||||||
    addDialog({
 | 
					    addDialog({
 | 
				
			||||||
      title: `分配 ${row.username} 用户的角色`,
 | 
					      title: `分配 ${row.username} 用户的角色`,
 | 
				
			||||||
      props: {
 | 
					      props: {
 | 
				
			||||||
        formInline: {
 | 
					        formInline: {
 | 
				
			||||||
          username: row?.username ?? "",
 | 
					          username: row?.username ?? "",
 | 
				
			||||||
          nickname: row?.nickname ?? "",
 | 
					          nickName: row?.nickName ?? "",
 | 
				
			||||||
          roleOptions: roleOptions.value ?? [],
 | 
					          roleOptions: roleOptions.value ?? [],
 | 
				
			||||||
          ids
 | 
					          ids
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -476,9 +526,25 @@ export function useUser(tableRef: Ref, treeRef: Ref) {
 | 
				
			|||||||
      contentRenderer: () => h(roleForm),
 | 
					      contentRenderer: () => h(roleForm),
 | 
				
			||||||
      beforeSure: (done, { options }) => {
 | 
					      beforeSure: (done, { options }) => {
 | 
				
			||||||
        const curData = options.props.formInline as RoleFormItemProps;
 | 
					        const curData = options.props.formInline as RoleFormItemProps;
 | 
				
			||||||
        console.log("curIds", curData.ids);
 | 
					        const userClone = cloneDeep(row);
 | 
				
			||||||
        // 根据实际业务使用curData.ids和row里的某些字段去调用修改角色接口即可
 | 
					        userClone["dept"] = { id: userClone.parentId };
 | 
				
			||||||
        done(); // 关闭弹框
 | 
					        userClone["roles"] = curData.ids.map(x => ({
 | 
				
			||||||
 | 
					          id: x
 | 
				
			||||||
 | 
					        }));
 | 
				
			||||||
 | 
					        userClone["jobs"] = userClone.jobOptionsId.map(x => ({
 | 
				
			||||||
 | 
					          id: x
 | 
				
			||||||
 | 
					        }));
 | 
				
			||||||
 | 
					        delete userClone.title;
 | 
				
			||||||
 | 
					        delete userClone.higherDeptOptions;
 | 
				
			||||||
 | 
					        delete userClone.parentId;
 | 
				
			||||||
 | 
					        delete userClone.roleOptions;
 | 
				
			||||||
 | 
					        delete userClone.jobOptions;
 | 
				
			||||||
 | 
					        delete userClone.roleOptionsId;
 | 
				
			||||||
 | 
					        delete userClone.jobOptionsId;
 | 
				
			||||||
 | 
					        User.edit(userClone).finally(() => {
 | 
				
			||||||
 | 
					          done();
 | 
				
			||||||
 | 
					          onSearch();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -488,13 +554,15 @@ export function useUser(tableRef: Ref, treeRef: Ref) {
 | 
				
			|||||||
    onSearch();
 | 
					    onSearch();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // 归属部门
 | 
					    // 归属部门
 | 
				
			||||||
    const { data } = await getDeptList();
 | 
					    // const { data } = await getDeptList();
 | 
				
			||||||
    higherDeptOptions.value = handleTree(data);
 | 
					    const { data } = await Dept.getDeptTree({ enabled: true });
 | 
				
			||||||
    treeData.value = handleTree(data);
 | 
					    higherDeptOptions.value = handleTree(data, "id", "pid");
 | 
				
			||||||
 | 
					    treeData.value = handleTree(data, "id", "pid");
 | 
				
			||||||
    treeLoading.value = false;
 | 
					    treeLoading.value = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // 角色列表
 | 
					    // 角色列表
 | 
				
			||||||
    roleOptions.value = (await getAllRoleList()).data;
 | 
					    roleOptions.value = (await Role.get()).data.content;
 | 
				
			||||||
 | 
					    jobOptions.value = (await Job.get()).data.content;
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return {
 | 
					  return {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										321
									
								
								src/views/system/user/utils/info.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										321
									
								
								src/views/system/user/utils/info.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,321 @@
 | 
				
			|||||||
 | 
					import { type Ref, h, ref, watch, reactive, onMounted, computed } from "vue";
 | 
				
			||||||
 | 
					import croppingUpload from "../upload.vue";
 | 
				
			||||||
 | 
					import { baseUrlAvatar } from "@/api/utils";
 | 
				
			||||||
 | 
					import { zxcvbn } from "@zxcvbn-ts/core";
 | 
				
			||||||
 | 
					import { isAllEmpty, isNull, isEmail } from "@pureadmin/utils";
 | 
				
			||||||
 | 
					import { addDialog } from "@/components/ReDialog";
 | 
				
			||||||
 | 
					import Cookies from "js-cookie";
 | 
				
			||||||
 | 
					import * as User from "@/api/system/user";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  ElForm,
 | 
				
			||||||
 | 
					  ElInput,
 | 
				
			||||||
 | 
					  ElFormItem,
 | 
				
			||||||
 | 
					  ElProgress,
 | 
				
			||||||
 | 
					  ElButton
 | 
				
			||||||
 | 
					} from "element-plus";
 | 
				
			||||||
 | 
					import { message } from "@/utils/message";
 | 
				
			||||||
 | 
					import { formRulesPwd, formRulesEmail } from "./rule";
 | 
				
			||||||
 | 
					import type { FormInstance } from "element-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function useUser(tableRef: Ref, treeRef: Ref) {
 | 
				
			||||||
 | 
					  console.log(tableRef, treeRef);
 | 
				
			||||||
 | 
					  // 上传头像信息
 | 
				
			||||||
 | 
					  const avatarInfo = ref();
 | 
				
			||||||
 | 
					  const ruleFormRef = ref();
 | 
				
			||||||
 | 
					  // 重置的新密码
 | 
				
			||||||
 | 
					  const pwdForm = reactive({
 | 
				
			||||||
 | 
					    newPwd: "",
 | 
				
			||||||
 | 
					    oldPwd: "",
 | 
				
			||||||
 | 
					    newPwdCop: ""
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  const pwdProgress = [
 | 
				
			||||||
 | 
					    { color: "#e74242", text: "非常弱" },
 | 
				
			||||||
 | 
					    { color: "#EFBD47", text: "弱" },
 | 
				
			||||||
 | 
					    { color: "#ffa500", text: "一般" },
 | 
				
			||||||
 | 
					    { color: "#1bbf1b", text: "强" },
 | 
				
			||||||
 | 
					    { color: "#008000", text: "非常强" }
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					  const ruleEmailFormRef = ref();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 重置的新邮箱
 | 
				
			||||||
 | 
					  const emailForm = reactive({
 | 
				
			||||||
 | 
					    pwd: "",
 | 
				
			||||||
 | 
					    code: "",
 | 
				
			||||||
 | 
					    email: ""
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  // 当前密码强度(0-4)
 | 
				
			||||||
 | 
					  const curScore = ref();
 | 
				
			||||||
 | 
					  const form = reactive({
 | 
				
			||||||
 | 
					    // 左侧部门树的id
 | 
				
			||||||
 | 
					    deptId: "",
 | 
				
			||||||
 | 
					    username: "",
 | 
				
			||||||
 | 
					    createTime: "",
 | 
				
			||||||
 | 
					    phone: "",
 | 
				
			||||||
 | 
					    status: ""
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  /** 用户信息 */
 | 
				
			||||||
 | 
					  const userInfo = computed(() => {
 | 
				
			||||||
 | 
					    return JSON.parse(Cookies.get("userInfo"));
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  /** 获取邮箱验证码 */
 | 
				
			||||||
 | 
					  const getEmailCode = email => {
 | 
				
			||||||
 | 
					    if (isNull(email)) {
 | 
				
			||||||
 | 
					      message("email必填", {
 | 
				
			||||||
 | 
					        type: "error"
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    } else if (!isEmail(email)) {
 | 
				
			||||||
 | 
					      message("email格式错误", {
 | 
				
			||||||
 | 
					        type: "error"
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      console.log("email", email);
 | 
				
			||||||
 | 
					      User.resetEmail(email)
 | 
				
			||||||
 | 
					        .then(() => {
 | 
				
			||||||
 | 
					          message("更换邮箱成功", {
 | 
				
			||||||
 | 
					            type: "success"
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .catch(error => {
 | 
				
			||||||
 | 
					          message(`${error}`, {
 | 
				
			||||||
 | 
					            type: "error"
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  onMounted(async () => {
 | 
				
			||||||
 | 
					    console.log(userInfo);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** 上传头像 */
 | 
				
			||||||
 | 
					  function handleUpload(row) {
 | 
				
			||||||
 | 
					    addDialog({
 | 
				
			||||||
 | 
					      title: "裁剪、上传头像",
 | 
				
			||||||
 | 
					      width: "50%",
 | 
				
			||||||
 | 
					      draggable: false,
 | 
				
			||||||
 | 
					      closeOnClickModal: false,
 | 
				
			||||||
 | 
					      contentRenderer: () =>
 | 
				
			||||||
 | 
					        h(croppingUpload, {
 | 
				
			||||||
 | 
					          imgSrc: baseUrlAvatar(row.avatarName),
 | 
				
			||||||
 | 
					          onCropper: info => (avatarInfo.value = info)
 | 
				
			||||||
 | 
					        }),
 | 
				
			||||||
 | 
					      beforeSure: done => {
 | 
				
			||||||
 | 
					        console.log("avatarInfo.value", avatarInfo.value);
 | 
				
			||||||
 | 
					        User.updateAvatarByid({ id: row.id, avatar: avatarInfo.value.blob });
 | 
				
			||||||
 | 
					        // 根据实际业务使用avatarInfo.value和row里的某些字段去调用上传头像接口即可
 | 
				
			||||||
 | 
					        done(); // 关闭弹框
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  watch(
 | 
				
			||||||
 | 
					    pwdForm,
 | 
				
			||||||
 | 
					    ({ newPwd }) =>
 | 
				
			||||||
 | 
					      (curScore.value = isAllEmpty(newPwd) ? -1 : zxcvbn(newPwd).score)
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					  /** 重置密码 */
 | 
				
			||||||
 | 
					  function handleReset() {
 | 
				
			||||||
 | 
					    addDialog({
 | 
				
			||||||
 | 
					      title: `重置 ${userInfo.value.user.nickName} 用户的密码`,
 | 
				
			||||||
 | 
					      width: "30%",
 | 
				
			||||||
 | 
					      draggable: true,
 | 
				
			||||||
 | 
					      closeOnClickModal: false,
 | 
				
			||||||
 | 
					      contentRenderer: () => (
 | 
				
			||||||
 | 
					        <>
 | 
				
			||||||
 | 
					          <ElForm
 | 
				
			||||||
 | 
					            ref={ruleFormRef}
 | 
				
			||||||
 | 
					            model={pwdForm}
 | 
				
			||||||
 | 
					            {...{ rules: formRulesPwd }}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <ElFormItem prop="oldPwd" label="请输入旧密码:">
 | 
				
			||||||
 | 
					              <ElInput
 | 
				
			||||||
 | 
					                clearable
 | 
				
			||||||
 | 
					                show-password
 | 
				
			||||||
 | 
					                type="password"
 | 
				
			||||||
 | 
					                v-model={pwdForm.oldPwd}
 | 
				
			||||||
 | 
					                placeholder="请输入旧密码"
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					            </ElFormItem>
 | 
				
			||||||
 | 
					            <ElFormItem prop="newPwd" label="请输入新密码:">
 | 
				
			||||||
 | 
					              <ElInput
 | 
				
			||||||
 | 
					                clearable
 | 
				
			||||||
 | 
					                show-password
 | 
				
			||||||
 | 
					                type="password"
 | 
				
			||||||
 | 
					                v-model={pwdForm.newPwd}
 | 
				
			||||||
 | 
					                placeholder="请输入新密码"
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					            </ElFormItem>
 | 
				
			||||||
 | 
					            <div class="mt-4 flex">
 | 
				
			||||||
 | 
					              {pwdProgress.map(({ color, text }, idx) => (
 | 
				
			||||||
 | 
					                <div
 | 
				
			||||||
 | 
					                  class="w-[19vw]"
 | 
				
			||||||
 | 
					                  style={{ marginLeft: idx !== 0 ? "4px" : 0 }}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  <ElProgress
 | 
				
			||||||
 | 
					                    striped
 | 
				
			||||||
 | 
					                    striped-flow
 | 
				
			||||||
 | 
					                    duration={curScore.value === idx ? 6 : 0}
 | 
				
			||||||
 | 
					                    percentage={curScore.value >= idx ? 100 : 0}
 | 
				
			||||||
 | 
					                    color={color}
 | 
				
			||||||
 | 
					                    stroke-width={10}
 | 
				
			||||||
 | 
					                    show-text={false}
 | 
				
			||||||
 | 
					                  />
 | 
				
			||||||
 | 
					                  <p
 | 
				
			||||||
 | 
					                    class="text-center"
 | 
				
			||||||
 | 
					                    style={{ color: curScore.value === idx ? color : "" }}
 | 
				
			||||||
 | 
					                  >
 | 
				
			||||||
 | 
					                    {text}
 | 
				
			||||||
 | 
					                  </p>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					              ))}
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <ElFormItem prop="newPwdCop" label="请确认新密码:">
 | 
				
			||||||
 | 
					              <ElInput
 | 
				
			||||||
 | 
					                clearable
 | 
				
			||||||
 | 
					                show-password
 | 
				
			||||||
 | 
					                type="password"
 | 
				
			||||||
 | 
					                v-model={pwdForm.newPwdCop}
 | 
				
			||||||
 | 
					                placeholder="请确认新密码"
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					            </ElFormItem>
 | 
				
			||||||
 | 
					          </ElForm>
 | 
				
			||||||
 | 
					        </>
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					      closeCallBack: () =>
 | 
				
			||||||
 | 
					        Object.assign(pwdForm, {
 | 
				
			||||||
 | 
					          newPwd: "",
 | 
				
			||||||
 | 
					          oldPwd: "",
 | 
				
			||||||
 | 
					          newPwdCop: ""
 | 
				
			||||||
 | 
					        }),
 | 
				
			||||||
 | 
					      beforeSure: done => {
 | 
				
			||||||
 | 
					        ruleFormRef.value.validate(valid => {
 | 
				
			||||||
 | 
					          if (valid) {
 | 
				
			||||||
 | 
					            if (pwdForm.newPwd !== pwdForm.newPwdCop) {
 | 
				
			||||||
 | 
					              message(`两次密码不想等`, {
 | 
				
			||||||
 | 
					                type: "error"
 | 
				
			||||||
 | 
					              });
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					              // 表单规则校验通过
 | 
				
			||||||
 | 
					              message(`已成功重置 ${userInfo.value.user.nickName} 用户的密码`, {
 | 
				
			||||||
 | 
					                type: "success"
 | 
				
			||||||
 | 
					              });
 | 
				
			||||||
 | 
					              // 根据实际业务使用pwdForm.newPwd和row里的某些字段去调用重置用户密码接口即可
 | 
				
			||||||
 | 
					              done(); // 关闭弹框
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  /** 更换邮箱 */
 | 
				
			||||||
 | 
					  function handleResetEmail() {
 | 
				
			||||||
 | 
					    addDialog({
 | 
				
			||||||
 | 
					      title: `更换 ${userInfo.value.user.nickName} 用户的邮箱`,
 | 
				
			||||||
 | 
					      width: "30%",
 | 
				
			||||||
 | 
					      draggable: true,
 | 
				
			||||||
 | 
					      closeOnClickModal: false,
 | 
				
			||||||
 | 
					      contentRenderer: () => (
 | 
				
			||||||
 | 
					        <>
 | 
				
			||||||
 | 
					          <ElForm
 | 
				
			||||||
 | 
					            ref={ruleEmailFormRef}
 | 
				
			||||||
 | 
					            model={emailForm}
 | 
				
			||||||
 | 
					            {...{ rules: formRulesEmail }}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <ElFormItem prop="email" label="新邮箱:">
 | 
				
			||||||
 | 
					              <ElInput
 | 
				
			||||||
 | 
					                clearable
 | 
				
			||||||
 | 
					                type="email"
 | 
				
			||||||
 | 
					                v-model={emailForm.email}
 | 
				
			||||||
 | 
					                placeholder="请输入邮箱"
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					            </ElFormItem>
 | 
				
			||||||
 | 
					            <ElFormItem prop="code" label="验证码:">
 | 
				
			||||||
 | 
					              <ElInput
 | 
				
			||||||
 | 
					                clearable
 | 
				
			||||||
 | 
					                type="text"
 | 
				
			||||||
 | 
					                v-model={emailForm.code}
 | 
				
			||||||
 | 
					                placeholder="请输入验证码"
 | 
				
			||||||
 | 
					                v-slots={{
 | 
				
			||||||
 | 
					                  append: () => (
 | 
				
			||||||
 | 
					                    <ElButton onClick={() => getEmailCode(emailForm.email)}>
 | 
				
			||||||
 | 
					                      获取验证码
 | 
				
			||||||
 | 
					                    </ElButton>
 | 
				
			||||||
 | 
					                  )
 | 
				
			||||||
 | 
					                }}
 | 
				
			||||||
 | 
					              ></ElInput>
 | 
				
			||||||
 | 
					            </ElFormItem>
 | 
				
			||||||
 | 
					            <ElFormItem prop="pwd" label="当前密码:">
 | 
				
			||||||
 | 
					              <ElInput
 | 
				
			||||||
 | 
					                clearable
 | 
				
			||||||
 | 
					                show-password
 | 
				
			||||||
 | 
					                type="password"
 | 
				
			||||||
 | 
					                v-model={emailForm.pwd}
 | 
				
			||||||
 | 
					                placeholder="请输入当前密码"
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					            </ElFormItem>
 | 
				
			||||||
 | 
					          </ElForm>
 | 
				
			||||||
 | 
					        </>
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					      closeCallBack: () =>
 | 
				
			||||||
 | 
					        Object.assign(emailForm, {
 | 
				
			||||||
 | 
					          pwd: "",
 | 
				
			||||||
 | 
					          code: "",
 | 
				
			||||||
 | 
					          email: ""
 | 
				
			||||||
 | 
					        }),
 | 
				
			||||||
 | 
					      beforeSure: done => {
 | 
				
			||||||
 | 
					        ruleEmailFormRef.value.validate(valid => {
 | 
				
			||||||
 | 
					          if (valid) {
 | 
				
			||||||
 | 
					            console.log("emailForm", emailForm);
 | 
				
			||||||
 | 
					            User.updateEmail({
 | 
				
			||||||
 | 
					              code: emailForm.code,
 | 
				
			||||||
 | 
					              pass: emailForm.pwd,
 | 
				
			||||||
 | 
					              email: emailForm.email
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					              .then(() => {
 | 
				
			||||||
 | 
					                // 表单规则校验通过
 | 
				
			||||||
 | 
					                message(
 | 
				
			||||||
 | 
					                  `已成功更换 ${userInfo.value.user.nickName} 用户的邮箱`,
 | 
				
			||||||
 | 
					                  {
 | 
				
			||||||
 | 
					                    type: "success"
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					                // 根据实际业务使用pwdForm.newPwd和row里的某些字段去调用重置用户密码接口即可
 | 
				
			||||||
 | 
					                done(); // 关闭弹框
 | 
				
			||||||
 | 
					              })
 | 
				
			||||||
 | 
					              .catch(error => {
 | 
				
			||||||
 | 
					                console.log("error", error.response);
 | 
				
			||||||
 | 
					                console.log("error", error.response.data.message);
 | 
				
			||||||
 | 
					                message(`验证码错误:${error.response.data.message}`, {
 | 
				
			||||||
 | 
					                  type: "error"
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					              });
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  //更新用户谢谢
 | 
				
			||||||
 | 
					  const submitEditUser = async (formEl: FormInstance | undefined, userI) => {
 | 
				
			||||||
 | 
					    if (!formEl) return;
 | 
				
			||||||
 | 
					    await formEl.validate((valid, fields) => {
 | 
				
			||||||
 | 
					      if (valid) {
 | 
				
			||||||
 | 
					        console.log("userI!", userI);
 | 
				
			||||||
 | 
					        User.editUser({
 | 
				
			||||||
 | 
					          id: userI.id,
 | 
				
			||||||
 | 
					          nickName: userI.nickName,
 | 
				
			||||||
 | 
					          gender: userI.gender,
 | 
				
			||||||
 | 
					          phone: userI.phone
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        console.log("error submit!", fields);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    form,
 | 
				
			||||||
 | 
					    userInfo,
 | 
				
			||||||
 | 
					    handleUpload,
 | 
				
			||||||
 | 
					    handleReset,
 | 
				
			||||||
 | 
					    handleResetEmail,
 | 
				
			||||||
 | 
					    submitEditUser
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -4,14 +4,15 @@ import { isPhone, isEmail } from "@pureadmin/utils";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/** 自定义表单规则校验 */
 | 
					/** 自定义表单规则校验 */
 | 
				
			||||||
export const formRules = reactive(<FormRules>{
 | 
					export const formRules = reactive(<FormRules>{
 | 
				
			||||||
  nickname: [{ required: true, message: "用户昵称为必填项", trigger: "blur" }],
 | 
					  nickName: [{ required: true, message: "用户昵称为必填项", trigger: "blur" }],
 | 
				
			||||||
  username: [{ required: true, message: "用户名称为必填项", trigger: "blur" }],
 | 
					  username: [{ required: true, message: "用户名称为必填项", trigger: "blur" }],
 | 
				
			||||||
  password: [{ required: true, message: "用户密码为必填项", trigger: "blur" }],
 | 
					  password: [{ required: true, message: "用户密码为必填项", trigger: "blur" }],
 | 
				
			||||||
  phone: [
 | 
					  phone: [
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					      required: true,
 | 
				
			||||||
      validator: (rule, value, callback) => {
 | 
					      validator: (rule, value, callback) => {
 | 
				
			||||||
        if (value === "") {
 | 
					        if (value === "") {
 | 
				
			||||||
          callback();
 | 
					          callback(new Error("手机号为必填项"));
 | 
				
			||||||
        } else if (!isPhone(value)) {
 | 
					        } else if (!isPhone(value)) {
 | 
				
			||||||
          callback(new Error("请输入正确的手机号码格式"));
 | 
					          callback(new Error("请输入正确的手机号码格式"));
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
@ -24,9 +25,10 @@ export const formRules = reactive(<FormRules>{
 | 
				
			|||||||
  ],
 | 
					  ],
 | 
				
			||||||
  email: [
 | 
					  email: [
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					      required: true,
 | 
				
			||||||
      validator: (rule, value, callback) => {
 | 
					      validator: (rule, value, callback) => {
 | 
				
			||||||
        if (value === "") {
 | 
					        if (value === "") {
 | 
				
			||||||
          callback();
 | 
					          callback(new Error("邮箱为必填项"));
 | 
				
			||||||
        } else if (!isEmail(value)) {
 | 
					        } else if (!isEmail(value)) {
 | 
				
			||||||
          callback(new Error("请输入正确的邮箱格式"));
 | 
					          callback(new Error("请输入正确的邮箱格式"));
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
@ -35,5 +37,69 @@ export const formRules = reactive(<FormRules>{
 | 
				
			|||||||
      },
 | 
					      },
 | 
				
			||||||
      trigger: "blur"
 | 
					      trigger: "blur"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  parentId: [{ required: true, message: "部门为必填项", trigger: "blur" }],
 | 
				
			||||||
 | 
					  roleOptionsId: [{ required: true, message: "角色为必填项", trigger: "blur" }],
 | 
				
			||||||
 | 
					  jobOptionsId: [{ required: true, message: "岗位为必填项", trigger: "blur" }]
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 自定义修改密码规则校验 */
 | 
				
			||||||
 | 
					export const formRulesPwd = reactive(<FormRules>{
 | 
				
			||||||
 | 
					  oldPwd: [{ required: true, message: "旧密码为必填项", trigger: "blur" }],
 | 
				
			||||||
 | 
					  newPwd: [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      required: true,
 | 
				
			||||||
 | 
					      validator: (rule, value, callback) => {
 | 
				
			||||||
 | 
					        if (value === "") {
 | 
				
			||||||
 | 
					          callback(new Error("新密码为必填项"));
 | 
				
			||||||
 | 
					        } else if (value.length < 6) {
 | 
				
			||||||
 | 
					          callback(new Error("密码长度小于6"));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          callback();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      trigger: "blur"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  newPwdCop: [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      required: true,
 | 
				
			||||||
 | 
					      validator: (rule, value, callback) => {
 | 
				
			||||||
 | 
					        if (value === "") {
 | 
				
			||||||
 | 
					          callback(new Error("确认新密码为必填项"));
 | 
				
			||||||
 | 
					        } else if (value.length < 6) {
 | 
				
			||||||
 | 
					          callback(new Error("密码长度小于6"));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          callback();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      trigger: "blur"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					/** 自定义修改邮箱规则校验 */
 | 
				
			||||||
 | 
					export const formRulesEmail = reactive(<FormRules>{
 | 
				
			||||||
 | 
					  email: [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      required: true,
 | 
				
			||||||
 | 
					      validator: (rule, value, callback) => {
 | 
				
			||||||
 | 
					        if (value === "") {
 | 
				
			||||||
 | 
					          callback(new Error("邮箱为必填项"));
 | 
				
			||||||
 | 
					        } else if (!isEmail(value)) {
 | 
				
			||||||
 | 
					          callback(new Error("请输入正确的邮箱格式"));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          callback();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      trigger: "blur"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  code: [
 | 
				
			||||||
 | 
					    { required: true, message: "验证码为必填项", trigger: "blur" },
 | 
				
			||||||
 | 
					    { min: 4, max: 8, message: "Length should be 4 to 8", trigger: "blur" }
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  pwd: [
 | 
				
			||||||
 | 
					    { required: true, message: "密码为必填项", trigger: "blur" },
 | 
				
			||||||
 | 
					    { min: 6, max: 18, message: "Length should be 4 to 8", trigger: "blur" }
 | 
				
			||||||
  ]
 | 
					  ]
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
				
			|||||||
@ -4,18 +4,22 @@ interface FormItemProps {
 | 
				
			|||||||
  title: string;
 | 
					  title: string;
 | 
				
			||||||
  higherDeptOptions: Record<string, unknown>[];
 | 
					  higherDeptOptions: Record<string, unknown>[];
 | 
				
			||||||
  parentId: number;
 | 
					  parentId: number;
 | 
				
			||||||
  nickname: string;
 | 
					 | 
				
			||||||
  username: string;
 | 
					  username: string;
 | 
				
			||||||
 | 
					  nickName: string;
 | 
				
			||||||
  password: string;
 | 
					  password: string;
 | 
				
			||||||
  phone: string | number;
 | 
					  phone: string | number;
 | 
				
			||||||
  email: string;
 | 
					  email: string;
 | 
				
			||||||
  sex: string | number;
 | 
					  gender: string | number;
 | 
				
			||||||
  status: number;
 | 
					  enabled: boolean;
 | 
				
			||||||
  dept?: {
 | 
					  dept?: {
 | 
				
			||||||
    id?: number;
 | 
					    id?: number;
 | 
				
			||||||
    name?: string;
 | 
					    name?: string;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  remark: string;
 | 
					  remark: string;
 | 
				
			||||||
 | 
					  roleOptionsId: number[];
 | 
				
			||||||
 | 
					  roleOptions: Record<string, number>[];
 | 
				
			||||||
 | 
					  jobOptionsId: number[];
 | 
				
			||||||
 | 
					  jobOptions: Record<string, number>[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
interface FormProps {
 | 
					interface FormProps {
 | 
				
			||||||
  formInline: FormItemProps;
 | 
					  formInline: FormItemProps;
 | 
				
			||||||
@ -23,7 +27,7 @@ interface FormProps {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
interface RoleFormItemProps {
 | 
					interface RoleFormItemProps {
 | 
				
			||||||
  username: string;
 | 
					  username: string;
 | 
				
			||||||
  nickname: string;
 | 
					  nickName: string;
 | 
				
			||||||
  /** 角色列表 */
 | 
					  /** 角色列表 */
 | 
				
			||||||
  roleOptions: any[];
 | 
					  roleOptions: any[];
 | 
				
			||||||
  /** 选中的角色列表 */
 | 
					  /** 选中的角色列表 */
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user