create-jnrs-template-vue 1.1.4 → 1.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/jnrs-template-vue/.prettierrc.json +1 -1
  2. package/jnrs-template-vue/auto-imports.d.ts +1 -0
  3. package/jnrs-template-vue/components.d.ts +11 -2
  4. package/jnrs-template-vue/package.json +18 -17
  5. package/jnrs-template-vue/public/system/menu.json +29 -9
  6. package/jnrs-template-vue/src/App.vue +36 -5
  7. package/jnrs-template-vue/src/api/{base → system}/index.ts +30 -6
  8. package/jnrs-template-vue/src/assets/styles/init.scss +8 -3
  9. package/jnrs-template-vue/src/assets/styles/root.scss +7 -24
  10. package/jnrs-template-vue/src/layout/RouterTabs.vue +5 -4
  11. package/jnrs-template-vue/src/layout/SideMenu.vue +29 -20
  12. package/jnrs-template-vue/src/layout/SideMenuItem.vue +1 -1
  13. package/jnrs-template-vue/src/layout/TopHeader.vue +30 -19
  14. package/jnrs-template-vue/src/layout/index.vue +36 -6
  15. package/jnrs-template-vue/src/locales/en.ts +9 -0
  16. package/jnrs-template-vue/src/locales/index.ts +16 -0
  17. package/jnrs-template-vue/src/locales/zhCn.ts +9 -0
  18. package/jnrs-template-vue/src/main.ts +5 -1
  19. package/jnrs-template-vue/src/router/index.ts +10 -4
  20. package/jnrs-template-vue/src/types/index.d.ts +6 -0
  21. package/jnrs-template-vue/src/utils/common.ts +58 -0
  22. package/jnrs-template-vue/src/views/common/403.vue +2 -2
  23. package/jnrs-template-vue/src/views/common/404.vue +2 -2
  24. package/jnrs-template-vue/src/views/home/index.vue +6 -3
  25. package/jnrs-template-vue/src/views/login/index.vue +15 -26
  26. package/jnrs-template-vue/src/views/system/dict/index.vue +176 -0
  27. package/jnrs-template-vue/src/views/system/menu/index.vue +67 -0
  28. package/jnrs-template-vue/src/views/system/mine/baseInfo.vue +38 -30
  29. package/jnrs-template-vue/src/views/system/mine/securitySettings.vue +22 -31
  30. package/jnrs-template-vue/src/views/system/role/editDialog.vue +94 -0
  31. package/jnrs-template-vue/src/views/system/role/index.vue +30 -3
  32. package/jnrs-template-vue/src/views/visual/index.vue +6 -1
  33. package/jnrs-template-vue/vite.config.ts +6 -4
  34. package/jnrs-template-vue/viteMockServe/dictItemRes.json +27 -0
  35. package/jnrs-template-vue/viteMockServe/dictRes.json +141 -0
  36. package/jnrs-template-vue/viteMockServe/fail.ts +26 -0
  37. package/jnrs-template-vue/viteMockServe/index.ts +18 -25
  38. package/jnrs-template-vue/viteMockServe/{login.json → loginRes.json} +1 -0
  39. package/jnrs-template-vue/viteMockServe/success.ts +31 -0
  40. package/package.json +1 -1
  41. package/jnrs-template-vue/src/types/index.ts +0 -1
  42. package/jnrs-template-vue/src/views/system/user/index.vue +0 -9
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "semi": false,
3
3
  "singleQuote": true,
4
- "printWidth": 100,
4
+ "printWidth": 120,
5
5
  "tabWidth": 2,
6
6
  "useTabs": false,
7
7
  "trailingComma": "none",
@@ -6,5 +6,6 @@
6
6
  // biome-ignore lint: disable
7
7
  export {}
8
8
  declare global {
9
+ const ElMessage: typeof import('element-plus/es').ElMessage
9
10
  const ElMessageBox: typeof import('element-plus/es').ElMessageBox
10
11
  }
