Forráskód Böngészése

用户管理版块的部分接口联调

刘洋 1 éve
szülő
commit
f3562a1dba

+ 1 - 1
.env

@@ -6,5 +6,5 @@ VITE_APP_TITLE=质控平台
 
 VITE_APP_TOKEN_PREFIX = token
 VITE_APP_PROXY_PREFIX = /api
-VITE_APP_BASE_URL=/
+VITE_APP_BASE_URL=http://192.168.10.86:7710
 VITE_HASH_ROUTE=Y

+ 1 - 1
.env.development

@@ -1,2 +1,2 @@
 VITE_ENV_TYPE=development
-VITE_HTTP_PROXY=N
+VITE_HTTP_PROXY=Y

+ 2 - 2
build/config/proxy.js

@@ -9,8 +9,8 @@ export function createViteProxy(isOpenProxy, envConfig) {
   const proxy = {
     [envConfig.proxy]: {
       target: envConfig.url,
-      changeOrigin: true,
-      rewrite: (path) => path.replace(new RegExp(`^${envConfig.proxy}`), ''),
+      // changeOrigin: true,
+      // rewrite: (path) => path.replace(new RegExp(`^${envConfig.proxy}`), ''),
     },
   };
   console.log('proxy:', proxy);

+ 35 - 8
src/api/user.js

@@ -2,28 +2,55 @@ import { request } from '@/utils/request.js';
 
 export const login = (data) =>
   request({
-    url: '/api/login',
+    url: '/api/admin/common/login',
     method: 'post',
     data,
     loading: true,
+    noAuth: true,
   });
-export const logout = (data) =>
+export const getOrgStructList = () =>
   request({
-    url: '/api/logout',
-    method: 'post',
+    url: '/api/admin/org/list',
+  });
+export const addOrgNode = (data) =>
+  request({
+    url: '/api/admin/org/save',
+    data,
+    loading: true,
+  });
+export const toggleOrgNodeStatus = (data) =>
+  request({
+    url: '/api/admin/org/enable',
     data,
+    loading: true,
   });
-export const getMenus = () =>
+export const getUserList = (data) =>
   request({
-    url: '/api/getMenus',
-    method: 'get',
+    url: '/api/admin/user/list',
+    params: data,
+  });
+export const getRoleList = (data) =>
+  request({
+    url: '/api/admin/role/list',
+    params: data,
   });
 export const addUser = (data) =>
   request({
-    url: '/api/add',
+    url: '/api/admin/user/save',
+    data,
+  });
+export const logout = (data) =>
+  request({
+    url: '/api/logout',
     method: 'post',
     data,
   });
+export const getMenus = () =>
+  request({
+    url: '/api/admin/common/get_menu', //真实接口url
+    method: 'post',
+  });
+
 export const editUser = (data) =>
   request({
     url: '/api/edit',

+ 9 - 6
src/hooks/useClearDialog.js

@@ -1,17 +1,19 @@
-import { ref, watch } from 'vue';
+import { reactive, watch, ref } from 'vue';
 import { cloneDeep } from 'lodash';
 
-export default function useClearDialog(data, props, getDetail) {
-  let formData = ref(cloneDeep(data));
+export default function useClearDialog(data, props, formRef, getDetail) {
+  let formData = reactive(cloneDeep(data));
   let isEdit = ref(false);
   watch(
     () => props.curRow,
     (val) => {
       if (!val) {
-        formData.value = cloneDeep(data);
+        let cloneData = cloneDeep(data);
+        for (let key in cloneData) {
+          formData[key] = cloneData[key];
+        }
         isEdit.value = false;
       } else {
-        formData.value = cloneDeep(val);
         isEdit.value = true;
       }
     }
@@ -20,8 +22,9 @@ export default function useClearDialog(data, props, getDetail) {
     () => props.visible,
     (visible) => {
       if (!visible) {
-        formData.value = cloneDeep(data);
+        formRef?.value?.clearValidate();
       } else {
+        formRef?.value?.clearValidate();
         !!props.curRow && getDetail && getDetail();
       }
     }

+ 9 - 9
src/hooks/useFetchTable.js

@@ -8,18 +8,18 @@ import { ref, reactive, watch } from 'vue';
 // }
 export default function useFetchTable(apiFn, options = {}, immediately = true) {
   let pagination = reactive({
-    page: 1,
+    pageNumber: 1,
     pageSize: options?.pageSize || 10,
     total: 0,
   });
   //tdesign的分页器组件的onChange方法,涵盖了页码的change和pageSize的change 两者的监听
   const onChange = (pageInfo) => {
     pagination.Size = pageInfo.pageSize;
-    pagination.page = pageInfo.current;
+    pagination.pageNumber = pageInfo.current;
   };
   const onPageSizeChange = (size) => {
     pagination.pageSize = size;
-    pagination.page = 1;
+    pagination.pageNumber = 1;
   };
 
   const loading = ref(false);
@@ -28,13 +28,13 @@ export default function useFetchTable(apiFn, options = {}, immediately = true) {
     loading.value = true;
     try {
       let params = {
-        page: pagination.page,
+        pageNumber: pagination.pageNumber,
         pageSize: pagination.pageSize,
-        ...(options.params?.value || {}),
+        ...(options.params || {}),
       };
       let res = await apiFn(params);
       //下方代码 后续根据实际接口返回字段进行修改
-      let list = Array.isArray(res.list) ? res.list : [];
+      let list = Array.isArray(res.records) ? res.records : [];
       tableData.value = list;
       pagination.total = res.total;
       loading.value = false;
@@ -46,10 +46,10 @@ export default function useFetchTable(apiFn, options = {}, immediately = true) {
   };
 
   const search = () => {
-    if (pagination.page === 1) {
+    if (pagination.pageNumber === 1) {
       fetchData();
     } else {
-      pagination.page = 1;
+      pagination.pageNumber = 1;
     }
   };
 
@@ -58,7 +58,7 @@ export default function useFetchTable(apiFn, options = {}, immediately = true) {
     fetchData();
   }
   watch(
-    () => pagination.page,
+    () => pagination.pageNumber,
     () => {
       fetchData();
     }

+ 1 - 1
src/main.js

@@ -14,7 +14,7 @@ import './style/global.less';
 import 'uno.css';
 import { setGlobalOptions } from 'vue-request';
 import packageJson from '../package.json';
-import './mock/index';
+// import './mock/index';
 setGlobalOptions({
   manual: true, //当 manual 设置为 true 时,你需要手动触发 run 或者 runAsync 才会发起请求 ,见vue-request文档:https://www.attojs.com/api/#manual
 });

+ 4 - 5
src/router/index.js

@@ -5,7 +5,7 @@ import {
 } from 'vue-router';
 import NProgress from 'nprogress';
 import { useUserStore } from '@/store';
-import { local } from '@/utils/tool';
+import { clear } from '@/utils/tool';
 import 'nprogress/nprogress.css';
 
 import routes from './routes';
@@ -29,22 +29,21 @@ router.beforeEach(async (to, from, next) => {
   const userStore = useUserStore();
   const toTitle = to.meta.title ? to.meta.title : to.name;
   document.title = `${toTitle} - ${title}`;
-  const token = local.get(import.meta.env.VITE_APP_TOKEN_PREFIX);
+  // const token = local.get(import.meta.env.VITE_APP_TOKEN_PREFIX);
   if (whiteRoutes.includes(to.name)) {
     next();
     return;
   }
   // 登录状态下
-  if (token) {
+  if (userStore.user) {
     // if (to.name === 'Login') {
     //   next({ path: defaultRoutePath });
     //   return;
     // }
-
     if (!userStore.routers) {
       const data = await userStore.requestUserMenu();
       if (!data) {
-        userStore.clearToken();
+        clear();
         next(
           to.fullPath === '/'
             ? { name: 'Login' }

+ 5 - 0
src/router/modules/myWorkbenches.js

@@ -6,6 +6,7 @@ export default {
     title: '我的工作台',
     sort: 0,
     isModule: true,
+    alias: 'workManage',
   },
   children: [
     {
@@ -16,6 +17,7 @@ export default {
         title: '工作台',
         sort: 1,
         icon: 'app',
+        alias: 'workChildManage',
       },
       children: [
         {
@@ -28,6 +30,7 @@ export default {
           meta: {
             title: '消息提醒',
             sort: 1,
+            alias: 'message',
           },
         },
         {
@@ -38,6 +41,7 @@ export default {
           meta: {
             title: '待办任务',
             sort: 2,
+            alias: 'work',
           },
         },
         {
@@ -48,6 +52,7 @@ export default {
           meta: {
             title: '通知公告',
             sort: 3,
+            alias: 'notice',
           },
         },
       ],

+ 4 - 0
src/router/modules/projectQuality.js

@@ -6,6 +6,7 @@ export default {
     title: '项目质量管理',
     sort: 6,
     isModule: true,
+    alias: 'projectQualityManage',
   },
   children: [
     {
@@ -16,6 +17,7 @@ export default {
         title: '项目质量管理',
         sort: 1,
         icon: 'control-platform',
+        alias: 'projectChildQualityManage',
       },
       children: [
         {
@@ -28,6 +30,7 @@ export default {
           meta: {
             title: '质量问题反馈',
             sort: 1,
+            alias: 'qualityProblem',
           },
         },
         {
@@ -40,6 +43,7 @@ export default {
           meta: {
             title: '质量问题查询',
             sort: 1,
+            alias: 'qualityProblemQuery',
           },
         },
       ],

+ 7 - 0
src/router/modules/resourceGuard.js

@@ -6,6 +6,7 @@ export default {
     title: '资源保障',
     sort: 3,
     isModule: true,
+    alias: 'resourceManage',
   },
   children: [
     {
@@ -16,6 +17,7 @@ export default {
         title: '人资保障',
         sort: 1,
         icon: 'usergroup',
+        alias: 'humanManage',
       },
       children: [
         {
@@ -28,6 +30,7 @@ export default {
           meta: {
             title: '人员档案管理',
             sort: 1,
+            alias: 'userArchives',
           },
         },
         {
@@ -40,6 +43,7 @@ export default {
           meta: {
             title: '人员调配',
             sort: 2,
+            alias: 'userAllocate',
           },
         },
       ],
@@ -52,6 +56,7 @@ export default {
         title: '设备保障',
         sort: 2,
         icon: 'print',
+        alias: 'deviceManage',
       },
       children: [
         {
@@ -64,6 +69,7 @@ export default {
           meta: {
             title: '出入库登记查询',
             sort: 1,
+            alias: 'deviceInOut',
           },
         },
         {
@@ -76,6 +82,7 @@ export default {
           meta: {
             title: '设备资源监控',
             sort: 2,
+            alias: 'deviceControl',
           },
         },
       ],

+ 9 - 1
src/router/modules/serviceUnit.js

@@ -6,6 +6,7 @@ export default {
     title: '服务单元管理',
     sort: 1,
     isModule: true,
+    alias: 'serviceManage',
   },
   children: [
     {
@@ -16,6 +17,7 @@ export default {
         title: '派单管理',
         sort: 1,
         icon: 'user-talk',
+        alias: 'crmManage',
       },
       children: [
         {
@@ -26,6 +28,7 @@ export default {
           meta: {
             title: '派单管理',
             sort: 1,
+            alias: 'crm',
           },
         },
       ],
@@ -38,6 +41,7 @@ export default {
         title: '服务单元管理',
         sort: 2,
         icon: 'server',
+        alias: 'serviceChildManage',
       },
       children: [
         {
@@ -50,6 +54,7 @@ export default {
           meta: {
             title: '服务单元管理',
             sort: 1,
+            alias: 'service',
           },
         },
         {
@@ -62,6 +67,7 @@ export default {
           meta: {
             title: '服务范围管理',
             sort: 2,
+            alias: 'serviceScope',
           },
         },
         {
@@ -73,7 +79,8 @@ export default {
             ),
           meta: {
             title: '新增服务范围',
-            bind: 'RangeManage', //注意,这种不是菜单,但是也属于路由,比如name为"RangeManage"的时候,该路由也要有权限。需要在addRoute的时候考虑进去
+            bind: '"serviceScope"',
+            // bind: 'RangeManage', //注意,这种不是菜单,但是也属于路由,比如name为"RangeManage"的时候,该路由也要有权限。需要在addRoute的时候考虑进去
           },
         },
         {
@@ -86,6 +93,7 @@ export default {
           meta: {
             title: '服务区域规划',
             sort: 3,
+            alias: 'serviceRegion',
           },
         },
       ],

+ 13 - 3
src/router/modules/sop.js

@@ -6,6 +6,7 @@ export default {
     title: 'SOP管理',
     sort: 2,
     isModule: true,
+    alias: 'sopManage',
   },
   children: [
     {
@@ -16,6 +17,7 @@ export default {
         title: 'SOP管理',
         sort: 1,
         icon: 'layers',
+        alias: 'sopChildManage',
       },
       children: [
         {
@@ -26,6 +28,7 @@ export default {
           meta: {
             title: '教务处SOP管理',
             sort: 1,
+            alias: 'office',
           },
         },
         {
@@ -34,7 +37,8 @@ export default {
           component: () => import('@/views/sop/sop-manage/sop-flow/index.vue'),
           meta: {
             title: 'SOP流程',
-            bind: 'OfficeSop',
+            bind: 'office',
+            // bind: 'OfficeSop',
           },
         },
         {
@@ -43,7 +47,8 @@ export default {
           component: () => import('@/views/sop/sop-manage/sop-step/index.vue'),
           meta: {
             title: '当前SOP流程',
-            bind: 'OfficeSop',
+            alias: 'office',
+            // bind: 'OfficeSop',
           },
         },
         {
@@ -52,7 +57,7 @@ export default {
           component: () =>
             import('@/views/sop/sop-manage/student-sop/index.vue'),
           meta: {
-            title: '研究生SOP管理',
+            title: '研究生SOP管理', //后端菜单暂时没有提供,等待需求落定
             sort: 2,
           },
         },
@@ -64,6 +69,7 @@ export default {
           meta: {
             title: '设备出入库登记',
             sort: 3,
+            alias: 'deviceInOutSop',
           },
         },
         {
@@ -74,6 +80,7 @@ export default {
           meta: {
             title: '项目计划变更报备',
             sort: 4,
+            alias: 'projectExchange',
           },
         },
       ],
@@ -86,6 +93,7 @@ export default {
         title: 'SOP监控',
         sort: 1,
         icon: 'browse',
+        alias: 'sopControlManage',
       },
       children: [
         {
@@ -96,6 +104,7 @@ export default {
           meta: {
             title: '延期预警',
             sort: 2,
+            alias: 'delayWarn',
           },
         },
         {
@@ -106,6 +115,7 @@ export default {
           meta: {
             title: '违规登记',
             sort: 3,
+            alias: 'violation',
           },
         },
       ],

+ 10 - 0
src/router/modules/system.js

@@ -6,6 +6,7 @@ export default {
     title: '系统管理',
     sort: 2,
     isModule: true,
+    alias: 'systemManage',
   },
   children: [
     {
@@ -16,6 +17,7 @@ export default {
         title: '配置管理',
         sort: 1,
         icon: 'setting',
+        alias: 'configureManage',
       },
       children: [
         {
@@ -26,6 +28,7 @@ export default {
           meta: {
             title: '客户配置',
             sort: 1,
+            alias: 'custom',
           },
         },
         {
@@ -36,6 +39,7 @@ export default {
           meta: {
             title: '供应商配置',
             sort: 1,
+            alias: 'supplier',
           },
         },
         {
@@ -46,6 +50,7 @@ export default {
           meta: {
             title: '设备配置',
             sort: 1,
+            alias: 'device',
           },
         },
         {
@@ -58,6 +63,7 @@ export default {
           meta: {
             title: '服务档位配置',
             sort: 1,
+            alias: 'level',
           },
         },
         {
@@ -68,6 +74,7 @@ export default {
           meta: {
             title: '考勤配置',
             sort: 1,
+            alias: 'dingConfigure',
           },
         },
       ],
@@ -80,6 +87,7 @@ export default {
         title: '通知日志',
         sort: 1,
         icon: 'root-list',
+        alias: 'logManage',
       },
       children: [
         {
@@ -90,6 +98,7 @@ export default {
           meta: {
             title: '通知公告管理',
             sort: 1,
+            alias: 'notice',
           },
         },
         {
@@ -100,6 +109,7 @@ export default {
           meta: {
             title: '日志查询',
             sort: 2,
+            alias: 'log',
           },
         },
       ],

+ 8 - 0
src/router/modules/user.js

@@ -6,6 +6,7 @@ export default {
     title: '用户管理',
     sort: 2,
     isModule: true,
+    alias: 'userManage',
   },
   children: [
     {
@@ -16,6 +17,7 @@ export default {
         title: '组织架构管理',
         sort: 1,
         icon: 'fork',
+        alias: 'orgManage',
       },
       children: [
         {
@@ -26,6 +28,7 @@ export default {
           meta: {
             title: '组织架构管理',
             sort: 1,
+            alias: 'org',
           },
         },
       ],
@@ -38,6 +41,7 @@ export default {
         title: '用户权限管理',
         sort: 2,
         icon: 'pin',
+        alias: 'userPrivilegeManage',
       },
       children: [
         {
@@ -48,6 +52,7 @@ export default {
           meta: {
             title: '用户管理',
             sort: 1,
+            alias: 'user',
           },
         },
         {
@@ -58,6 +63,7 @@ export default {
           meta: {
             title: '角色管理',
             sort: 2,
+            alias: 'role',
           },
         },
       ],
@@ -70,6 +76,7 @@ export default {
         title: '密码管理',
         sort: 1,
         icon: 'lock-on',
+        alias: 'pwdManage',
       },
       children: [
         {
@@ -80,6 +87,7 @@ export default {
           meta: {
             title: '密码修改',
             sort: 1,
+            alias: 'pwd',
           },
         },
       ],

+ 5 - 0
src/router/modules/workHours.js

@@ -6,6 +6,7 @@ export default {
     title: '工时管理',
     sort: 5,
     isModule: true,
+    alias: 'hoursManage',
   },
   children: [
     {
@@ -16,6 +17,7 @@ export default {
         title: '工时管理',
         sort: 1,
         icon: 'history',
+        alias: 'hoursChildManage',
       },
       children: [
         {
@@ -28,6 +30,7 @@ export default {
           meta: {
             title: '异常审核',
             sort: 1,
+            alias: 'exception',
           },
         },
         {
@@ -40,6 +43,7 @@ export default {
           meta: {
             title: '考勤提交',
             sort: 2,
+            alias: 'dingSubmit',
           },
         },
         {
@@ -52,6 +56,7 @@ export default {
           meta: {
             title: '工时统计',
             sort: 3,
+            alias: 'hourSubmit',
           },
         },
       ],

+ 1 - 1
src/router/routes.js

@@ -4,7 +4,7 @@ const routes = [
     name: 'Layout',
     path: '/',
     component: () => import('@/layout/index.vue'),
-    redirect: '/my-workbenches',
+    redirect: '/login',
     children: [],
     meta: {
       title: '',

+ 28 - 26
src/store/modules/user.js

@@ -3,7 +3,7 @@ import { cloneDeep } from 'lodash';
 import { getMenus, logout, login } from '@/api/user';
 import router from '@/router/index';
 import asyncRoutes from '@/router/asyncRoutes';
-import { getTreeList, local } from '@/utils/tool';
+import { getTreeList, local, session, clear } from '@/utils/tool';
 import { whiteMenuList } from '@/router/asyncRoutes';
 // 路由扁平化
 const flatAsyncRoutes = (routes, breadcrumb = []) => {
@@ -38,7 +38,8 @@ const findRoutersItemByName = (name, arr = asyncRoutes, finds = []) => {
   for (let i = 0; i < arr.length; i++) {
     const item = arr[i];
     //asyncRoutes里,当有非菜单的路由时,其meta里会有bind字段定义,也要考虑进来
-    if (item.name === name || item.meta?.bind === name) {
+    // if (item.name === name || item.meta?.bind === name) {
+    if (item.meta.alias === name || item.meta?.bind === name) {
       finds.push(item);
     }
     if (item.children) {
@@ -51,7 +52,7 @@ const findRoutersItemByName = (name, arr = asyncRoutes, finds = []) => {
 const filterAsyncRouter = (routerMap) => {
   const accessedRouters = [];
   routerMap.forEach((item) => {
-    const targets = findRoutersItemByName(item.name);
+    const targets = findRoutersItemByName(item.url);
     if (targets.length) {
       targets.forEach((target) => {
         const route = {
@@ -72,9 +73,11 @@ const filterAsyncRouter = (routerMap) => {
 };
 
 const useUserStore = defineStore('user', {
-  persist: true,
-  storage: localStorage,
-  paths: ['user'],
+  // persist: true,
+  persist: {
+    storage: sessionStorage,
+    paths: ['user'],
+  },
   state: () => ({
     routers: undefined,
     user: undefined,
@@ -85,17 +88,17 @@ const useUserStore = defineStore('user', {
   }),
 
   actions: {
-    setToken(token) {
-      local.set(import.meta.env.VITE_APP_TOKEN_PREFIX, token);
-    },
+    // setToken(token) {
+    //   local.set(import.meta.env.VITE_APP_TOKEN_PREFIX, token);
+    // },
 
-    getToken() {
-      return local.get(import.meta.env.VITE_APP_TOKEN_PREFIX);
-    },
+    // getToken() {
+    //   return local.get(import.meta.env.VITE_APP_TOKEN_PREFIX);
+    // },
 
-    clearToken() {
-      local.remove(import.meta.env.VITE_APP_TOKEN_PREFIX);
-    },
+    // clearToken() {
+    //   local.remove(import.meta.env.VITE_APP_TOKEN_PREFIX);
+    // },
     setState(data) {
       this.$patch(data);
     },
@@ -109,7 +112,7 @@ const useUserStore = defineStore('user', {
     setCurPageModule(name) {
       this.curPageModule = name;
       let item = this.menus.find((item) => item.name === name);
-      this.moduleMenus = item.children;
+      this.moduleMenus = item?.children || [];
     },
     setHeaderMenus(menus) {
       let newMenus = cloneDeep(menus);
@@ -138,25 +141,23 @@ const useUserStore = defineStore('user', {
               router.push({ name: 'Login' });
               return;
             }
-            let allMenus = [...whiteMenuList, ...response];
+            let allMenus = [...whiteMenuList, ...(response.privileges || [])];
             this.setMenu(allMenus);
             resolve(allMenus);
           })
-          .catch((_) => {
-            this.clearToken();
+          .catch((error) => {
+            reject(error);
+            clear();
+            this.resetUserInfo();
             router.push({ name: 'Login' });
           });
-      }).catch((error) => {
-        this.clearToken();
-        router.push({ name: 'Login' });
       });
     },
 
     login(form) {
       return login(form)
-        .then((r) => {
-          this.setToken(r.token);
-          this.setInfo(r);
+        .then((userInfo) => {
+          this.setInfo(userInfo);
           return true;
         })
         .catch((e) => {
@@ -167,7 +168,8 @@ const useUserStore = defineStore('user', {
 
     async logout() {
       await logout();
-      this.clearToken();
+      // this.clearToken();
+      clear();
       this.resetUserInfo();
     },
   },

+ 1 - 1
src/style/tdesign-reset.less

@@ -8,7 +8,7 @@
   }
 }
 .t-form__item {
-  margin-bottom: 15px;
+  // margin-bottom: 15px;
 }
 .t-dialog--default {
   padding-top: 20px;

+ 7 - 1
src/utils/crypto.js

@@ -4,6 +4,12 @@ import Utf8 from 'crypto-js/enc-utf8';
 import AES from 'crypto-js/aes';
 import SHA1 from 'crypto-js/sha1';
 import MD5 from 'crypto-js/md5';
+import { cookie } from '@/utils/tool';
+
+if (!cookie.get('deviceId')) {
+  cookie.set('deviceId', MD5(Math.random() + '-' + Date.now()));
+}
+export const DEVICE_ID = cookie.get('deviceId');
 
 export const getBase64 = (content) => {
   const words = Utf8.parse(content);
@@ -42,7 +48,7 @@ export const getAuthorization = (infos, type) => {
       infos.timestamp
     }&${infos.token}`;
     const sign = Base64.stringify(SHA1(str));
-    return `Token ${infos.account}:${sign}`;
+    return `Token ${infos.sessionId}:${sign}`;
   }
 };
 

+ 35 - 24
src/utils/request.js

@@ -5,6 +5,28 @@ import { get, isEmpty } from 'lodash';
 import qs from 'qs';
 import { h } from 'vue';
 import { LoadingPlugin } from 'tdesign-vue-next';
+import { getAuthorization, DEVICE_ID } from './crypto';
+
+function setAuth(config) {
+  let userSession = sessionStorage.getItem('user');
+  if (userSession && !config.noAuth) {
+    let user = JSON.parse(userSession).user;
+    const timestamp = new Date().getTime();
+    const authorization = getAuthorization(
+      {
+        method: config.method,
+        uri: config.url.split('?')[0],
+        timestamp,
+        sessionId: user.sessionId,
+        token: user.accessToken,
+      },
+      'token'
+    );
+    config.headers['Authorization'] = authorization;
+    config.headers['time'] = timestamp;
+  }
+}
+
 function createService() {
   // 创建一个 axios 实例
   const service = axios.create();
@@ -12,6 +34,7 @@ function createService() {
   // HTTP request 拦截器
   service.interceptors.request.use(
     (config) => {
+      setAuth(config);
       if (config.loading) {
         LoadingPlugin(true);
       }
@@ -33,16 +56,16 @@ function createService() {
         LoadingPlugin(false);
       }
       // 以下代码看后端是否有统一在接口里增加外层code的规范
-      // if (response.data.code && response.data.code !== 200) {
-      //   Message.error({
-      //     content: response.data.message,
-      //     icon: () => h(IconFaceFrownFill),
-      //   });
-      // }
+      if (response.data.code && response.data.code !== 200) {
+        Message.error({
+          content: response.data.message,
+          icon: () => h(IconFaceFrownFill),
+        });
+      }
       if (response.config.download && response.config.responseType === 'blob') {
         download(response);
       }
-      return response.data;
+      return response.data?.data;
     },
     (error) => {
       if (error.config.loading) {
@@ -86,10 +109,6 @@ function createService() {
   return service;
 }
 
-function stringify(data) {
-  return qs.stringify(data, { allowDots: true, encode: false });
-}
-
 /**
  * @description 创建请求方法
  * @param {Object} service axios 实例
@@ -97,10 +116,11 @@ function stringify(data) {
 function createRequest(service) {
   return function (config) {
     const env = import.meta.env;
-    const token = local.get(env.VITE_APP_TOKEN_PREFIX);
     const configDefault = {
       headers: {
-        'Authorization': `Bearer ${token}`,
+        'platform': 'WEB',
+        'deviceId': DEVICE_ID,
+        // 'Authorization': `Bearer ${token}`,
         'Content-Type': get(
           config,
           'headers.Content-Type',
@@ -108,21 +128,12 @@ function createRequest(service) {
         ),
       },
       method: 'post',
-      timeout: 60000,
-      baseURL:
-        env.VITE_HTTP_PROXY === 'Y'
-          ? env.VITE_APP_PROXY_PREFIX
-          : env.VITE_APP_BASE_URL,
+      timeout: 380000,
+      baseURL: env.VITE_HTTP_PROXY === 'Y' ? '' : env.VITE_APP_BASE_URL,
       data: {},
     };
     const option = Object.assign(configDefault, config);
 
-    // json
-    if (!isEmpty(option.params)) {
-      option.url = `${option.url}?${stringify(option.params)}`;
-      option.params = {};
-    }
-
     return service(option);
   };
 }

+ 6 - 1
src/utils/tool.js

@@ -81,6 +81,11 @@ export const session = {
   },
 };
 
+export const clear = () => {
+  localStorage.clear();
+  sessionStorage.clear();
+};
+
 /**
  * CookieStorage
  */
@@ -305,7 +310,7 @@ export const getTreeList = (oldDataList, sortField = '') => {
     ? dataList.sort((a, b) => a.sort - b.sort)
     : dataList;
   const formatArray = sortArray.reduce((arr, cur) => {
-    const pid = cur.parentId ? cur.parentId : 0;
+    const pid = cur.parentId ? cur.parentId : '-1';
     const parent = formatObj[pid];
     if (parent) {
       parent.children ? parent.children.push(cur) : (parent.children = [cur]);

+ 24 - 14
src/views/login/index.vue

@@ -8,9 +8,9 @@
         class="login-form"
         :rules="rules"
       >
-        <t-form-item name="a">
+        <t-form-item name="loginName">
           <t-input
-            v-model="formData.a"
+            v-model="formData.loginName"
             clearable
             placeholder="账号"
             size="large"
@@ -21,9 +21,9 @@
           </t-input>
         </t-form-item>
 
-        <t-form-item name="b">
+        <t-form-item name="password">
           <t-input
-            v-model="formData.b"
+            v-model="formData.password"
             type="password"
             clearable
             placeholder="密码"
@@ -49,11 +49,12 @@
 </template>
 
 <script setup name="Login">
-import { ref, reactive, computed } from 'vue';
+import { ref, reactive, computed, watch } from 'vue';
 import { DesktopIcon, LockOnIcon } from 'tdesign-icons-vue-next';
 import { useRoute, useRouter } from 'vue-router';
 import { useUserStore } from '@/store';
 import { MessagePlugin } from 'tdesign-vue-next';
+import { getBase64 } from '@/utils/crypto';
 
 const form = ref(null);
 
@@ -61,14 +62,14 @@ const route = useRoute();
 const router = useRouter();
 
 const formData = reactive({
-  a: '',
-  b: '',
+  loginName: 'sysadmin',
+  password: '123456',
 });
 const rules = {
-  a: [
+  loginName: [
     { required: true, message: '请输入账号', type: 'error', trigger: 'change' },
   ],
-  b: [
+  password: [
     { required: true, message: '请输入密码', type: 'error', trigger: 'change' },
   ],
 };
@@ -77,12 +78,21 @@ const userStore = useUserStore();
 
 const loginHandle = () => {
   form.value.validate().then(async (result) => {
-    const redirect = route.query.redirect
-      ? route.query.redirect
-      : '/my-workbenches';
+    const redirect = route.query.redirect;
+    // ? route.query.redirect
+    // : '/my-workbenches';
     if (result === true) {
-      await userStore.login({});
-      router.push(redirect);
+      await userStore.login({
+        loginName: formData.loginName,
+        password: getBase64(formData.password),
+        type: 'ACCOUNT',
+      });
+      await userStore.requestUserMenu();
+      if (redirect) {
+        router.push(redirect);
+      } else {
+        router.push({ name: userStore.menus[0].name });
+      }
     }
   });
 };

+ 122 - 39
src/views/user/auth-manage/user-manage/add-user-dialog.vue

@@ -6,30 +6,35 @@
     :width="600"
     :closeOnOverlayClick="false"
   >
-    <t-form ref="formRef" :model="formData" labelWidth="120px">
-      <t-form-item label="姓名">
-        <t-input v-model="formData.a"></t-input>
+    <t-form ref="formRef" :data="formData" labelWidth="120px" :rules="rules">
+      <t-form-item label="登录名" name="loginName">
+        <t-input v-model="formData.loginName"></t-input>
       </t-form-item>
-      <t-form-item label="性别">
-        <t-radio-group v-model="formData.b">
-          <t-radio value="1">男</t-radio>
-          <t-radio value="2">女</t-radio>
-        </t-radio-group>
+      <t-form-item label="姓名" name="realName">
+        <t-input v-model="formData.realName"></t-input>
       </t-form-item>
-      <t-form-item label="手机">
-        <t-input v-model="formData.c"></t-input>
+      <t-form-item label="性别" name="genderStr">
+        <t-radio-group v-model="formData.genderStr">
+          <t-radio value="男">男</t-radio>
+          <t-radio value="女">女</t-radio>
+        </t-radio-group>
       </t-form-item>
-      <t-form-item label="所属节点">
-        <t-tree-select v-model="formData.d" :data="treeData" />
+      <t-form-item label="手机" name="mobileNumber">
+        <t-input v-model="formData.mobileNumber"></t-input>
       </t-form-item>
-      <t-form-item label="角色">
-        <t-select v-model="formData.e"></t-select>
+      <t-form-item label="所属机构" name="orgId">
+        <t-tree-select
+          v-model="formData.orgId"
+          :data="treeData"
+          :treeProps="treeProps"
+        />
       </t-form-item>
-      <t-form-item label="状态">
-        <t-select v-model="formData.c">
-          <t-option value="1">启用</t-option>
-          <t-option value="2">禁用</t-option>
-        </t-select>
+      <t-form-item label="角色" name="roleIds">
+        <t-select
+          v-model="formData.roleIds"
+          :options="roleList"
+          multiple
+        ></t-select>
       </t-form-item>
     </t-form>
     <template #foot>
@@ -42,39 +47,117 @@
 </template>
 <script setup name="AddUserDialog">
 import useClearDialog from '@/hooks/useClearDialog';
-import { ref, watch } from 'vue';
+import { ref, computed } from 'vue';
+import { getOrgStructList, getRoleList, addUser } from '@/api/user';
+import { useRequest } from 'vue-request';
 const props = defineProps({
   visible: Boolean,
   curRow: Object,
 });
-const emit = defineEmits(['update:visible']);
+const emit = defineEmits(['update:visible', 'success']);
 const formRef = ref(null);
 const getDetail = async () => {
   //编辑状态下获取回显数据的接口请求业务,如果curRow里的字段够用,就直接把curRow里的字段赋值给formData
-  alert('获取详情中...');
+  for (let key in formData) {
+    if (key !== 'roleIds') {
+      formData[key] = props.curRow[key];
+    }
+  }
+  formData.roleIds = props.curRow.roles.map((item) => item.id);
 };
 const { formData, isEdit } = useClearDialog(
   {
-    a: '',
-    b: '',
-    c: '',
-    d: '',
-    e: '',
-    f: '',
+    loginName: '',
+    realName: '',
+    genderStr: '男',
+    mobileNumber: '',
+    orgId: '',
+    roleIds: '',
   },
   props,
+  formRef,
   getDetail
 );
-const treeData = ref([
-  {
-    label: '节点0',
-    value: '0',
-    children: [
-      { label: '节点1', value: '1' },
-      { label: '节点2', value: '2' },
-    ],
+const { data: treeData } = useRequest(getOrgStructList, {
+  manual: false,
+});
+const { data: roleData } = useRequest(getRoleList, {
+  manual: false,
+  defaultParams: [{ pageNumber: 1, pageSize: 1000 }],
+});
+const roleList = computed(() => {
+  return roleData.value?.records.map((item) => ({
+    label: item.name,
+    value: item.id,
+  }));
+});
+const treeProps = {
+  keys: {
+    label: 'name',
+    value: 'id',
+    children: 'children',
   },
-]);
-
-const save = () => {};
+};
+const rules = {
+  loginName: [
+    {
+      required: true,
+      message: '请填写登录名',
+      type: 'error',
+      trigger: 'blur',
+    },
+  ],
+  realName: [
+    {
+      required: true,
+      message: '请填写真实姓名',
+      type: 'error',
+      trigger: 'blur',
+    },
+  ],
+  mobileNumber: [
+    {
+      required: true,
+      message: '请填写手机号',
+    },
+  ],
+  orgId: [
+    {
+      required: true,
+      message: '请选择机构',
+    },
+  ],
+  roleIds: [
+    {
+      required: true,
+      message: '请选择角色',
+    },
+    {
+      validator: (val) => {
+        if (!val?.length) {
+          return {
+            result: false,
+            message: '请选择角色',
+          };
+        }
+        return {
+          result: true,
+          type: 'success',
+        };
+      },
+    },
+  ],
+};
+const addHandler = () => {
+  addUser({ ...formData, id: props.curRow?.id || undefined }).then(() => {
+    emit('success');
+  });
+};
+const save = () => {
+  formRef.value.validate().then(async (result) => {
+    if (result === true) {
+      addHandler();
+    }
+  });
+};
 </script>

+ 21 - 12
src/views/user/auth-manage/user-manage/index.vue

@@ -23,12 +23,20 @@
           onChange,
           total: pagination.total,
         }"
+        v-loading="tableLoading"
       >
+        <template #roles="{ row }">
+          {{ row.roles.map((item) => item.name).join('、') }}
+        </template>
+        <template #enable="{ row }">
+          {{ row.enable ? '启用' : '禁用' }}
+        </template>
       </t-table>
     </div>
     <AddUserDialog
       v-model:visible="showAddUserDialog"
       :curRow="curRow"
+      @success="addSuccess"
     ></AddUserDialog>
   </div>
 </template>
@@ -36,21 +44,18 @@
 <script setup name="User" lang="jsx">
 import { reactive, ref } from 'vue';
 import { useRequest } from 'vue-request';
-import { getTableData } from '@/api/test';
+import { getUserList } from '@/api/user';
 import useFetchTable from '@/hooks/useFetchTable';
 import AddUserDialog from './add-user-dialog.vue';
 const showAddUserDialog = ref(false);
 const curRow = ref(null);
 const columns = [
-  { colKey: 'a', title: '用户ID' },
-  { colKey: 'b', title: '姓名' },
-  { colKey: 'c', title: '性别' },
-  { colKey: 'd', title: '手机' },
-  { colKey: 'e', title: '所属节点' },
-  { colKey: 'f', title: '角色' },
-  { colKey: 'g', title: '状态' },
-  { colKey: 'h', title: '创建人' },
-  { colKey: 'i', title: '创建时间' },
+  { colKey: 'id', title: '用户ID', width: 180 },
+  { colKey: 'realName', title: '姓名' },
+  { colKey: 'genderStr', title: '性别', width: 60 },
+  { colKey: 'mobileNumber', title: '手机' },
+  { colKey: 'roles', title: '角色', minWidth: 200 },
+  { colKey: 'enable', title: '状态', width: 80 },
   {
     title: '操作',
     colKey: 'operate',
@@ -109,9 +114,13 @@ const {
   tableData,
   fetchData,
   onChange,
-} = useFetchTable(getTableData);
+  search,
+} = useFetchTable(getUserList);
 
-const refresh = async () => {};
+const addSuccess = () => {
+  showAddUserDialog.value = false;
+  search();
+};
 </script>
 
 <style></style>

+ 49 - 25
src/views/user/org-struct-manage/struct-manage/add-node-dialog.vue

@@ -6,18 +6,16 @@
     :width="600"
     :closeOnOverlayClick="false"
   >
-    <t-form ref="formRef" :model="formData" labelWidth="120px">
-      <t-form-item label="节点名称">
-        <t-input v-model="formData.a"></t-input>
+    <t-form ref="formRef" :data="formData" labelWidth="120px" :rules="rules">
+      <t-form-item label="节点名称" name="name">
+        <t-input v-model="formData.name"></t-input>
       </t-form-item>
       <t-form-item label="父节点">
-        <t-tree-select v-model="formData.b" :data="treeData" />
-      </t-form-item>
-      <t-form-item label="状态">
-        <t-select v-model="formData.c">
-          <t-option value="1">启用</t-option>
-          <t-option value="2">禁用</t-option>
-        </t-select>
+        <t-tree-select
+          v-model="formData.parentId"
+          :data="orgTreeList"
+          :treeProps="treeProps"
+        />
       </t-form-item>
     </t-form>
     <template #foot>
@@ -31,35 +29,61 @@
 <script setup name="AddNodeDialog">
 import { ref } from 'vue';
 import useClearDialog from '@/hooks/useClearDialog';
+import { addOrgNode } from '@/api/user';
 const props = defineProps({
   visible: Boolean,
   curRow: Object,
+  orgTreeList: Array,
 });
-const emit = defineEmits(['update:visible']);
+const emit = defineEmits(['update:visible', 'success']);
 const formRef = ref(null);
 const getDetail = async () => {
   //编辑状态下获取回显数据的接口请求业务,如果curRow里的字段够用,就直接把curRow里的字段赋值给formData
-  alert('获取详情中...');
+  formData.name = props.curRow.name;
+  formData.parentId = props.curRow.parentId || '';
 };
 const { formData, isEdit } = useClearDialog(
   {
-    a: '',
-    b: '',
-    c: '',
+    name: '',
+    parentId: '',
   },
   props,
+  formRef,
   getDetail
 );
-const treeData = ref([
-  {
-    label: '节点0',
-    value: '0',
-    children: [
-      { label: '节点1', value: '1' },
-      { label: '节点2', value: '2' },
-    ],
+const treeProps = {
+  keys: {
+    label: 'name',
+    value: 'id',
+    children: 'children',
   },
-]);
+};
+const rules = {
+  name: [
+    {
+      required: true,
+      message: '请填写节点名称',
+    },
+  ],
+};
+const addHandler = () => {
+  let params = {
+    name: formData.name,
+    parentId: formData.parentId,
+  };
+  if (props.curRow) {
+    params.id = props.curRow.id;
+  }
+  addOrgNode(params).then(() => {
+    emit('success');
+  });
+};
 
-const save = () => {};
+const save = () => {
+  formRef.value.validate().then(async (result) => {
+    if (result === true) {
+      addHandler();
+    }
+  });
+};
 </script>

+ 27 - 23
src/views/user/org-struct-manage/struct-manage/index.vue

@@ -17,42 +17,43 @@
         :columns="columns"
         :data="tableData"
         bordered
-        :pagination="{
-          defaultCurrent: 1,
-          defaultPageSize: 10,
-          onChange,
-          total: pagination.total,
-        }"
+        v-loading="tableLoading"
       >
+        <template #enable="{ row }">{{
+          row.enable ? '启用' : '禁用'
+        }}</template>
       </t-table>
     </div>
     <AddNodeDialog
       v-model:visible="showAddNodeDialog"
       :curRow="curRow"
+      :orgTreeList="tableData || []"
+      @success="addSuccess"
     ></AddNodeDialog>
   </div>
 </template>
 
 <script setup name="StructManage" lang="jsx">
-import { reactive, ref } from 'vue';
+import { computed, ref } from 'vue';
+import { MessagePlugin } from 'tdesign-vue-next';
 import { useRequest } from 'vue-request';
-import { getTableData } from '@/api/test';
-import useFetchTable from '@/hooks/useFetchTable';
+import { getOrgStructList, toggleOrgNodeStatus } from '@/api/user';
 import AddNodeDialog from './add-node-dialog.vue';
 const showAddNodeDialog = ref(false);
 const curRow = ref(null);
+const toggleStatus = (row) => {
+  toggleOrgNodeStatus({ id: row.id, enable: !row.enable }).then(() => {
+    MessagePlugin.success('操作成功');
+    run();
+  });
+};
 const columns = [
-  { colKey: 'a', title: '管理节点' },
-  { colKey: 'b', title: '类型' },
-  { colKey: 'c', title: '父节点' },
-  { colKey: 'd', title: '状态' },
-  { colKey: 'e', title: '创建人' },
-  { colKey: 'f', title: '创建时间' },
+  { colKey: 'name', title: '管理节点' },
+  { colKey: 'enable', title: '状态' },
   {
     title: '操作',
     colKey: 'operate',
     fixed: 'right',
-    width: 120,
     cell: (h, { row }) => {
       return (
         <div class="table-operations">
@@ -72,9 +73,10 @@ const columns = [
             hover="color"
             onClick={(e) => {
               e.stopPropagation();
+              toggleStatus(row);
             }}
           >
-            禁用
+            {row.enable ? '禁用' : '启用'}
           </t-link>
         </div>
       );
@@ -82,14 +84,16 @@ const columns = [
   },
 ];
 
-const refresh = async () => {};
 const {
+  data: tableData,
   loading: tableLoading,
-  pagination,
-  tableData,
-  fetchData,
-  onChange,
-} = useFetchTable(getTableData);
+  run,
+} = useRequest(getOrgStructList);
+run();
+const addSuccess = () => {
+  showAddNodeDialog.value = false;
+  run();
+};
 </script>
 
 <style></style>

+ 1 - 1
vite.config.js

@@ -55,7 +55,7 @@ export default defineConfig((configEnv) => {
     ],
     server: {
       host: '0.0.0.0',
-      port: 8888,
+      port: 8899,
       open: true,
       proxy: createViteProxy(isOpenProxy, envConfig),
     },