create-jnrs-template-vue 1.1.3 → 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.
Files changed (41) hide show
  1. package/README.md +5 -5
  2. package/bin/create.mjs +1 -1
  3. package/jnrs-template-vue/README.md +2 -2
  4. package/jnrs-template-vue/components.d.ts +1 -0
  5. package/jnrs-template-vue/package.json +23 -23
  6. package/jnrs-template-vue/public/system/menu.json +8 -4
  7. package/jnrs-template-vue/src/App.vue +36 -5
  8. package/jnrs-template-vue/src/assets/fonts/.keep +0 -0
  9. package/jnrs-template-vue/src/assets/fonts/AlibabaPuHuiTi-Regular.woff2 +0 -0
  10. package/jnrs-template-vue/src/assets/fonts/AlimamaShuHeiTi-Bold.woff2 +0 -0
  11. package/jnrs-template-vue/src/assets/images/common/jnrs-white.svg +1 -0
  12. package/jnrs-template-vue/src/assets/styles/fonts.scss +24 -0
  13. package/jnrs-template-vue/src/assets/styles/init.scss +38 -0
  14. package/jnrs-template-vue/src/assets/styles/main.scss +27 -0
  15. package/jnrs-template-vue/src/assets/styles/root.scss +12 -0
  16. package/jnrs-template-vue/src/layout/BlankLayout.vue +2 -1
  17. package/jnrs-template-vue/src/layout/RouterTabs.vue +14 -9
  18. package/jnrs-template-vue/src/layout/SideMenu.vue +95 -27
  19. package/jnrs-template-vue/src/layout/SideMenuItem.vue +4 -4
  20. package/jnrs-template-vue/src/layout/TopHeader.vue +85 -86
  21. package/jnrs-template-vue/src/layout/index.vue +12 -8
  22. package/jnrs-template-vue/src/locales/en.ts +9 -0
  23. package/jnrs-template-vue/src/locales/index.ts +16 -0
  24. package/jnrs-template-vue/src/locales/zhCn.ts +9 -0
  25. package/jnrs-template-vue/src/main.ts +8 -2
  26. package/jnrs-template-vue/src/router/routes.ts +16 -16
  27. package/jnrs-template-vue/src/types/index.ts +1 -0
  28. package/jnrs-template-vue/src/utils/common.ts +58 -0
  29. package/jnrs-template-vue/src/views/home/index.vue +4 -1
  30. package/jnrs-template-vue/src/views/login/index.vue +222 -38
  31. package/jnrs-template-vue/src/views/system/mine/securitySettings.vue +11 -12
  32. package/jnrs-template-vue/src/views/visual/index.vue +6 -1
  33. package/jnrs-template-vue/tsconfig.json +6 -1
  34. package/jnrs-template-vue/vite.config.ts +2 -2
  35. package/jnrs-template-vue/viteMockServe/index.ts +5 -0
  36. package/package.json +1 -1
  37. package/jnrs-template-vue/src/assets/styles/base.css +0 -28
  38. package/jnrs-template-vue/src/assets/styles/main.css +0 -1
  39. package/jnrs-template-vue/src/utils/storage.ts +0 -7
  40. package/jnrs-template-vue/src/utils/validate.ts +0 -321
  41. package/jnrs-template-vue/src/utils/validator.ts +0 -153
@@ -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
- const { menuCollapse, documentFullscreen } = storeToRefs(systemStore)
14
- const { toggleCollapse, toggleFullScreen } = systemStore
19
+ const { documentFullscreen } = storeToRefs(systemStore)
20
+ const { toggleFullScreen } = systemStore
21
+ const globalSettingRef = ref()
15
22
 
