فهرست منبع

Merge branch 'master' of http://121.40.98.15:3001/kym/charge-java

skyline 2 سال پیش
والد
کامیت
146a8c42dd

+ 1 - 0
admin-web/src/layout/component/aside.vue

@@ -88,6 +88,7 @@ const closeLayoutAsideMobileMode = () => {
 // 设置/过滤路由(非静态路由/是否显示在菜单中)
 const setFilterRoutes = () => {
 	if (themeConfig.value.layout === 'columns') return false;
+
 	state.menuList = filterRoutesFun(routesList.value);
 };
 // 路由过滤递归函数

+ 0 - 10
admin-web/src/main.ts

@@ -25,16 +25,6 @@ app.config.globalProperties.$auth =(auth:any,all:boolean=false)=>{
     }
     // console.log("$auth:",auth)
     return true;
-    //TODO 全局权限校验
-  /*  if(Array.isArray(auth)){
-        if(all){
-            return useUserInfo().userInfos.permList.some((v: string) => auth.includes(v))
-        }else{
-            return useUserInfo().userInfos.permList.some((v: string) => auth.includes(v))
-        }
-    }else{
-        return useUserInfo().userInfos.permList.some((v: string) => v === auth)
-    }*/
 }
 
 directive(app);

+ 15 - 21
admin-web/src/router/frontEnd.ts

@@ -1,13 +1,13 @@
 import { RouteRecordRaw } from 'vue-router';
 import { storeToRefs } from 'pinia';
 import { formatTwoStageRoutes, formatFlatteningRoutes, router } from '/@/router/index';
-import {  notFoundAndNoPower ,adminRoutes} from '/@/router/route';
 import pinia from '/@/stores';
 import { Session } from '/@/utils/storage';
 import { useUserInfo } from '/@/stores/userInfo';
 import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
 import { useRoutesList } from '/@/stores/routesList';
 import { NextLoading } from '/@/utils/loading';
+import {adminRoutes,notFoundAndNoPower,  staticRoutes} from '/@/router/route';
 
 // 前端控制路由
 
