Преглед на файлове

管理后台菜单路由

zuy преди 2 години
родител
ревизия
bc53794306

+ 2 - 1
admin-web/src/App.vue

@@ -129,7 +129,8 @@ onUnmounted(() => {
 watch(
 	() => route.path,
 	() => {
-    console.log("App.vue watch route path",route.path)
+    console.log("route path",route.path)
+
 		other.useTitle();
 	},
 	{

+ 0 - 2
admin-web/src/layout/index.vue

@@ -46,8 +46,6 @@ const onLayoutResize = () => {
 onBeforeMount(() => {
 	onLayoutResize();
 	window.addEventListener('resize', onLayoutResize);
-
-  console.error("admin home xxxx")
 });
 // 页面卸载时
 onUnmounted(() => {

+ 6 - 4
admin-web/src/layout/routerView/parent.vue

@@ -1,11 +1,13 @@
 <template>
 	<div class="layout-parent">
 		<router-view v-slot="{ Component }">
-			<transition :name="setTransitionName" mode="out-in">
-				<keep-alive :include="getKeepAliveNames">
+      {{Component.path}}
+<!--			<transition :name="setTransitionName" mode="out-in">-->
 					<component :is="Component" :key="state.refreshRouterViewKey"  v-show="!isIframePage" />
-				</keep-alive>
-			</transition>
+<!--				<keep-alive :include="getKeepAliveNames">-->
+<!--				</keep-alive>-->
+
+<!--			</transition>-->
 		</router-view>
 		<transition :name="setTransitionName" mode="out-in">
 			<Iframes class="w100" v-show="isIframePage" :refreshKey="state.iframeRefreshKey" :name="setTransitionName" :list="state.iframeList" />

+ 1 - 1
admin-web/src/router/backEnd.ts

@@ -33,7 +33,7 @@ const dynamicViewsModules: Record<string, Function> = Object.assign({}, { ...lay
  */
 export async function initBackEndControlRoutes() {
 	// 界面 loading 动画开始执行
-	if (window.nextLoading === undefined) NextLoading.start();
+	// if (window.nextLoading === undefined) NextLoading.start();
 	// 无 token 停止执行下一步
 	if (!Session.get('token')) return false;
 	// 触发初始化用户信息 pinia

+ 3 - 3
admin-web/src/router/frontEnd.ts

@@ -65,10 +65,10 @@ export function setFilterRouteEnd() {
 	// 关联问题 No match found for location with path 'xxx'
 	filterRouteEnd[0].children = [...setFilterRoute(filterRouteEnd[0].children), ...notFoundAndNoPower];
 	return filterRouteEnd;*/
-	debugger
 	let filterRouteEnd: any =[];
 	filterRouteEnd.push(adminRoutes[0])
-	let  adminRouteList: Array<RouteRecordRaw> = adminRoutes[0].children;
+	let  adminRouteList: RouteRecordRaw[] | undefined = adminRoutes[0].children;
+	// @ts-ignore
 	adminRouteList.forEach((item:RouteRecordRaw)=>{
 		filterRouteEnd.push(item)
 		if(item.children&&item.children.length>0){
@@ -136,7 +136,7 @@ export function setFilterMenuAndCacheTagsViewRoutes() {
 	let menuList = setFilterHasPermsMenu(adminRoutes, userInfos.value.permList);
 	console.log("设置后台菜单>>>",menuList)
 	storesRoutesList.setRoutesList(menuList);
-	// setCacheTagsViewRoutes();
+	setCacheTagsViewRoutes();
 }
 
 /**

+ 4 - 3
admin-web/src/router/index.ts

@@ -116,7 +116,7 @@ router.beforeEach(async (to, from, next) => {
     NProgress.configure({showSpinner: true});
     if (to.meta.title) NProgress.start();
     const token = Session.get('token');
-    console.error(token)
+    // console.error(token)
     if (to.path === '/login' && !token) {
         next();
         NProgress.done();
@@ -126,7 +126,7 @@ router.beforeEach(async (to, from, next) => {
             Session.clear();
             NProgress.done();
         } else if (token && to.path === '/login') {
-            next('/home');
+            next('/');
             NProgress.done();
         } else {
             const storesRoutesList = useRoutesList(pinia);
@@ -152,12 +152,13 @@ router.beforeEach(async (to, from, next) => {
             // next();
             NProgress.done();
         }
+        NProgress.done();
     }
 });
 
 // 路由加载后
 router.afterEach(() => {
-    NProgress.done();
+    // NProgress.done();
 });
 
 // 导出路由

+ 1 - 1
admin-web/src/router/route.ts

@@ -77,7 +77,7 @@ export const staticRoutes: Array<RouteRecordRaw> = [
  */
 export const adminRoutes: Array<RouteRecordRaw> = [
     {
-        path: '/admin',
+        path: '/',
         name: 'admin',
         component: () => import('/@/layout/index.vue'),
         redirect: '/admin/home',

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

@@ -2,15 +2,16 @@
 import { createPinia,PiniaPlugin,PiniaPluginContext } from 'pinia';
 
 import {  toRaw } from 'vue'
+import {Session} from '/@/utils/storage';
 
 // 数据存储本地
 const setStorage = (key: string, value: any) => {
-    localStorage.setItem(key, JSON.stringify(value))
+    Session.set(key,value)
+   // sessionStorage.setItem(key, JSON.stringify(value))
 }
 // 获取本地数据
 const getStorage = (key: string) => {
-    const data = localStorage.getItem(key)
-    return data ? JSON.parse(data) : {};
+    return Session.get(key)
 }
 
 const piniaPlugin = (context: PiniaPluginContext) => {
@@ -18,10 +19,10 @@ const piniaPlugin = (context: PiniaPluginContext) => {
     // $subscribe state值发生变化时会执行传入的回调
     store.$subscribe(() => {
         // 每次修改值的时候更新localStorage数据
-        setStorage(`pinia-${store.$id}`, toRaw(store.$state))
+        setStorage(`piniaKey-${store.$id}`, toRaw(store.$state))
     })
     // 每次构建项目的时候从本地存储取值
-    const data = getStorage(`pinia-${store.$id}`)
+    const data = getStorage(`piniaKey-${store.$id}`)
    // 并将取的值赋给state
     return {
         ...data

+ 2 - 2
admin-web/src/utils/loading.ts

@@ -9,7 +9,7 @@ import '/@/theme/loading.scss';
 export const NextLoading = {
 	// 创建 loading
 	start: () => {
-		const bodys: Element = document.body;
+	/*	const bodys: Element = document.body;
 		const div = <HTMLElement>document.createElement('div');
 		div.setAttribute('class', 'loading-next');
 		const htmls = `
@@ -29,7 +29,7 @@ export const NextLoading = {
 		`;
 		div.innerHTML = htmls;
 		bodys.insertBefore(div, bodys.childNodes[0]);
-		window.nextLoading = true;
+		window.nextLoading = true;*/
 	},
 	// 移除 loading
 	done: (time: number = 0) => {

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

@@ -67,12 +67,14 @@ service.interceptors.response.use(
         }
     },
     (error) => {
-        console.error(error)
+        // console.error(error)
         // 对响应错误做点什么
         if (error.message.indexOf('timeout') != -1) {
             ElMessage.error('网络超时');
         } else if (error.message == 'Network Error') {
             ElMessage.error('网络连接错误');
+        } else if (error.message.includes("404")) {
+            ElMessage.error('接口不存在');
         } else {
             if (error.response.data) {
                 ElMessage.error(error.response.data.message || error.response.statusText);

+ 0 - 4
admin-web/src/utils/storage.ts

@@ -1,8 +1,4 @@
 import Cookies from 'js-cookie';
-import {useThemeConfig} from "/@/stores/themeConfig";
-import pinia from "/@/stores";
-
-const storesThemeConfig = useThemeConfig(pinia);
 /**
  * window.localStorage 浏览器永久缓存
  * @method set 设置永久缓存

+ 177 - 0
admin-web/src/views/admin/account/detail.vue

@@ -0,0 +1,177 @@
+<style scoped lang="scss">
+
+</style>
+<template>
+    <div class="system-dialog-container">
+        <el-drawer
+                :title="state.dialog.title"
+                v-model="state.dialog.isShowDialog"
+                width="820px"
+                append-to-body
+                destroy-on-close
+                :close-on-click-modal="false"
+                >
+            <el-form
+                    :model="state.form"
+                    :rules="rules"
+                    :label-position="labelPosition"
+                    ref="formRef"
+                    size="default"
+                    label-width="100px"
+                    class="mt5">
+                                    <el-input
+                            v-model="state.formQuery.avatar"
+                            placeholder="头像"
+                            clearable
+                            style="width: 100%">
+                    </el-input>
+                                                        <el-input
+                            v-model="state.formQuery.companyId"
+                            placeholder="公司id"
+                            clearable
+                            style="width: 100%">
+                    </el-input>
+                                                                                                <el-input
+                            v-model="state.formQuery.lastLoginTime"
+                            placeholder="最后登录时间"
+                            clearable
+                            style="width: 100%">
+                    </el-input>
+                                                        <el-input
+                            v-model="state.formQuery.mobilePhone"
+                            placeholder="手机号"
+                            clearable
+                            style="width: 100%">
+                    </el-input>
+                                                        <el-input
+                            v-model="state.formQuery.nickname"
+                            placeholder="昵称"
+                            clearable
+                            style="width: 100%">
+                    </el-input>
+                                                        <el-input
+                            v-model="state.formQuery.password"
+                            placeholder="密码"
+                            clearable
+                            style="width: 100%">
+                    </el-input>
+                                                        <el-input
+                            v-model="state.formQuery.status"
+                            placeholder="0:禁用 1:启用"
+                            clearable
+                            style="width: 100%">
+                    </el-input>
+                                                                            <el-input
+                            v-model="state.formQuery.username"
+                            placeholder="用户名"
+                            clearable
+                            style="width: 100%">
+                    </el-input>
+                                </el-form>
+
+            <template #footer>
+				<div class="dialog-footer">
+					<el-button @click="onCancel" size="default">取 消</el-button>
+					<el-button :loading="state.btnLoading" type="primary" @click="onSubmit" size="default">{{ state.dialog.submitTxt }}</el-button>
+				</div>
+            </template>
+        </el-drawer>
+    </div>
+</template>
+
+<script setup lang="ts" name="AdminUserDialog">
+    import {defineAsyncComponent, reactive, onMounted, ref} from 'vue';
+    import {Msg} from "/@/utils/message";
+    import {$body, $get} from "/@/utils/request";
+    import u from '/@/utils/u'
+    import type {FormInstance, FormRules} from 'element-plus';
+
+    // 引入组件
+    const ExtDetailForm = defineAsyncComponent(() => import('/@/components/form/ExtDetailForm.vue'));
+
+    // 定义子组件向父组件传值/事件
+    const emit = defineEmits(['refresh']);
+    const formRef = ref();
+    //定义初始变量,重置使用
+    const initState = ()=>({
+        ruleForm: {
+            id:0
+        },
+        btnLoading: false,
+        dialog: {
+            isShowDialog: false,
+            type: '',
+            title: '',
+            submitTxt: '',
+        },
+        rules: {},
+    })
+
+    // 定义变量内容
+    const state = reactive(initState());
+
+
+    // 打开弹窗
+    const open = (action: string='add', row: any) => {
+        state.dialog.title = u.dialog.actions[action].title +"『用户表』"
+        state.dialog.submitTxt = u.dialog.actions[action].btn +"『用户表』"
+        state.dialog.isShowDialog = true;
+        if (action !=='add') {
+            loadData(row.id);
+        }
+    };
+    // 关闭弹窗
+    const onClose = () => {
+        state.dialog.isShowDialog = false;
+        Object.assign(state,initState())
+    };
+    // 取消
+    const onCancel = () => {
+        onClose();
+    };
+    // 提交
+    const onSubmit = () => {
+        formRef.value.validate((valid, fields) => {
+            // console.log('basic checkForm!', valid,fields)
+            if (valid) {
+                state.btnLoading = true;
+                const url = state.ruleForm.id > 0 ? "adminUser/modify" : "adminUser/add"
+                    $body(url, state.ruleForm).then(() => {
+                    state.btnLoading = false;
+                    Msg.message('操作成功');
+                    console.log('submit!')
+                    onClose();
+                    emit('refresh');
+                })
+            } else {
+                state.btnLoading = false;
+                Msg.message('表单校验失败', 'error');
+            }
+        })
+
+        // formRef.value.checkForm().then(() => {
+        //
+        // }).catch(() => {
+        //     state.btnLoading = false;
+        //     Msg.message('表单校验失败', 'error');
+        // })
+    };
+
+    const handleFormChange = (formData: any) => {
+        console.log(formData)
+    }
+
+    // 初始化表格数据
+    const loadData = (id: number) => {
+            $get(`adminUser/detail/${id}`).then((res: any) => {
+            state.ruleForm = res;
+        })
+    }
+
+    // 暴露变量
+    defineExpose({
+        open
+    });
+
+
+</script>

+ 2 - 2
admin-web/src/views/admin/account/index.vue

@@ -31,7 +31,7 @@
 
       <el-form
           :model="state.formQuery"
-          ref="formRulesOneRef"
+          ref="queryRef"
           size="default" label-width="0px" class="mt5">
         <el-input
             v-model="state.formQuery.avatar"
@@ -161,7 +161,7 @@ import ExtPage from '/@/components/form/ExtPage.vue'
 
 import mittBus from '/@/utils/mitt';
 
-const AdminUserDialog = defineAsyncComponent(() => import("/@/views/page/AdminUserDialog.vue"));
+const AdminUserDialog = defineAsyncComponent(() => import("/@/views/admin/account/detail.vue"));
 
 //定义引用
 const queryRef = ref();

+ 6 - 0
admin-web/src/views/admin/index.vue

@@ -1,5 +1,6 @@
 <template>
   <div class="home-container layout-pd">
+    XXXXXXXXXXX
     <el-row :gutter="15" class="home-card-one mb15">
       <el-col
           :xs="24"
@@ -66,6 +67,9 @@
 </template>
 
 <script setup lang="ts" name="home">
+import NProgress from 'nprogress';
+import 'nprogress/nprogress.css';
+
 import { reactive, onMounted, ref, watch, nextTick, onActivated, markRaw } from 'vue';
 import * as echarts from 'echarts';
 import { storeToRefs } from 'pinia';
@@ -503,6 +507,8 @@ const initEchartsResize = () => {
 };
 // 页面加载时
 onMounted(() => {
+  console.error("home onMounted")
+  NProgress.done();
   initEchartsResize();
 });
 // 由于页面缓存原因,keep-alive

+ 6 - 93
admin-web/src/views/admin/log/opt/index.vue

@@ -1,100 +1,13 @@
 <template>
-  <div class="system-container layout-padding">
-    <el-card shadow="hover" class="layout-padding-auto">
-      <div class="system-user-search mb15">
-        <ext-query-form ref="queryRef" v-model="state.formQuery" :columns="state.columns" @on-change="loadData(true)"/>
-      </div>
 
-      <ext-table
-          :height="state.tableData.height"
-          :data-list="state.tableData.data"
-          :columns="state.columns"
-          :border="true"
-          :loading="state.tableData.loading">
-      </ext-table>
-
-      <ext-page v-model:value="state.pageQuery" @change="loadData(false)"/>
-    </el-card>
-  </div>
 </template>
 
-<script setup lang="ts" name="optLog">
-import {reactive, onMounted,nextTick,ref} from 'vue';
-import ExtPage from '/@/components/form/ExtPage.vue'
-import {$body} from "/@/utils/request";
-import u from '/@/utils/u'
-import ExtQueryForm from "/@/components/form/ExtQueryForm.vue";
-import ExtTable from "/@/components/form/ExtTable.vue";
-
-const queryRef = ref();
-// 定义变量内容
-const state = reactive({
-  tableData: {
-    data: [],
-    total: 0,
-    loading: false,
-    height:600
-  },
-  formQuery: {
-    nickName: null
-  },
-  pageQuery: {
-    pageIndex: 1,
-    pageSize: 20,
-    total: 0
-  },
-  columns: [
-    {label: '操作人', width: 100, query: true, prop: 'userName', type: 'text',fixed: 'left'},
-    {label: '操作时间', width: 180, query: true, prop: 'createAt', type: 'date', conf: {format: (val: any) => u.fmt.fmtDateTime(val)}},
-    {label: '操作实体', prop: 'model', query: true, type: 'text'},
-    {label: '操作IP', prop: 'ip', type: 'text', query: false},
-    {label: '操作接口', prop: 'method', query: true, type: 'text'},
-    {label: '操作描述', prop: 'title', query: true, type: 'text'},
-    {label: '结果描述', prop: 'result', query: true, type: 'dict', width:120,conf: {dict: 'Result.status'}, fixed: 'right'},
-  ] as Array<any>
-});
-
-// 初始化表格数据
-const loadData = (refresh: boolean = false) => {
-  if (refresh) {
-    state.pageQuery.pageIndex = 1;
-  }
-  state.tableData.loading = true;
-  $body(`/opLog/list`, {...state.formQuery, ...state.pageQuery}).then((res: any) => {
-    let {list, count} = res;
-    state.tableData.data = list;
-    state.tableData.loading = false;
-    state.pageQuery.total = count;
-  }).catch(e => {
-    console.error(e)
-    state.tableData.loading = false;
-  })
-};
-
-
-// 页面加载时
-onMounted(() => {
-  loadData();
-
-  nextTick(() => {
-    let bodyHeight = document.body.clientHeight;
-    let queryHeight = queryRef.value.$el.clientHeight;
-    state.tableData.height = bodyHeight - queryHeight - 220
-  })
-});
+<script>
+export default {
+  name: "index"
+}
 </script>
 
-<style scoped lang="scss">
-.system-container {
-  :deep(.el-card__body) {
-    display: flex;
-    flex-direction: column;
-    flex: 1;
-    overflow: auto;
+<style scoped>
 
-    .el-table {
-      flex: 1;
-    }
-  }
-}
-</style>
+</style>

+ 1 - 1
admin-web/src/views/error/401.vue

@@ -28,7 +28,7 @@ import { Session } from '/@/utils/storage';
 const onSetAuth = () => {
 	// https://gitee.com/lyt-top/vue-next-admin/issues/I5C3JS
 	// 清除缓存/token等
-	Session.clear();
+	// Session.clear();
 	// 使用 reload 时,不需要调用 resetRoute() 重置路由
 	window.location.reload();
 };

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

@@ -110,7 +110,7 @@ const encryptData = (str:string)=>{
 }
 
 const initData = () => {
-  $get("/dict/dictList", {}).then((res: any) => {
+  $body("/dataDict/list", {}).then((res: any) => {
     Session.set("dicts", res);
   });
 
@@ -126,13 +126,13 @@ const initData = () => {
       state.loading.signIn = false;
       ElNotification.success({
         title: 'Success',
-        message: "欢迎," + user.name,
+        message: "欢迎," + user.username,
         offset: 100,
       })
     }
   }).catch(err => {
     ElMessage.error("登录状态失效,请重新登录管理控制台");
-    Session.clear();
+    // Session.clear();
     state.loading.signIn = false;
   });
 }
@@ -155,26 +155,14 @@ const onSignIn = async () => {
     console.log(res)
     if (satoken) {
       // 存储 token 到浏览器缓存
-      debugger
       Session.set('token', satoken);
       Cookies.set('userId', id);
 
       initData();
-      refreshLogin();
+      // refreshLogin();
       state.loading.signIn = false;
 
-      //检验登录权限
-      if (!themeConfig.value.isRequestRoutes) {
-        // 前端控制路由,2、请注意执行顺序
-        // const isNoPower = await initFrontEndControlRoutes();
-        signInSuccess(false);
-      } else {
-        // 模拟后端控制路由,isRequestRoutes 为 true,则开启后端控制路由
-        // 添加完动态路由,再进行 router 跳转,否则可能报错 No match found for location with path "/"
-        // const isNoPower = await initBackEndControlRoutes();
-        // 执行完 initBackEndControlRoutes,再执行 signInSuccess
-        signInSuccess(false);
-      }
+      signInSuccess(false);
     } else {
       ElMessage.error(res.msg);
       state.loading.signIn = false;
@@ -202,7 +190,7 @@ const signInSuccess = (isNoPower: boolean | undefined) => {
         query: Object.keys(<string>route.query?.params).length > 0 ? JSON.parse(<string>route.query?.params) : '',
       });
     } else {
-      router.push('/admin');
+      router.push('/');
     }
     // 登录成功提示
     const signInText = t('message.signInText');

+ 3 - 3
admin-web/src/views/login/index.vue

@@ -30,11 +30,11 @@
 								</el-tab-pane>-->
 							</el-tabs>
 						</div>
-						<Scan v-if="state.isScan" />
-						<div class="login-content-main-sacn" @click="state.isScan = !state.isScan">
+<!--						<Scan v-if="state.isScan" />-->
+<!--						<div class="login-content-main-sacn" @click="state.isScan = !state.isScan">
 							<i class="iconfont" :class="state.isScan ? 'icon-diannao1' : 'icon-barcode-qr'"></i>
 							<div class="login-content-main-sacn-delta"></div>
-						</div>
+						</div>-->
 					</div>
 				</div>
 			</div>

+ 1 - 1
admin/src/main/java/com/kym/admin/controller/AdminUserController.java

@@ -42,7 +42,7 @@ public class AdminUserController extends IController {
     @SysLog("账号信息读取")
     @GetMapping("/profile")
     R<?> profile() {
-        return resp(() -> adminUserService.profile());
+        return resp(adminUserService::profile);
     }
 
 }

+ 59 - 0
admin/src/main/java/com/kym/admin/controller/DataDictController.java

@@ -0,0 +1,59 @@
+package com.kym.admin.controller;
+
+import com.kym.common.IQuery;
+import com.kym.common.R;
+import com.kym.common.controller.IController;
+import com.kym.entity.miniapp.DataDict;
+import com.kym.service.miniapp.DataDictService;
+import jakarta.annotation.Resource;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+
+/**
+ * <p>
+ * 数据字典 前端控制器
+ * </p>
+ * <ul>
+ *     <li>字典以常量形式定义在业务实体类中,业务逻辑以常量替代,取消魔法值</li>
+ *     <li>字典只提供查询接口,修改、新增由数据库DML执行实现</li>
+ *     <li>为保持与前端及关联系统一致,字典定义后不可修改,不可删除,可废弃</li>
+ * </ul>
+ *
+ * @author zuy
+ * @since 2023-08-13
+ */
+@RestController
+@RequestMapping("/dataDict")
+public class DataDictController extends IController {
+
+    @Resource
+    private DataDictService dataDictService;
+
+    /**
+     * 字典列表
+     *
+     * @param query
+     * @return
+     */
+    @PostMapping("list")
+    public R<?> list(@RequestBody IQuery<DataDict> query) {
+        return resp(() -> dataDictService.list(query));
+    }
+
+
+    /**
+     * 字典列表
+     *
+     * @param query
+     * @return
+     */
+    @PostMapping("listV2")
+    public R<?> listV2(@RequestBody IQuery<DataDict> query) {
+        return resp(() -> dataDictService.listV2(query));
+    }
+
+
+}

+ 18 - 1
service/src/main/java/com/kym/service/admin/impl/AdminUserServiceImpl.java

@@ -6,12 +6,17 @@ import cn.hutool.crypto.asymmetric.RSA;
 import cn.hutool.crypto.digest.DigestAlgorithm;
 import cn.hutool.crypto.digest.Digester;
 import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.kym.common.R;
 import com.kym.common.constant.ResponseEnum;
+import com.kym.common.utils.CommUtil;
 import com.kym.entity.admin.AdminUser;
+import com.kym.entity.admin.AdminUserRole;
 import com.kym.mapper.admin.AdminUserMapper;
+import com.kym.service.admin.AdminUserRoleService;
 import com.kym.service.admin.AdminUserService;
+import jakarta.annotation.Resource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Value;
@@ -19,6 +24,7 @@ import org.springframework.stereotype.Service;
 
 import java.nio.charset.StandardCharsets;
 import java.time.LocalDateTime;
+import java.util.List;
 import java.util.Map;
 
 
@@ -44,6 +50,9 @@ public class AdminUserServiceImpl extends ServiceImpl<AdminUserMapper, AdminUser
     private String publicKey;
 
 
+    @Resource
+    private AdminUserRoleService adminUserRoleService;
+
     @Override
     public R login(String mobilePhone, String password) {
         var user = lambdaQuery().eq(AdminUser::getMobilePhone, mobilePhone).one();
@@ -77,6 +86,14 @@ public class AdminUserServiceImpl extends ServiceImpl<AdminUserMapper, AdminUser
      */
     @Override
     public Object profile() {
-        return null;
+        long userId = CommUtil.null2Long(StpUtil.getSession().get("userId"));
+        AdminUser user = getById(userId);
+        user.setPassword(null);
+        user.setStatus(null);
+
+        QueryChainWrapper<AdminUserRole> wrapper = new QueryChainWrapper<>(AdminUserRole.class);
+        wrapper.eq("admin_user_id",userId);
+        List<AdminUserRole> list = wrapper.list();
+        return Map.of("user",user,"roles",list);
     }
 }