16
23
  const handleLogout = async () => {
17
24
  try {
@@ -25,46 +32,59 @@ 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>
31
42
  <div class="topHeader">
32
- <div class="header_left">
43
+ <div class="left">
33
44
  <el-icon
34
- class="headerBtn"
35
- :class="{ sideBtn_active: menuCollapse }"
36
- @click="toggleCollapse()"
45
+ class="btn"
46
+ title="可视化看板"
47
+ @click="
48
+ handleRouter({
49
+ name: 'Visual'
50
+ })
51
+ "
37
52
  >
38
- <Fold />
53
+ <el-icon><Platform /></el-icon>
39
54
  </el-icon>
40
- <el-icon class="headerBtn fullBtn" @click="toggleFullScreen()">
55
+ </div>
56
+ <div class="right">
57
+ <el-icon class="btn" title="全屏切换" @click="showGlobalSetting()">
58
+ <el-icon><Setting /></el-icon>
59
+ </el-icon>
60
+ <el-icon class="btn" title="全屏切换" @click="toggleFullScreen()">
41
61
  <component :is="!documentFullscreen ? 'FullScreen' : 'Rank'" />
42
62
  </el-icon>
43
- </div>
44
- <div class="header_right">
45
63
  <!-- 头像和用户名 -->
46
64
  <el-popover
47
65
  placement="bottom"
48
66
  trigger="click"
49
67
  :teleported="false"
50
- :width="300"
68
+ :width="260"
51
69
  :hide-after="0"
52
70
  >
53
71
  <template #reference>
54
72
  <span class="userMenu_reference">
55
- <img :src="avatar" alt="" />
56
- <span style="margin: 0 10px">
57
- <span>{{ userInfo.name }}</span>
58
- <span class="userMenu_roleName" v-if="userInfo.role">[{{ userInfo.role }}]</span>
73
+ <img class="userMenu_avatar" :src="avatar" alt="avatar" />
74
+ <span>{{ userInfo.name }}</span>
75
+ <span class="userMenu_roleName" :style="{ color: roleColor }" v-if="userInfo.role">
76
+ [{{ roleLabel }}]
59
77
  </span>
60
- <el-icon><arrow-down /></el-icon>
78
+ <el-icon class="userMenu_icon"><arrow-down /></el-icon>
61
79
  </span>
62
80
  </template>
63
81
  <div class="userMenu_dropdown">
64
- <img :src="avatar" alt="" />
82
+ <img class="userMenu_dropdown_avatar" :src="avatar" alt="avatar" />
65
83
  <b>
66
84
  {{ userInfo.name }}
67
- <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>
68
88
  </b>
69
89
  <div class="loginDateTime">
70
90
  <span>登录时间</span>
@@ -90,119 +110,98 @@ const handleLogout = async () => {
90
110
  </el-popover>
91
111
  </div>
92
112
  </div>
113
+ <GlobalSetting ref="globalSettingRef" />
93
114
  </template>
94
115
 
95
116
  <style lang="scss" scoped>
117
+ $topHoverSize: 35px;
118
+
96
119
  .topHeader {
120
+ position: relative;
121
+ z-index: 15;
97
122
  width: 100%;
98
123
  height: 100%;
99
124
  display: flex;
100
125
  align-items: center;
101
126
  justify-content: space-between;
102
- background: #fff;
103
- padding-left: 0;
104
- z-index: 10;
105
- box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
106
- :deep(.el-radio-button__inner:hover) {
107
- color: #d15f2c;
108
- }
109
- :deep(.is-active .el-radio-button__inner:hover) {
110
- color: #fff;
111
- }
112
- .headerBtn {
127
+ background: var(--jnrs-card-primary);
128
+ padding: 0 8px;
129
+ box-shadow: 0 1px 2px var(--jnrs-font-primary-03);
130
+
131
+ .btn {
132
+ position: relative;
113
133
  margin: 0 8px;
114
- font-size: 24px;
134
+ font-size: 22px;
115
135
  transition: all 0.25s ease 0s;
116
136
  cursor: pointer;
117
137
  &:hover {
118
- color: #d15f2c;
138
+ color: var(--jnrs-color-primary);
139
+ &::after {
140
+ content: '';
141
+ position: absolute;
142
+ top: 50%;
143
+ left: 50%;
144
+ transform: translate(-50%, -50%);
145
+ width: $topHoverSize;
146
+ height: $topHoverSize;
147
+ background: var(--jnrs-color-primary);
148
+ opacity: 0.1;
149
+ border-radius: 50%;
150
+ }
119
151
  }
120
152
  }
121
- .fullBtn {
122
- font-size: 20px;
123
- }
124
- .sideBtn_active {
125
- transform: rotate(-180deg);
126
- }
127
- .header_left {
128
- display: flex;
129
- align-items: center;
130
- }
131
- .header_right {
153
+
154
+ .left,
155
+ .right {
132
156
  display: flex;
133
157
  align-items: center;
134
- .header_right_item {
135
- display: flex;
136
- align-items: center;
137
- }
138
- .modeLable {
139
- padding-right: 8px;
140
- margin-left: 30px;
141
- color: #d15f2c;
142
- font-size: 14px;
143
- }
144
- }
145
- .hoverBtn {
146
- position: relative;
147
- top: 1px;
148
- font-size: 24px;
149
- margin-left: 30px;
150
- cursor: pointer;
151
- &:hover {
152
- color: #d15f2c;
153
- }
154
158
  }
159
+
155
160
  .userMenu_reference {
156
161
  display: flex;
157
162
  align-items: center;
158
- margin-left: 30px;
159
- font-size: 16px;
160
- color: #424242;
163
+ margin-left: 16px;
164
+ transition: all 0.25s ease;
161
165
  cursor: pointer;
162
166
  &:hover {
163
- color: #d15f2c;
167
+ color: var(--jnrs-color-primary);
168
+ .userMenu_icon {
169
+ color: var(--jnrs-color-primary);
170
+ }
164
171
  }
165
- img {
166
- width: 35px;
167
- height: 35px;
172
+ .userMenu_avatar {
173
+ width: $topHoverSize;
174
+ height: $topHoverSize;
168
175
  border-radius: 50%;
169
- border: 1px solid #ccc;
170
- overflow: hidden;
171
- object-fit: cover;
172
- object-position: center center;
173
- flex-grow: 0;
174
- flex-shrink: 0;
176
+ margin-right: 4px;
177
+ }
178
+ .userMenu_icon {
179
+ margin-left: 4px;
180
+ color: var(--jnrs-font-primary-06);
175
181
  }
176
182
  }
177
183
  .userMenu_dropdown {
178
- padding: 10px;
179
184
  text-align: center;
180
185
  img {
181
186
  width: 80px;
182
187
  height: 80px;
183
- border: 1px solid #ccc;
184
188
  border-radius: 50%;
185
- overflow: hidden;
186
- object-fit: cover;
187
- object-position: center center;
188
189
  }
189
190
  b {
190
191
  display: block;
191
- width: 100%;
192
192
  font-size: 16px;
193
- color: #000;
194
- margin-bottom: 5px;
193
+ color: var(--jnrs-font-primary);
195
194
  }
196
195
  .loginDateTime {
197
- color: #999;
196
+ color: var(--jnrs-font-primary-06);
198
197
  }
199
198
  .userMenu_dropdown_btn {
200
- margin-top: 20px;
199
+ margin-top: 8px;
201
200
  }
202
201
  }
203
202
  .userMenu_roleName {
204
203
  display: inline;
205
- color: #d15f2c;
204
+ color: var(--jnrs-color-primary);
206
205
  }
207
206
  }
208
207
  </style>
@@ -5,10 +5,10 @@ import RouterTabs from './RouterTabs.vue'
5
5
  </script>
6
6
 
7
7
  <template>
8
- <el-container class="layout-container">
8
+ <el-container class="layout_container">
9
9
  <SideMenu />
10
10
  <el-container>
11
- <el-header class="layout-header">
11
+ <el-header class="layout_header">
12
12
  <TopHeader />
13
13
  </el-header>
14
14
  <RouterTabs />
@@ -24,14 +24,18 @@ import RouterTabs from './RouterTabs.vue'
24
24
  </template>
25
25
 
26
26
  <style lang="scss" scoped>
27
- .layout-container {
27
+ .layout_header {
28
28
  width: 100%;
29
- height: 100%;
30
- background: #f2f2f2;
29
+ height: var(--jnrs-head-height);
30
+ padding: 0;
31
31
  }
32
32
 
33
- .layout-header {
34
- height: 50px;
35
- padding: 0;
33
+ .layout_container {
34
+ width: 100%;
35
+ height: 100%;
36
+
37
+ .el-main {
38
+ padding: 16px;
39
+ }
36
40
  }
37
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.css'
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,10 +9,13 @@ 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
 
13
- // element-plus 相关
18
+ // element-plus 自动引入所有图标
14
19
  for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
15
20
  app.component(key, component)
16
21
  }
@@ -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')
@@ -10,25 +10,25 @@ export const LAYOUT_NAME = 'Layout'
10
10
  export const GLOBAL_COMPONENT = import('@/layout/BlankLayout.vue')
11
11
 
12
12
  export const routes = [
13
- // {
14
- // path: '/login',
15
- // component: () => import('@/layout/BlankLayout.vue'),
16
- // meta: { title: '登录' },
17
- // children: [
18
- // {
19
- // path: '',
20
- // name: 'Login',
21
- // meta: { title: '登录', noAuth: true },
22
- // component: () => import('@/views/login/index.vue')
23
- // }
24
- // ]
25
- // },
26
13
  {
27
- name: 'Login',
28
14
  path: '/login',
29
- component: () => import('@/views/login/index.vue'),
30
- meta: { title: '登录', noAuth: true, global: true }
15
+ component: () => import('@/layout/BlankLayout.vue'),
16
+ meta: { title: '登录' },
17
+ children: [
18
+ {
19
+ path: '',
20
+ name: 'Login',
21
+ meta: { title: '登录', noAuth: true },
22
+ component: () => import('@/views/login/index.vue')
23
+ }
24
+ ]
31
25
  },
26
+ // {
27
+ // name: 'Login',
28
+ // path: '/login',
29
+ // component: () => import('@/views/login/index.vue'),
30
+ // meta: { title: '登录', noAuth: true, global: true }
31
+ // },
32
32
  {
33
33
  name: LAYOUT_NAME,
34
34
  path: '/',
@@ -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>