Browse Source

fix(菜单): muns

tangning 3 years ago
parent
commit
91fe49756b

+ 2 - 6
index.html

@@ -10,16 +10,12 @@
     />
     <title><%= title %></title>
     <link rel="icon" href="/favicon.ico" />
-    <script async defer
-    data-app-id="7b5958d5-1ae6-4ad5-8a87-5fc8a4b92999" 
-    data-url="http://192.168.0.186:3000/api/collect" 
-    data-track-url="'http://192.168.0.186:3000/api/track" 
-    src="https://allreally.oss-cn-shenzhen.aliyuncs.com/wasm/test_legacy/medici.js">
-   </script>
+    
   </head>
 
   <body>
     <script>
+      
       (() => {
         var htmlRoot = document.getElementById('htmlRoot');
         var theme = window.localStorage.getItem('__APP__DARK__MODE__');

+ 136 - 0
src/api/staff/list.ts

@@ -0,0 +1,136 @@
+import { defHttp } from '/@/utils/http/axios';
+import { PageParams, ListGetResultModel, DelParams, roleParams } from './model';
+import { Result } from '/#/axios';
+
+enum Api {
+  pageList = '/newV4/service/manage/sysUser/list',
+  sysUserAdd = '/newV4/service/manage/sysUser/add',
+  updatePassword = '/newV4/service/manage/sysUser/rePassword',
+  preDel = '/zfb-api/zfb/shop/sys/user/preDeleteStaff',
+  roleList = '/zfb-api/zfb/shop/sys/user/roleList',
+  getRoleListByParam = '/zfb-api/zfb/shop/sys/user/getRoleListByParam',
+  staffSave = '/zfb-api/zfb/shop/sys/user/staffSave',
+  update = '/zfb-api/zfb/shop/sys/user/update',
+  checkUser = '/zfb-api/zfb/user/checkUserExists',
+  deleteStaff = '/zfb-api/zfb/shop/sys/user/deleteStaff',
+  getNumByStaff = '/zfb-api/zfb/shop/sys/user/getNumByStaff',
+  clean = '/zfb-api/zfb/loginOutByUser',
+}
+
+/**
+ * @description: Get sample list value
+ */
+
+export const clean = (params) =>
+  defHttp.post<Result>({
+    url: Api.clean,
+    params,
+    data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+
+export function updatePasswordApi(params) {
+    return defHttp.post<Result>(
+      { url: Api.updatePassword, params },
+      // { errorMessageMode: 'none' },
+    );
+} 
+export const staffListApi = (params: PageParams) =>
+  defHttp.post<ListGetResultModel>({
+    url: Api.pageList,
+    params,
+    data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+
+export const ListApi = (params: PageParams) =>
+  defHttp.post<ListGetResultModel>({
+    url: Api.pageList,
+    params,
+    data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+
+export const getNumByStaff = (params: any) =>
+  defHttp.get<Result>({
+    url: Api.getNumByStaff,
+    params,
+    data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+export const delApi = (params: DelParams) =>
+  defHttp.post<Result>({
+    url: Api.deleteStaff,
+    params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+export const preDelApi = (params: number) =>
+  defHttp.post<Result>({
+    url: Api.preDel,
+    params: { userId: params },
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+export const getRoleListByParam = (params: roleParams) =>
+  defHttp.post<Result>({
+    url: Api.getRoleListByParam,
+    params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+export const roleLIstApi = (params) =>
+  defHttp.post<Result>({
+    url: Api.roleList,
+    params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+export const checkUserApi = (params) =>
+  defHttp.post<boolean>({
+    url: Api.checkUser,
+    params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+
+export const saveApi = (params) =>
+  defHttp.post<Result>({
+    url: Api.staffSave,
+    params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+export const updateApi = (params) =>
+  defHttp.post<Result>({
+    url: Api.update,
+    params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });

+ 30 - 0
src/api/staff/model.ts

@@ -0,0 +1,30 @@
+import { BasicPageParams, BasicFetchResult } from '/@/api/model/baseModel';
+/**
+ * @description: Request list interface parameters
+ */
+export type PageParams = BasicPageParams;
+
+export interface DelParams {
+  userId: number;
+  toUserId: number;
+  toUserPhone: string;
+}
+
+export interface roleParams {
+  type: number;
+  roleId: number;
+}
+export interface StaffListItem {
+  id: number;
+
+  name: string;
+  company: string;
+  phone: string;
+  status: string;
+  role: string;
+  createTime: string;
+}
+/**
+ * @description: Request list return value
+ */
+export type ListGetResultModel = BasicFetchResult<StaffListItem>;

+ 112 - 0
src/api/sys/model/systemModel.ts

@@ -0,0 +1,112 @@
+import { type } from 'os';
+import { BasicPageParams, BasicFetchResult } from '/@/api/model/baseModel';
+
+export type AccountParams = BasicPageParams & {
+  account?: string;
+  nickname?: string;
+};
+export type DelAccountParams = {
+  userId: string;
+};
+
+export type RoleParams = {
+  roleName?: string;
+  status?: string;
+};
+
+export type SaveRoleParams = {
+  deptId: string;
+  deptIdList: (number | string)[];
+  deptName: string;
+  menuIdList: number[];
+  roleName: string;
+};
+
+export type RolePageParams = BasicPageParams & RoleParams;
+
+export type CheckUserParams = {
+  phone?: string;
+};
+
+export type deleteRoleParams = {
+  id?: number;
+};
+
+export type DeptParams = {
+  deptName?: string;
+  status?: string;
+};
+export type RoleIdParams = {
+  roleId?: number;
+}
+export type MenuParams = {
+  icon: string;
+  name: string;
+  orderNum: number;
+  parentId: number;
+  parentName: string;
+  perms: string;
+  status: number;
+  type: number;
+  url: string;
+};
+
+export interface AccountListItem {
+  id: string;
+  account: string;
+  email: string;
+  nickname: string;
+  role: number;
+  createTime: string;
+  remark: string;
+  status: number;
+}
+
+export interface DeptListItem {
+  id: string;
+  orderNo: string;
+  createTime: string;
+  remark: string;
+  status: number;
+}
+
+export interface MenuListItem {
+  menuId: string;
+  children?: MenuListItem[];
+  icon: string;
+  name: string;
+  orderNum: number;
+  parentId: number;
+  parentName: string;
+  perms: string;
+  status: number;
+  type: number;
+  url: string;
+}
+
+export interface RoleListItem {
+  id: string;
+  roleName: string;
+  roleType: string;
+  recStatus: string;
+  createUserId: number;
+  roleValue: string;
+  status: number;
+  orderNo: string;
+  createTime: string;
+  description: string;
+  updateTime: string;
+}
+
+/**
+ * @description: Request list return value
+ */
+export type AccountListGetResultModel = BasicFetchResult<AccountListItem>;
+
+export type DeptListGetResultModel = BasicFetchResult<DeptListItem>;
+
+export type MenuListGetResultModel = BasicPageParams<MenuListItem>;
+
+export type RolePageListGetResultModel = BasicFetchResult<RoleListItem>;
+
+export type RoleListGetResultModel = RoleListItem[];

+ 1 - 0
src/api/sys/model/userModel.ts

@@ -33,6 +33,7 @@ export interface GetUserInfoModel {
   userId: string | number;
   // 用户名
   username: string;
+  nickName: string;
   // 真实名字
   realName: string;
   // 头像

+ 126 - 0
src/api/sys/system.ts

@@ -0,0 +1,126 @@
+import {
+  AccountParams,
+  DelAccountParams,
+  DeptListItem,
+  MenuParams,
+  RoleParams,
+  RolePageParams,
+  CheckUserParams,
+  MenuListGetResultModel,
+  DeptListGetResultModel,
+  AccountListGetResultModel,
+  RolePageListGetResultModel,
+  RoleListGetResultModel,
+  SaveRoleParams,
+  RoleIdParams,
+  deleteRoleParams,
+} from './model/systemModel';
+import { Result } from '/#/axios';
+import { defHttp } from '/@/utils/http/axios';
+import { TreeMenuNode } from '/@/utils/treeUtils';
+  // import { ContentTypeEnum } from '/@/enums/httpEnum';
+// sys/user/list
+// /sys/role/list
+// sys/menu/queryAll
+// sys/menu/update
+enum Api {
+  // MenuList = '/newV4/service/manage/sysMenu/getByRoleId',
+  MenuList = '/newV4/service/manage/sysMenu/list',
+  saveMenu = '/newV4/service/manage/sysMenu/add',
+  updateMenu = '/newV4/service/manage/sysMenu/update',
+  deleteMenu = '/zfb-api/zfb/shop/sys/menu/delete',
+  MenuUser = '/zfb-api/zfb/shop/sys/menu/delete',
+  getByRoleId = '/newV4/service/manage/sysMenu/getByRoleId',
+
+  AccountList = '/zfb-api/zfb/shop/sys/user/list',
+  saveAccount = '/zfb-api/zfb/shop/sys/user/save',
+  updateAccount = '/zfb-api/zfb/shop/sys/user/update',
+  IsAccountExist = '/basic-api/system/accountExist',
+  deleteAccountUser = '/zfb-api/zfb/shop/sys/user/preDeleteStaff',
+
+  RolePageList = '/newV4/service/manage/sysRole/list',
+  setRoleStatus = '/basic-api/system/setRoleStatus',
+  saveRole = '/newV4/service/manage/sysRole/add',
+  deleteRole = '/newV4/service/manage/sysRole/delete',
+  updateRole = '/newV4/service/manage/sysRole/update',
+  GetAllRoleList = '/newV4/service/manage/sysRole/allList',
+  roleSelectList = '/zfb-api/zfb/shop/sys/role/select',
+  giveMenu = '/newV4/service/manage/sysRole/giveMenu',
+
+  DeptList = '/zfb-api/zfb/shop/sys/dept/list',
+
+  checkUser = '/zfb-api/zfb/user/checkUserExists',
+}
+
+export const getAccountList = (params: AccountParams) =>
+  defHttp.post<AccountListGetResultModel>({ url: Api.AccountList, params });
+
+export const deleteAccountUserApi = (params: DelAccountParams) =>
+  defHttp.post<AccountListGetResultModel>({ url: Api.deleteAccountUser, params });
+
+export const saveAccountUserApi = (params: AccountParams) =>
+  defHttp.post<AccountListGetResultModel>({ url: Api.saveAccount, params });
+
+export const updateAccountUserApi = (params: AccountParams) =>
+  defHttp.post<AccountListGetResultModel>({ url: Api.updateAccount, params });
+
+//decpored
+
+export const getDeptList = (params?: DeptListItem) =>
+  defHttp.get<DeptListGetResultModel>({ url: Api.DeptList, params });
+
+export const getByRoleId = (params: RoleIdParams) =>
+  defHttp.get<TreeMenuNode>({ url: Api.getByRoleId, params });
+
+export const giveMenu = (params) =>
+  defHttp.post<MenuListGetResultModel>({ url: Api.giveMenu, params });
+
+export const getMenuList = (params?: RoleIdParams) =>
+  defHttp.post<MenuListGetResultModel>({
+    url: Api.MenuList,
+    params: {
+      pageNum:1,
+      pageSize:100,
+    },
+  });
+//menu
+export const saveMenuApi = (params?: MenuParams) =>
+  defHttp.post<MenuListGetResultModel>({ url: Api.saveMenu, params });
+
+export const updateMenuApi = (params?: MenuParams) =>
+  defHttp.post<MenuListGetResultModel>({ url: Api.updateMenu, params });
+
+export const deleteMenuApi = (params?: (string | number)[]) =>
+  defHttp.post<MenuListGetResultModel>({ url: Api.deleteMenu, params });
+
+//roles
+export const getRoleListByPage = (params?: RolePageParams) =>
+  defHttp.post<RolePageListGetResultModel>({ url: Api.RolePageList, params });
+
+export const getAllRoleList = (params?: RoleParams) =>
+  defHttp.post<RoleListGetResultModel>({ url: Api.GetAllRoleList, params });
+
+export const roleSelectListApi = (params?: RoleParams) =>
+  defHttp.post<RoleListGetResultModel>({ url: Api.roleSelectList, params });
+
+export const setRoleStatus = (id: number, status: string) =>
+  defHttp.post({ url: Api.setRoleStatus, params: { id, status } });
+
+export const saveRoleApi = (params: SaveRoleParams) =>
+  //TODO 临时加deptId调试
+  defHttp.post({ url: Api.saveRole, params: params });
+//TODO 临时d加eptId调试
+export const updateRoleApi = (params: SaveRoleParams) =>
+  defHttp.post({ url: Api.updateRole, params: params });
+
+export const deleteRoleApi = (params: deleteRoleParams) =>
+  defHttp.post({ url: Api.deleteRole, params: params });
+
+export const isAccountExist = (account: string) =>
+  defHttp.post({ url: Api.IsAccountExist, params: { account } }, { errorMessageMode: 'none' });
+
+export const deptListApi = (params?: RolePageParams) =>
+  defHttp.post<RolePageListGetResultModel>({ url: Api.DeptList, params });
+
+export const checkUserApi = (params?: CheckUserParams) =>
+  defHttp.post<Result>({ url: Api.checkUser, params });

+ 2 - 0
src/locales/lang/zh-CN/layout.ts

@@ -45,6 +45,8 @@ export default {
     menuTypeMixSidebar: '左侧菜单混合模式',
     menuTypeMix: '顶部菜单混合模式',
     menuTypeTopMenu: '顶部菜单模式',
+    menuDistribution: '菜单分配',
+    setRoles: '修改权限',
 
     on: '开',
     off: '关',

+ 2 - 0
src/locales/lang/zh-CN/routes/dashboard.ts

@@ -5,6 +5,8 @@ export default {
   analysis: '分析页',
   corporation: '企业管理',
   operate: '官网运营管理',
+  system: '系统管理',
+  systemUser: '账号管理',
   operateNews: '新闻管理',
   operateRecruit: '招聘管理',
   operateMessage: '留言管理',

+ 17 - 0
src/locales/lang/zh-CN/routes/staff.ts

@@ -0,0 +1,17 @@
+export default {
+  deptName: '所属公司',
+  userName: '员工名称',
+  nickName: '员工昵称',
+  setpaswd: '修改密码',
+  mobile: '手机',
+  permList: '权益',
+  createTime: '创建时间',
+  updateTime: '修改时间',
+  staffList: '员工列表',
+  updateBtn: '修改密码',
+  password: '修改密码',
+  roleType: {
+    0: '公司管理员',
+    1: '公司员工',
+  },
+};

+ 73 - 0
src/locales/lang/zh-CN/routes/system.ts

@@ -0,0 +1,73 @@
+const account = {
+  roleBut:'权限',
+  userName: '用户名',
+  accountList: '账户列表',
+  addHost: '新增主持人',
+  edit: '编辑用户资料',
+  delText: '删除此账号',
+  departmentList: '部门列表',
+  departmentName: '部门名称',
+  addDepartment: '新增部门',
+  editDepartment: '编辑部门',
+  addUser: '新增账号',
+  editUser: '编辑账号',
+  parentDept: '上级部门',
+  infoData: {
+    title: '用户{userId}的资料',
+    content: '这是用户资料详情页面。本页面仅用于演示相同路由在tab中打开多个页面并且显示不同的数据',
+  },
+  disable: '禁用账号',
+  set: '修改密码',
+  userProfile: '用户资料',
+  log: '操作日志',
+  userinfo: '这是用户{userId}资料Tab',
+  userlog: '这是用户{userId}操作日志Tab',
+  setTitle: '详情:用户',
+  enable: '启用',
+  stopUsing: '停用',
+  description:  '角色说明',
+  remarks: '备注',
+  newMenu: '新增菜单',
+  editMenu: '编辑菜单',
+  menuList: '菜单列表',
+  menuType: '菜单类型',
+  menuName: '菜单名称',
+  menuName1: '请输入菜单名称',
+  menuName2: '请输入正确的菜单名称',
+  menuPath: '菜单路径',
+  routerPath: '菜单路径',
+  menuUrl: '外链地址',
+  menuParentName: '上级菜单',
+  component: '组件路径',
+  icon: '图标',
+  perms: '权限标识',
+  passwordOld: '当前密码',
+  passwordNew: '新密码',
+  passwordNew1: '请输入新密码',
+  confirmPassword: '确认密码',
+  confirmPassword1: '不能为空',
+  confirmPassword2: '两次输入的密码不一致!',
+  isExt: {
+    title: '是否外链',
+    1: '是',
+    0: '否',
+    url: '',
+  },
+  type: {
+    title: '类型',
+    0: '目录',
+    1: '菜单',
+    2: '按钮',
+    3: '按钮',
+  },
+  roleTitle: '角色列表',
+  isPlatformRole: '是否启用',
+  sortOrder: '排序',
+  status: '状态',
+  isShow: '是否显示',
+};
+
+export default {
+  ...account,
+  buttonMenuWaring: '上级菜单只能为菜单类型',
+};

+ 11 - 11
src/router/routes/modules/account.ts

@@ -16,22 +16,22 @@ export const accountRoute: AppRouteRecordRaw = {
     {
       path: 'user',
       name: 'User',
-      component: () => import('/@/views/account/index.vue'),
+      component: () => import('/@/views/staff/list.vue'),
       meta: {
         title: t('routes.dashboard.account'),
         hideChildrenInMenu: true,
       },
     },
-    {
-      path: 'details',
-      name: 'Details',
-      component: () => import('/@/views/account/details/index.vue'),
-      meta: {
-        title: t('routes.dashboard.details'),
-        hideChildrenInMenu: true,
-        hideMenu: true,
-      },
-    },
+    // {
+    //   path: 'details',
+    //   name: 'Details',
+    //   component: () => import('/@/views/account/details/index.vue'),
+    //   meta: {
+    //     title: t('routes.dashboard.details'),
+    //     hideChildrenInMenu: true,
+    //     hideMenu: true,
+    //   },
+    // },
     // {
     //   path: 'overview',
     //   name: 'Overview',

+ 38 - 0
src/router/routes/modules/staff.ts

@@ -0,0 +1,38 @@
+import type { AppRouteModule } from '/@/router/types';
+
+import { LAYOUT } from '/@/router/constant';
+import { t } from '/@/hooks/web/useI18n';
+
+const staff: AppRouteModule = {
+  path: '/staff',
+  name: 'Staff',
+  component: LAYOUT,
+  redirect: '/staff/list',
+  meta: {
+    icon: 'medical-icon:care-staff-area',
+    title: t('routes.dashboard.staff'),
+    orderNo: 102,
+  },
+  children: [
+    {
+      path: 'list',
+      name: 'StaffList',
+      component: () => import('/@/views/staff/list.vue'),
+      meta: {
+        title: t('routes.dashboard.staffList'),
+        icon: 'ic:outline-remember-me',
+      },
+    },
+    {
+      path: 'clean',
+      name: 'StaffClean',
+      component: () => import('/@/views/staff/clean.vue'),
+      meta: {
+        title: t('routes.dashboard.staffClean'),
+        icon: 'ic:outline-remember-me',
+      },
+    },
+  ],
+};
+
+export default staff;

+ 48 - 0
src/router/routes/modules/user.ts

@@ -0,0 +1,48 @@
+import type { AppRouteModule } from '/@/router/types';
+
+import { LAYOUT } from '/@/router/constant';
+import { t } from '/@/hooks/web/useI18n';
+
+const order: AppRouteModule = {
+  path: '/system',
+  name: 'System',
+  component: LAYOUT,
+  redirect: '/system/user',
+  meta: {
+    icon: 'carbon:cics-system-group',
+    title: t('routes.dashboard.system'),
+    orderNo: 200,
+  },
+  children: [
+    {
+      path: 'user',
+      name: 'User',
+      component: () => import('/@/views/staff/list.vue'),
+      meta: {
+        title: t('routes.dashboard.systemUser'),
+        icon: 'carbon:user-multiple',
+        hideChildrenInMenu: true,
+      },
+    },{
+      path: 'role',
+      name: 'RoleManagement',
+      meta: {
+        title: t('routes.demo.system.role'),
+        icon: 'carbon:user-role',
+        ignoreKeepAlive: true,
+      },
+      component: () => import('/@/views/system/role/index.vue'),
+    },{
+      path: 'menu',
+      name: 'MenuManagement',
+      meta: {
+        title: t('routes.demo.system.menu'),
+        icon: 'ant-design:menu-unfold-outlined',
+        ignoreKeepAlive: true,
+      },
+      component: () => import('/@/views/system/menu/index.vue'),
+    },
+  ],
+};
+
+export default order;

+ 83 - 0
src/utils/treeUtils.ts

@@ -0,0 +1,83 @@
+// import type { AppRouteRecordRaw } from '/@/router/types';
+
+export interface TreeNode {
+  id: number;
+  parentId: number;
+  name: string;
+  key?: string;
+  level?: string;
+  children?: TreeNode[];
+}
+export interface TreeMenuNode {
+  menuId: number;
+  parentId: number;
+  name: string;
+  type?: number;
+  id: number;
+  children?: TreeMenuNode[];
+}
+
+// function traverse(tree: TreeMenuNode[], rootId: number) {
+//   tree.forEach((item) => {
+//     if (item.parentId == rootId) {
+//       console.log('name', item.name);
+//       console.log('menuId', item.menuId);
+//       console.log('rootId', rootId);
+//       // temp.push(item.parentId);
+//       // item.key = temp;
+//     }
+//     if (item.children?.length) {
+//       traverse(item.children, item.menuId);
+//     }
+//   });
+// }
+
+export function makeTree(treeNodes: TreeNode[]): TreeNode[] {
+  // 提前生成节点查找表。
+  // 如果明确节点是顺序可以保证先父后子,可以省去这次遍历,在后面边遍历过程中填充查找表
+  const nodesMap = new Map<number, TreeNode>(treeNodes.map((node) => [node.id, node]));
+
+  // 引入虚拟根节点来统一实现 parent 始终有效,避免空判断
+  const virtualRoot = {} as Partial<TreeNode>;
+  treeNodes.forEach((node) => {
+    const parent = nodesMap.get(node.parentId) ?? virtualRoot;
+    (parent.children ??= []).push(node);
+  });
+  // if (virtualRoot.children?.length) {
+  //   traverse(virtualRoot.children, virtualRoot.children[0].id);
+  // }
+
+  return virtualRoot.children ?? [];
+}
+
+export function getTreeId(treeNodes: TreeMenuNode[]): number[] {
+  // 提前生成节点查找表。
+  // 如果明确节点是顺序可以保证先父后子,可以省去这次遍历,在后面边遍历过程中填充查找表
+  // const nodesMap = new Map<number, TreeNode>(treeNodes.map((node) => [node.id, node]));
+  // 引入虚拟根节点来统一实现 parent 始终有效,避免空判断
+  let TreeIdList:number[] =  []
+  function getTreeIdList(list:TreeMenuNode[]) {
+    return list.map(ele => {
+      TreeIdList.push(ele.id)
+      if(ele.children){
+        getTreeIdList(ele.children)
+      }
+    })
+  }
+  getTreeIdList(treeNodes)
+  console.log('TreeIdList',TreeIdList,treeNodes)
+  return TreeIdList ?? [];
+}
+
+export function makeMenuTree(treeNodes: TreeMenuNode[]): TreeMenuNode[] {
+  console.log('makeMenuTree',treeNodes)
+  const nodesMap = new Map<number, TreeMenuNode>(treeNodes.map((node) => [node.menuId, node]));
+
+  // 引入虚拟根节点来统一实现 parent 始终有效,避免空判断
+  const virtualRoot = {} as Partial<TreeMenuNode>;
+  treeNodes.forEach((node) => {
+    const parent = nodesMap.get(node.parentId) ?? virtualRoot;
+    (parent.children ??= []).push(node);
+  });
+  return virtualRoot.children ?? [];
+}

+ 5 - 0
src/views/staff/category.vue

@@ -0,0 +1,5 @@
+<template>
+  <div> 设备管理 </div>
+</template>
+
+<script lang="ts" setup></script>

+ 78 - 0
src/views/staff/clean.vue

@@ -0,0 +1,78 @@
+<template>
+  <div class="p-4">
+    <BasicForm @register="register" @submit="handleSubmit" />
+  </div>
+</template>
+<script lang="ts">
+  import { defineComponent } from 'vue';
+  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { clean } from '/@/api/staff/list';
+  // import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
+  export default defineComponent({
+    components: {
+      BasicForm,
+    },
+    setup() {
+      const { t } = useI18n();
+      const { createMessage } = useMessage();
+      const schemas: FormSchema[] = [
+        {
+          field: 'userName',
+          component: 'Input',
+          label: '手机号',
+          colProps: {
+            span: 8,
+          },
+          componentProps: {
+            // type:"number"
+          },
+          rules: [
+            {
+              required: true,
+              // @ts-ignore
+              validator: async (rule, value) => {
+                var reg_tel =
+                  /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/;
+                // var reg = /\S+@\S+\.\S+/;
+                if (!value) {
+                  /* eslint-disable-next-line */
+
+                  return Promise.reject(t('common.phone'));
+                }
+                if (!reg_tel.test(value)) {
+                  /* eslint-disable-next-line */
+                  return Promise.reject(t('common.phoneError'));
+                }
+                return Promise.resolve();
+              },
+              trigger: 'change',
+            },
+          ],
+        },
+      ];
+      const [register, { setProps, validate, resetFields }] = useForm({
+        labelWidth: 120,
+        schemas,
+        actionColOptions: {
+          span: 4,
+        },
+        submitButtonOptions: {
+          text: '清除状态',
+        },
+      });
+      async function handleSubmit() {
+        let data = await validate();
+        await clean({ userName: data.userName }); //
+        createMessage.success(t('common.optSuccess'));
+        setTimeout(() => resetFields(), 500);
+      }
+      return {
+        handleSubmit,
+        setProps,
+        register,
+      };
+    },
+  });
+</script>

+ 124 - 0
src/views/staff/delListModal.vue

@@ -0,0 +1,124 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @cancel="resetFields"
+    @register="register"
+    title="删除员工"
+    @ok="handleOk"
+  >
+    <div class="pt-3px pr-3px">
+      <BasicForm @register="registerForm">
+        <template #tips>
+          <div>请将员工的数据迁移后,再删除员工(删除员工后,权益将进行解绑)</div>
+        </template>
+      </BasicForm>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { defineComponent, ref, unref } from 'vue';
+  import { delApi } from '/@/api/staff/list';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  const { t } = useI18n();
+
+  export default defineComponent({
+    components: { BasicModal, BasicForm },
+    props: {
+      userData: { type: Object },
+    },
+    emits: ['reload'],
+    setup(_, context) {
+      const modelRef = ref({
+        toUserId: 0,
+        userId: 0,
+      });
+      const options = ref([]);
+      const { createMessage } = useMessage();
+      const schemas: FormSchema[] = [
+        {
+          field: 'toUserPhone',
+          component: 'Select',
+          label: '选择迁移的员工',
+          required: true,
+          itemProps: {
+            validateTrigger: 'blur',
+          },
+          colProps: {
+            span: 22,
+          },
+          componentProps: {
+            options: options.value,
+          },
+        },
+        {
+          field: 'tips',
+          component: 'Select',
+          slot: 'tips',
+          label: ' ',
+        },
+      ];
+      const [registerForm, { validate, resetFields, updateSchema }] = useForm({
+        labelWidth: 120,
+        schemas,
+        showActionButtonGroup: false,
+        actionColOptions: {
+          span: 24,
+        },
+      });
+
+      const [register, { closeModal }] = useModalInner((data) => {
+        data && onDataReceive(data);
+      });
+      function onDataReceive(data) {
+        data = unref(data);
+        modelRef.value.userId = data.id;
+        console.log('onDataReceive', data);
+        // 方式1;
+        if (data.option) {
+          options.value = data.option.map((ele) => {
+            ele.label = ele.nickName;
+            ele.value = ele.phone;
+            return ele;
+          });
+          updateSchema({
+            field: 'toUserPhone',
+            component: 'Select',
+            label: '选择迁移的员工',
+            required: true,
+            itemProps: {
+              validateTrigger: 'blur',
+            },
+            colProps: {
+              span: 22,
+            },
+            componentProps: {
+              options: data.option,
+              onChange: function (value, item) {
+                modelRef.value.toUserId = item.id;
+                console.log('onChange', value, item);
+              },
+            },
+          });
+        }
+      }
+
+      async function handleOk() {
+        let data = await validate();
+        let res = await delApi({
+          toUserPhone: data.toUserPhone,
+          userId: modelRef.value.userId,
+          toUserId: modelRef.value.toUserId,
+        });
+        context && context.emit('reload', res);
+        createMessage.success(t('common.optSuccess'));
+        closeModal();
+        resetFields();
+      }
+
+      return { options, register, registerForm, model: modelRef, handleOk, resetFields };
+    },
+  });
+</script>

+ 300 - 0
src/views/staff/detailsModal.vue

@@ -0,0 +1,300 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @cancel="resetFields"
+    @register="register"
+    :title="title"
+    @ok="handleOk"
+  >
+    <div class="pt-3px pr-3px">
+      <BasicForm @register="registerForm" :model="modelRef" />
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { defineComponent, ref, computed } from 'vue';
+  import { checkUserApi, saveApi, updateApi, getRoleListByParam } from '/@/api/staff/list'; //roleLIstApi
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { useUserStore } from '/@/store/modules/user';
+  const { t } = useI18n();
+  export default defineComponent({
+    components: { BasicModal, BasicForm },
+    props: {
+      userData: { type: Object },
+    },
+    emits: ['ok'],
+    setup(_, context) {
+      const modelRef = ref({});
+      const userStore = useUserStore();
+      const userinfo = computed(() => userStore.getUserInfo);
+      const { companyId } = userinfo.value;
+      console.log('companyId', companyId);
+      const permListOptions = computed(() => {
+        return [
+          {
+            label: '带看',
+            value: '1',
+          },
+          {
+            label: '拍摄',
+            value: '2',
+          },
+        ];
+      });
+      const schemas: FormSchema[] = [
+        {
+          field: 'phone',
+          component: 'Input',
+          label: '手机号',
+          colProps: {
+            span: 18,
+          },
+          // helpMessage: '手机号需在指房宝APP注册后才可新增',
+          required: false,
+          rules: [
+            {
+              required: true,
+              // @ts-ignore
+              validator: async (rule, value) => {
+                var reg_tel =
+                  /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/;
+                // var reg = /\S+@\S+\.\S+/;
+                if (!value) {
+                  return Promise.reject(t('common.phone'));
+                }
+                if (!reg_tel.test(value)) {
+                  /* eslint-disable-next-line */
+                  return Promise.reject(t('common.phoneError'));
+                }
+                try {
+                  if (title.value == '编辑') {
+                    return Promise.resolve();
+                  }
+                  let res = await checkUserApi({ phone: value });
+                  console.log('res', res, 'title', title.value);
+                  if (res == true) {
+                    return Promise.resolve();
+                  } else {
+                    return Promise.reject('手机号未在指房宝APP中进行注册');
+                  }
+                } catch (err) {
+                  return Promise.reject(err);
+                }
+              },
+              trigger: 'change',
+            },
+          ],
+        },
+        {
+          field: 'nickName',
+          component: 'Input',
+          label: '员工名称',
+          colProps: {
+            span: 22,
+          },
+          componentProps: {
+            maxLength: 15,
+          },
+          rules: [
+            {
+              required: true,
+              // @ts-ignore
+              validator: async (rule, value) => {
+                var reg_tel = /^[a-zA-Z\u4e00-\u9fa5]+$/;
+                // var reg = /\S+@\S+\.\S+/;
+                if (!value) {
+                  return Promise.reject('请输入员工名称');
+                }
+                if (!reg_tel.test(value)) {
+                  /* eslint-disable-next-line */
+                  return Promise.reject('请输入正确的员工名称');
+                }
+                return Promise.resolve();
+              },
+              trigger: 'change',
+            },
+          ],
+        },
+        // {
+        //   field: 'companyId',
+        //   label: '公司',
+        //   component: 'ApiSelect',
+        //   itemProps: {
+        //     validateTrigger: 'blur',
+        //   },
+        //   colProps: {
+        //     span: 22,
+        //   },
+        //   required: true,
+        //   ifShow: getCheckRole('plat_admin'),
+        //   componentProps: {
+        //     api: ListAllCompanyApi,
+        //     showSearch: true,
+        //     resultField: 'list',
+        //     labelField: 'name',
+        //     valueField: 'id',
+        //     immediate: true,
+        //     params: {
+        //       page: 1,
+        //       limit: 1000,
+        //     },
+        //     required: true,
+        //     onChange: companyIdChange,
+        //   },
+        // },
+        {
+          field: 'roleId',
+          component: 'ApiSelect',
+          label: '角色',
+          required: true,
+          itemProps: {
+            validateTrigger: 'blur',
+          },
+          colProps: {
+            span: 22,
+          },
+          defaultValue: 8,
+          componentProps: {
+            options: [
+              {
+                label: '公司员工',
+                value: 8,
+                key: 8,
+              },
+            ],
+          },
+        },
+        // {
+        //   field: 'status',
+        //   label: '状态',
+        //   component: 'RadioButtonGroup',
+        //   required: true,
+        //   defaultValue: 1,
+        //   itemProps: {
+        //     validateTrigger: 'blur',
+        //   },
+        //   componentProps: {
+        //     options: [
+        //       { label: '是', value: 1 },
+        //       { label: '否', value: 0 },
+        //     ],
+        //   },
+        // },
+        {
+          field: 'id',
+          component: 'Input',
+          label: 'id',
+          show: false,
+        },
+      ];
+      const title = ref('新 增');
+      const { createMessage } = useMessage();
+      const [registerForm, { setFieldsValue, validate, updateSchema, resetFields }] = useForm({
+        labelWidth: 120,
+        schemas,
+        showActionButtonGroup: false,
+        actionColOptions: {
+          span: 24,
+        },
+      });
+
+      const [register, { closeModal }] = useModalInner((data) => {
+        data && onDataReceive(data);
+      });
+      function onDataReceive(data) {
+        // 方式1;
+        console.log('useModalInner', data);
+        setFieldsValue({
+          ...data,
+          roleId: data.roleId != 2 ? data.roleId : '',
+        });
+        let setSchema = [
+          {
+            field: 'roleId',
+            component: 'ApiSelect',
+            componentProps: {
+              disabled: data.roleId == 2 ? false : data.id ? true : false,
+              api: getRoleListByParam,
+              labelField: 'roleName',
+              valueField: 'roleId',
+              params: {
+                type: data.roleId ? 1 : 0,
+                roleId: data.roleId,
+              },
+            },
+          },
+          {
+            field: 'phone',
+            componentProps: {
+              // disabled: getCheckRole('plat_admin') ? false : data.id ? true : false,
+            },
+          },
+          {
+            field: 'companyId',
+            componentProps: {
+              disabled: data.id ? (data.roleId != 2 ? true : false) : false,
+            },
+          },
+          {
+            field: 'permList',
+            componentProps: {
+              disabled: data.roleId == 2 ? false : data.id ? true : false,
+              params: {
+                companyId: data.companyId || companyId,
+              },
+            },
+          },
+        ];
+        title.value = data.id ? '编辑' : '新增';
+        updateSchema(setSchema);
+      }
+      function companyIdChange(companyId) {
+        // resetFields(['permList'])
+        updateSchema([
+          {
+            field: 'permList',
+            componentProps: {
+              params: {
+                companyId: companyId,
+              },
+            },
+          },
+        ]);
+        setFieldsValue({
+          permList: [],
+        });
+      }
+      async function handleOk() {
+        let data = await validate();
+        const requestApi = data.id ? updateApi : saveApi;
+        let res = await requestApi({
+          ...data,
+          userName: data.phone,
+          phone: data.phone,
+          nickName: data.nickName,
+          roleId: data.roleId,
+          id: data.id,
+        });
+        console.log('res', res);
+        context && context.emit('ok', res);
+        createMessage.success(t('common.optSuccess'));
+        closeModal();
+        resetFields();
+      }
+
+      return {
+        register,
+        title,
+        schemas,
+        registerForm,
+        modelRef,
+        handleOk,
+        resetFields,
+        permListOptions,
+      };
+    },
+  });
+</script>

+ 299 - 0
src/views/staff/list.vue

@@ -0,0 +1,299 @@
+<template>
+  <div class="p-4">
+    <BasicTable @register="registerTable">
+      <template #toolbar>
+        <a-button
+          type="primary"
+          @click="handleCreate"
+          >新增</a-button
+        >
+      </template>
+      <template #role="{ record }">
+        {{ renderRoleType(record.role) }}
+      </template>
+      <template #status="{ record }">
+        {{ renderStatus(record.status) }}
+      </template>
+      <template #createTime="{ record }">
+        <Time :value="record.createTime" mode="datetime" />
+      </template>
+      <!-- , -->
+      <template #action="{ record }">
+        <TableAction
+          :actions="[
+            {
+              label: '编辑',
+              onClick: handleEdit.bind(null, record),
+            },
+            {
+              color: 'warning',
+              label: t('routes.staff.setpaswd'),
+              onClick: handleOpenModal.bind(null, record),
+            },
+            {
+              label: '删除',
+              color: 'error',
+              popConfirm: {
+                title: '是否确认删除',
+                confirm: handleDelete.bind(null, record),
+              },
+            },
+          ]"
+        />
+      </template>
+    </BasicTable>
+    <DetailsModal @register="registerDetail" @ok="reload" />
+    <SetpaswordModal @register="register" @reload="reload" />
+    <!--<DelListModal @register="registerDelList" @reload="reload" /> -->
+  </div>
+</template>
+<script lang="ts">
+  import { defineComponent, computed, onMounted, ref } from 'vue';
+  import { BasicTable, useTable, BasicColumn, FormProps, TableAction } from '/@/components/Table';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { useModal } from '/@/components/Modal';
+  import { uploadApi } from '/@/api/sys/upload';
+  import SetpaswordModal from './setpaswordModal.vue';
+  import DetailsModal from './detailsModal.vue';
+  // import DelListModal from './delListModal.vue';
+  import { Alert } from 'ant-design-vue';
+  // import { h } from 'vue';
+  import { ListApi, delApi, preDelApi, getNumByStaff } from '/@/api/staff/list';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  // import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
+  import { RoleEnum } from '/@/enums/roleEnum';
+  import { useGo } from '/@/hooks/web/usePage';
+  import { Time } from '/@/components/Time';
+  import { useUserStore } from '/@/store/modules/user';
+  export default defineComponent({
+    components: {
+      BasicTable,
+      TableAction,
+      Time,
+      SetpaswordModal,
+      DetailsModal,
+      // DelListModal,
+      Alert,
+    },
+    setup() {
+      const [register, { openModal }] = useModal();
+      const surplusSubNum = ref({
+        lookNum: 0,
+        shotNum: 0,
+      });
+      const [registerDetail, { openModal: openDetaileModal }] = useModal();
+      const [registerDelList, { openModal: openDelListeModal }] = useModal();
+      const { createConfirm, createMessage } = useMessage();
+      const userStore = useUserStore();
+      // const { getCheckRole } = userStore;
+      const roleList = computed(() => userStore.getRoleList);
+      console.log('getRoleList', roleList);
+      const go = useGo();
+      const { t } = useI18n();
+      onMounted(() => {
+        // getNumByStaffData();
+      });
+
+      const columns: BasicColumn[] = [
+        {
+          title: 'ID',
+          dataIndex: 'id',
+          fixed: 'left',
+          width: 60,
+        },
+        // {
+        //   title: t('routes.staff.deptName'),
+        //   dataIndex: 'companyName',
+        //   width: 160,
+        // },
+        // {
+        //   title: t('routes.staff.userName'),
+        //   dataIndex: 'userName',
+        //   width: 80,
+        // },
+        {
+          title: t('routes.staff.userName'),
+          dataIndex: 'nickName',
+          width: 160,
+        },
+        // {
+        //   title: '手机',
+        //   dataIndex: 'phone',
+        //   width: 160,
+        // },
+        {
+          title: t('common.roleName'),
+          dataIndex: 'roleName',
+          width: 80,
+        },
+
+        {
+          title: '创建人',
+          dataIndex: 'createUserName',
+          width: 80,
+        },
+
+        {
+          title: t('routes.staff.createTime'),
+          dataIndex: 'createTime',
+          slots: { customRender: 'createTime' },
+          width: 130,
+        },
+        {
+          title: '操作',
+          dataIndex: '',
+          // ifShow: !getCheckRole('tourist'),
+          slots: { customRender: 'action' },
+          fixed: 'right',
+          width: 100,
+        },
+      ];
+
+      const searchForm: Partial<FormProps> = {
+        labelWidth: 100,
+        schemas: [
+          {
+            field: 'staffName',
+            label: t('routes.staff.userName'),
+            component: 'Input',
+            componentProps: {
+              maxLength: 15,
+            },
+            colProps: {
+              xl: 6,
+              xxl: 6,
+            },
+          },
+          {
+            field: 'staffPhone',
+            label: t('common.mobile'),
+            component: 'Input',
+            componentProps: {
+              maxLength: 15,
+            },
+            colProps: {
+              xl: 6,
+              xxl: 6,
+            },
+          },
+        ],
+      };
+
+      const [registerTable, { reload }] = useTable({
+        title: t('routes.staff.staffList'),
+        api: ListApi,
+        columns: columns,
+        useSearchForm: true,
+        formConfig: searchForm,
+        showTableSetting: true,
+        tableSetting: { fullScreen: true },
+        showIndexColumn: false,
+        rowKey: 'id',
+        fetchSetting: {
+          pageField: 'pageNum',
+          sizeField: 'pageSize',
+          listField: 'list',
+          totalField: 'total',
+        },
+        pagination: { pageSize: 20 },
+        afterFetch: (T) => {
+          return T;
+        },
+        bordered: true,
+        sortFn: (sortInfo) => {
+          let order = sortInfo.order && sortInfo.order.replace('end', '');
+          return { ...sortInfo, sidx: sortInfo.field, order: order };
+        },
+      });
+
+      function renderRoleType(type: number): string {
+        switch (type) {
+          case 0:
+            return t('routes.staff.roleType.0');
+          case 1:
+            return t('routes.staff.roleType.1');
+          default:
+            return '';
+        }
+      }
+      function renderStatus(type: number): string {
+        switch (type) {
+          case 1:
+            return t('common.normal');
+          case 0:
+            return t('common.unNormal');
+          default:
+            return '';
+        }
+      }
+      function handleOpenModal(record: Recordable) {
+        openModal(true, record);
+      }
+      function handleCreate() {
+        // if (
+        //   getCheckRole([RoleEnum.COMPANY_ADMIN]) &&
+        //   surplusSubNum.value.lookNum == 0 &&
+        //   surplusSubNum.value.shotNum == 0
+        // ) {
+        //   return createMessage.error('新增失败,可添加员工数量为0个');
+        // }
+        openDetaileModal(true, {});
+      }
+      function handleEdit(record: Recordable) {
+        openDetaileModal(true, record);
+      }
+      function getNumByStaffData() {
+        getNumByStaff({}).then((res) => {
+          surplusSubNum.value.lookNum = res.lookNum;
+          surplusSubNum.value.shotNum = res.shotNum;
+        });
+      }
+      async function handleDelete(record) {
+        let check = await preDelApi(record.id); //
+        if (Array.isArray(check)) {
+          return openDelListeModal(true, {
+            ...record,
+            option: check,
+          });
+        }
+        createMessage.success(t('common.optSuccess'));
+        reload();
+        // handDelconfirm(record);
+      }
+      function handDelconfirm(record) {
+        createConfirm({
+          iconType: 'warning',
+          title: '警告',
+          content: `此操作将对${record.userName}进行删除, 是否继续?`,
+          onOk: async () => {
+            await delApi({ userId: record.id });
+            reload();
+          },
+        });
+      }
+      return {
+        registerTable,
+        registerDetail,
+        registerDelList,
+        openDelListeModal,
+        createMessage,
+        handDelconfirm,
+        t,
+        reload,
+        go,
+        renderRoleType,
+        renderStatus,
+        handleCreate,
+        handleOpenModal,
+        register,
+        handleEdit,
+        handleDelete,
+        uploadApi: uploadApi as any,
+        RoleEnum,
+        surplusSubNum,
+        // getCheckRole,
+        getNumByStaffData,
+      };
+    },
+  });
+</script>

+ 98 - 0
src/views/staff/setpaswordModal.vue

@@ -0,0 +1,98 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    @ok="handSubmit"
+    :title="t('routes.staff.updateBtn')"
+    @visible-change="handleVisibleChange"
+    @cancel="resetFields"
+  >
+    <div class="pt-3px pr-3px">
+      <BasicForm @register="registerForm" />
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { encodeStr } from '/@/utils/encodeUtil';
+  import { defineComponent, nextTick } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
+  import { updatePasswordApi } from '/@/api/staff/list';
+  import { useMessage } from '/@/hooks/web/useMessage';
+
+  const { createMessage } = useMessage();
+
+  export default defineComponent({
+    components: { BasicModal, BasicForm },
+    props: {
+      userData: { type: Object },
+    },
+    setup(props) {
+      const { t } = useI18n();
+      const schemas: FormSchema[] = [
+        {
+          field: 'id',
+          component: 'Input',
+          label: 'id',
+          show: false,
+        },
+        {
+          field: 'password',
+          component: 'StrengthMeter',
+          label: t('routes.staff.password'),
+          labelWidth: 120,
+          required: true,
+          colProps: { span: 18 },
+        },
+      ];
+
+      const [
+        registerForm,
+        {
+          setFieldsValue,
+          validate,
+          resetFields,
+          // setProps
+        },
+      ] = useForm({
+        labelWidth: 120,
+        schemas,
+        showActionButtonGroup: false,
+        actionColOptions: {
+          span: 24,
+        },
+      });
+
+      const [register, { closeModal }] = useModalInner((data) => {
+        data && onDataReceive(data);
+      });
+
+      function onDataReceive(data) {
+        setFieldsValue({
+          id: data.id,
+        });
+      }
+      async function handSubmit() {
+        const { id, password } = await validate();
+        await updatePasswordApi({ id, newPassword: encodeStr(window.btoa(password)) });
+        createMessage.success(t('common.optSuccess'));
+        resetFields();
+        closeModal();
+      }
+      function handleVisibleChange(v) {
+        v && props.userData && nextTick(() => onDataReceive(props.userData));
+      }
+
+      return {
+        handSubmit,
+        register,
+        t,
+        schemas,
+        registerForm,
+        handleVisibleChange,
+        resetFields,
+      };
+    },
+  });
+</script>

+ 5 - 0
src/views/staff/sorts.vue

@@ -0,0 +1,5 @@
+<template>
+  <div> 设备管理 </div>
+</template>
+
+<script lang="ts" setup></script>

+ 2 - 1
src/views/sys/login/LoginForm.vue

@@ -139,10 +139,11 @@
         username: data.account,
         mode: 'none', //不要默认的错误提示
       });
+      console.log('userInfo',userInfo)
       if (userInfo) {
         notification.success({
           message: t('sys.login.loginSuccessTitle'),
-          description: `${t('sys.login.loginSuccessDesc')}: ${userInfo.realName}`,
+          description: `${t('sys.login.loginSuccessDesc')}: ${userInfo.nickName}`,
           duration: 3,
         });
       }

+ 106 - 0
src/views/system/menu/MenuDrawer.vue

@@ -0,0 +1,106 @@
+<template>
+  <BasicDrawer
+    v-bind="$attrs"
+    @register="registerDrawer"
+    showFooter
+    :showDetailBack="false"
+    :title="getTitle"
+    width="50%"
+    @ok="handleSubmit"
+  >
+    <BasicForm @register="registerForm" />
+  </BasicDrawer>
+</template>
+<script lang="ts">
+  import { defineComponent, ref, computed, unref } from 'vue';
+  import { BasicForm, useForm } from '/@/components/Form/index';
+  import { formSchema } from './menu.data';
+  import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
+
+  import { getMenuList, saveMenuApi, updateMenuApi } from '/@/api/sys/system';
+  import { makeMenuTree, TreeMenuNode } from '/@/utils/treeUtils';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  
+  interface getMenuListInterf {
+    list:TreeMenuNode[]
+  }
+  export default defineComponent({
+    name: 'MenuDrawer',
+    components: { BasicDrawer, BasicForm },
+    emits: ['success', 'register'],
+    setup(_, { emit }) {
+      const isUpdate = ref(true);
+      const tData = ref<TreeMenuNode[]>([]);
+      const menuId = ref(0);
+
+      const [registerForm, { resetFields, setFieldsValue, updateSchema, validate }] = useForm({
+        labelWidth: 100,
+        schemas: formSchema,
+        showActionButtonGroup: false,
+        baseColProps: { lg: 12, md: 24 },
+      });
+
+      const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
+        resetFields();
+        setDrawerProps({ confirmLoading: false });
+        isUpdate.value = !!data?.isUpdate;
+
+        if (unref(isUpdate)) {
+          console.log('data.record', data.record.menuId);
+          menuId.value = data.record.menuId;
+          setFieldsValue({
+            ...data.record,
+          });
+        }
+        const treeData = (await getMenuList({roleId:1})) as any as getMenuListInterf;
+        console.log('treeData',treeData)
+        tData.value = makeMenuTree(treeData.list);
+
+        updateSchema({
+          field: 'parentId',
+          componentProps: {
+            treeData:treeData.list,
+          },
+        });
+      });
+
+      const getTitle = computed(() =>
+        !unref(isUpdate) ? t('routes.system.newMenu') : t('routes.system.editMenu'),
+      );
+      const { createMessage } = useMessage();
+      const { t } = useI18n();
+      async function handleSubmit() {
+        try {
+          const values = await validate();
+          setDrawerProps({ confirmLoading: true });
+          // TODO custom api
+          console.log(values);
+          values.parentId ??= '';
+          const parent = tData.value.find((i) => i.menuId === values.parentId);
+          if (values.type === 0) {
+            values.component = 'LAYOUT';
+          }
+          if (values.type === 2 && parent && parent.type !== 1) {
+            createMessage.error(t('routes.system.buttonMenuWaring'));
+            return;
+          }
+
+          if (!unref(isUpdate)) {
+            await saveMenuApi(values);
+          } else {
+            values.menuId = menuId.value;
+            await updateMenuApi(values);
+          }
+
+          closeDrawer();
+          emit('success');
+        } finally {
+          setDrawerProps({ confirmLoading: false });
+        }
+      }
+
+      return { registerDrawer, registerForm, getTitle, handleSubmit };
+    },
+  });
+</script>

+ 130 - 0
src/views/system/menu/index.vue

@@ -0,0 +1,130 @@
+<template>
+  <div>
+    <BasicTable @register="registerTable" @fetch-success="onFetchSuccess" :searchInfo="searchInfo">
+      <template #toolbar>
+        <a-button type="primary" @click="handleCreate"> {{ t('routes.system.newMenu') }} </a-button>
+      </template>
+      <template #action="{ record }">
+        <TableAction
+          :actions="[
+            {
+              icon: 'clarity:note-edit-line',
+              onClick: handleEdit.bind(null, record),
+            },
+            {
+              icon: 'ant-design:delete-outlined',
+              color: 'error',
+              popConfirm: {
+                title: t('common.operating'),
+                confirm: handleDelete.bind(null, record),
+              },
+            },
+          ]"
+        />
+      </template>
+    </BasicTable>
+    <MenuDrawer @register="registerDrawer" @success="handleSuccess" />
+  </div>
+</template>
+<script lang="ts">
+  import { defineComponent, reactive } from 'vue';
+
+  import { BasicTable, useTable, TableAction } from '/@/components/Table';
+  import { getMenuList, deleteMenuApi } from '/@/api/sys/system';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  const { t } = useI18n();
+  import { useDrawer } from '/@/components/Drawer';
+  import MenuDrawer from './MenuDrawer.vue';
+
+  import { columns, searchFormSchema } from './menu.data';
+  import { makeMenuTree } from '/@/utils/treeUtils';
+  export default defineComponent({
+    name: 'MenuManagement',
+    components: { BasicTable, MenuDrawer, TableAction },
+    setup() {
+      // collapseAll
+      const searchInfo = reactive<Recordable>({});
+      searchInfo.order = 'asc';
+      const [registerDrawer, { openDrawer }] = useDrawer();
+      const [registerTable, { reload }] = useTable({
+        title: t('routes.system.menuList'),
+        api: getMenuList,
+        columns,
+        formConfig: {
+          labelWidth: 120,
+          schemas: searchFormSchema,
+        },
+        isTreeTable: true,
+        pagination: false,
+        striped: false,
+        useSearchForm: false,
+        showTableSetting: true,
+        bordered: true,
+        showIndexColumn: true,
+        canResize: true,
+        rowKey: 'id',
+        fetchSetting: {
+          pageField: 'pageNum',
+          sizeField: 'pageSize',
+          listField: 'list',
+          totalField: 'total',
+        },
+        actionColumn: {
+          width: 80,
+          title: t('common.operating'),
+          dataIndex: 'action',
+          slots: { customRender: 'action' },
+          fixed: 'right',
+        },
+        afterFetch: handleAfterFetch,
+      });
+
+      function handleAfterFetch(data) {
+        return makeMenuTree(data);
+      }
+
+      function handleCreate() {
+        openDrawer(true, {
+          isUpdate: false,
+        });
+      }
+
+      function handleEdit(record: Recordable) {
+        record.parentId === 0 && Reflect.set(record, 'parentId', null);
+        console.log('record', record.parentId);
+        openDrawer(true, {
+          record,
+          isUpdate: true,
+        });
+      }
+
+      async function handleDelete(record: Recordable) {
+        try {
+          await deleteMenuApi([String(record.menuId)]);
+          reload();
+        } catch (error) {}
+      }
+
+      function handleSuccess() {
+        reload();
+      }
+
+      function onFetchSuccess() {
+        // 演示默认展开所有表项
+        // nextTick();
+      }
+
+      return {
+        registerTable,
+        registerDrawer,
+        handleCreate,
+        handleEdit,
+        handleDelete,
+        handleSuccess,
+        onFetchSuccess,
+        searchInfo,
+        t,
+      };
+    },
+  });
+</script>

+ 275 - 0
src/views/system/menu/menu.data.ts

@@ -0,0 +1,275 @@
+import { BasicColumn } from '/@/components/Table';
+import { FormSchema } from '/@/components/Table';
+import { h } from 'vue';
+import { Tag } from 'ant-design-vue';
+import { Icon } from '/@/components/Icon';
+import { useI18n } from '/@/hooks/web/useI18n';
+const { t } = useI18n();
+// const label =[]
+
+export const columns: BasicColumn[] = [
+  {
+    title: 'ID',
+    dataIndex: 'menuId',
+    width: 80,
+  },
+  {
+    title: t('routes.system.component'),
+    dataIndex: 'path',//component
+    width: 80,
+  },
+  {
+    title: t('routes.system.menuName'),
+    dataIndex: 'name',
+    width: 200,
+    align: 'left',
+    fixed: 'left',
+  },
+  // {
+  //   title: t('routes.system.menuParentName'),
+  //   dataIndex: 'parentName',
+  //   width: 100,
+  // },
+  {
+    title: t('routes.system.icon'),
+    dataIndex: 'icon',
+    width: 50,
+    customRender: ({ record }) => {
+      return h(Icon, { icon: record.icon });
+    },
+  },
+  // permission
+  {
+    title: t('routes.system.perms'),
+    dataIndex: 'perms',
+    width: 250,
+  },
+  {
+    title: t('routes.system.type.title'),
+    dataIndex: 'type',
+    width: 100,
+    customRender: ({ record }) => {
+      let color: string;
+      let label: string;
+      const type: number = record.type;
+      switch (type) {
+        case 0:
+          color = 'processing';
+          label = t('routes.system.type.0');
+          break;
+        case 1:
+          color = 'warning';
+          label = t('routes.system.type.1');
+          break;
+        case 2:
+          color = 'error';
+          label = t('routes.system.type.2');
+          break;
+        default:
+          color = 'green';
+          label = t('routes.system.type.0');
+          break;
+      }
+
+      return h(Tag, { color: color }, () => label);
+    },
+  },
+  {
+    title: t('routes.system.sortOrder'),
+    dataIndex: 'orderNum',
+    width: 50,
+  },
+
+  {
+    title: t('routes.system.status'),
+    dataIndex: 'status',
+    width: 80,
+    customRender: ({ record }) => {
+      const status = record.status;
+      const enable = ~~status === 0;
+      const color = enable ? 'green' : 'red';
+      const text = enable ? t('routes.system.enable') : t('routes.system.stopUsing');
+      return h(Tag, { color: color }, () => text);
+    },
+  },
+  {
+    title: t('routes.system.menuPath'),
+    dataIndex: 'path',
+    width: 180,
+  },
+  {
+    title: t('routes.system.menuUrl'),
+    dataIndex: 'url',
+    width: 180,
+  },
+];
+
+const isDir = (type: number) => type === 0;
+const isMenu = (type: number) => type === 1;
+const isButton = (type: number) => type === 2;
+const idShowExt = (isExt: number) => isExt === 1;
+
+export const searchFormSchema: FormSchema[] = [
+  {
+    field: 'name',
+    label: t('routes.system.menuName'),
+    component: 'Input',
+    componentProps: {
+      maxLength: 100,
+    },
+    colProps: { span: 8 },
+  },
+  {
+    field: 'status',
+    label: t('routes.system.status'),
+    component: 'Select',
+    componentProps: {
+      options: [
+        { label: t('routes.system.enable'), value: 0 },
+        { label: t('routes.system.stopUsing'), value: 1 },
+      ],
+    },
+    colProps: { span: 8 },
+  },
+];
+
+export const formSchema: FormSchema[] = [
+  {
+    field: 'type',
+    label: t('routes.system.menuType'),
+    component: 'RadioButtonGroup',
+    defaultValue: 0,
+
+    componentProps: {
+      options: [
+        { label: t('routes.system.type.0'), value: 0 },
+        { label: t('routes.system.type.1'), value: 1 },
+        { label: t('routes.system.type.2'), value: 2 },
+      ],
+    },
+    colProps: { lg: 24, md: 24 },
+  },
+  {
+    field: 'name',
+    label: t('routes.system.menuName'),
+    component: 'Input',
+    componentProps: {
+      maxLength: 50,
+    },
+    rules: [
+      {
+        required: true,
+        // @ts-ignore
+        validator: async (_, value) => {
+          // const reg_tel = /^[a-zA-Z0-9\u4e00-\u9fa5()]+$/;
+          // var reg = /\S+@\S+\.\S+/;
+          if (!value) {
+            return Promise.reject(t('routes.system.menuName1'));
+          }
+          // if (!reg_tel.test(value)) {
+          //   /* eslint-disable-next-line */
+          //   return Promise.reject(t('routes.system.menuName2'));
+          // }
+          return Promise.resolve();
+        },
+        trigger: 'change',
+      },
+    ],
+  },
+
+  {
+    field: 'parentId',
+    label: t('routes.system.menuParentName'),
+    component: 'TreeSelect',
+    componentProps: {
+      replaceFields: {
+        label: 'name',
+        key: 'id',
+        value: 'id',
+      },
+      getPopupContainer: () => document.body,
+    },
+  },
+
+  {
+    field: 'orderNum',
+    label: t('routes.system.sortOrder'),
+    defaultValue: 0,
+    component: 'InputNumber',
+    required: true,
+  },
+  {
+    field: 'icon',
+    label: t('routes.system.icon'),
+    component: 'IconPicker',
+    required: true,
+    ifShow: ({ values }) => !isButton(values.type),
+  },
+
+  {
+    field: 'path',
+    label: t('routes.system.routerPath'),
+    component: 'Input',
+    required: true,
+    ifShow: ({ values }) => !isButton(values.type),
+  },
+  {
+    field: 'component',
+    label: t('routes.system.component'),
+    component: 'Input',
+    ifShow: ({ values }) => isMenu(values.type),
+  },
+  {
+    field: 'perms',
+    label: t('routes.system.perms'),
+    defaultValue: '',
+    component: 'Input',
+    ifShow: ({ values }) => !isDir(values.type),
+  },
+  {
+    field: 'status',
+    label: t('routes.system.status'),
+    component: 'RadioButtonGroup',
+    defaultValue: 0,
+    componentProps: {
+      options: [
+        { label: t('routes.system.enable'), value: 0 },
+        { label: t('routes.system.stopUsing'), value: 1 },
+      ],
+    },
+  },
+  {
+    field: 'isExt',
+    label: t('routes.system.isExt.title'),
+    component: 'RadioButtonGroup',
+    defaultValue: 0,
+    componentProps: {
+      options: [
+        { label: t('routes.system.isExt.1'), value: 1 },
+        { label: t('routes.system.isExt.0'), value: 0 },
+      ],
+    },
+    ifShow: ({ values }) => !isButton(values.type),
+  },
+
+  {
+    field: 'url',
+    label: t('routes.system.menuUrl'),
+    component: 'Input',
+    ifShow: ({ values }) => idShowExt(values.isExt),
+  },
+
+  {
+    field: 'hideMenu',
+    label: t('routes.system.isShow'),
+    component: 'RadioButtonGroup',
+    defaultValue: 0,
+    componentProps: {
+      options: [
+        { label: t('routes.system.isExt.1'), value: 0 },
+        { label: t('routes.system.isExt.0'), value: 1 },
+      ],
+    },
+    ifShow: ({ values }) => !isButton(values.type),
+  },
+];

+ 111 - 0
src/views/system/role/RoleDrawer.vue

@@ -0,0 +1,111 @@
+<template>
+  <BasicDrawer
+    v-bind="$attrs"
+    @register="registerDrawer"
+    showFooter
+    :showDetailBack="false"
+    :title="getTitle"
+    width="500px"
+    @ok="handleSubmit"
+  >
+    <BasicForm @register="registerForm">
+      <template #menu="{ model, field }">
+        <BasicTree
+          v-model:value="model[field]"
+          :treeData="treeData"
+          :replaceFields="{ title: 'name', key: 'id' }"
+          :checkable="true"
+          toolbar
+          :title="t('layout.setting.menuDistribution')"
+        />
+      </template>
+    </BasicForm>
+  </BasicDrawer>
+</template>
+<script lang="ts">
+  import { defineComponent, ref, computed, unref, } from 'vue';
+  import { BasicForm, useForm } from '/@/components/Form/index';
+  import { formSchema } from './role.data';
+  import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
+  // TreeItem;
+  import { BasicTree } from '/@/components/Tree';
+  import { makeMenuTree, TreeMenuNode } from '/@/utils/treeUtils';
+  import { getMenuList, saveRoleApi, updateRoleApi } from '/@/api/sys/system';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { useUserStore } from '/@/store/modules/user';
+
+  export default defineComponent({
+    name: 'RoleDrawer',
+    components: { BasicDrawer, BasicForm, BasicTree },
+    emits: ['success', 'register'],
+    setup(_, { emit }) {
+      const isUpdate = ref(true);
+      const treeData = ref<TreeMenuNode[]>([]);
+      const userStore = useUserStore();
+      const roles = computed(() => userStore.getUserInfo?.roleId);
+      const { t } = useI18n();
+      const roleId = ref(0);
+      const [registerForm, { resetFields, setFieldsValue, validate, updateSchema }] = useForm({
+        labelWidth: 90,
+        schemas: formSchema,
+        showActionButtonGroup: false,
+      });
+
+      const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
+        resetFields();
+        console.log('data',data,roles)
+        setDrawerProps({ confirmLoading: false });
+        // 需要在setFieldsValue之前先填充treeData,否则Tree组件可能会报key not exist警告
+        if (unref(treeData).length === 0) {
+          const tData = (await getMenuList({roleId:unref(roles)})) as any as TreeMenuNode[];
+          treeData.value = makeMenuTree(tData);
+          console.log('makeMenuTree',treeData.value)
+        }
+        isUpdate.value = !!data?.isUpdate;
+        updateSchema({
+          field: 'status',
+          ifShow: unref(isUpdate),
+        })
+        if (unref(isUpdate)) {
+          roleId.value = data.record.roleId;
+          setFieldsValue({
+            ...data.record,
+          });
+        }
+      });
+
+      const getTitle = computed(() =>
+        !unref(isUpdate) ? t('common.addRoleName') : t('common.editRoleName'),
+      );
+
+      async function handleSubmit() {
+        try {
+          const values = await validate();
+          setDrawerProps({ confirmLoading: true });
+          // let result;
+          console.log('values', values);
+          if (!unref(isUpdate)) {
+            await saveRoleApi(values);
+          } else {
+            values.roleId = roleId.value;
+            await updateRoleApi(values);
+          }
+
+          closeDrawer();
+          emit('success');
+        } finally {
+          setDrawerProps({ confirmLoading: false });
+        }
+      }
+
+      return {
+        registerDrawer,
+        registerForm,
+        getTitle,
+        handleSubmit,
+        treeData,
+        t,
+      };
+    },
+  });
+</script>

+ 130 - 0
src/views/system/role/index.vue

@@ -0,0 +1,130 @@
+<template>
+  <div>
+    <BasicTable @register="registerTable">
+      <template #toolbar>
+        <a-button type="primary" @click="handleCreate"> 新增角色 </a-button>
+      </template>
+      <template #action="{ record }">
+        <TableAction
+          :actions="[
+            {
+              label: t('common.edit'),
+              onClick: handleEdit.bind(null, record),
+            },{
+              label: t('routes.system.roleBut'),
+              onClick: handleRole.bind(null, record),
+            },{
+              label: t('common.delText'),
+              color: 'error',
+              popConfirm: {
+                title: t('common.delConfirm'),
+                confirm: handleDelete.bind(null, record),
+              },
+            },
+          ]"
+        />
+      </template>
+    </BasicTable>
+    <RoleDrawer @register="registerDrawer" @success="handleSuccess" />
+    <TreeModal @register="register" @reload="reload" />
+  </div>
+</template>
+<script lang="ts">
+  import { defineComponent, nextTick } from 'vue';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { BasicTable, useTable, TableAction } from '/@/components/Table';
+  import { getRoleListByPage, deleteRoleApi } from '/@/api/sys/system';
+  import { useDrawer } from '/@/components/Drawer';
+  import RoleDrawer from './RoleDrawer.vue';
+  import TreeModal from './treeModal.vue';
+  import { useModal } from '/@/components/Modal';
+
+  // import { useUserStore } from '/@/store/modules/user';
+
+  import { columns, searchFormSchema } from './role.data';
+
+  export default defineComponent({
+    name: 'RoleManagement',
+    components: { BasicTable, TableAction,  RoleDrawer, TreeModal },// 
+    setup() {
+      const { t } = useI18n();
+      const [registerDrawer, { openDrawer }] = useDrawer();
+      const [register, { openModal }] = useModal();
+      // const userStore = useUserStore();
+      // const { getCheckRole } = userStore;
+      const [registerTable, { reload }] = useTable({
+        title: t('routes.system.roleTitle'),
+        api: getRoleListByPage,
+        columns,
+        formConfig: {
+          labelWidth: 120,
+          schemas: searchFormSchema,
+        },
+        useSearchForm: true,
+        showTableSetting: true,
+        bordered: true,
+        showIndexColumn: false,
+        fetchSetting: {
+          pageField: 'pageNum',
+          sizeField: 'pageSize',
+          listField: 'list',
+          totalField: 'total',
+        },
+        actionColumn: {
+          // ifShow: getCheckRole('super'),
+          width: 110,
+          title: t('common.operating'),
+          dataIndex: 'action',
+          slots: { customRender: 'action' },
+          fixed: undefined,
+        },
+      });
+
+      function handleCreate() {
+        openDrawer(true, {
+          isUpdate: false,
+        });
+      }
+
+      function handleRole(record: Recordable) {
+        openModal(true, record);
+      }
+
+      function handleEdit(record: Recordable) {
+        openDrawer(true, {
+          record,
+          isUpdate: true,
+        });
+      }
+
+      async function handleDelete(record: Recordable) {
+        try {
+          console.log('roleId', [record.roleId]);
+          const result = await deleteRoleApi({id:record.id});
+          console.log('result', result);
+          nextTick(reload);
+        } catch (error) {
+          console.log('error', error);
+        }
+      }
+
+      function handleSuccess() {
+        reload();
+      }
+
+      return {
+        registerTable,
+        registerDrawer,
+        handleCreate,
+        handleEdit,
+        handleDelete,
+        handleSuccess,
+        handleRole,
+        register,
+        reload,
+        // getCheckRole,
+        t,
+      };
+    },
+  });
+</script>

+ 151 - 0
src/views/system/role/role.data.ts

@@ -0,0 +1,151 @@
+import { BasicColumn } from '/@/components/Table';
+import { FormSchema } from '/@/components/Table';
+import { h } from 'vue';
+// import { Switch } from 'ant-design-vue';
+import { Time } from '/@/components/Time';
+import { getAllRoleList } from '/@/api/sys/system'
+// import { ListAllCompanyApi } from '/@/api/corporation/list';
+import { useI18n } from '/@/hooks/web/useI18n';
+const { t } = useI18n();
+
+export const columns: BasicColumn[] = [
+  {
+    title: 'ID',
+    dataIndex: 'id',
+    width: 80,
+  },
+  {
+    title: t('common.roleNameText'),
+    dataIndex: 'roleName',
+    width: 200,
+  },
+  {
+    title: t('routes.system.description'),
+    dataIndex: 'description',
+    width: 180,
+  },
+  {
+    title: '创建人',
+    dataIndex: 'createUserName',
+    width: 100,
+  },
+  {
+    title: t('routes.staff.createTime'),
+    dataIndex: 'createTime',
+    width: 180,
+    customRender: ({ record }) => {
+      return h(Time, {
+        value: record.createTime,
+        mode: 'datetime',
+      });
+    },
+  },
+  // {
+  //   title: t('routes.system.remarks'),
+  //   dataIndex: 'remark',
+  // },
+];
+
+export const searchFormSchema: FormSchema[] = [
+  {
+    field: 'roleName',
+    label: t('common.roleNameText'),
+    component: 'Input',
+    componentProps: {
+      maxLength: 100,
+    },
+    colProps: { span: 8 },
+  },
+  // {
+  //   field: 'canShow',
+  //   label: '状态',
+  //   component: 'Select',
+  //   componentProps: {
+  //     options: [
+  //       { label: '启用', value: '0' },
+  //       { label: '停用', value: '1' },
+  //     ],
+  //   },
+  //   colProps: { span: 8 },
+  // },
+];
+
+export const formSchema: FormSchema[] = [
+  {
+    label: '',
+    field: 'id',
+    component: 'Input',
+    show:false,
+  },
+  {
+    field: 'roleName',
+    label: t('common.roleNameText'),
+    required: true,
+    component: 'Input',
+  },
+  // {
+  //   field: 'companyId',
+  //   label: t('routes.staff.companyId'),
+  //   component: 'ApiSelect',
+  //   // required: true,
+  //   itemProps: {
+  //     validateTrigger: 'blur',
+  //   },
+  //   componentProps: {
+  //     api: getAllRoleList,
+  //     resultField: 'data',
+  //     labelField: 'roleName',
+  //     valueField: 'id',
+  //     immediate: true,
+  //     onChange: function () {
+  //       // Reflect.set(modalRecord, 'shippingName', opt.label);
+  //     },
+  //     params: {
+  //       page: 1,
+  //       limit: 1000,
+  //     },
+  //     required: true,
+  //   },
+  // },
+  // {
+  //   field: 'canShow',
+  //   label: '状态',
+  //   component: 'RadioButtonGroup',
+  //   defaultValue: 0,
+  //   componentProps: {
+  //     options: [
+  //       { label: '启用', value: 0 },
+  //       { label: '停用', value: 1 },
+  //     ],
+  //   },
+  // },
+  {
+    field: 'status',
+    label: t('routes.system.isPlatformRole'),
+    component: 'RadioButtonGroup',
+    defaultValue: 0,
+    componentProps: {
+      options: [
+        { label: '启用', value: 1 },
+        { label: '禁用', value: 0 },
+      ],
+    },
+  },
+  {
+    label: t('routes.system.description'),
+    field: 'description',
+    component: 'InputTextArea',
+  },
+  // {
+  //   label: ' ',
+  //   field: 'menuIdList',
+  //   slot: 'menu',
+  //   component: 'Input',
+  // },
+  // {
+  //   label: ' ',
+  //   field: 'deptIdList',
+  //   slot: 'dept',
+  //   component: 'Input',
+  // },
+];

+ 88 - 0
src/views/system/role/treeModal.vue

@@ -0,0 +1,88 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    @ok="handSubmit"
+    :title="t('layout.setting.setRoles')"
+    @visible-change="handleVisibleChange"
+    @cancel="closeModal"
+  >
+    <div class="pt-3px pr-3px">
+      <BasicTree v-if="unref(treeData).length !== 0"
+        v-model:value="treeModel"
+        :treeData="treeData"
+        :replaceFields="{ title: 'name', key: 'id' }"
+        :checkable="true"
+        toolbar
+        :title="t('layout.setting.menuDistribution')"
+      />
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { BasicTree } from '/@/components/Tree';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { defineComponent, nextTick, ref, unref, computed } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { makeMenuTree, TreeMenuNode, getTreeId } from '/@/utils/treeUtils';
+  import { getMenuList, getByRoleId, giveMenu } from '/@/api/sys/system';
+  import { useUserStore } from '/@/store/modules/user';
+
+  const { createMessage } = useMessage();
+  interface getMenuListInterf {
+    list:TreeMenuNode[]
+  }
+  export default defineComponent({
+    components: { BasicModal, BasicTree },
+    props: {
+      userData: { type: Object },
+    },
+    setup(props) {
+      const { t } = useI18n();
+      const treeModel = ref<number[]>([]);
+      const treeData = ref<TreeMenuNode[]>([]);
+      const userStore = useUserStore();
+      const roles = computed(() => userStore.getUserInfo?.roleId);
+      const tableDataId = ref<number>(0)
+
+      const [register, { closeModal }] = useModalInner((data) => {
+        data && onDataReceive(data);
+      });
+
+      async function onDataReceive(data) {
+        // 需要在setFieldsValue之前先填充treeData,否则Tree组件可能会报key not exist警告
+        if (unref(treeData).length === 0) {
+          const tData = (await getMenuList({roleId:unref(roles)})) as any as getMenuListInterf;
+          treeData.value = makeMenuTree(tData.list);
+        }
+        if(data){
+          tableDataId.value = data.id
+          const roleData = (await getByRoleId({roleId:data.id||unref(roles)})) as any as TreeMenuNode[];
+          treeModel.value = getTreeId(roleData)
+          console.log('treeModel.value',treeModel.value)
+        }
+      }
+      async function handSubmit() {
+        // const { id, password } = await validate();
+        await giveMenu({ roleId:tableDataId.value || unref(roles), menuIds: treeModel.value });
+        createMessage.success(t('common.optSuccess'));
+        closeModal();
+      }
+      function handleVisibleChange(v) {
+        v && props.userData && nextTick(() => onDataReceive(props.userData));
+      }
+
+      return {
+        handSubmit,
+        register,
+        t,
+        unref,
+        treeModel,
+        treeData,
+        handleVisibleChange,
+        closeModal,
+      };
+    },
+  });
+</script>

+ 0 - 0
src/views/system/user/index.vue