create-jnrs-vue 1.2.21 → 1.2.23

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 (52) hide show
  1. package/README.md +1 -1
  2. package/jnrs-vue/.env.development +1 -1
  3. package/jnrs-vue/README.md +1 -1
  4. package/{bin → jnrs-vue/bin}/upgrade.mjs +2 -2
  5. package/jnrs-vue/package.json +6 -3
  6. package/jnrs-vue/src/api/common/index.ts +2 -2
  7. package/jnrs-vue/src/api/demos/index.ts +73 -32
  8. package/jnrs-vue/src/api/request.ts +10 -11
  9. package/jnrs-vue/src/api/system/index.ts +27 -26
  10. package/jnrs-vue/src/components/common/CardTable.vue +3 -3
  11. package/jnrs-vue/src/components/common/DictTag.vue +1 -1
  12. package/jnrs-vue/src/components/common/ImageView.vue +4 -4
  13. package/jnrs-vue/src/components/common/PdfView.vue +4 -4
  14. package/jnrs-vue/src/components/select/SelectManager.vue +2 -2
  15. package/jnrs-vue/src/composables/useCrud.ts +29 -10
  16. package/jnrs-vue/src/layout/RouterTabs.vue +6 -6
  17. package/jnrs-vue/src/layout/SideMenuItem.vue +2 -2
  18. package/jnrs-vue/src/layout/TopHeader.vue +2 -1
  19. package/jnrs-vue/src/layout/index.vue +2 -1
  20. package/jnrs-vue/src/locales/en.ts +1 -1
  21. package/jnrs-vue/src/main.ts +2 -7
  22. package/jnrs-vue/src/router/index.ts +5 -4
  23. package/jnrs-vue/src/stores/index.ts +8 -0
  24. package/jnrs-vue/src/stores/system/auth.ts +67 -0
  25. package/jnrs-vue/src/types/index.ts +2 -81
  26. package/jnrs-vue/src/types/system.d.ts +115 -0
  27. package/jnrs-vue/src/types/system.js +1 -0
  28. package/jnrs-vue/src/types/system.ts +124 -0
  29. package/jnrs-vue/src/types/webSocket.ts +4 -4
  30. package/jnrs-vue/src/utils/dict.ts +59 -0
  31. package/jnrs-vue/src/utils/file.ts +1 -1
  32. package/jnrs-vue/src/utils/index.ts +4 -0
  33. package/jnrs-vue/src/utils/packages.ts +6 -65
  34. package/jnrs-vue/src/utils/permissions.ts +1 -1
  35. package/jnrs-vue/src/views/demos/crud/index.vue +29 -17
  36. package/jnrs-vue/src/views/demos/simpleTable/index.vue +2 -2
  37. package/jnrs-vue/src/views/demos/unitTest/RequestPage.vue +30 -7
  38. package/jnrs-vue/src/views/demos/unitTest/index.vue +2 -2
  39. package/jnrs-vue/src/views/home/index.vue +1 -1
  40. package/jnrs-vue/src/views/login/index.vue +2 -2
  41. package/jnrs-vue/src/views/system/dict/index.vue +4 -4
  42. package/jnrs-vue/src/views/system/mine/baseInfo.vue +2 -2
  43. package/jnrs-vue/src/views/system/mine/securitySettings.vue +1 -1
  44. package/jnrs-vue/src/views/visual/index.vue +3 -4
  45. package/jnrs-vue/vite.config.ts +2 -2
  46. package/jnrs-vue/viteMockServe/fail.ts +3 -3
  47. package/jnrs-vue/viteMockServe/file.ts +1 -1
  48. package/jnrs-vue/viteMockServe/index.ts +7 -16
  49. package/jnrs-vue/viteMockServe/json/loginRes_user.json +21 -1
  50. package/jnrs-vue/viteMockServe/success.ts +5 -5
  51. package/package.json +2 -3
  52. package/jnrs-vue/src/api/user/index.ts +0 -12
package/README.md CHANGED
@@ -40,7 +40,7 @@ jnrs-vue/
40
40
  │ ├── router/ # 路由配置