@@ -17,22 +17,31 @@ declare module 'vue' {
17
17
  ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
18
18
  ElCard: typeof import('element-plus/es')['ElCard']
19
19
  ElCascader: typeof import('element-plus/es')['ElCascader']
20
- ElCol: typeof import('element-plus/es')['ElCol']
20
+ ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
21
21
  ElContainer: typeof import('element-plus/es')['ElContainer']
22
+ ElDatePickerPanel: typeof import('element-plus/es')['ElDatePickerPanel']
23
+ ElDialog: typeof import('element-plus/es')['ElDialog']
22
24
  ElForm: typeof import('element-plus/es')['ElForm']
23
25
  ElFormItem: typeof import('element-plus/es')['ElFormItem']
24
26
  ElHeader: typeof import('element-plus/es')['ElHeader']
25
27
  ElIcon: typeof import('element-plus/es')['ElIcon']
26
28
  ElInput: typeof import('element-plus/es')['ElInput']
29
+ ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
27
30
  ElMain: typeof import('element-plus/es')['ElMain']
28
31
  ElMenu: typeof import('element-plus/es')['ElMenu']
29
32
  ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
33
+ ElOption: typeof import('element-plus/es')['ElOption']
30
34
  ElPopover: typeof import('element-plus/es')['ElPopover']
31
- ElRow: typeof import('element-plus/es')['ElRow']
35
+ ElSelect: typeof import('element-plus/es')['ElSelect']
32
36
  ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
37
+ ElSwitch: typeof import('element-plus/es')['ElSwitch']
38
+ ElTable: typeof import('element-plus/es')['ElTable']
39
+ ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
33
40
  ElTabPane: typeof import('element-plus/es')['ElTabPane']
34
41
  ElTabs: typeof import('element-plus/es')['ElTabs']
42
+ ElTag: typeof import('element-plus/es')['ElTag']
35
43
  ElUpload: typeof import('element-plus/es')['ElUpload']
44
+ ElWatermark: typeof import('element-plus/es')['ElWatermark']
36
45
  }
37
46
  export interface GlobalDirectives {
38
47
  vLoading: typeof import('element-plus/es')['ElLoadingDirective']
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jnrs-template-vue",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
4
4
  "description": "JNRS 信息化管理系统模板",
5
5
  "author": "Talia-Tan",
6
6
  "private": true,
@@ -22,32 +22,33 @@
22
22
  "@jnrs/core": "*",
23
23
  "@jnrs/shared": "*",
24
24
  "@jnrs/vue-core": "*",
25
- "element-plus": "^2.11.4",
26
- "pinia": "^3.0.3",
27
- "pinia-plugin-persistedstate": "^4.5.0",
28
- "vue": "^3.5.22"
25
+ "element-plus": "^2.11.9",
26
+ "pinia": "^3.0.4",
27
+ "pinia-plugin-persistedstate": "^4.7.1",
28
+ "vue": "^3.5.25",
29
+ "vue-i18n": "^9.14.5"
29
30
  },
30
31
  "devDependencies": {
31
- "@tsconfig/node22": "^22.0.2",
32
- "@types/node": "^22.18.6",
33
- "@typescript-eslint/parser": "^8.46.2",
34
- "@vitejs/plugin-vue": "^6.0.1",
32
+ "@tsconfig/node22": "^22.0.5",
33
+ "@types/node": "^22.19.1",
34
+ "@typescript-eslint/parser": "^8.48.1",
35
+ "@vitejs/plugin-vue": "^6.0.2",
35
36
  "@vue/eslint-config-prettier": "^10.2.0",
36
37
  "@vue/eslint-config-typescript": "^14.6.0",
37
38
  "@vue/tsconfig": "^0.8.1",
38
- "eslint": "^9.33.0",
39
+ "eslint": "^9.39.1",
39
40
  "eslint-plugin-vue": "~10.4.0",
40
- "jiti": "^2.5.1",
41
+ "jiti": "^2.6.1",
41
42
  "npm-run-all2": "^8.0.4",
42
43
  "prettier": "3.6.2",
43
44
  "sass": "^1.94.2",
44
- "typescript": "~5.9.0",
45
- "unplugin-auto-import": "^20.2.0",
46
- "unplugin-vue-components": "^29.1.0",
47
- "vite": "^7.1.7",
45
+ "typescript": "~5.9.3",
46
+ "unplugin-auto-import": "^20.3.0",
47
+ "unplugin-vue-components": "^29.2.0",
48
+ "vite": "^7.2.2",
48
49
  "vite-plugin-compression": "^0.5.1",
49
50
  "vite-plugin-mock": "^3.0.2",
50
- "vite-plugin-vue-devtools": "^8.0.2",
51
- "vue-tsc": "^3.1.0"
51
+ "vite-plugin-vue-devtools": "^8.0.5",
52
+ "vue-tsc": "^3.1.5"
52
53
  }
