@yyp92-cli/template-react-pc 2.1.0 → 2.2.0

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 (76) hide show
  1. package/package.json +4 -1
  2. package/CHANGELOG.md +0 -55
  3. package/template/.env.development +0 -5
  4. package/template/.env.production +0 -4
  5. package/template/.env.test +0 -4
  6. package/template/.eslintrc.cjs +0 -18
  7. package/template/README.md +0 -15
  8. package/template/index.html +0 -13
  9. package/template/package.json +0 -42
  10. package/template/pnpm-lock.yaml +0 -3570
  11. package/template/public/vite.svg +0 -1
  12. package/template/src/antdTheme/darkTheme.ts +0 -285
  13. package/template/src/antdTheme/lightTheme.ts +0 -286
  14. package/template/src/app.scss +0 -29
  15. package/template/src/app.tsx +0 -14
  16. package/template/src/assets/iconfont/demo.css +0 -539
  17. package/template/src/assets/iconfont/demo_index.html +0 -211
  18. package/template/src/assets/iconfont/iconfont.css +0 -19
  19. package/template/src/assets/iconfont/iconfont.js +0 -1
  20. package/template/src/assets/iconfont/iconfont.json +0 -16
  21. package/template/src/assets/iconfont/iconfont.ttf +0 -0
  22. package/template/src/assets/iconfont/iconfont.woff +0 -0
  23. package/template/src/assets/iconfont/iconfont.woff2 +0 -0
  24. package/template/src/assets/react.svg +0 -1
  25. package/template/src/components/403/index.tsx +0 -22
  26. package/template/src/components/404/index.tsx +0 -24
  27. package/template/src/components/index.ts +0 -3
  28. package/template/src/components/layout/content/index.module.scss +0 -22
  29. package/template/src/components/layout/content/index.tsx +0 -109
  30. package/template/src/components/layout/footer/index.module.scss +0 -12
  31. package/template/src/components/layout/footer/index.tsx +0 -15
  32. package/template/src/components/layout/header/index.module.scss +0 -21
  33. package/template/src/components/layout/header/index.tsx +0 -115
  34. package/template/src/components/layout/index.module.scss +0 -8
  35. package/template/src/components/layout/index.tsx +0 -47
  36. package/template/src/components/layout/side/index.module.scss +0 -31
  37. package/template/src/components/layout/side/index.tsx +0 -109
  38. package/template/src/components/layout-horizontal/content/index.module.scss +0 -22
  39. package/template/src/components/layout-horizontal/content/index.tsx +0 -105
  40. package/template/src/components/layout-horizontal/footer/index.module.scss +0 -12
  41. package/template/src/components/layout-horizontal/footer/index.tsx +0 -15
  42. package/template/src/components/layout-horizontal/header/index.module.scss +0 -23
  43. package/template/src/components/layout-horizontal/header/index.tsx +0 -115
  44. package/template/src/components/layout-horizontal/index.module.scss +0 -8
  45. package/template/src/components/layout-horizontal/index.tsx +0 -48
  46. package/template/src/components/layout-horizontal/side/index.module.scss +0 -32
  47. package/template/src/components/layout-horizontal/side/index.tsx +0 -104
  48. package/template/src/components/login/index.module.scss +0 -23
  49. package/template/src/components/login/index.tsx +0 -133
  50. package/template/src/global/constants.ts +0 -5
  51. package/template/src/pages/home/index.module.scss +0 -0
  52. package/template/src/pages/home/index.tsx +0 -90
  53. package/template/src/router/router.tsx +0 -190
  54. package/template/src/service/api.ts +0 -9
  55. package/template/src/service/config.ts +0 -9
  56. package/template/src/service/index.ts +0 -1
  57. package/template/src/service/request/index.ts +0 -267
  58. package/template/src/service/request/type.ts +0 -5
  59. package/template/src/service/service.ts +0 -27
  60. package/template/src/store/antdToken.ts +0 -35
  61. package/template/src/store/login.ts +0 -38
  62. package/template/src/store/menus.ts +0 -30
  63. package/template/src/store/permission.ts +0 -30
  64. package/template/src/store/token.ts +0 -30
  65. package/template/src/theme/darkTheme.scss +0 -47
  66. package/template/src/theme/lightTheme.scss +0 -49
  67. package/template/src/utils/base64ToBlob.ts +0 -41
  68. package/template/src/utils/cache.ts +0 -44
  69. package/template/src/utils/changeTheme.ts +0 -14
  70. package/template/src/utils/download.ts +0 -45
  71. package/template/src/utils/filterMenu.ts +0 -34
  72. package/template/src/utils/index.ts +0 -5
  73. package/template/src/vite-env.d.ts +0 -5
  74. package/template/tsconfig.json +0 -45
  75. package/template/tsconfig.node.json +0 -10
  76. package/template/vite.config.ts +0 -49