41
41
  │ ├── api/ # 接口定义(已含 request 实例)
42
42
  │ ├── types/ # 类型定义
43
- │ ├── store/ # 状态管理
43
+ │ ├── stores/ # 状态管理
44
44
  │ ├── utils/ # 工具函数
45
45
  │ ├── locales/ # 国际化
46
46
  │ └── main.ts # 应用入口
@@ -5,7 +5,7 @@ VITE_USE_MOCK = true
5
5
 
6
6
  # 后端接口基地址 - 开发环境
7
7
  # VITE_BASE_URL = '192.168.1.120:6001'
8
- VITE_BASE_URL = '192.168.1.112:5010'
8
+ VITE_BASE_URL = '192.168.1.50:5001'
9
9
 
10
10
  # 应用运行主机(置空默认为 localhost)
11
11
  VITE_APP_HOST = ''
@@ -26,7 +26,7 @@ jnrs-vue/
26
26
  │ ├── router/ # 路由配置
27
27
  │ ├── api/ # 接口定义(已含 request 实例)
28
28
  │ ├── types/ # 类型定义
29
- │ ├── store/ # 状态管理
29
+ │ ├── stores/ # 状态管理
30
30
  │ ├── utils/ # 工具函数
31
31
  │ ├── locales/ # 国际化
32
32
  │ └── main.ts # 应用入口
@@ -7,7 +7,7 @@
7
7
  */
8
8
 
9
9
  import { execSync } from 'child_process'
10
- import { cpSync, readFileSync, writeFileSync } from 'fs'
10
+ import { cpSync, readFileSync, writeFileSync, rmSync } from 'fs'
11
11
  import { join } from 'path'
12
12
 
13
13
  console.log('🔄 正在拉取最新模板...')
@@ -37,4 +37,4 @@ console.log(' - 检查 package.json 差异')
37
37
  console.log(' - src/ 目录未自动更新,请手动合并新功能')
38
38
 
39
39
  // 4. 清理临时目录
40
- execSync('rm -rf _temp_new')
40
+ rmSync('_temp_new', { recursive: true, force: true })
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jnrs-vue",
3
- "version": "1.2.21",
3
+ "version": "1.2.23",
4
4
  "description": "JNRS 信息化管理系统",
5
5
  "author": "talia_tan",
6
6
  "private": true,
@@ -8,6 +8,9 @@
8
8
  "engines": {
9
9
  "node": "^20.19.0 || >=22.12.0"
10
10
  },
11
+ "bin": {
12
+ "upgrade-jnrs-vue": "./bin/upgrade.mjs"
13
+ },
11
14
  "scripts": {
12
15
  "dev": "vite",
13
16
  "build": "run-p type-check \"build-only {@}\" --",
@@ -19,8 +22,8 @@
19
22
  },
