create-jnrs-template-vue 1.1.4 → 1.1.5

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.
@@ -17,8 +17,8 @@ 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']
21
20
  ElContainer: typeof import('element-plus/es')['ElContainer']
21
+ ElDatePickerPanel: typeof import('element-plus/es')['ElDatePickerPanel']
22
22
  ElForm: typeof import('element-plus/es')['ElForm']
23
23
  ElFormItem: typeof import('element-plus/es')['ElFormItem']
24
24
  ElHeader: typeof import('element-plus/es')['ElHeader']
@@ -28,7 +28,6 @@ declare module 'vue' {
28
28
  ElMenu: typeof import('element-plus/es')['ElMenu']
29
29
  ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
30
30
  ElPopover: typeof import('element-plus/es')['ElPopover']
31
- ElRow: typeof import('element-plus/es')['ElRow']
32
31
  ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
33
32
  ElTabPane: typeof import('element-plus/es')['ElTabPane']
34
33
  ElTabs: typeof import('element-plus/es')['ElTabs']
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jnrs-template-vue",
3
- "version": "1.1.4",
3
+ "version": "1.1.5",
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
  }
@@ -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'
9
+ import { changeLocales as changeLocalesForCore } from '@jnrs/core'
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,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
+ }
@@ -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,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
9
  import { LogoutApi } from '@/api/base/index'
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,10 +50,13 @@ 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>
@@ -58,7 +72,9 @@ const handleLogout = async () => {
58
72
  <span class="userMenu_reference">
59
73
  <img class="userMenu_avatar" :src="avatar" alt="avatar" />
60
74
  <span>{{ userInfo.name }}</span>
61
- <span class="userMenu_roleName" v-if="userInfo.role">[{{ userInfo.role }}]</span>
75
+ <span class="userMenu_roleName" :style="{ color: roleColor }" v-if="userInfo.role">
76
+ [{{ roleLabel }}]
77
+ </span>
62
78
  <el-icon class="userMenu_icon"><arrow-down /></el-icon>
63
79
  </span>
64
80
  </template>
@@ -66,7 +82,9 @@ const handleLogout = async () => {
66
82
  <img class="userMenu_dropdown_avatar" :src="avatar" alt="avatar" />
67
83
  <b>
68
84
  {{ userInfo.name }}
69
- <span class="userMenu_roleName" v-if="userInfo.role">[{{ userInfo.role }}]</span>
85
+ <span class="userMenu_roleName" :style="{ color: roleColor }" v-if="userInfo.role">
86
+ [{{ roleLabel }}]
87
+ </span>
70
88
  </b>
71
89
  <div class="loginDateTime">
72
90
  <span>登录时间</span>
@@ -92,6 +110,7 @@ const handleLogout = async () => {
92
110
  </el-popover>
93
111
  </div>
94
112
  </div>
113
+ <GlobalSetting ref="globalSettingRef" />
95
114
  </template>
96
115
 
97
116
  <style lang="scss" scoped>
@@ -107,7 +126,7 @@ $topHoverSize: 35px;
107
126
  justify-content: space-between;
108
127
  background: var(--jnrs-card-primary);
109
128
  padding: 0 8px;
110
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
129
+ box-shadow: 0 1px 2px var(--jnrs-font-primary-03);
111
130
 
112
131
  .btn {
113
132
  position: relative;
@@ -142,9 +161,13 @@ $topHoverSize: 35px;
142
161
  display: flex;
143
162
  align-items: center;
144
163
  margin-left: 16px;
164
+ transition: all 0.25s ease;
145
165
  cursor: pointer;
146
166
  &:hover {
147
167
  color: var(--jnrs-color-primary);
168
+ .userMenu_icon {
169
+ color: var(--jnrs-color-primary);
170
+ }
148
171
  }
149
172
  .userMenu_avatar {
150
173
  width: $topHoverSize;
@@ -35,7 +35,7 @@ import RouterTabs from './RouterTabs.vue'
35
35
  height: 100%;
36
36
 
37
37
  .el-main {
38
- padding: 10px;
38
+ padding: 16px;
39
39
  }
40
40
  }
41
41
  </style>
@@ -0,0 +1,9 @@
1
+ export default {
2
+ main: {
3
+ title: 'Management System'
4
+ },
5
+ login: {
6
+ title: 'Login'
7
+ },
8
+ layout: {}
9
+ }
@@ -0,0 +1,16 @@
1
+ import { createI18n } from 'vue-i18n'
2
+ import zhCN from './zhCn'
3
+ import en from './en'
4
+
5
+ const i18n = createI18n({
6
+ legacy: false, // 启用 Composition API 模式
7
+ globalInjection: true, // 允许在模板中使用 $t
8
+ locale: 'zhCn',
9
+ fallbackLocale: 'en',
10
+ messages: {
11
+ zhCn: zhCN,
12
+ en: en
13
+ }
14
+ })
15
+
16
+ export default i18n
@@ -0,0 +1,9 @@
1
+ export default {
2
+ main: {
3
+ title: '信息化管理系统模板'
4
+ },
5
+ login: {
6
+ title: '登录'
7
+ },
8
+ layout: {}
9
+ }
@@ -1,5 +1,7 @@
1
1
  import 'element-plus/dist/index.css'
2
- import './assets/styles/main.scss'
2
+ import 'element-plus/theme-chalk/dark/css-vars.css'
3
+ import '@jnrs/shared/styles/theme.scss'
4
+ import '@/assets/styles/main.scss'
3
5
 
4
6
  import { createApp } from 'vue'
5
7
  import { createPinia } from 'pinia'
@@ -7,6 +9,9 @@ import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
7
9
  import * as ElementPlusIconsVue from '@element-plus/icons-vue'
8
10
  import App from './App.vue'
9
11
  import { router } from './router'
12
+ import locales from './locales/index'
13
+ import { changeLocales as changeLocalesForShared } from '@jnrs/shared'
14
+ changeLocalesForShared('en')
10
15
 
11
16
  const app = createApp(App)
12
17
 
@@ -21,4 +26,5 @@ pinia.use(piniaPluginPersistedstate)
21
26
 
22
27
  app.use(pinia)
23
28
  app.use(router)
29
+ app.use(locales)
24
30
  app.mount('#app')
@@ -1 +1,2 @@
1
+ export type * from '@jnrs/shared'
1
2
  export type * from '@jnrs/vue-core'
@@ -0,0 +1,58 @@
1
+ import {
2
+ getOneDictList as _getOneDictList,
3
+ getDictLabel as _getDictLabel,
4
+ getDictValue as _getDictValue,
5
+ getDictColor as _getDictColor
6
+ } from '@jnrs/shared'
7
+ import { useAuthStore } from '@jnrs/vue-core/pinia'
8
+
9
+ /**
10
+ * 根据字典名称获取字典数据
11
+ * @param name 字典名称
12
+ * @returns 某字典名称所对应的字典列表数据
13
+ */
14
+ export const getOneDictList = (name: string) => {
15
+ const { dict } = useAuthStore()
16
+ if (dict) {
17
+ return _getOneDictList(name, dict)
18
+ }
19
+ }
20
+
21
+ /**
22
+ * 根据字典名称和字典值获取字典标签
23
+ * @param name 字典名称
24
+ * @param value 字典值
25
+ * @returns 某字典名称所对应的字典标签
26
+ */
27
+ export const getDictLabel = (name: string, value: string | number) => {
28
+ const { dict } = useAuthStore()
29
+ if (dict) {
30
+ return _getDictLabel(name, value, dict)
31
+ }
32
+ }
33
+
34
+ /**
35
+ * 根据字典名称和字典标签获取字典值
36
+ * @param name 字典名称
37
+ * @param label 字典标签
38
+ * @returns 某字典名称所对应的字典值
39
+ */
40
+ export const getDictValue = (name: string, label: string) => {
41
+ const { dict } = useAuthStore()
42
+ if (dict) {
43
+ return _getDictValue(name, label, dict)
44
+ }
45
+ }
46
+
47
+ /**
48
+ * 根据字典名称和字典值获取字典颜色
49
+ * @param name 字典名称
50
+ * @param value 字典值
51
+ * @returns 某字典名称所对应的字典颜色
52
+ */
53
+ export const getDictColor = (name: string, value: string | number) => {
54
+ const { dict } = useAuthStore()
55
+ if (dict) {
56
+ return _getDictColor(name, value, dict)
57
+ }
58
+ }
@@ -13,6 +13,7 @@ const loginParams = ref({
13
13
 
14
14
  const routeOptions = ref<MenuItem[]>([])
15
15
  const currentRoute = ref('')
16
+ const datePicker = ref(new Date())
16
17
 
17
18
  onMounted(() => {
18
19
  handleInfoApi()
@@ -76,7 +77,7 @@ const handleRouteChange = () => {
76
77
  </script>
77
78
 
78
79
  <template>
79
- <div style="background-color: #fff">
80
+ <div>
80
81
  <h1>Playground - 测试组件</h1>
81
82
  <p>网络请求测试</p>
82
83
  <el-button-group>
@@ -108,6 +109,8 @@ const handleRouteChange = () => {
108
109
  <span>{{ data.meta.title }}</span>
109
110
  </template>
110
111
  </el-cascader>
112
+ <p>Element 组件测试</p>
113
+ <el-date-picker-panel v-model="datePicker" />
111
114
  <!-- <MyButton type="primary">测试按钮</MyButton>
112
115
  <MyModal v-model="show">内容</MyModal> -->
113
116
  </div>
@@ -5,6 +5,7 @@ import { LoginApi } from '@/api/base/index'
5
5
  import { useAuthStore } from '@/stores'
6
6
  import { handleRouter, useRoute } from '@jnrs/vue-core/router'
7
7
  import { isWeakPwd } from '@jnrs/shared/validator'
8
+ import { formatDateTime, formatWeekday } from '@jnrs/shared'
8
9
 
9
10
  const route = useRoute()
10
11
  const loading = ref(false)
@@ -34,6 +35,7 @@ const submitForm = () => {
34
35
  try {
35
36
  const res = await LoginApi(ruleForm.value)
36
37
  const { token, dict, ...userInfo } = res
38
+ userInfo.loginDateTime = formatDateTime() + ' ' + formatWeekday()
37
39
  const { asyncSetAuth } = useAuthStore()
38
40
  await asyncSetAuth({
39
41
  token: token,
@@ -102,14 +104,6 @@ const submitForm = () => {
102
104
  </template>
103
105
 
104
106
  <style scoped lang="scss">
105
- @use 'sass:math';
106
-
107
- $design-width: 1920; // 设计稿宽度
108
-
109
- @function px2vw($px) {
110
- @return math.div($px, $design-width) * 100vw;
111
- }
112
-
113
107
  .main {
114
108
  position: relative;
115
109
  width: 100%;
@@ -147,8 +141,8 @@ $design-width: 1920; // 设计稿宽度
147
141
  width: 50%;
148
142
  height: 100%;
149
143
  box-shadow: 5px 0 10px rgba(0, 0, 0, 0.5);
150
- background: url('@/assets/img/common/card_bg.png') no-repeat;
151
- background-size: 100% 100%;
144
+ // background: url('@/assets/img/common/card_bg.png') no-repeat;
145
+ // background-size: 100% 100%;
152
146
  text-align: center;
153
147
  font-size: 22px;
154
148
 
@@ -3,9 +3,8 @@ import { reactive, ref } from 'vue'
3
3
  import { LoginApi, PasswordChangeApi } from '@/api/base'
4
4
  import { useAuthStore } from '@/stores'
5
5
  import { handleRouter } from '@jnrs/vue-core/router'
6
- import { isWeakPwd } from '@/utils/validator'
7
- import type { FormInstance } from 'element-plus'
8
- import type { RuleItem } from 'async-validator'
6
+ import { isWeakPwd } from '@jnrs/shared/validator'
7
+ import type { FormInstance, FormItemRule } from 'element-plus'
9
8
  import { ElMessage } from 'element-plus'
10
9
  import { LogoutApi } from '@/api/base/index'
11
10
 
@@ -21,25 +20,25 @@ const rules = reactive({
21
20
  originPassword: [{ required: true, message: '请输入', trigger: 'change' }],
22
21
  password: [
23
22
  { required: true, message: '请输入', trigger: 'change' },
24
- { min: 6, max: 36, message: '密码长度为 6 - 36 个字符', trigger: 'change' },
25
23
  {
26
- validator: (rule: RuleItem, value: string | undefined, callback: (error?: Error) => void) =>
27
- isWeakPwd(rule, value, callback)
24
+ validator: isWeakPwd,
25
+ trigger: 'change'
28
26
  }
29
- ] as RuleItem[],
27
+ ],
30
28
  repassword: [
31
29
  { required: true, message: '请输入', trigger: 'change' },
32
30
  {
33
- validator: (rule: RuleItem, value: string | undefined, callback: (error?: Error) => void) => {
34
- if (value != '' && value !== ruleForm.value.password) {
35
- callback(new Error('两次密码不一致!'))
31
+ validator: (rule: FormItemRule, value: string, callback: (error?: string) => void) => {
32
+ if (value && value !== ruleForm.value.password) {
33
+ callback('两次密码不一致!')
36
34
  } else {
37
35
  callback()
38
36
  }
39
37
  },
40
- required: false
38
+ required: false,
39
+ trigger: 'change'
41
40
  }
42
- ] as RuleItem[]
41
+ ]
43
42
  })
44
43
 
45
44
  const submitForm = async (formEl: FormInstance | undefined) => {
@@ -20,4 +20,9 @@ const goBack = () => {
20
20
  </div>
21
21
  </template>
22
22
 
23
- <style lang="scss" scoped></style>
23
+ <style lang="scss" scoped>
24
+ @use 'sass:math';
25
+ @function px2vw($px) {
26
+ @return math.div($px, 1920) * 100vw;
27
+ }
28
+ </style>
@@ -6,7 +6,7 @@ import Components from 'unplugin-vue-components/vite'
6
6
  import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
7
7
  import compression from 'vite-plugin-compression'
8
8
  import { viteMockServe } from 'vite-plugin-mock'
9
- // import vueDevTools from 'vite-plugin-vue-devtools'
9
+ import vueDevTools from 'vite-plugin-vue-devtools'
10
10
 
11
11
  const path = (url: string) => fileURLToPath(new URL(url, import.meta.url))
12
12
  const config = loadEnv('development', './')
@@ -15,11 +15,12 @@ const isMock = config.VITE_USE_MOCK === 'true'
15
15
  export default defineConfig({
16
16
  plugins: [
17
17
  vue(),
18
- // vueDevTools(),
18
+ vueDevTools(),
19
19
  AutoImport({
20
20
  resolvers: [ElementPlusResolver()]
21
21
  }),
22
22
  Components({
23
+ dirs: [], // 禁用本地组件自动导入
23
24
  resolvers: [ElementPlusResolver()]
24
25
  }),
25
26
  compression({
@@ -49,7 +50,7 @@ export default defineConfig({
49
50
  '/api': {
50
51
  target: 'http://' + config.VITE_BASE_URL,
51
52
  changeOrigin: true,
52
- rewrite: (path) => path.replace(/^\/api/, '')
53
+ rewrite: (path: string) => path.replace(/^\/api/, '')
53
54
  },
54
55
  '/ws': {
55
56
  target: 'ws://' + config.VITE_BASE_URL,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-jnrs-template-vue",
3
- "version": "1.1.4",
3
+ "version": "1.1.5",
4
4
  "description": "巨能前端工程化开发,Vue 项目模板脚手架",
5
5
  "keywords": [
6
6
  "vue",