@@ -1,267 +0,0 @@
1
- import axios from 'axios'
2
- import { notification, message } from 'antd'
3
- import type { AxiosRequestConfig, AxiosError, AxiosResponse } from 'axios'
4
- import type { MyInternalAxiosRequestConfig } from './type'
5
- import router from '@/router/router'
6
- import { userInfoStore } from '@/store/login'
7
- import { tokenStore } from '@/store/token'
8
- import { menusStore } from '@/store/menus'
9
- import { permissionStore } from '@/store/permission'
10
-
11
- // * 存储待取消的请求:key 是请求唯一标识,value 是 AbortController 实例
12
- const pendingRequests = new Map()
13
-
14
- /**
15
- * * 生成请求唯一标识
16
- * @param config - Axios 请求配置
17
- * @returns 唯一标识字符串
18
- */
19
- const generateKey = (config: AxiosRequestConfig) => {
20
- const {
21
- method,
22
- url,
23
- params,
24
- data
25
- } = config
26
-
27
- // 拼接方法、URL、参数(params 是 URL 参数,data 是请求体参数)
28
- return [
29
- method?.toUpperCase(),
30
- url,
31
- JSON.stringify(params || {}),
32
- JSON.stringify(data || {})
33
- ].join('&')
34
- }
35
-
36
- /**
37
- * * 添加请求到待取消列表(若存在重复请求则先取消)
38
- * @param config - Axios 请求配置
39
- */
40
- const addPendingRequest = (config: AxiosRequestConfig) => {
41
- const requestKey = generateKey(config)
42
-
43
- // 若存在重复请求,先取消旧请求
44
- if (pendingRequests.has(requestKey)) {
45
- const controller = pendingRequests.get(requestKey)
46
- controller.abort(`取消重复请求:${requestKey}`)
47
- pendingRequests.delete(requestKey)
48
- }
49
-
50
- // 创建新的 AbortController 并关联到请求
51
- const controller = new AbortController()
52
- // 将 signal 绑定到请求配置
53
- config.signal = controller.signal
54
- pendingRequests.set(requestKey, controller)
55
- }
56
-
57
- /**
58
- * * 从待取消列表中移除请求(请求完成/失败/取消时调用)
59
- * @param config - Axios 请求配置
60
- */
61
- const removePendingRequest = (config: AxiosRequestConfig) => {
62
- const requestKey = generateKey(config)
63
-
64
- if (pendingRequests.has(requestKey)) {
65
- pendingRequests.delete(requestKey)
66
- }
67
- }
68
-
69
- // * Token 过期处理函数
70
- function handleTokenExpired() {
71
- // 1. 清除本地存储的 Token(避免死循环)
72
- userInfoStore.getState().clearUserInfo()
73
- tokenStore.getState().clearToken()
74
- menusStore.getState().clearMenus()
75
- permissionStore.getState().clearPermissions()
76
-
77
- // 排除登录页,避免死循环
78
- const currentPath = window.location.pathname
79
- const isLoginPage = currentPath === '/login'
80
-
81
- if (!isLoginPage) {
82
- // todo 暂时写死
83
- router.navigate(`/login?redirect=${currentPath || '/'}`, {
84
- replace: true,
85
- })
86
- }
87
-
88
- // 3. 可选:显示提示信息
89
- message.error('登录已过期,请重新登录')
90
- }
91
-
92
-
93
- // * 创建 Axios 实例
94
- const instance = axios.create({
95
- // 从环境变量取 baseURL
96
- baseURL: import.meta.env.VITE_APP_BASE_API,
97
- timeout: 5000
98
- })
99
-
100
- // * 请求拦截器:添加取消逻辑
101
- instance.interceptors.request.use(
102
- (config: MyInternalAxiosRequestConfig) => {
103
- // 允许通过配置关闭取消功能(例如某些特殊长轮询请求)
104
- if (config.cancelable !== false) {
105
- addPendingRequest(config)
106
- }
107
-
108
- const token = tokenStore.getState().token
109
-
110
- if (config.headers && token) {
111
- config.headers.Authorization = `Bearer ${token}`
112
- }
113
-
114
- return config
115
- },
116
- (error) => Promise.reject(error)
117
- )
118
-
119
- // * 响应拦截器:清理已完成的请求
120
- instance.interceptors.response.use(
121
- (response: AxiosResponse) => {
122
- const {
123
- config,
124
- data: responseData
125
- } = response ?? {}
126
- const {
127
- code,
128
- message
129
- } = responseData ?? {}
130
-
131
- removePendingRequest(config)
132
-
133
- // * 统一处理接口成功后,返回的 code !== 0 的错误,这样业务代码就不用写错误的逻辑了
134
- if (code !== 0) {
135
- // handleTokenExpired()
136
- message.error(message)
137
- return Promise.reject(message)
138
- }
139
-
140
- // 直接返回响应体数据
141
- return responseData
142
- },
143
- (error: AxiosError) => {
144
- const {
145
- config,
146
- response
147
- } = error ?? {}
148
- const { status, statusText } = response ?? {}
149
-
150
- // 移除已失败/取消的请求
151
- if (error.config) {
152
- removePendingRequest(error.config)
153
- }
154
-
155
- // 区分取消错误和其他错误
156
- if (axios.isCancel(error)) {
157
- // 取消请求不视为错误,返回 null
158
- return Promise.resolve(null)
159
- }
160
-
161
- // * token 过期, 后端返回 401 状态码
162
- if (status === 401) {
163
- handleTokenExpired()
164
-
165
- return Promise.reject(error)
166
- }
167
-
168
- // 异常处理程序
169
- if (response && status) {
170
- notification.error({
171
- message: `请求错误 ${status}: ${config?.url}`,
172
- description: statusText
173
- })
174
- }
175
- else if (!response) {
176
- notification.error({
177
- message: '网络异常',
178
- description: '您的网络发生异常,无法连接服务器'
179
- })
180
- }
181
-
182
- // 其他错误处理(如网络错误、404等)
183
- return Promise.reject(error)
184
- }
185
- )
186
-
187
- // 扩展实例:添加手动取消方法
188
- const requestFn = {
189
- ...instance,
190
-
191
- request<T = any>(config: AxiosRequestConfig) {
192
- // 返回 promise
193
- return new Promise<T>((resolve, reject) => {
194
- instance
195
- .request<any, T>(config)
196
- .then((res) => {
197
- resolve(res)
198
- })
199
- .catch((err) => {
200
- reject(err)
201
- })
202
- })
203
- },
204
-
205
- get(config: AxiosRequestConfig) {
206
- return this.request({
207
- ...config,
208
- method: 'GET'
209
- })
210
- },
211
-
212
- post(config: AxiosRequestConfig) {
213
- return this.request({
214
- ...config,
215
- method: 'POST'
216
- })
217
- },
218
-
219
- delete(config: AxiosRequestConfig) {
220
- return this.request({
221
- ...config,
222
- method: 'DELETE'
223
- })
224
- },
225
-
226
- patch(config: AxiosRequestConfig) {
227
- return this.request({
228
- ...config,
229
- method: 'PATCH'
230
- })
231
- },
232
-
233
- /**
234
- * 手动取消单个请求
235
- * @param config - 请求配置(需包含 method、url,可选 params/data)
236
- * @param message - 取消原因
237
- * @returns 是否取消成功
238
- */
239
- cancelOne: (
240
- config: AxiosRequestConfig,
241
- message: string = '手动取消请求'
242
- ) => {
243
- const key = generateKey(config)
244
-
245
- if (pendingRequests.has(key)) {
246
- pendingRequests.get(key).abort(message)
247
- pendingRequests.delete(key)
248
-
249
- return true
250
- }
251
-
252
- return false
253
- },
254
-
255
- /**
256
- * 取消所有待处理的请求
257
- * @param message - 取消原因
258
- */
259
- cancelAll: (message: string = '取消所有请求') => {
260
- pendingRequests.forEach((controller, key) => {
261
- controller.abort(`${message}:${key}`)
262
- pendingRequests.delete(key)
263
- })
264
- }
265
- }
266
-
267
- export default requestFn
@@ -1,5 +0,0 @@
1
- import type { InternalAxiosRequestConfig } from 'axios'
2
-
3
- export interface MyInternalAxiosRequestConfig extends InternalAxiosRequestConfig {
4
- cancelable?: boolean
5
- }
@@ -1,27 +0,0 @@
1
- import requestFn from './request'
2
- import {apiUrl} from './api'
3
-
4
- // 具体的接口
5
- export const getDemo = () => {
6
- const queryData = {}
7
-
8
- return requestFn.get({
9
- url: apiUrl.demoUrl,
10
- params: {
11
- name: '111',
12
- age: 20
13
- }
14
- })
15
- }
16
-
17
- export const postDemo = () => {
18
- const queryData = {}
19
-
20
- return requestFn.post({
21
- url: apiUrl.demoUrl1,
22
- data: {
23
- name: '111222',
24
- age: 20
25
- }
26
- })
27
- }
@@ -1,35 +0,0 @@
1
- /**
2
- * * 用户信息
3
- */
4
- import { create } from 'zustand'
5
- import { persist } from 'zustand/middleware'
6
- import { ANTDTOKEN} from '@/global/constants'
7
- import { lightToken } from '@/antdTheme/lightTheme'
8
- import { darkToken } from '@/antdTheme/darkTheme'
9
-
10
- type AntdTokenStoreState = {
11
- antdToken: any
12
- }
13
-
14
- type AntdTokenStoreActions = {
15
- setAntdToken: (
16
- antdToken: AntdTokenStoreState['antdToken']
17
- ) => void,
18
- }
19
-
20
- type AntdTokenStore = AntdTokenStoreState & AntdTokenStoreActions
21
-
22
- export const antdTokenStore = create<AntdTokenStore>()(
23
- persist(
24
- (set) => ({
25
- antdToken: {},
26
- setAntdToken: (isDark) => {
27
- const antdToken = isDark ? darkToken : lightToken
28
- return set({antdToken})
29
- },
30
- }),
31
- {
32
- name: ANTDTOKEN
33
- }
34
- )
35
- )
@@ -1,38 +0,0 @@
1
- /**
2
- * * 用户信息
3
- */
4
- import { create } from 'zustand'
5
- import { persist } from 'zustand/middleware'
6
- import { USER_INFO} from '@/global/constants'
7
-
8
- type UserInfoStoreState = {
9
- userInfo: {
10
- userId?: string,
11
- userName?: string
12
- }
13
- }
14
-
15
- type UserInfoStoreActions = {
16
- setUserInfo: (
17
- userInfo: UserInfoStoreState['userInfo']
18
- ) => void,
19
- clearUserInfo: () => void
20
- }
21
-
22
- type UserInfoStore = UserInfoStoreState & UserInfoStoreActions
23
-
24
- export const userInfoStore = create<UserInfoStore>()(
25
- persist(
26
- (set) => ({
27
- userInfo: {
28
- userName: '小明',
29
- userId: '111'
30
- },
31
- setUserInfo: (userInfo) => set({userInfo}),
32
- clearUserInfo: () => set({userInfo: {}})
33
- }),
34
- {
35
- name: USER_INFO
36
- }
37
- )
38
- )
@@ -1,30 +0,0 @@
1
- /**
2
- * * 用户菜单
3
- */
4
- import { create } from 'zustand'
5
- import { persist } from 'zustand/middleware'
6
- import { MENUS} from '@/global/constants'
7
-
8
- type MenusStoreState = {
9
- menus: any[]
10
- }
11
-
12
- type MenusStoreActions = {
13
- setMenus: (menus: string[]) => void,
14
- clearMenus: () => void
15
- }
16
-
17
- type MenusStore = MenusStoreState & MenusStoreActions
18
-
19
- export const menusStore = create<MenusStore>()(
20
- persist(
21
- (set) => ({
22
- menus: [],
23
- setMenus: (menus) => set({menus}),
24
- clearMenus: () => set({menus: []}),
25
- }),
26
- {
27
- name: MENUS
28
- }
29
- )
30
- )
@@ -1,30 +0,0 @@
1
- /**
2
- * * 用户信息
3
- */
4
- import { create } from 'zustand'
5
- import { persist } from 'zustand/middleware'
6
- import { PERMISSION} from '@/global/constants'
7
-
8
- type PermissionStoreState = {
9
- permissions: string[]
10
- }
11
-
12
- type PermissionStoreActions = {
13
- setPermissions: (permissions: string[]) => void,
14
- clearPermissions: () => void
15
- }
16
-
17
- type PermissionStore = PermissionStoreState & PermissionStoreActions
18
-
19
- export const permissionStore = create<PermissionStore>()(
20
- persist(
21
- (set) => ({
22
- permissions: [],
23
- setPermissions: (permissions) => set({permissions}),
24
- clearPermissions: () => set({permissions: []}),
25
- }),
26
- {
27
- name: PERMISSION
28
- }
29
- )
30
- )
@@ -1,30 +0,0 @@
1
- /**
2
- * * 用户信息
3
- */
4
- import { create } from 'zustand'
5
- import { persist } from 'zustand/middleware'
6
- import { LOGIN_TOKEN} from '@/global/constants'
7
-
8
- type UserInfoStoreState = {
9
- token: string
10
- }
11
-
12
- type UserInfoStoreActions = {
13
- setToken: (token: string) => void,
14
- clearToken: () => void
15
- }
16
-
17
- type UserInfoStore = UserInfoStoreState & UserInfoStoreActions
18
-
19
- export const tokenStore = create<UserInfoStore>()(
20
- persist(
21
- (set) => ({
22
- token: '',
23
- setToken: (token) => set({token}),
24
- clearToken: () => set({token: ''})
25
- }),
26
- {
27
- name: LOGIN_TOKEN
28
- }
29
- )
30
- )
@@ -1,47 +0,0 @@
1
- :root[data-theme="dark"] {
2
- --primary-text-color: #FFFFFF;
3
- --primary-white-color: #2A2A2D;
4
-
5
- // 全局主色
6
- --primary-color: #3591F4;
7
- --primary-color1: rgba(53, 145, 244, 0.1);
8
- // 链接色
9
- --link-color: #3591F4;
10
- // 成功色
11
- --success-color: #0CAA43;
12
- --success-color1: rgba(12, 170, 67, 0.1);
13
- // 警告色
14
- --warning-color: #FFA00A;
15
- --warning-color1: rgba(255, 160, 10, 0.1);
16
- // 错误色
17
- --error-color: #F43835;
18
- --error-color1: rgba(244, 56, 53, 0.1);
19
-
20
- // 主文本色
21
- --text-color: #FFFFFF;
22
- // 次文本色
23
- --text-color-secondary: #898D97;
24
-
25
- // 白的背景
26
- --bg-white-color: #1C1C1C;
27
- --bg-grey-color: #161616;
28
- --bg-grey-color1: transparent;
29
- --bg-black2-color: #222222;
30
- --bg-hover-color: rgba(53, 145, 244, 0.1);
31
- --bg-white-color1: rgba(0, 0, 0, 0.5);
32
-
33
- // 边框、输入框、分割线
34
- --border-color-base: #2A2A2D;
35
- // icon
36
- --icon-color: #898D97;
37
-
38
- // 主字号
39
- --font-size-base: 14px;
40
-
41
- // 组件/浮层圆角
42
- --border-radius-base: 4px;
43
- --modal-border-radius-base: 5px;
44
-
45
- // 阴影
46
- --box-shadow-color: #000000;
47
- }
@@ -1,49 +0,0 @@
1
- :root[data-theme="light"] {
2
- --primary-text-color: #FFFFFF;
3
- --primary-white-color: #FFFFFF;
4
-
5
- // 全局主色
6
- --primary-color: #3591F4;
7
- --primary-color1: rgba(53, 145, 244, 0.1);
8
- // 链接色
9
- --link-color: var(--primary-color);
10
- // 成功色
11
- --success-color: #0CAA43;
12
- --success-color1: rgba(12, 170, 67, 0.1);
13
- // 警告色
14
- --warning-color: #FFA00A;
15
- --warning-color1: rgba(255, 160, 10, 0.1);
16
- // 错误色
17
- --error-color: #F43835;
18
- --error-color1: rgba(244, 56, 53, 0.1);
19
-
20
- // 主文本色
21
- --text-color: #363A45;
22
- // 次文本色
23
- --text-color-secondary: #898D97;
24
-
25
- // 白的背景
26
- --bg-white-color: var(--primary-white-color);
27
- --bg-grey-color: #F2F4F9;
28
- --bg-grey-color1: var(--bg-grey-color);
29
- --bg-black2-color: var(--primary-white-color);
30
- --bg-hover-color: rgba(53, 145, 244, 0.1);
31
- --bg-white-color1: rgba(255, 255, 255, 0.5);
32
-
33
- // 边框、输入框、分割线
34
- --border-color-base: #DDE6F0;
35
- // icon
36
- --icon-color: #CCD6DD;
37
-
38
-
39
-
40
- // 主字号
41
- --font-size-base: 14px;
42
-
43
- // 组件/浮层圆角
44
- --border-radius-base: 4px;
45
- --modal-border-radius-base: 5px;
46
-
47
- // 阴影
48
- --box-shadow-color: #000000;
49
- }
@@ -1,41 +0,0 @@
1
- import { v4 as uuidv4 } from 'uuid'
2
-
3
- export const base64ToBlob = (
4
- base64String: any,
5
- type: string,
6
- fileName: string
7
- ) => {
8
- type = type || 'png'
9
- let base64Arr = [];
10
-
11
- try {
12
- base64Arr = base64String?.split?.(",");
13
- }
14
- catch (error) {
15
- base64String = `data:image/${type || "png"};base64,` + base64String;
16
- }
17
-
18
- base64Arr = base64String?.split(",");
19
-
20
- let mime = base64Arr?.[0]?.match(/:(.*?);/)?.[1] || `image/${type}`;
21
- // 去掉url的头,并转化为byte
22
- let bytes = window.atob(base64Arr[1]);
23
- // 处理异常,将ascii码小于0的转换为大于0
24
- let ab = new window.ArrayBuffer(bytes.length);
25
- // 生成视图(直接针对内存):8位无符号整数,长度1个字节
26
- let ia = new window.Uint8Array(ab);
27
-
28
- for (let i = 0; i < bytes.length; i++) {
29
- ia[i] = bytes.charCodeAt(i);
30
- }
31
- let dateTime = new Date();
32
- let name = uuidv4();
33
- const blobObject: any = new window.Blob([ab], {
34
- type: mime,
35
- });
36
-
37
- //禁止改动
38
- blobObject.name = `${name}.${type}`;
39
-
40
- return blobObject;
41
- }
@@ -1,44 +0,0 @@
1
- enum CacheType {
2
- Local,
3
- Session
4
- }
5
-
6
- class Cache {
7
- storage: Storage
8
-
9
- constructor(type: CacheType) {
10
- this.storage = type === CacheType.Local
11
- ? localStorage
12
- : sessionStorage
13
- }
14
-
15
- setCache(key: string, value: any) {
16
- if (value) {
17
- this.storage.setItem(key, JSON.stringify(value))
18
- }
19
- }
20
-
21
- getCache(key: string) {
22
- const value = this.storage.getItem(key)
23
-
24
- if (value) {
25
- return JSON.parse(value)
26
- }
27
- }
28
-
29
- removeCache(key: string) {
30
- this.storage.removeItem(key)
31
- }
32
-
33
- clear() {
34
- this.storage.clear()
35
- }
36
- }
37
-
38
- const localCache = new Cache(CacheType.Local)
39
- const sessionCache = new Cache(CacheType.Session)
40
-
41
- export {
42
- localCache,
43
- sessionCache
44
- }
@@ -1,14 +0,0 @@
1
- // 主题切换
2
- export const getDarkTheme = (isDark: boolean) => {
3
- // 获取根元素
4
- const root = document.documentElement;
5
-
6
- if (!isDark) {
7
- // 修改 data-theme 属性的值为 "light"
8
- root.setAttribute('data-theme', 'light');
9
- return
10
- }
11
-
12
- // 修改 data-theme 属性的值为 "dark"
13
- root.setAttribute('data-theme', 'dark');
14
- }