You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

392 lines
10 KiB

1 month ago
1 month ago
4 weeks ago
  1. <script setup>
  2. // 导航栏在这
  3. import {onMounted, ref} from 'vue'
  4. import {useRoute, useRouter} from 'vue-router'
  5. import {ElMessage} from 'element-plus'
  6. import API from '@/util/http'
  7. import dmmn from '../assets/link.png'
  8. import moment from 'moment'
  9. import ChangePassword from '@/components/changePassword.vue'
  10. // 获取当前路由实例
  11. const route = useRoute()
  12. // 存储接口返回的菜单数据
  13. const menuList = ref([])
  14. /**
  15. * 调用 /menu/tree 接口获取菜单数据
  16. */
  17. const fetchMenuTree = async function() {
  18. try {
  19. const result = await API({ url: '/menu/tree', data: {id: adminData.value.roleId} })
  20. return result.data // 直接返回接口响应数据
  21. } catch (error) {
  22. console.error('菜单数据请求失败:', error)
  23. return { code: 500, msg: '获取菜单失败' }
  24. }
  25. }
  26. function filterMenu(menuList) {
  27. return menuList
  28. .filter(menu => menu.menuType !== 4)
  29. .map(menu => ({
  30. ...menu,
  31. children: menu.children ? filterMenu(menu.children) : []
  32. }))
  33. .sort((a, b) => a.priority - b.priority); // 按 id 升序
  34. }
  35. /**
  36. * 映射菜单名称到路由路径
  37. */
  38. const getRoutePath = (menu) => {
  39. // 路由映射表:key为接口menuName,value为对应路由路径
  40. const routeMap = {
  41. '工作台': '/workspace',
  42. '财务审核': '/rechargeAudit',
  43. '充值审核': '/rechargeAudit',
  44. '退款审核': '/refundAudit',
  45. '汇率管理': '/rate',
  46. '消耗管理': '/coinConsume',
  47. '消耗页面': '/coinConsume',
  48. '权限管理': '/permissions',
  49. '充值管理': '/coinRecharge',
  50. '充值页面': '/coinRecharge',
  51. '退款管理': '/coinRefund',
  52. '退款页面': '/coinRefund',
  53. '客户账户明细': '/usergold',
  54. };
  55. // 未匹配的菜单默认使用id作为路由(可根据实际需求调整)
  56. return routeMap[menu.menuName] || '/workspace'
  57. }
  58. const router = useRouter()
  59. const imgrule1 = dmmn
  60. const messageVisible = ref(false)
  61. // 这是获取用户信息的接口
  62. const adminData = ref({
  63. name: ''
  64. })
  65. const getAdminData = async function () {
  66. try {
  67. const result = await API({ url: '/admin/userinfo', data: {} })
  68. adminData.value = result
  69. console.log('请求成功', result)
  70. console.log('用户信息', adminData.value)
  71. } catch (error) {
  72. console.log('请求失败', error)
  73. }
  74. }
  75. // 获取地区
  76. const areas = ref([])
  77. const currentArea = ref('全部')
  78. const getAreas = async function () {
  79. try {
  80. const result = await API({ url: '/general/adminMarkets', data: {
  81. account: adminData.value.account,
  82. } })
  83. areas.value = result.data
  84. console.log('请求成功', result)
  85. } catch (error) {
  86. console.log('请求失败', error)
  87. }
  88. }
  89. // 查看个人信息弹出框
  90. const openMessage = function () {
  91. messageVisible.value = true
  92. }
  93. const closeMessage = function () {
  94. messageVisible.value = false
  95. }
  96. const message = function () {
  97. openMessage()
  98. }
  99. // 导出列表数据
  100. const exportList = ref([])
  101. // 导出列表加载状态
  102. const exportListLoading = ref(false)
  103. //根据状态返回对应的标签类型
  104. const getTagType = (state) => {
  105. switch (state) {
  106. case 0:
  107. return 'info';
  108. case 1:
  109. return 'primary';
  110. case 2:
  111. return'success';
  112. case 3:
  113. return 'danger';
  114. default:
  115. return 'info';
  116. }
  117. }
  118. //根据状态返回对应的标签文案
  119. const getTagText = (state) => {
  120. switch (state) {
  121. case 0:
  122. return '待执行';
  123. case 1:
  124. return '执行中';
  125. case 2:
  126. return'执行完成';
  127. case 3:
  128. return '执行出错';
  129. default:
  130. return '未知状态';
  131. }
  132. }
  133. // 下载导出文件
  134. const downloadExportFile = (item) => {
  135. if (item.state === 2) {
  136. const link = document.createElement('a')
  137. link.href = item.url
  138. link.download = item.fileName
  139. link.click()
  140. } else {
  141. ElMessage.warning('文件还在导出中,请稍后再试')
  142. }
  143. }
  144. function logout() {
  145. const machineId = localStorage.getItem('machineId')
  146. localStorage.removeItem('token')
  147. router.push('/login?machineId=' + machineId)
  148. ElMessage.success('退出成功')
  149. }
  150. // 挂载
  151. onMounted(async function () {
  152. // 获取用户信息
  153. await getAdminData()
  154. const menus = await fetchMenuTree()
  155. menuList.value = filterMenu(menus)
  156. })
  157. // 处理地区点击事件,直接在组件内更新当前地区,包老师改的,直接传参
  158. const changeDataByArea = (item) => {
  159. currentArea.value = item
  160. }
  161. // 控制导出列表弹窗显示状态
  162. const exportListVisible = ref(false)
  163. // 显示修改密码弹窗
  164. const showPasswordDialog = ref(false)
  165. // 打开导出列表弹窗
  166. const openExportList = () => {
  167. getExportList()
  168. exportListVisible.value = true
  169. }
  170. //打开修改密码弹窗
  171. const openChangePassword = () => {
  172. showPasswordDialog.value = true
  173. }
  174. </script>
  175. <template>
  176. <div class="common-layout">
  177. <el-container>
  178. <el-aside style="
  179. width: 15%;
  180. min-width: 180px;
  181. position: fixed; /* 固定位置 */
  182. top: 0;
  183. left: 0;
  184. height: 100vh; /* 高度占满视口 */
  185. z-index: 100; /* 确保侧边栏在其他元素之上 */
  186. ">
  187. <div class="logo">
  188. <img src="../assets/新logo.png" alt="logo" style="width: 80px; height: 80px" />
  189. <!-- <div style="font-size: 16px; font-weight: bold; color: black; text-align: center;" ><h1>海外金币管理系统</h1></div> -->
  190. </div>
  191. <el-card style="min-height: 90%;">
  192. <el-menu
  193. :router="true"
  194. class="el-menu-vertical-demo"
  195. :default-active="$route.path"
  196. >
  197. <!-- 递归渲染菜单层级 -->
  198. <template v-for="menu in menuList" :key="menu.id">
  199. <!-- 有子菜单的父级菜单menuType=2 且存在children -->
  200. <el-sub-menu
  201. v-if="menu.children && menu.children.length > 0"
  202. :index="menu.id.toString()"
  203. >
  204. <template #title>
  205. <el-icon><Folder /></el-icon>
  206. <span>{{ menu.menuName }}</span>
  207. </template>
  208. <!-- 子菜单 -->
  209. <template v-for="child in menu.children" :key="child.id">
  210. <!-- 子菜单为叶子节点无children -->
  211. <el-menu-item
  212. v-if="!child.children || child.children.length === 0"
  213. :index="getRoutePath(child)"
  214. >
  215. <span>{{ child.menuName }}</span>
  216. </el-menu-item>
  217. <!-- 子菜单有下级 -->
  218. <el-sub-menu
  219. v-else
  220. :index="child.id.toString()"
  221. >
  222. <template #title>
  223. <span>{{ child.menuName }}</span>
  224. </template>
  225. <!-- 嵌归 下一级-->
  226. <template v-for="grandChild in child.children" :key="grandChild.id">
  227. <el-menu-item :index="getRoutePath(grandChild)">
  228. <span>{{ grandChild.menuName }}</span>
  229. </el-menu-item>
  230. </template>
  231. </el-sub-menu>
  232. </template>
  233. </el-sub-menu>
  234. <!-- 无子菜单的一级菜单 -->
  235. <el-menu-item
  236. v-else
  237. :index="getRoutePath(menu)"
  238. >
  239. <el-icon><Folder /></el-icon>
  240. <span>{{ menu.menuName }}</span>
  241. </el-menu-item>
  242. </template>
  243. </el-menu>
  244. </el-card>
  245. </el-aside>
  246. <el-container style="margin-left: 15%; min-width: 180px">
  247. <!-- 修改 el-header 样式 -->
  248. <el-header style="
  249. position: fixed;
  250. top: 0;
  251. left: 15%;
  252. right: 0;
  253. z-index: 80;
  254. background: white;
  255. ">
  256. <el-menu class="el-menu-demo" mode="horizontal" :ellipsis="false">
  257. <el-sub-menu index="1" class="admin">
  258. <template #title>
  259. <el-image :src="imgrule1" alt="错误" style="width: 50px; height: 50px" />
  260. <span style="margin-left: 10px">{{ adminData.name }}</span>
  261. </template>
  262. <el-menu-item @click="message()">查看个人信息</el-menu-item>
  263. <el-menu-item @click="openChangePassword">修改密码</el-menu-item>
  264. <el-menu-item @click="logout">退出登录</el-menu-item>
  265. </el-sub-menu>
  266. </el-menu>
  267. </el-header>
  268. <el-main style="margin-top: 60px">
  269. <!-- 60px el-header 的大致高度可根据实际情况调整 -->
  270. <router-view></router-view>
  271. </el-main>
  272. </el-container>
  273. </el-container>
  274. <!-- 查看个人信息 -->
  275. <el-dialog v-model="messageVisible" title="查看个人信息" width="500px">
  276. <el-form :model="adminData">
  277. <el-form-item label="用户姓名" label-width="100px" label-position="left">
  278. <span class="message-font">{{ adminData.adminName }}</span>
  279. </el-form-item>
  280. <el-form-item label="精网号" label-width="100px" label-position="left">
  281. <span class="message-font">{{ adminData.account }}</span>
  282. </el-form-item>
  283. <el-form-item label="地区" label-width="100px" label-position="left">
  284. <span class="message-font">{{ adminData.markets }}</span>
  285. </el-form-item>
  286. <el-form-item label="注册时间" label-width="100px" label-position="left">
  287. <span class="message-font">{{ adminData.createTime }}</span>
  288. </el-form-item>
  289. </el-form>
  290. <template #footer>
  291. <div class="dialog-footer">
  292. <el-button text @click="closeMessage()">关闭</el-button>
  293. </div>
  294. </template>
  295. </el-dialog>
  296. <!-- 自定义密码修改弹窗组件 -->
  297. <el-dialog
  298. v-model="showPasswordDialog"
  299. :center="true"
  300. width="470px"
  301. >
  302. <ChangePassword @confirm="showPasswordDialog = false"/>
  303. </el-dialog>
  304. </div>
  305. </template>
  306. <style scoped>
  307. .message-font {
  308. font-size: 16px;
  309. font-weight: bold;
  310. }
  311. .item {
  312. margin-top: 20px;
  313. margin-right: 40px;
  314. }
  315. .admin {
  316. margin-left: auto;
  317. }
  318. .el-aside {
  319. min-height: 100vh;
  320. width: 200px;
  321. }
  322. /* background-color: #BFD8D2; */
  323. .logo {
  324. margin: 20px 0px 20px 20px;
  325. display: flex;
  326. }
  327. .el-menu-demo {
  328. border: none;
  329. /* 去除边框 */
  330. padding: 0;
  331. /* 去除内边距 */
  332. float: right;
  333. /* 将菜单向右浮动 */
  334. }
  335. .el-menu-vertical-demo:not(.el-menu--collapse) {
  336. width: 240px;
  337. min-height: 400px;
  338. border: none;
  339. /* 去除边框 */
  340. }
  341. </style>