53
54
  }
@@ -27,7 +27,8 @@
27
27
  "meta": {
28
28
  "title": "系统管理",
29
29
  "icon": "Tools",
30
- "todoCount": 99
30
+ "todoCount": 99,
31
+ "permissions": ["system:view"]
31
32
  },
32
33
  "children": [
33
34
  {
@@ -35,8 +36,8 @@
35
36
  "name": "SystemMine",
36
37
  "meta": {
37
38
  "title": "个人中心",
38
- "icon": "User",
39
- "todoCount": 99
39
+ "todoCount": 99,
40
+ "permissions": ["mine:view", "mine:edit"]
40
41
  },
41
42
  "component": "/system/mine/index"
42
43
  },
@@ -45,19 +46,38 @@
45
46
  "name": "SystemUser",
46
47
  "meta": {
47
48
  "title": "用户管理",
48
- "icon": "User",
49
- "todoCount": 0
49
+ "todoCount": 0,
50
+ "permissions": ["user:view", "user:edit"]
50
51
  },
51
- "component": "/system/user/index"
52
+ "component": "/system/user/index",
53
+ "redirect": "/crud"
52
54
  },
53
55
  {
54
56
  "path": "/system/role",
55
57
  "name": "SystemRole",
56
58
  "meta": {
57
- "title": "(redirect test)"
59
+ "title": "角色管理",
60
+ "permissions": ["role:view", "role:edit"]
58
61
  },
59
- "component": "/system/role/index",
60
- "redirect": "/crud"
62
+ "component": "/system/role/index"
63
+ },
64
+ {
65
+ "path": "/system/dict",
66
+ "name": "SystemDict",
67
+ "meta": {
68
+ "title": "字典管理",
69
+ "permissions": ["dict:view", "dict:edit"]
70
+ },
71
+ "component": "/system/dict/index"
72
+ },
73
+ {
74
+ "path": "/system/menu",
75
+ "name": "SystemMenu",
76
+ "meta": {
77
+ "title": "菜单管理",
78
+ "permissions": ["menu:view", "menu:edit"]
79
+ },
80
+ "component": "/system/menu/index"
61
81
  }
62
82
  ]
63
83
  }
@@ -1,14 +1,45 @@
1
1
  <script setup lang="ts">