@@ -28,10 +28,10 @@ export async function initFrontEndControlRoutes() {
 	// await useUserInfo(pinia).setUserInfos();
 	// 无登录权限时,添加判断
 	// https://gitee.com/lyt-top/vue-next-admin/issues/I64HVO
-	console.log("路由权限过滤")
 	//TODO 角色过滤替换为权限过滤
 	// if (useUserInfo().userInfos.roles.length <= 0) return Promise.resolve(true);
 	// 添加动态路由
+
 	await setAddRoute();
 
 	// 设置递归过滤有权限的路由到 pinia routesList 中(已处理成多级嵌套路由)及缓存多级嵌套数组处理后的一维数组
@@ -45,24 +45,13 @@ export async function initFrontEndControlRoutes() {
  * @link 参考:https://next.router.vuejs.org/zh/api/#addroute
  */
 export async function setAddRoute() {
+	console.log("添加路由",adminRoutes)
 	await setFilterRouteEnd().forEach((route: RouteRecordRaw) => {
 		console.log("添加路由:",route)
 		router.addRoute(route);
 	});
 }
 
-/**
- * 删除/重置路由
- * @method router.removeRoute
- * @description 此处循环为 dynamicRoutes(/@/router/route)第一个顶级 children 的路由一维数组,非多级嵌套
- * @link 参考:https://next.router.vuejs.org/zh/api/#push
- */
-export async function frontEndsResetRoute() {
-	await setFilterRouteEnd().forEach((route: RouteRecordRaw) => {
-		const routeName: any = route.name;
-		router.hasRoute(routeName) && router.removeRoute(routeName);
-	});
-}
 
 /**
  * 获取有当前用户权限标识的路由数组,进行对原路由的替换
@@ -70,7 +59,8 @@ export async function frontEndsResetRoute() {
  * @returns 返回替换后的路由数组
  */
 export function setFilterRouteEnd() {
-	let filterRouteEnd: any = formatTwoStageRoutes(formatFlatteningRoutes(null));
+
+	let filterRouteEnd: any = formatTwoStageRoutes(formatFlatteningRoutes(adminRoutes));
 	// notFoundAndNoPower 防止 404、401 不在 layout 布局中,不设置的话,404、401 界面将全屏显示
 	// 关联问题 No match found for location with path 'xxx'
 	filterRouteEnd[0].children = [...setFilterRoute(filterRouteEnd[0].children), ...notFoundAndNoPower];
@@ -109,7 +99,7 @@ export function setCacheTagsViewRoutes() {
 	const stores = useUserInfo(pinia);
 	const tagsViewRoutes = useTagsViewRoutes(pinia);
 	const { userInfos } = storeToRefs(stores);
-	let permMenus = setFilterHasPermsMenu(adminRoutes, userInfos.value.permList);
+	let permMenus = setFilterHasPermsMenu(staticRoutes, userInfos.value.permList);
 	// 添加到 pinia setTagsViewRoutes 中
 	let cachetagsViewRoutes = formatTwoStageRoutes(formatFlatteningRoutes(permMenus))[0].children
 	// console.log("piana tagsViewRoutes>>>",cachetagsViewRoutes)
@@ -126,10 +116,13 @@ export function setFilterMenuAndCacheTagsViewRoutes() {
 	const storesRoutesList = useRoutesList(pinia);
 	const { userInfos } = storeToRefs(stores);
 	//管理后台路由设置
+	// debugger
+	let routes = [...staticRoutes]
+	console.log("设置后台菜单>>>",adminRoutes)
 	let menuList = setFilterHasPermsMenu(adminRoutes, userInfos.value.permList);
-	// console.log(menuList)
+	console.log("设置后台菜单>>>",menuList)
 	storesRoutesList.setRoutesList(menuList);
-	setCacheTagsViewRoutes();
+	// setCacheTagsViewRoutes();
 }
 
 /**
@@ -155,13 +148,14 @@ export function hasMenuPermission(permList: any, route: any) {
  * @returns 返回有权限的路由数组 `meta.roles` 中控制
  */
 export function setFilterHasPermsMenu(routes: any, permList:Array<string>) {
-	const menu: any = [];
+	const menuList: any = [];
 	routes.forEach((route: any) => {
 		const item = { ...route };
 		if (hasMenuPermission(permList, item)) {
 			if (item.children) item.children = setFilterHasPermsMenu(item.children, permList);
-			menu.push(item);
+			console.log(item)
+			menuList.push(item);
 		}
 	});
-	return menu;
+	return menuList;
 }

+ 5 - 6
admin-web/src/router/index.ts

@@ -9,8 +9,6 @@ import {useThemeConfig} from '/@/stores/themeConfig';
 import {Session} from '/@/utils/storage';
 import {staticRoutes, notFoundAndNoPower, adminRoutes} from '/@/router/route';
 import {initFrontEndControlRoutes} from '/@/router/frontEnd';
-import {initBackEndControlRoutes} from '/@/router/backEnd';
-import {$get} from "/@/utils/request";
 
 /**
  * 1、前端控制路由时:isRequestRoutes 为 false,需要写 roles,需要走 setFilterRoute 方法。
@@ -48,14 +46,14 @@ export const router = createRouter({
  * @returns 返回处理后的一维路由菜单数组
  */
 export function formatFlatteningRoutes(arr: any) {
-    //console.log("formatFlatteningRoutes",arr)
+    console.log("formatFlatteningRoutes",arr)
     if (arr.length <= 0) return false;
     for (let i = 0; i < arr.length; i++) {
         if (arr[i].children) {
             arr = arr.slice(0, i + 1).concat(arr[i].children, arr.slice(i + 1));
         }
     }
-    //console.log("formatFlatteningRoutes1111",arr)
+    console.log("formatFlatteningRoutes1111",arr)
     return arr;
 }
 
@@ -113,11 +111,12 @@ export function formatTwoStageRoutes(arr: any) {
 
 // 路由加载前
 router.beforeEach(async (to, from, next) => {
-    // console.log("route>>>:", from)
-    // console.log("route>>>:", to, router)
+
+    console.log("route>>>:", to, router)
     NProgress.configure({showSpinner: true});
     if (to.meta.title) NProgress.start();
     const token = Session.get('token');
+    console.error(token)
     if (to.path === '/login' && !token) {
         next();
         NProgress.done();

+ 0 - 48
admin-web/src/router/route.ts

@@ -271,54 +271,6 @@ export const adminRoutes: Array<RouteRecordRaw> = [
                     },
                 ]
             },
-            /*{
-                path: '/admin/config',
-                name: 'adminConfig',
-                component: () => import('/@/layout/routerView/parent.vue'),
-                redirect: "/admin/config/list",
-                meta: {
-                    title: '配置中心',
-                    isLink: '',
-                    isHide: false,
-                    isKeepAlive: true,
-                    isAffix: false,
-                    isIframe: false,
-
-                    icon: 'ele-Setting',
-                },
-                children: [
-                    {
-                        path: '/admin/config/list',
-                        name: 'configList',
-                        component: () => import('/@/views/admin/config/list/index.vue'),
-                        meta: {
-                            title: '配置清单',
-                            isLink: '',
-                            isHide: false,
-                            isKeepAlive: true,
-                            isAffix: false,
-                            isIframe: false,
-
-                            icon: 'ele-Setting',
-                        },
-                    },
-                    {
-                        path: '/admin/config/dict',
-                        name: 'configDIct',
-                        component: () => import('/@/views/admin/config/dict/index.vue'),
-                        meta: {
-                            title: '数据字典',
-                            isLink: '',
-                            isHide: false,
-                            isKeepAlive: true,
-                            isAffix: false,
-                            isIframe: false,
-                            //
-                            icon: 'ele-Connection',
-                        },
-                    },
-                ]
-            },*/
             {
                 path: '/admin/optList',
                 name: 'adminOptList',

+ 1 - 2
admin-web/src/utils/request.ts

@@ -28,8 +28,7 @@ service.interceptors.request.use(
     (config) => {
         // 在发送请求之前做些什么 token
         if (Session.get('token')) {
-            config.headers!['Authorization'] = `${Session.get('token')}`;
-            config.headers!['X-Token'] = `${Session.get('token')}`;
+            config.headers!['satoken'] = `${Session.get('token')}`;
         }
         return config;
     },

+ 305 - 6
admin-web/src/views/admin/account/index.vue

@@ -1,13 +1,312 @@
+<style scoped lang="scss">
+.system-container {
+
+  :deep(.el-card__body) {
+    display: flex;
+    flex-direction: column;
+    flex: 1;
+    overflow: auto;
+
+    .el-table {
+      flex: 1;
+    }
+
+  }
+}
+
+.page-content {
+  margin-bottom: 20px;
+}
+
+.page-pager {
+  background-color: #fff;
+  height: 24px;
+}
+</style>
 <template>
+  <div class="system-container layout-padding">
+    <el-card shadow="hover" class="layout-padding-auto">
+      <el-form
+          :model="state.queryForm"
+          ref="formRulesOneRef"
+          size="default" label-width="0px" class="mt5">
+
+      </el-form>
+
+      <ext-query-form
+          class="page-search"
+          ref="queryRef"
+          v-model="state.formQuery"
+          :columns="state.columns"
+          :import-config="state.importConfig"
+          :export-config="state.exportConfig"
+          @on-change="loadData(true)"
+          @imported="loadData(true)">
+        <!--  <template #extraQuery></template>
+          <template #extraLeft></template>
+          <template #extraRight></template>-->
+        <template #extraLeft>
+          <ext-button name="创建"
+                      auth="'department.add'" icon="ele-FolderAdd"
+                      size="default" type="success"
+                      class="ml10" @click="onRowClick('add',null)"/>
+        </template>
+      </ext-query-form>
 
+      <el-row :gutter="20">
+
+        <el-col :span="24">
+          <ext-table
+              class="page-content"
+              :height="state.tableHeight"
+              :data-list="state.tableData.data"
+              :columns="state.columns"
+              :border="true"
+              :selectable="true"
+              :loading="state.tableData.loading">
+          </ext-table>
+
+          <!--          <el-affix position="bottom" :offset="48">-->
+          <ext-page class="page-pager" v-model:value="state.pageQuery" @change="loadData(false)"/>
+          <!--          </el-affix>-->
+        </el-col>
+      </el-row>
+
+    </el-card>
+  </div>
+  <UserDialog ref="userDialogRef" @refresh="loadData(true)"/>
 </template>
 
-<script>
-export default {
-  name: "index"
+<script setup lang="ts" name="UserList">
+import {watch, defineAsyncComponent, getCurrentInstance, nextTick, onBeforeMount, onMounted, reactive, ref} from 'vue';
+import {$body, $get} from "/@/utils/request";
+import u from '/@/utils/u'
+import {Msg} from "/@/utils/message";
+import {Session} from "/@/utils/storage";
+import ExtButton from '/@/components/form/ExtButton.vue'
+import ExtPage from '/@/components/form/ExtPage.vue'
+import ExtQueryForm from "/@/components/form/ExtQueryForm.vue";
+import ExtTable from "/@/components/form/ExtTable.vue";
+
+import {ElButton, ElTree, ElTag} from 'element-plus'
+
+const {proxy}: any = getCurrentInstance();
+
+
+const UserDialog = defineAsyncComponent(() => import("/@/views/admin/user/dialog.vue"));
+
+//定义引用
+const queryRef = ref();
+const userDialogRef = ref();
+const treeRef = ref<InstanceType<typeof ElTree>>()
+//定义变量
+const state = reactive({
+  treeData: [],
+  filterText: null,
+  formQuery: {
+    departmentId: null
+  },
+  pageQuery: {
+    pageIndex: 1,
+    pageSize: 10,
+    total: 0
+  },
+  tableData: {
+    data: [] as Array<any>,
+    loading: false
+  },
+  importConfig: {},
+  exportConfig: {},
+  columns: [
+    {label: '头像', prop: 'avatar', query: false, type: 'avatar', resizable: true},
+    {
+      label: '用户名', prop: 'userName', query: true, type: "text", resizable: true,
+      render: (h: any, row: any) => {
+        return h('div', null, [
+          h('div', {
+            style: {
+              cursor: 'pointer',
+              color: 'var(--el-color-primary-light-1)'
+            },
+            onClick: () => {
+              onRowClick('view', row)
+            }
+          }, row.userName)])
+      }
+    },
+    {label: '姓名', prop: 'name', query: true, type: 'text', resizable: true},
+    {label: '手机号', prop: 'mobile', query: true, type: 'text', resizable: true},
+    {label: '邮箱', prop: 'email', query: true, type: 'text', resizable: true},
+    {
+      label: '部门', prop: 'departmentId', query: true, type: 'dept', resizable: true,
+      render: (h: any, row: any) => {
+        return h('div', null,
+            row.deptList?row.deptList.map((k: any) => h(ElTag, {
+              type: 'primary'
+            }, k.name)):'')
+      }
+    },
+    {
+      label: '角色', prop: 'roleId', query: true, type: 'select', resizable: true, conf: {url: 'entity/list', query: {entity: 'role'}},
+      render: (h: any, row: any) => {
+        return h('div', null,
+            row.roleList?row.roleList.map((k: any) => h(ElTag, {
+              type: 'success'
+            }, k.name)):'')
+      }
+    },
+    {
+      label: '岗位', prop: 'postId', query: true, type: 'text', resizable: true, conf: {url: 'entity/list', query: {entity: 'post'}},
+      render: (h: any, row: any) => {
+        return h('div', null,
+            row.postList ? row.postList.map((k: any) => h(ElTag, {
+              type: 'danger'
+            }, k.name)) : '')
+      }
+    },
+
+    {label: '工号', prop: 'code', width: 150, query: true, type: 'text', resizable: true},
+    {label: '是否删除', prop: 'deleted', query: true, type: 'bool'},
+    {label: '登录ip', prop: 'ip', width: 150, query: false, type: 'text', resizable: true},
+    {label: '职业信息', prop: 'job', query: false, type: 'text', resizable: true},
+    {label: '上次登录时间', prop: 'lastLoginAt', width: 180, query: true, type: 'datetime', resizable: true, conf: {format: (val: any) => u.fmt.fmtDateTime(val)}},
+    {label: '用户状态', prop: 'status', width: 150, sortable: 'custom', align: 'center', query: true, type: 'dict', conf: {dict: 'User.status'}},
+    {label: '创建时间', prop: 'createAt', query: true, type: 'datetime', resizable: true, conf: {format: (val: any) => u.fmt.fmtDate(val)}},
+    {label: '更新时间', prop: 'updateAt', query: true, type: 'datetime', resizable: true, conf: {format: (val: any) => u.fmt.fmtDate(val)}},
+    {
+      label: '操作', prop: 'action', width: 180, type: 'render', align: 'center', fixed: 'right',
+      render: (h: any, row: any) => {
+        return (
+            h('div', null, [
+              (proxy.$auth('user.modify')) ?
+                  h(ElButton, {
+                    type: 'warning',
+                    size: 'default',
+                    text: true,
+                    onClick: () => {
+                      onRowClick('edit', row)
+                    }
+                  }, () => '编辑') : '',
+              (proxy.$auth('user.remove')) ?
+                  h(ElButton, {
+                    type: 'danger',
+                    text: true,
+                    onClick() {
+                      onRowDel(row)
+                    }
+                  }, () => '重置密码') : '',
+            ])
+        )
+
+      }
+    }
+  ],
+  tableHeight: 500
+})
+
+
+interface Tree {
+  [key: string]: any
+}
+
+watch(() => state.filterText, (val) => {
+  treeRef.value!.filter(val)
+})
+
+
+// 监听双向绑定 modelValue 的变化
+// watch(
+//         () => state.pageIndex,
+//         () => {
+//
+//         }
+// );
+
+//生命周期钩子
+onBeforeMount(() => {
+  let token = Session.get("token")
+  let encodeToken = encodeURIComponent(token)
+
+})
+
+onMounted(() => {
+  loadData();
+  loadTreeData()
+
+  nextTick(() => {
+    let bodyHeight = document.body.clientHeight;
+    let queryHeight = queryRef.value.$el.clientHeight;
+    state.tableHeight = bodyHeight - queryHeight - 220
+  })
+})
+
+
+//region 方法区
+// 初始化表格数据
+const loadData = (refresh: boolean = false) => {
+  if (refresh) {
+    state.pageQuery.pageIndex = 1;
+  }
+  state.tableData.loading = true;
+  $body(`/user/list`, {...state.formQuery, ...state.pageQuery}).then((res: any) => {
+    let {list, count} = res;
+    state.tableData.data = list;
+    state.pageQuery.total = count;
+    state.tableData.loading = false;
+  }).catch(e => {
+    console.error(e)
+    state.tableData.loading = false;
+  })
+};
+
+// 打开修改用户弹窗
+const onRowClick = (type: string, row: any) => {
+  userDialogRef.value.open(type, row);
+};
+// 删除用户
+const onRowDel = (row: any) => {
+  Msg.confirm(`此操作将永久删除:『${row.name}』,是否继续?`).then(() => {
+    $get(`/user/delete/${row.id}`).then(() => {
+      Msg.message("删除成功", 'success')
+    }).catch(() => {
+      Msg.message("删除失败", 'error')
+    })
+  });
+};
+
+
+const filterNode = (value: string, data: Tree) => {
+  if (!value) return true
+  return data.name.includes(value)
 }
-</script>
 
-<style scoped>
+const handleNodeClick = (data: any) => {
+  console.log(data)
+  if (data) {
+    if (state.formQuery.departmentId === data.id) {
+      state.formQuery.departmentId = null;
+      treeRef.value?.setCurrentKey(null)
+    } else {
+      state.formQuery.departmentId = data.id;
+    }
+  }
+  loadData();
+}
+
+const loadTreeData = () => {
+  state.tableData.loading = true;
+  state.tableData.data = [];
+  $body(`/department/tree`).then((res: any) => {
+    state.treeData = res;
+  })
+};
+
+
+//endregion
+
 
-</style>
+// 暴露变量
+// defineExpose({
+//     loadData,
+// });
+</script>

+ 3 - 3
admin-web/src/views/login/component/account.vue

@@ -155,8 +155,8 @@ const onSignIn = async () => {
     console.log(res)
     if (satoken) {
       // 存储 token 到浏览器缓存
-      Session.set('token', res.token);
-      Cookies.set('userName', res.userName);
+      Session.set('token', satoken);
+      Cookies.set('userId', id);
 
       initData();
       refreshLogin();
@@ -201,7 +201,7 @@ const signInSuccess = (isNoPower: boolean | undefined) => {
         query: Object.keys(<string>route.query?.params).length > 0 ? JSON.parse(<string>route.query?.params) : '',
       });
     } else {
-      router.push('/');
+      router.push('/admin');
     }
     // 登录成功提示
     const signInText = t('message.signInText');

+ 3 - 0
common/src/main/java/com/kym/common/filter/RequestLogFilter.java

@@ -36,6 +36,7 @@ public class RequestLogFilter implements Filter {
 
     private String IP = "ip";
     private String SEQ = "seq";
+    private  final String Timestamp = "ts";
 
 
     @Override
@@ -61,11 +62,13 @@ public class RequestLogFilter implements Filter {
         String seq = UUID.fastUUID().toString(true);
         MDC.put(IP, ip);
         MDC.put(SEQ, seq);
+        long start = System.currentTimeMillis();
 
         logger.info("request>>>uri:{}", request.getRequestURI());
         try {
             filterChain.doFilter(request, response);
         } finally {
+            logger.info("request<<<uri:{},cost:{}", request.getRequestURI(),(System.currentTimeMillis()-start));
             MDC.remove(IP);
             MDC.remove(SEQ);
         }