20
23
  "dependencies": {
21
24
  "@element-plus/icons-vue": "^2.3.2",
22
- "@jnrs/shared": "1.1.15",
23
- "@jnrs/vue-core": "1.2.10",
25
+ "@jnrs/shared": "1.1.16",
26
+ "@jnrs/vue-core": "1.2.11",
24
27
  "@jnrs/lingshu-smart": "2.2.4",
25
28
  "@vueuse/core": "^14.1.0",
26
29
  "element-plus": "^2.13.3",
@@ -7,7 +7,7 @@ import { axiosRequest } from '../request'
7
7
  */
8
8
  export const FileApi = (uniqueFileName: string): Promise<Blob> => {
9
9
  return axiosRequest({
10
- url: '/api/files/' + uniqueFileName,
10
+ url: '/files/' + uniqueFileName,
11
11
  method: 'get',
12
12
  responseType: 'blob',
13
13
  showErrorMsg: false
@@ -19,7 +19,7 @@ export const FileApi = (uniqueFileName: string): Promise<Blob> => {
19
19
  */
20
20
  // import { useFetch } from '@vueuse/core'
21
21
  // export const FileApi = (uniqueFileName: string) => {
22
- // return useFetch(`/api/files/${uniqueFileName}`, {
22
+ // return useFetch(`/files/${uniqueFileName}`, {
23
23
  // method: 'get',
24
24
  // headers: {
25
25
  // responseType: 'blob'
@@ -1,12 +1,20 @@
1
- import type { Pagination, PageTableData, FileContainer } from '@/types'
1
+ /**
2
+ * @Author : TanRui
3
+ * @WeChat : Tan578853789
4
+ * @File : demos/index.ts
5
+ * @Date : 2026/03/01
6
+ * @Desc. : 示例模块接口文档(可作为 AI Agent 上下文来源)
7
+ */
8
+
9
+ import type { IBusinessResponse } from '@jnrs/shared'
10
+ import type { IPagination, IPageTableData, IFile, IUser } from '@/types'
2
11
  import { axiosRequest } from '../request'
3
- import { extractFieldId } from '@/utils/file'
4
- import { objectToFormData } from '@/utils/packages'
12
+ import { objectToFormData } from '@/utils'
5
13
 
6
14
  /**
7
- * 项目
15
+ * 项目 - 详情
8
16
  */
9
- export interface ProjectItem extends FileContainer {
17
+ export interface Project extends IFile {
10
18
  id: string
11
19
  programCode: string
12
20
  program: string
@@ -23,9 +31,9 @@ export interface ProjectItem extends FileContainer {
23
31
  }
24
32
 
25
33
  /**
26
- * 新增
34
+ * 新增项目 - 忽略字段
27
35
  */
28
- type AddProjectOmitKeys =
36
+ type CreateProjectOmit =
29
37
  | 'id'
30
38
  | 'programCode'
31
39
  | 'program'
@@ -37,28 +45,54 @@ type AddProjectOmitKeys =
37
45
  | 'imageDocument'
38
46
  | 'attachmentDocument'
39
47
 
40
- export type AddProjectItem = Omit<ProjectItem, AddProjectOmitKeys> & {
48
+ /**
49
+ * 项目 - 创建
50
+ */
51
+ export type EditProject = Omit<Project, CreateProjectOmit> & {
41
52
  id?: string
42
- managerId?: Record<string, unknown> | unknown
53
+ managerId?: Record<string, unknown> | number
43
54
  newAttachmentFile: []
44
55
  newImageFiles: []
45
56
  }
46
57
 
47
58
  /**
48
- * 查询
59
+ * 项目 - 查询
49
60
  */
50
- export interface ProjectQuery extends Pagination {
61
+ export interface ProjectQuery extends IPagination {
51
62
  code?: string
52
63
  projectType?: '敏捷型' | '瀑布型' | '混合型'
53
64
  manager?: string
54
65
  }
55
66
 
67
+ // 测试 获取数据
68
+ export const DataApiTest = (id: string): Promise<IUser> => {
69
+ return axiosRequest({
70
+ url: '/auth/user-info',
71
+ method: 'get',
72
+ params: {
73
+ id
74
+ }
75
+ })
76
+ }
77
+
78
+ // 测试 获取全量数据
79
+ export const FullDataApiTest = (id: string): Promise<IBusinessResponse<IUser>> => {
80
+ return axiosRequest({
81
+ url: '/auth/user-info',
82
+ method: 'get',
83
+ params: {
84
+ id
85
+ },
86
+ returnFullResponse: true // 需要返回完整响应数据时使用该选项
87
+ })
88
+ }
89
+
56
90
  /**
57
91
  * 测试 404 错误
58
92
  */
59
93
  export const NotFoundApi = () => {
60
94
  return axiosRequest({
61
- url: '/mock/notFound',
95
+ url: '/notFound',
62
96
  method: 'get'
63
97
  })
64
98
  }
@@ -68,7 +102,7 @@ export const NotFoundApi = () => {
68
102
  */
69
103
  export const NoNeedAuthApi = () => {
70
104
  return axiosRequest({
71
- url: '/mock/auth/no',
105
+ url: '/auth/no',
72
106
  method: 'post',
73
107
  noAuth: true
74
108
  })
@@ -80,7 +114,7 @@ export const NoNeedAuthApi = () => {
80
114
  */
81
115
  export const NoAuthApi = (showErrorMsg: boolean) => {
82
116
  return axiosRequest({
83
- url: '/mock/auth/no',
117
+ url: '/auth/no',
84
118
  method: 'post',
85
119
  showErrorMsg
86
120
  })
@@ -89,43 +123,50 @@ export const NoAuthApi = (showErrorMsg: boolean) => {
89
123
  /**
90
124
  * 数据详情
91
125
  */
92
- export const DetailsApi = (): Promise<FileContainer> => {
126
+ export const DetailsApi = (): Promise<IFile> => {
93
127
  return axiosRequest({
94
- url: '/mock/details',
128
+ url: '/details',
95
129
  method: 'get'
96
130
  })
97
131
  }
98
132
 
99
133
  /**
100
- * 表单编辑(包含文件上传类需使用 formData 类型)
134
+ * 项目 - 编辑
101
135
  */
102
- export const EditApi = (data: AddProjectItem) => {
103
- const formData = objectToFormData({
104
- ...data,
105
- managerId: extractFieldId(data.managerId, 'managerId')
106
- })
136
+ export const EditProjectApi = (data: EditProject) => {
107
137
  return axiosRequest({
108
- url: '/mock/demos/save',
138
+ url: '/demos/save',
109
139
  method: 'post',
110
- data: formData
140
+ data: objectToFormData(data) // 包含文件上传类需使用 formData 类型
141
+ })
142
+ }
143
+
144
+ /**
145
+ * 项目 - 更新
146
+ */
147
+ export const UpdateProjectApi = (data: Project) => {
148
+ return axiosRequest({
149
+ url: '/demos/update',
150
+ method: 'put',
151
+ data
111
152
  })
112
153
  }
113
154
 
114
155
  /**
115
156
  * 删除数据
116
157
  */
117
- export const DelApi = (id: string) => {
158
+ export const DeleteProjectApi = (id: string) => {
118
159
  return axiosRequest({
119
- url: `/mock/demos/delete/${id}`,
160
+ url: `/demos/delete/${id}`,
120
161
  method: 'delete'
121
162
  })
122
163
  }
123
164
  /**
124
165
  * 列表数据
125
166
  */
126
- export const ListApi = (data?: ProjectQuery): Promise<PageTableData<ProjectItem>> => {
167
+ export const ProjectListApi = (data?: ProjectQuery): Promise<IPageTableData<Project>> => {
127
168
  return axiosRequest({
128
- url: '/mock/demos/table',
169
+ url: '/demos/table',
129
170
  method: 'get',
130
171
  data
131
172
  })
@@ -134,9 +175,9 @@ export const ListApi = (data?: ProjectQuery): Promise<PageTableData<ProjectItem>
134
175
  /**
135
176
  * 下载数据导入模板
136
177
  */
137
- export const ImportTemplateApi = (): Promise<Blob> => {
178
+ export const DownloadTemplateApi = (): Promise<Blob> => {
138
179
  return axiosRequest({
139
- url: '/mock/project/template',
180
+ url: '/project/template',
140
181
  method: 'post'
141
182
  })
142
183
  }
@@ -146,7 +187,7 @@ export const ImportTemplateApi = (): Promise<Blob> => {
146
187
  */
147
188
  export const ImportDataApi = (data: FormData) => {
148
189
  return axiosRequest({
149
- url: '/mock/project/import',
190
+ url: '/project/import',
150
191
  method: 'post',
151
192
  data
152
193
  })
@@ -157,7 +198,7 @@ export const ImportDataApi = (data: FormData) => {
157
198
  */
158
199
  export const ExportApi = (data: Record<string, unknown>): Promise<Blob> => {
159
200
  return axiosRequest({
160
- url: '/mock/project/export',
201
+ url: '/project/export',
161
202
  method: 'post',
162
203
  data
163
204
  })
@@ -6,9 +6,10 @@
6
6
  * @Desc. : axios 网络请求实例
7
7
  */
8
8
 
9
- import type { BusinessRequest, BusinessResponse } from '@jnrs/shared/request'
9
+ import type { IBusinessRequest, IBusinessResponse } from '@jnrs/shared'
10
10
  import { createAxiosInstance } from '@jnrs/shared/request'
11
- import { useMockStore, useAuthStore } from '@jnrs/vue-core/pinia'
11
+ import { useMockStore } from '@jnrs/vue-core/pinia'
12
+ import { useAuthStore } from '@/stores'
12
13
  import { handleRouter } from '@jnrs/vue-core/router'
13
14
  import { ElMessage } from 'element-plus'
14
15
 
@@ -31,20 +32,18 @@ const axiosInstance = createAxiosInstance({
31
32
  * @param options 请求配置项
32
33
  * @returns Promise<T> 响应数据
33
34
  */
34
- const axiosRequest = <T = BusinessResponse>(options: BusinessRequest): Promise<T> => {
35
+ const axiosRequest = <T = IBusinessResponse>(options: IBusinessRequest): Promise<T> => {
35
36
  if (!axiosInstance) {
36
37
  throw new Error('请先调用 createRequest 初始化 axios 实例')
37
38
  }
38
39
 
39
- // 如果是模拟请求,则将请求地址改为模拟地址
40
- const { isMock } = useMockStore()
40
+ const { useMockServe } = useMockStore()
41
41
 
42
- if (isMock) {
43
- options.url = options.mockUrl
44
- ? options.mockUrl
45
- : options.url.startsWith('/mock')
46
- ? options.url
47
- : '/mock' + options.url
42
+ // 如果开启 mock 模式,则将请求地址改为 mock 地址,否则使用 api 地址
43
+ if (useMockServe) {
44
+ options.url = '/api/mock' + options.url
45
+ } else {
46
+ options.url = '/api' + options.url
48
47
  }
49
48
 
50
49
  return axiosInstance(options)
@@ -1,16 +1,17 @@
1
- import type { Dict, DictItem, User, Role } from '@jnrs/shared'
2
- import type { MenuItem } from '@jnrs/vue-core'
1
+ import type { IDict, IDictItem, IRole } from '@/types'
2
+ import type { IMenuItem } from '@jnrs/vue-core'
3
+ import type { IUser } from '@/types'
3
4
  import { axiosRequest } from '../request'
4
- import { objectToFormData } from '@/utils/packages'
5
+ import { objectToFormData } from '@/utils'
5
6
 
6
7
  // 菜单
7
- export const MenuApi = (): Promise<MenuItem[]> => {
8
- return axiosRequest({
9
- url: '/system/menu.json', // /public 文件夹下
10
- mockUrl: '/mock/menu',
11
- method: 'get',
12
- noAuth: true // 本地数据忽略 token 验证
13
- })
8
+ export const MenuApi = async (): Promise<IMenuItem[]> => {
9
+ const response = await fetch('/system/menu.json')
10
+ if (!response.ok) {
11
+ throw new Error(`Failed to load menu.json: ${response.status} ${response.statusText}`)
12
+ }
13
+ const data = await response.json()
14
+ return data.data
14
15
  }
15
16
 
16
17
  // 登录
@@ -22,16 +23,16 @@ interface LoginParams {
22
23
  /**
23
24
  * 登录结果
24
25
  */
25
- export interface LoginResult extends User {
26
+ export interface LoginResult extends IUser {
26
27
  token: string
27
- dict: Dict
28
+ dict: IDict
28
29
  }
29
30
 
30
31
  export const LoginApi = (data: LoginParams): Promise<LoginResult> => {
31
32
  return axiosRequest({
32
- url: '/api/auth/login',
33
+ url: '/auth/login',
33
34
  method: 'post',
34
- data,
35
+ data: objectToFormData(data),
35
36
  noAuth: true
36
37
  })
37
38
  }
@@ -39,15 +40,15 @@ export const LoginApi = (data: LoginParams): Promise<LoginResult> => {
39
40
  // 退出登录
40
41
  export const LogoutApi = () => {
41
42
  return axiosRequest({
42
- url: '/api/auth/logout',
43
+ url: '/auth/logout',
43
44
  method: 'get'
44
45
  })
45
46
  }
46
47
 
47
48
  // 获取用户信息
48
- export const UserInfoApi = (): Promise<User> => {
49
+ export const UserInfoApi = (): Promise<IUser> => {
49
50
  return axiosRequest({
50
- url: '/api/auth/user-info',
51
+ url: '/auth/user-info',
51
52
  method: 'get'
52
53
  })
53
54
  }
@@ -55,7 +56,7 @@ export const UserInfoApi = (): Promise<User> => {
55
56
  // 修改头像
56
57
  export const AvatarChangeApi = (data: File) => {
57
58
  return axiosRequest({
58
- url: '/api/user/avatar',
59
+ url: '/user/avatar',
59
60
  method: 'post',
60
61
  data: objectToFormData({ file: data })
61
62
  })
@@ -69,16 +70,16 @@ interface PasswordChange {
69
70
 
70
71
  export const PasswordChangeApi = (data: PasswordChange) => {
71
72
  return axiosRequest({
72
- url: '/api/auth/change-password',
73
+ url: '/auth/change-password',
73
74
  method: 'post',
74
75
  data
75
76
  })
76
77
  }
77
78
 
78
79
  // 获取字典列表
79
- export const DictApi = (): Promise<DictItem[]> => {
80
+ export const DictApi = (): Promise<IDictItem[]> => {
80
81
  return axiosRequest({
81
- url: '/api/dict-manager',
82
+ url: '/dict-manager',
82
83
  method: 'get'
83
84
  })
84
85
  }
@@ -86,24 +87,24 @@ export const DictApi = (): Promise<DictItem[]> => {
86
87
  // 获取单个字典
87
88
  export const DictDetailApi = (id: string) => {
88
89
  return axiosRequest({
89
- url: `/api/dict-manager/detail/${id}`,
90
+ url: `/dict-manager/detail/${id}`,
90
91
  method: 'get'
91
92
  })
92
93
  }
93
94
 
94
95
  // 修改单个字典
95
- export const DictChangeApi = (data: DictItem) => {
96
+ export const DictChangeApi = (data: IDictItem) => {
96
97
  return axiosRequest({
97
- url: '/api/dict-manager/detail',
98
+ url: '/dict-manager/detail',
98
99
  method: 'post',
99
100
  data
100
101
  })
101
102
  }
102
103
 
103
104
  // 获取角色列表
104
- export const RoleApi = (): Promise<Role[]> => {
105
+ export const RoleApi = (): Promise<IRole[]> => {
105
106
  return axiosRequest({
106
- url: '/api/role-manager',
107
+ url: '/role-manager',
107
108
  method: 'get',
108
109
  noAuth: true
109
110
  })
@@ -7,7 +7,7 @@
7
7
  -->
8
8
 
9
9
  <script setup lang="ts">
10
- import type { Pagination, PageTableData } from '@/types'
10
+ import type { IPagination, IPageTableData } from '@/types'
11
11
  import { ref, onActivated } from 'vue'
12
12
  import { JnPagination, JnTable } from '@jnrs/vue-core/components'
13
13
  import { debounce } from '@jnrs/shared/lodash'
@@ -17,7 +17,7 @@ export interface Props {
17
17
  * 获取数据表格 api 函数
18
18
  */
19
19
  // eslint-disable-next-line
20
- getTableDataApi?: (data?: Pagination) => Promise<PageTableData<any>>
20
+ getTableDataApi?: (data?: IPagination) => Promise<IPageTableData<any>>
21
21
  }
22
22
 
23
23
  const { getTableDataApi } = defineProps<Props>()
@@ -25,7 +25,7 @@ const { getTableDataApi } = defineProps<Props>()
25
25
  const loading = ref(false)
26
26
  const tableData = ref()
27
27
  const total = ref(0)
28
- const pagination = ref<Pagination>({ pageNo: 1, pageSize: 20 })
28
+ const pagination = ref<IPagination>({ pageNo: 1, pageSize: 20 })
29
29
 
30
30
  const getTable = debounce(async () => {
31
31
  if (!getTableDataApi) {
@@ -8,7 +8,7 @@
8
8
 
9
9
  <script setup lang="ts">
10
10
  import { computed } from 'vue'
11
- import { getDictLabel, getDictColor } from '@/utils/packages'
11
+ import { getDictLabel, getDictColor } from '@/utils'
12
12
 
13
13
  export interface Props {
14
14
  dictName: string
@@ -1,6 +1,6 @@
1
1
  <script lang="ts" setup>
2
- import type { FileItem } from '@jnrs/shared'
3
- import type { Attachment } from '@/types'
2
+ import type { IFileItem } from '@jnrs/shared'
3
+ import type { IAttachment } from '@/types'
4
4
  import { ref, watch, onActivated, onDeactivated, onBeforeUnmount } from 'vue'
5
5
  import { blobToUrl } from '@jnrs/shared'
6
6
  import { debounce } from '@jnrs/shared/lodash'
@@ -12,7 +12,7 @@ export interface Props {
12
12
  /**
13
13
  * 要加载的文件列表 | 文件名唯一标识 uniqueFileName
14
14
  */
15
- loadKeys: Attachment[] | string | undefined
15
+ loadKeys: IAttachment[] | string | undefined
16
16
 
17
17
  /**
18
18
  * 是否清理文件副作用
@@ -26,7 +26,7 @@ const { loadKeys, clearSideEffects = false } = defineProps<Props>()
26
26
  const posterUrl = ref('')
27
27
 
28
28
  // 存储每个 URL 对应的 URL 对象
29
- const fileList = ref<FileItem[]>([])
29
+ const fileList = ref<IFileItem[]>([])
30
30
 
31
31
  // 存储每个 URL 对应的 revoke 函数用于副作用清理
32
32
  const revokeFns = ref<(() => void)[]>([])
@@ -1,6 +1,6 @@
1
1
  <script lang="ts" setup>
2
- import type { FileItem } from '@jnrs/shared'
3
- import type { Attachment } from '@/types'
2
+ import type { IFileItem } from '@jnrs/shared'
3
+ import type { IAttachment } from '@/types'
4
4
  import { ref, watch, onActivated, onDeactivated, onBeforeUnmount } from 'vue'
5
5
  import { blobToUrl } from '@jnrs/shared'
6
6
  import { FileApi } from '@/api/common'
@@ -11,7 +11,7 @@ export interface Props {
11
11
  /**
12
12
  * 要加载的文件列表 | 文件名唯一标识 uniqueFileName
13
13
  */
14
- loadKeys: Attachment[] | string | undefined
14
+ loadKeys: IAttachment[] | string | undefined
15
15
 
16
16
  /**
17
17
  * 是否清理文件副作用
@@ -22,7 +22,7 @@ export interface Props {
22
22
  const { loadKeys, clearSideEffects = false } = defineProps<Props>()
23
23
 
24
24
  // 存储每个 URL 对应的 URL 对象
25
- const fileList = ref<FileItem[]>([])
25
+ const fileList = ref<IFileItem[]>([])
26
26
 
27
27
  // 存储每个 URL 对应的 revoke 函数用于副作用清理
28
28
  const revokeFns = ref<(() => void)[]>([])
@@ -7,7 +7,7 @@
7
7
  -->
8
8
 
9
9
  <script setup lang="ts">
10
- import { ListApi } from '@/api/demos/index'
10
+ import { ProjectListApi } from '@/api/demos/index'
11
11
  import { JnSelectTemplate } from '@jnrs/vue-core/components'
12
12
  </script>
13
13
 
@@ -15,8 +15,8 @@ import { JnSelectTemplate } from '@jnrs/vue-core/components'
15
15
  <JnSelectTemplate
16
16
  tableName="项目经理"
17
17
  :keyValue="{ name: 'manager', id: 'managerId', code: 'code' }"
18
+ :listApi="ProjectListApi"
18
19
  optionSecondaryField="code"
19
- :listApi="ListApi"
20
20
  >
21
21
  <template #table>
22
22
  <el-table-column prop="manager" label="项目经理" align="center" sortable />
@@ -3,14 +3,14 @@ import type { FormInstance } from 'element-plus'
3
3
  import { ElMessage, ElMessageBox } from 'element-plus'
4
4
  import { debounce } from '@jnrs/shared/lodash'
5
5
  import { objectMatchAssign } from '@jnrs/shared'
6
- import type { Pagination, PageTableData } from '@/types'
6
+ import type { IPagination, IPageTableData } from '@/types'
7
7
 
8
8
  interface CrudOptions<TItem, TForm, TQuery> {
9
9
  // 初始值
10
10
  defaultForm: () => TForm
11
11
  defaultQuery?: () => TQuery
12
12
  // API
13
- listApi: (params: Partial<Pagination> & TQuery) => Promise<PageTableData<TItem> | TItem[]>
13
+ listApi: (params: Partial<IPagination> & TQuery) => Promise<IPageTableData<TItem> | TItem[]>
14
14
  saveApi: (data: TForm) => Promise<unknown>
15
15
  deleteApi?: (id: number) => Promise<unknown>
16
16
  // 可选:是否启用分页,默认 true
@@ -21,13 +21,22 @@ interface CrudOptions<TItem, TForm, TQuery> {
21
21
  }
22
22
 
23
23
  export function useCrud<TItem, TForm, TQuery = object>(options: CrudOptions<TItem, TForm, TQuery>) {
24
- const { defaultForm, defaultQuery, listApi, saveApi, deleteApi, pagination: enablePagination = true, transformItem, beforeEdit } = options
24
+ const {
25
+ defaultForm,
26
+ defaultQuery,
27
+ listApi,
28
+ saveApi,
29
+ deleteApi,
30
+ pagination: enablePagination = true,
31
+ transformItem,
32
+ beforeEdit
33
+ } = options
25
34
 
26
35
  // 列表状态
27
36
  const loading = ref(false)
28
37
  const tableData = ref<TItem[]>([]) as Ref<TItem[]>
29
38
  const total = ref(0)
30
- const pagination = ref<Pagination>({ pageNo: 1, pageSize: 20 })
39
+ const pagination = ref<IPagination>({ pageNo: 1, pageSize: 20 })
31
40
  const queryForm = ref(defaultQuery?.() ?? {}) as Ref<TQuery>
32
41
 
33
42
  // 表单状态
@@ -42,7 +51,7 @@ export function useCrud<TItem, TForm, TQuery = object>(options: CrudOptions<TIte
42
51
  const params = {
43
52
  ...(enablePagination ? pagination.value : {}),
44
53
  ...queryForm.value
45
- } as Partial<Pagination> & TQuery
54
+ } as Partial<IPagination> & TQuery
46
55
  const res = await listApi(params)
47
56
  // 支持返回数组或 { list, count } 格式
48
57
  if (Array.isArray(res)) {
@@ -74,7 +83,7 @@ export function useCrud<TItem, TForm, TQuery = object>(options: CrudOptions<TIte
74
83
  queueMicrotask(() => {
75
84
  formRef.value?.resetFields()
76
85
  const matched = objectMatchAssign(
77
- defaultForm() as Record<string, unknown>,
86
+ defaultForm() as Record<string, unknown>,
78
87
  row as Record<string, unknown>
79
88
  ) as TForm
80
89
  form.value = (beforeEdit ? beforeEdit(row, matched) : matched) as TForm
@@ -124,8 +133,18 @@ export function useCrud<TItem, TForm, TQuery = object>(options: CrudOptions<TIte
124
133
  }
125
134
 
126
135
  return {
127
- loading, tableData, total, pagination, queryForm,
128
- dialogRef, formRef, form,
129
- getList, openCreate, openEdit, submitForm, handleDelete
136
+ loading,
137
+ tableData,
138
+ total,
139
+ pagination,
140
+ queryForm,
141
+ dialogRef,
142
+ formRef,
143
+ form,
144
+ getList,
145
+ openCreate,
146
+ openEdit,
147
+ submitForm,
148
+ handleDelete
130
149
  }
131
- }
150
+ }