2
- console.log(
3
- '%cPowered by 🅹🅽🆁🆂 TECH',
4
- `background: #f2f2c1;
2
+ import { onMounted, watch } from 'vue'
3
+ import { useSystemStore } from '@/stores'
4
+ import { ElConfigProvider } from 'element-plus'
5
+ import zhCn from 'element-plus/es/locale/lang/zh-CN'
6
+ import en from 'element-plus/es/locale/lang/en'
7
+ import { useI18n } from 'vue-i18n'
8
+ import { changeLocales as changeLocalesForShared } from '@jnrs/shared/locales'
9
+ import { changeLocales as changeLocalesForCore } from '@jnrs/core/locales'
10
+
11
+ const { locale } = useI18n()
12
+ const { theme } = useSystemStore()
13
+ watch(
14
+ () => theme.locale,
15
+ (newValue) => {
16
+ locale.value = newValue
17
+ changeLocalesForShared(newValue)
18
+ changeLocalesForCore(newValue)
19
+ },
20
+ {
21
+ immediate: true
22
+ }
23
+ )
24
+ const localeMap = {
25
+ zhCn: zhCn,
26
+ en: en
27
+ }
28
+
29
+ onMounted(() => {
30
+ console.log(
31
+ '%cPowered by 🅹🅽🆁🆂 TECH',
32
+ `background: #f2f2c1;
5
33
  color: #d15f2c;
6
34
  font-weight: bold;
7
35
  padding: 0 8px;
8
36
  font-family: 'Helvetica Neue', sans-serif;`
9
- )
37
+ )
38
+ })
10
39
  </script>
11
40
 
12
41
  <template>
13
- <router-view></router-view>
42
+ <el-config-provider :locale="localeMap[theme.locale]">
43
+ <router-view></router-view>
44
+ </el-config-provider>
14
45
  </template>
@@ -1,6 +1,5 @@
1
1
  import { request } from '../request'
2
- import type { Dict } from '@/types'
3
- import type { User } from '@/types'
2
+ import type { Dict, DictItem, User } from '@jnrs/shared'
4
3
  import type { MenuItem } from '@jnrs/vue-core'
5
4
 
6
5
  // 登录结果
@@ -16,8 +15,8 @@ interface PasswordChange {
16
15
  }
17
16
 
18
17
  // 菜单
19
- export const MenuApi = () => {
20
- return request<MenuItem[]>({
18
+ export const MenuApi = (): Promise<MenuItem[]> => {
19
+ return request({
21
20
  url: '/system/menu.json', // /public 文件夹下
22
21
  mockUrl: '/mock/menu',
23
22
  method: 'get'
@@ -48,14 +47,14 @@ export const LogoutApi = () => {
48
47
  }
49
48
 
50
49
  // 获取用户信息
51
- export const UserInfoApi = () => {
50
+ export const UserInfoApi = (): Promise<User> => {
52
51
  return request({
53
52
  url: '/api/auth/user-info',
54
53
  method: 'get'
55
54
  })
56
55
  }
57
56
 
58
- //修改密码
57
+ // 修改密码
59
58
  export const PasswordChangeApi = (data: PasswordChange) => {
60
59
  return request({
61
60
  url: '/api/auth/change-password',
@@ -63,3 +62,28 @@ export const PasswordChangeApi = (data: PasswordChange) => {
63
62
  data
64
63
  })
65
64
  }
65
+
66
+ // 获取字典列表
67
+ export const DictApi = (): Promise<DictItem[]> => {
68
+ return request({
69
+ url: '/api/dict-manager',
70
+ method: 'get'
71
+ })
72
+ }
73
+
74
+ // 获取单个字典
75
+ export const DictDetailApi = (id: string) => {
76
+ return request({
77
+ url: `/api/dict-manager/detail/${id}`,
78
+ method: 'get'
79
+ })
80
+ }
81
+
82
+ // 修改单个字典
83
+ export const DictChangeApi = (data: DictItem) => {
84
+ return request({
85
+ url: '/api/dict-manager/detail',
86
+ method: 'post',
87
+ data
88
+ })
89
+ }
@@ -1,8 +1,8 @@
1
1
  *,
2
2
  *::before,
3
3
  *::after {
4
- box-sizing: border-box;
5
4
  margin: 0;
5
+ box-sizing: border-box;
6
6
  font-family: Alibaba-PuHuiTi-Regular;
7
7
  }
8
8
 
@@ -14,8 +14,13 @@ a {
14
14
  input:-webkit-autofill,
15
15
  input:-webkit-autofill:hover,
16
16
  input:-webkit-autofill:focus,
17
- input:-webkit-autofill:active {
18
- -webkit-box-shadow: 0 0 0 1000px var(--input-bg, #fff) inset !important;
17
+ input:-webkit-autofill:active,
18
+ input:autofill,
19
+ input:-webkit-autofill-strong-password,
20
+ input:-webkit-autofill-strong-password-viewable,
21
+ input:-webkit-autofill-and-obscured {
22
+ -webkit-box-shadow: 0 0 0 1000px rgba(255, 0, 0, 0) inset !important;
23
+ background-color: rgb(255, 0, 0) !important;
19
24
  }
20
25
 
21
26
  /*
@@ -1,29 +1,12 @@
1
- /* 默认样式(浅色模式) */
2
1
  :root {
3
- // 业务相关
4
- // --jnrs-color-primary: oklch(0.6 0.19 41); // jnrs 橙
5
- --jnrs-color-primary: oklch(0.51 0.21 264); // 蔚蓝
6
- --jnrs-color-primary-06: oklch(from var(--jnrs-color-primary) l c h / 0.6);
7
- --jnrs-color-primary-light: oklch(from var(--jnrs-color-primary) calc(l + 0.1) c h);
8
-
9
- // 状态相关
10
- --jnrs-color-success: oklch(0.8 0.17 147);
11
- --jnrs-color-error: oklch(0.65 0.24 33);
12
-
13
- // 框架相关
14
- --jnrs-font-primary: oklch(0.3 0.01 264);
15
- --jnrs-font-primary-06: oklch(from var(--jnrs-font-primary) l c h / 0.6);
16
- --jnrs-card-primary: oklch(1 0 0);
17
- --jnrs-background-primary: oklch(0.96 0 0);
2
+ // Layout 头部高度
18
3
  --jnrs-head-height: 50px;
4
+ --jnrs-routerTabs-height: 30px;
19
5
 
20
- // element-ui
21
- --el-menu-base-level-padding: 8px !important;
6
+ // // element-ui 样式
7
+ // --el-menu-base-level-padding: 8px !important;
22
8
  }
23
9
 
24
- /* 深色模式 */
25
- // @media (prefers-color-scheme: dark) {
26
- // :root {
27
- // --jnrs-background-primary: oklch(0 0 0);
28
- // }
29
- // }
10
+ .el-button--primary {
11
+ --el-button-bg-color: var(--jnrs-color-primary);
12
+ }
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import { ref, watch, computed, onMounted } from 'vue'
3
3
  import type { TabsPaneContext } from 'element-plus'
4
- import type { MenuItem } from '@/types'
4
+ import type { MenuItem } from '@jnrs/vue-core'
5
5
  import { handleRouter, getRoutes, useRoute } from '@jnrs/vue-core/router'
6
6
 
7
7
  // 初始化时添加当前路由
@@ -126,20 +126,21 @@ const handleTabClick = (tab: TabsPaneContext) => {
126
126
  z-index: 5;
127
127
  :deep(.el-tabs__header) {
128
128
  margin-bottom: 0;
129
- height: 32px;
129
+ height: var(--jnrs-routerTabs-height);
130
130
  }
131
131
  :deep(.el-tabs__item) {
132
132
  color: var(--jnrs-font-primary-06);
133
133
  font-size: 12px;
134
- height: 32px;
134
+ height: var(--jnrs-routerTabs-height);
135
135
  }
136
136
  :deep(.el-tabs__item.is-active) {
137
137
  color: var(--jnrs-color-primary);
138
- border-bottom-color: var(--jnrs-background-primary);
138
+ border-bottom-color: var(--jnrs-color-primary);
139
139
  }
140
140
  :deep(.el-tabs__nav) {
141
141
  border-radius: 0;
142
142
  border-left: none;
143
+ border-top: none;
143
144
  }
144
145
  :deep(.el-tabs__nav-prev) {
145
146
  color: var(--jnrs-color-primary);
@@ -3,7 +3,9 @@ import SideMenuItem from './SideMenuItem.vue'
3
3
  import { storeToRefs } from 'pinia'
4
4
  import { useRoute } from '@jnrs/vue-core/router'
5
5
  import { useSystemStore, useMenuStore } from '@/stores'
6
+ import { useI18n } from 'vue-i18n'
6
7
 
8
+ const { t } = useI18n()
7
9
  const systemStore = useSystemStore()
8
10
  const { menuCollapse } = storeToRefs(systemStore)
9
11
  const { toggleCollapse } = systemStore
@@ -15,8 +17,8 @@ const route = useRoute()
15
17
  <template>
16
18
  <el-aside class="sideMenu">
17
19
  <div class="logo" :class="{ logo_collapse: menuCollapse }">
18
- <span class="logo_text">信息化管理系统模板</span>
19
20
  <img class="logo_img" src="@/assets/images/common/jnrs-white.svg" alt="jnrs" />
21
+ <span class="logo_text">{{ t('main.title') }}</span>
20
22
  </div>
21
23
  <el-icon
22
24
  class="collapseBtn"
@@ -40,26 +42,30 @@ const route = useRoute()
40
42
  </template>
41
43
 
42
44
  <style lang="scss" scoped>
45
+ $mainFontColor: rgba(255, 255, 255, 0.8);
46
+
43
47
  .sideMenu {
44
48
  position: relative;
45
- z-index: 10;
49
+ z-index: 20;
46
50
  width: auto;
47
51
  height: 100%;
48
52
  padding: 0 8px;
49
- background: rgba(30, 30, 30, 1);
50
- box-shadow: 2px 0 2px rgba(0, 0, 0, 0.3);
53
+ background: oklch(0.24 0 0);
54
+ // background: var(--jnrs-card-primary);
55
+ box-shadow: 1px 0 1px var(--jnrs-font-primary-03);
51
56
  overflow-x: hidden;
57
+ color: $mainFontColor;
52
58
 
53
59
  .logo {
54
60
  position: relative;
55
- height: var(--jnrs-head-height);
61
+ height: calc(var(--jnrs-head-height) + var(--jnrs-routerTabs-height));
62
+ border-bottom: 1px solid rgb(248 248 248 / 15%);
56
63
 
57
64
  .logo_text {
58
65
  position: absolute;
59
- top: 50%;
66
+ bottom: 0;
60
67
  left: 50%;
61
68
  color: rgba(255, 255, 255, 1);
62
- font-size: 20px;
63
69
  font-weight: normal;
64
70
  font-family: AlimamaShuHeiTi-Bold;
65
71
  white-space: nowrap;
@@ -70,22 +76,23 @@ const route = useRoute()
70
76
 
71
77
  .logo_img {
72
78
  position: absolute;
73
- top: 50%;
79
+ top: 0;
74
80
  left: 50%;
75
- width: 100%;
76
- transform: translate(-50%, -50%);
81
+ width: 80%;
82
+ transform: translate(-50%, 50%);
77
83
  transition: all 0.3s ease;
78
- filter: opacity(0);
79
84
  }
80
85
  }
81
86
 
82
87
  .logo_collapse {
83
88
  .logo_text {
84
89
  transform: translate(-50%, -50%) scale(0);
85
- filter: opacity(0);
90
+ opacity: 0;
86
91
  }
87
92
  .logo_img {
88
- filter: opacity(1);
93
+ width: 100%;
94
+ top: 50%;
95
+ transform: translate(-50%, -50%);
89
96
  }
90
97
  }
91
98
 
@@ -93,7 +100,7 @@ const route = useRoute()
93
100
  position: absolute;
94
101
  bottom: 10px;
95
102
  font-size: 24px;
96
- color: #fff;
103
+ color: $mainFontColor;
97
104
  padding: 4px;
98
105
  border-radius: 50%;
99
106
  background-color: #424242;
@@ -130,8 +137,8 @@ const route = useRoute()
130
137
  .leftSide_menu {
131
138
  border: none;
132
139
  min-width: 180px;
133
- --el-menu-text-color: #f2f2f2;
134
- --el-menu-active-color: #f2f2f2;
140
+ --el-menu-text-color: $mainFontColor;
141
+ --el-menu-active-color: $mainFontColor;
135
142
  --el-menu-bg-color: none;
136
143
 
137
144
  :deep(.el-menu-item) {
@@ -150,7 +157,7 @@ const route = useRoute()
150
157
 
151
158
  :deep(.el-menu-item.is-active) {
152
159
  background: var(--jnrs-color-primary) !important;
153
- color: #f2f2f2 !important;
160
+ color: $mainFontColor !important;
154
161
  }
155
162
 
156
163
  .el-menu-item.is-active {
@@ -166,11 +173,13 @@ const route = useRoute()
166
173
  </style>
167
174
 
168
175
  <style lang="scss">
176
+ $mainFontColor: rgba(255, 255, 255, 0.8);
177
+
169
178
  // 弹出层样式
170
179
  .layoutPage_leftSide_menu_popper {
171
180
  background: #051524;
172
181
  border: none !important;
173
- left: 65px !important;
182
+ left: 74px !important;
174
183
  border-radius: 15px;
175
184
  padding: 0 10px;
176
185
  .el-menu {
@@ -179,7 +188,7 @@ const route = useRoute()
179
188
  .el-menu-item {
180
189
  border-radius: 10px;
181
190
  background-color: none;
182
- color: #f2f2f2;
191
+ color: $mainFontColor;
183
192
  &:hover {
184
193
  color: var(--jnrs-color-primary);
185
194
  background: none;
@@ -193,7 +202,7 @@ const route = useRoute()
193
202
  .el-menu-item.is-active {
194
203
  border-radius: 10px;
195
204
  background: var(--jnrs-color-primary);
196
- color: #f2f2f2;
205
+ color: $mainFontColor;
197
206
  }
198
207
  }
199
208
  </style>
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { useSystemStore } from '@/stores'
3
- import type { MenuItem } from '@/types'
3
+ import type { MenuItem } from '@jnrs/vue-core'
4
4
 
5
5
  defineProps<{
6
6
  listItem: MenuItem
@@ -1,17 +1,24 @@
1
1
  <script setup lang="ts">
2
+ import { GlobalSetting } from '@jnrs/vue-core/components'
3
+ import { ref, computed } from 'vue'
2
4
  import { storeToRefs } from 'pinia'
3
5
  import { ElMessageBox } from 'element-plus'
4
6
  import { handleRouter } from '@jnrs/vue-core/router'
5
7
  import { useSystemStore, useAuthStore } from '@/stores'
6
8
  import { useAvatar } from '@/composables/common/useAvatar'
7
- import { LogoutApi } from '@/api/base/index'
9
+ import { LogoutApi } from '@/api/system'
10
+ import { getDictLabel, getDictColor } from '@/utils/common'
8
11
 
9
12
  const { avatar } = useAvatar()
10
13
  const { userInfo, asyncClearAuth } = useAuthStore()
11
14
 
15
+ const roleLabel = computed(() => getDictLabel('role', userInfo?.role || ''))
16
+ const roleColor = computed(() => getDictColor('role', userInfo?.role || ''))
17
+
12
18
  const systemStore = useSystemStore()
13
19
  const { documentFullscreen } = storeToRefs(systemStore)
14
20
  const { toggleFullScreen } = systemStore
21
+ const globalSettingRef = ref()
15
22
 
16
23
  const handleLogout = async () => {
17
24
  try {
@@ -25,6 +32,10 @@ const handleLogout = async () => {
25
32
  handleRouter({ name: 'Login' }, 'replace')
26
33
  } catch {}
27
34
  }
35
+
36
+ const showGlobalSetting = () => {
37
+ globalSettingRef.value.handleShow()
38
+ }
28
39
  </script>
29
40
 
30
41
  <template>
@@ -39,38 +50,35 @@ const handleLogout = async () => {
39
50
  })
40
51
  "
41
52
  >
42
- <component :is="'Platform'" />
53
+ <el-icon><Platform /></el-icon>
43
54
  </el-icon>
44
55
  </div>
45
56
  <div class="right">
57
+ <el-icon class="btn" title="全屏切换" @click="showGlobalSetting()">
58
+ <el-icon><Setting /></el-icon>
59
+ </el-icon>
46
60
  <el-icon class="btn" title="全屏切换" @click="toggleFullScreen()">
47
61
  <component :is="!documentFullscreen ? 'FullScreen' : 'Rank'" />
48
62
  </el-icon>
49
63
  <!-- 头像和用户名 -->
50
- <el-popover
51
- placement="bottom"
52
- trigger="click"
53
- :teleported="false"
54
- :width="260"
55
- :hide-after="0"
56
- >
64
+ <el-popover placement="bottom" trigger="click" :teleported="false" :width="260" :hide-after="0">
57
65
  <template #reference>
58
66
  <span class="userMenu_reference">
59
67
  <img class="userMenu_avatar" :src="avatar" alt="avatar" />
60
- <span>{{ userInfo.name }}</span>
61
- <span class="userMenu_roleName" v-if="userInfo.role">[{{ userInfo.role }}]</span>
68
+ <span>{{ userInfo?.name }}</span>
69
+ <span class="userMenu_roleName" :style="{ color: roleColor }" v-if="userInfo?.role">[{{ roleLabel }}]</span>
62
70
  <el-icon class="userMenu_icon"><arrow-down /></el-icon>
63
71
  </span>
64
72
  </template>
65
73
  <div class="userMenu_dropdown">
66
74
  <img class="userMenu_dropdown_avatar" :src="avatar" alt="avatar" />
67
75
  <b>
68
- {{ userInfo.name }}
69
- <span class="userMenu_roleName" v-if="userInfo.role">[{{ userInfo.role }}]</span>
76
+ {{ userInfo?.name }}
77
+ <span class="userMenu_roleName" :style="{ color: roleColor }" v-if="userInfo?.role">[{{ roleLabel }}]</span>
70
78
  </b>
71
- <div class="loginDateTime">
79
+ <div class="loginDateTime" v-if="userInfo?.loginDateTime">
72
80
  <span>登录时间</span>
73
- <p>{{ userInfo.loginDateTime }}</p>
81
+ <p>{{ userInfo?.loginDateTime }}</p>
74
82
  </div>
75
83
  <div class="userMenu_dropdown_btn">
76
84
  <el-button
@@ -84,14 +92,13 @@ const handleLogout = async () => {
84
92
  >
85
93
  个人中心
86
94
  </el-button>
87
- <el-button type="danger" icon="SwitchButton" @click="handleLogout()">
88
- 退出系统
89
- </el-button>
95
+ <el-button type="danger" icon="SwitchButton" @click="handleLogout()">退出系统</el-button>
90
96
  </div>
91
97
  </div>
92
98
  </el-popover>
93
99
  </div>
94
100
  </div>
101
+ <GlobalSetting ref="globalSettingRef" />
95
102
  </template>
96
103
 
97
104
  <style lang="scss" scoped>
@@ -107,7 +114,7 @@ $topHoverSize: 35px;
107
114
  justify-content: space-between;
108
115
  background: var(--jnrs-card-primary);
109
116
  padding: 0 8px;
110
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
117
+ box-shadow: 0 1px 2px var(--jnrs-font-primary-03);
111
118
 
112
119
  .btn {
113
120
  position: relative;
@@ -142,9 +149,13 @@ $topHoverSize: 35px;
142
149
  display: flex;
143
150
  align-items: center;
144
151
  margin-left: 16px;
152
+ transition: all 0.25s ease;
145
153
  cursor: pointer;
146
154
  &:hover {
147
155
  color: var(--jnrs-color-primary);
156
+ .userMenu_icon {
157
+ color: var(--jnrs-color-primary);
158
+ }
148
159
  }
149
160
  .userMenu_avatar {
150
161
  width: $topHoverSize;