create-jnrs-template-vue 1.2.1 → 1.2.3

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 (69) hide show
  1. package/bin/create.mjs +3 -3
  2. package/jnrs-template-vue/auto-imports.d.ts +4 -0
  3. package/jnrs-template-vue/components.d.ts +0 -1
  4. package/jnrs-template-vue/package.json +3 -4
  5. package/jnrs-template-vue/public/system/menu.json +1 -1
  6. package/jnrs-template-vue/src/App.vue +1 -3
  7. package/jnrs-template-vue/src/api/common/index.ts +2 -2
  8. package/jnrs-template-vue/src/api/demos/index.ts +84 -48
  9. package/jnrs-template-vue/src/api/system/index.ts +10 -10
  10. package/jnrs-template-vue/src/api/user/index.ts +2 -2
  11. package/jnrs-template-vue/src/assets/styles/animation.scss +0 -0
  12. package/jnrs-template-vue/src/assets/styles/common.scss +4 -0
  13. package/jnrs-template-vue/src/assets/styles/fonts.scss +4 -1
  14. package/jnrs-template-vue/src/assets/styles/{main.scss → index.scss} +1 -0
  15. package/jnrs-template-vue/src/assets/styles/init.scss +4 -13
  16. package/jnrs-template-vue/src/assets/styles/root.scss +0 -3
  17. package/jnrs-template-vue/src/components/common/{JnDictTag.vue → DictTag.vue} +1 -1
  18. package/jnrs-template-vue/src/components/{base → common}/PdfView.vue +2 -2
  19. package/jnrs-template-vue/src/components/select/SelectManager.vue +20 -0
  20. package/jnrs-template-vue/src/composables/common/usePagination.ts +4 -4
  21. package/jnrs-template-vue/src/composables/common/useTable.ts +4 -4
  22. package/jnrs-template-vue/src/composables/tools/useMouseSelection.ts +150 -0
  23. package/jnrs-template-vue/src/layout/SideMenu.vue +1 -0
  24. package/jnrs-template-vue/src/layout/TopHeader.vue +1 -1
  25. package/jnrs-template-vue/src/locales/en.ts +1 -1
  26. package/jnrs-template-vue/src/locales/index.ts +1 -1
  27. package/jnrs-template-vue/src/main.ts +1 -1
  28. package/jnrs-template-vue/src/types/index.ts +45 -3
  29. package/jnrs-template-vue/src/views/demos/crud/index.vue +140 -40
  30. package/jnrs-template-vue/src/views/demos/unitTest/RequestPage.vue +1 -1
  31. package/jnrs-template-vue/src/views/demos/unitTest/index.vue +26 -2
  32. package/jnrs-template-vue/src/views/login/index.vue +7 -2
  33. package/jnrs-template-vue/src/views/system/dict/index.vue +2 -2
  34. package/jnrs-template-vue/src/views/system/menu/index.vue +2 -2
  35. package/jnrs-template-vue/src/views/system/mine/baseInfo.vue +1 -1
  36. package/jnrs-template-vue/tsconfig.json +1 -9
  37. package/jnrs-template-vue/vite.config.ts +1 -3
  38. package/jnrs-template-vue/viteMockServe/fail.ts +12 -0
  39. package/jnrs-template-vue/viteMockServe/file.ts +2 -3
  40. package/jnrs-template-vue/viteMockServe/json/tableRes.json +384 -342
  41. package/package.json +1 -1
  42. package/jnrs-template-vue/src/assets/images/fileIcon/iconArchive.png +0 -0
  43. package/jnrs-template-vue/src/assets/images/fileIcon/iconAudio.png +0 -0
  44. package/jnrs-template-vue/src/assets/images/fileIcon/iconCode.png +0 -0
  45. package/jnrs-template-vue/src/assets/images/fileIcon/iconExcel.png +0 -0
  46. package/jnrs-template-vue/src/assets/images/fileIcon/iconFile.png +0 -0
  47. package/jnrs-template-vue/src/assets/images/fileIcon/iconFlash.png +0 -0
  48. package/jnrs-template-vue/src/assets/images/fileIcon/iconGif.png +0 -0
  49. package/jnrs-template-vue/src/assets/images/fileIcon/iconImage.png +0 -0
  50. package/jnrs-template-vue/src/assets/images/fileIcon/iconMac.png +0 -0
  51. package/jnrs-template-vue/src/assets/images/fileIcon/iconOfd.png +0 -0
  52. package/jnrs-template-vue/src/assets/images/fileIcon/iconPdf.png +0 -0
  53. package/jnrs-template-vue/src/assets/images/fileIcon/iconPpt.png +0 -0
  54. package/jnrs-template-vue/src/assets/images/fileIcon/iconText.png +0 -0
  55. package/jnrs-template-vue/src/assets/images/fileIcon/iconUnknown.png +0 -0
  56. package/jnrs-template-vue/src/assets/images/fileIcon/iconVideo.png +0 -0
  57. package/jnrs-template-vue/src/assets/images/fileIcon/iconWindows.png +0 -0
  58. package/jnrs-template-vue/src/assets/images/fileIcon/iconWord.png +0 -0
  59. package/jnrs-template-vue/src/assets/images/fileIcon/iconWps.png +0 -0
  60. package/jnrs-template-vue/src/components/base/JnFileUpload.vue +0 -433
  61. package/jnrs-template-vue/src/components/common/JnDatetime.vue +0 -37
  62. package/jnrs-template-vue/src/components/common/JnEdit.vue +0 -68
  63. package/jnrs-template-vue/src/components/common/JnPagination.vue +0 -83
  64. package/jnrs-template-vue/src/components/common/JnTable.vue +0 -133
  65. package/jnrs-template-vue/src/composables/tools/useReactivityTableHeight.ts +0 -63
  66. /package/jnrs-template-vue/src/components/{base → common}/ImageView.vue +0 -0
  67. /package/jnrs-template-vue/viteMockServe/{fileSrc → file}/mock-pdf.pdf +0 -0
  68. /package/jnrs-template-vue/viteMockServe/{fileSrc → file}/mock-png-0.png +0 -0
  69. /package/jnrs-template-vue/viteMockServe/{fileSrc → file}/mock-png-1.png +0 -0
@@ -0,0 +1,150 @@
1
+ /**
2
+ * @Author : TanRui
3
+ * @WeChat : Tan578853789
4
+ * @File : useMouseSelection.ts
5
+ * @Date : 2025/04/14
6
+ * @Desc. : 鼠标框选表格进行多选、回车执行回调
7
+ */
8
+
9
+ import { onMounted, onUnmounted, onActivated, onDeactivated } from 'vue'
10
+
11
+ /**
12
+ * @param {*} containerClass 表格或容器类名,默认值 el-table,如果页面存在多个表格,则必须分别传入自定义类名
13
+ * @param {*} rowClass 表格或容器类名,默认值 el-table__row
14
+ * @param {*} callback 框选后的回调,默认处理的是 input[type='checkbox'] 元素
15
+ * @returns handleMouseDown
16
+ * @example <el-table @mousedown="handleMouseDown" @selection-change="handleSelectionChange">
17
+ */
18
+ export function useMouseSelection({
19
+ containerClass = 'jn_table',
20
+ rowClass = 'el-table__row',
21
+ callback = handleSelection
22
+ } = {}) {
23
+ let isDragging = false
24
+ let startPoint = { x: 0, y: 0 }
25
+ let endPoint = { x: 0, y: 0 }
26
+
27
+ onMounted(() => {
28
+ window.addEventListener('mouseup', handleMouseUp)
29
+ })
30
+
31
+ onUnmounted(() => {
32
+ window.removeEventListener('mouseup', handleMouseUp)
33
+ })
34
+
35
+ onActivated(() => {
36
+ window.addEventListener('mouseup', handleMouseUp)
37
+ })
38
+
39
+ onDeactivated(() => {
40
+ window.removeEventListener('mouseup', handleMouseUp)
41
+ })
42
+
43
+ // 鼠标按下事件
44
+ const handleMouseDown = (event: MouseEvent) => {
45
+ window.addEventListener('mousemove', handleMouseMove)
46
+ isDragging = false
47
+ startPoint = { x: event.clientX, y: event.clientY }
48
+ endPoint = { ...startPoint }
49
+ }
50
+
51
+ // 鼠标移动事件
52
+ const handleMouseMove = (event: MouseEvent) => {
53
+ endPoint = { x: event.clientX, y: event.clientY }
54
+ // 判断是否为拖动
55
+ if (Math.abs(endPoint.x - startPoint.x) > 5 && Math.abs(endPoint.y - startPoint.y) > 25) {
56
+ isDragging = true
57
+ }
58
+ // 如果没有拖动,则认为是单击
59
+ if (isDragging) {
60
+ selectRows()
61
+ }
62
+ setFixedRectBoxStyle()
63
+ }
64
+
65
+ // 鼠标抬起事件
66
+ const handleMouseUp = () => {
67
+ window.removeEventListener('mousemove', handleMouseMove)
68
+ // 如果没有拖动,则认为是单击
69
+ if (isDragging) {
70
+ isDragging = false
71
+ }
72
+ setFixedRectBoxStyle()
73
+ }
74
+
75
+ // 判断选中的行
76
+ const selectRows = () => {
77
+ const container = document.querySelector(`.${containerClass}`) as HTMLElement
78
+ const rows = container?.querySelectorAll(`.${rowClass}`) as NodeListOf<HTMLElement>
79
+ if (!rows) {
80
+ return false
81
+ }
82
+ rows.forEach((row) => {
83
+ const rect = row.getBoundingClientRect()
84
+ const isIntersecting =
85
+ rect.right > Math.min(startPoint.x, endPoint.x) &&
86
+ rect.left < Math.max(startPoint.x, endPoint.x) &&
87
+ rect.bottom > Math.min(startPoint.y, endPoint.y) &&
88
+ rect.top < Math.max(startPoint.y, endPoint.y)
89
+ if (isIntersecting && callback) {
90
+ callback(row)
91
+ }
92
+ })
93
+ }
94
+
95
+ // 设置框选框的位置
96
+ const setFixedRectBoxStyle = () => {
97
+ const selectionBox = document.querySelector('.useMouseSelection_fixedRectBox') as HTMLElement
98
+ if (selectionBox) {
99
+ const left = Math.min(startPoint.x, endPoint.x) + 'px'
100
+ const top = Math.min(startPoint.y, endPoint.y) + 'px'
101
+ const width = Math.abs(endPoint.x - startPoint.x) + 'px'
102
+ const height = Math.abs(endPoint.y - startPoint.y) + 'px'
103
+ Object.assign(selectionBox.style, {
104
+ display: isDragging ? 'block' : 'none',
105
+ left: left,
106
+ top: top,
107
+ width: width,
108
+ height: height
109
+ })
110
+
111
+ const container = document.querySelector(`.${containerClass}`) as HTMLElement
112
+ Object.assign(container.style, {
113
+ 'user-select': isDragging ? 'none' : 'auto'
114
+ })
115
+ }
116
+ }
117
+
118
+ checkAndAddElement()
119
+
120
+ return {
121
+ handleMouseDown
122
+ }
123
+ }
124
+
125
+ // 回调选中逻辑
126
+ const handleSelection = (row: HTMLElement) => {
127
+ const checkbox = row.querySelector("input[type='checkbox']") as HTMLInputElement
128
+ if (checkbox && !checkbox.checked) {
129
+ checkbox.click()
130
+ }
131
+ }
132
+
133
+ // 往页面上添加框选框元素
134
+ const checkAndAddElement = () => {
135
+ const fixedRectBox = document.querySelector('.useMouseSelection_fixedRectBox')
136
+ if (!fixedRectBox) {
137
+ const newDiv = document.createElement('div')
138
+ newDiv.className = 'useMouseSelection_fixedRectBox'
139
+ Object.assign(newDiv.style, {
140
+ display: 'none',
141
+ position: 'fixed',
142
+ 'z-index': 100,
143
+ border: '2px dashed #409eff',
144
+ 'background-color': 'rgba(64, 158, 255, 0.2)',
145
+ 'pointer-events': 'none',
146
+ 'will-change': 'transform'
147
+ })
148
+ document.body.appendChild(newDiv)
149
+ }
150
+ }
@@ -68,6 +68,7 @@ $mainFontColor: rgba(255, 255, 255, 0.8);
68
68
  font-weight: normal;
69
69
  font-family: AlimamaShuHeiTi-Bold;
70
70
  white-space: nowrap;
71
+ letter-spacing: 2px;
71
72
  transform: translate(-50%, -50%);
72
73
  transition: all 0.3s ease;
73
74
  filter: opacity(1);
@@ -8,7 +8,7 @@ import { useSystemStore, useAuthStore, useMenuStore } from '@jnrs/vue-core/pinia
8
8
  import { LogoutApi } from '@/api/system'
9
9
  import { getDictLabel, getDictColor } from '@/utils/packages'
10
10
 
11
- import ImageView from '@/components/base/ImageView.vue'
11
+ import ImageView from '@/components/common/ImageView.vue'
12
12
 
13
13
  const { userInfo, clearAuth } = useAuthStore()
14
14
  const { clearMenu } = useMenuStore()
@@ -8,7 +8,7 @@ export default {
8
8
  formAccount: 'Please enter your account',
9
9
  formPassword: 'Please enter your password',
10
10
  formBtn: 'Log In',
11
- greeting: 'Welcome to'
11
+ greeting: 'Welcome'
12
12
  },
13
13
  layout: {}
14
14
  }
@@ -4,7 +4,7 @@ import en from './en'
4
4
  import { zhCn as vueCore_zhCn, en as vueCore_en } from '@jnrs/vue-core/locales'
5
5
 
6
6
  const i18n = createI18n({
7
- legacy: false, // 启用 Composition API 模式
7
+ legacy: false, // legacy 为 false 则启用 Composition API 模式
8
8
  globalInjection: true, // 允许在模板中使用 $t
9
9
  locale: 'zhCn',
10
10
  fallbackLocale: 'en',
@@ -1,7 +1,7 @@
1
1
  import 'element-plus/dist/index.css'
2
2
  import 'element-plus/theme-chalk/dark/css-vars.css'
3
3
  import '@jnrs/shared/styles/theme.scss'
4
- import '@/assets/styles/main.scss'
4
+ import '@/assets/styles/index.scss'
5
5
 
6
6
  import { createApp } from 'vue'
7
7
  import { createPinia } from 'pinia'
@@ -1,5 +1,5 @@
1
1
  /**
2
- * 附件(文件)信息
2
+ * 文件信息
3
3
  */
4
4
  export interface Attachment {
5
5
  /**
@@ -15,7 +15,7 @@ export interface Attachment {
15
15
  */
16
16
  fileName: string
17
17
  /**
18
- * 文件名唯一标识
18
+ * 文件名唯一标识(用于文件获取 API)
19
19
  */
20
20
  uniqueFileName: string
21
21
  /**
@@ -29,10 +29,52 @@ export interface Attachment {
29
29
  }
30
30
 
31
31
  /**
32
- * 文档容器(用于图片或附件)
32
+ * 文件容器(用于图片或附件)
33
33
  */
34
34
  export interface Document {
35
35
  id: number
36
36
  description: string | null
37
37
  attachments: Attachment[]
38
38
  }
39
+
40
+ /**
41
+ * 图片 & 附件数据
42
+ */
43
+ export interface FileContainer {
44
+ /**
45
+ * 图片
46
+ */
47
+ imageDocument?: Document
48
+ /**
49
+ * 附件
50
+ */
51
+ attachmentDocument?: Document
52
+ }
53
+
54
+ /**
55
+ * 分页
56
+ */
57
+ export interface Pagination {
58
+ /**
59
+ * 当前页码
60
+ */
61
+ pageNo: number
62
+ /**
63
+ * 每页大小
64
+ */
65
+ pageSize: number
66
+ }
67
+
68
+ /**
69
+ * 分页列表数据
70
+ */
71
+ export interface PageTableData<T> extends Pagination {
72
+ /**
73
+ * 数据列表
74
+ */
75
+ list: T[]
76
+ /**
77
+ * 数据总数
78
+ */
79
+ count: number
80
+ }
@@ -1,22 +1,27 @@
1
1
  <script setup lang="ts">
2
2
  import type { FormInstance, FormRules } from 'element-plus'
3
- import type { Attachment } from '@/types'
3
+ import type { Attachment, Pagination } from '@/types'
4
4
  import type { ProjectItem, AddProjectItem } from '@/api/demos/index'
5
5
  import { ref, onActivated } from 'vue'
6
6
  import { ElMessage } from 'element-plus'
7
7
  import { Plus } from '@element-plus/icons-vue'
8
- import { objectMatchAssign } from '@jnrs/shared'
8
+ import { objectMatchAssign, dateFormatsToObject } from '@jnrs/shared'
9
+ import { debounce } from '@jnrs/shared/lodash'
9
10
  import { isNumberGtZero } from '@jnrs/shared/validator'
10
- import { getDictList, objectToFormData } from '@/utils/packages'
11
- import { DemosTableApi, DemosFormApi } from '@/api/demos/index'
12
- import JnTable from '@/components/common/JnTable.vue'
13
- import JnPagination from '@/components/common/JnPagination.vue'
14
- import ImageView from '@/components/base/ImageView.vue'
15
- import PdfView from '@/components/base/PdfView.vue'
16
- import JnEdit from '@/components/common/JnEdit.vue'
17
- import JnDictTag from '@/components/common/JnDictTag.vue'
18
- import JnDatetime from '@/components/common/JnDatetime.vue'
19
- import JnFileUpload from '@/components/base/JnFileUpload.vue'
11
+ import { getDictList, objectToFormData, downloadFile } from '@/utils/packages'
12
+ import {
13
+ DemosTableApi,
14
+ DemosFormApi,
15
+ DemosImportTemplateApi,
16
+ DemosImportDataApi,
17
+ DemosExportApi
18
+ } from '@/api/demos/index'
19
+
20
+ import { JnDialog, JnDatetime, JnPagination, JnFileUpload, JnTable, JnImportAndExport } from '@jnrs/vue-core/components'
21
+ import ImageView from '@/components/common/ImageView.vue'
22
+ import PdfView from '@/components/common/PdfView.vue'
23
+ import DictTag from '@/components/common/DictTag.vue'
24
+ import SelectManager from '@/components/select/SelectManager.vue'
20
25
 
21
26
  interface ProcessedProjectItem extends ProjectItem {
22
27
  newImageFiles?: Attachment[]
@@ -26,28 +31,30 @@ interface ProcessedProjectItem extends ProjectItem {
26
31
  const loading = ref(false)
27
32
  const tableData = ref<ProcessedProjectItem[]>([])
28
33
  const total = ref(0)
29
- const pagination = ref({ currentPage: 1, pageSize: 10 })
30
- const jnEditRef = ref()
31
- const ruleFormRef = ref<FormInstance>()
34
+ const pagination = ref<Pagination>({ pageNo: 1, pageSize: 10 })
32
35
 
36
+ // 编辑
37
+ const editDialogRef = ref()
38
+ const ruleFormRef = ref<FormInstance>()
33
39
  const ruleForm = ref<AddProjectItem>({
34
40
  id: '',
35
41
  name: '',
36
42
  program: '',
37
43
  projectType: undefined,
44
+ managerId: undefined,
38
45
  budget: 0,
39
46
  plannedStartDate: '',
40
47
  description: '',
41
48
  newImageFiles: [],
42
49
  newAttachmentFile: []
43
50
  })
44
-
45
51
  const rules = ref<FormRules>({
46
52
  name: [{ required: true, message: '请输入', trigger: 'change' }],
47
53
  program: [{ required: true, message: '请选择', trigger: 'change' }],
48
54
  projectType: [{ required: true, message: '请选择', trigger: 'change' }],
49
55
  plannedStartDate: [{ required: true, message: '请选择', trigger: 'change' }],
50
56
  newImageFiles: [{ required: true, message: '请上传', trigger: 'change' }],
57
+ managerId: [{ required: true, message: '请选择', trigger: 'change' }],
51
58
  budget: [
52
59
  { required: true, message: '请输入', trigger: 'change' },
53
60
  {
@@ -57,35 +64,49 @@ const rules = ref<FormRules>({
57
64
  ]
58
65
  })
59
66
 
60
- const handlePaginationChange = () => {
61
- console.log(pagination.value)
62
- }
67
+ // 查询
68
+ const queryForm = ref({
69
+ code: '',
70
+ projectType: undefined,
71
+ manager: '',
72
+ plannedStartDate: ''
73
+ })
63
74
 
64
75
  const handleSelectionChange = (row: ProjectItem[]) => {
65
76
  console.log(row)
66
77
  }
67
78
 
68
- const getDemosTable = async () => {
79
+ const getDemosTable = debounce(async () => {
69
80
  try {
70
- const res = await DemosTableApi()
71
- tableData.value = res.map((item) => ({
81
+ const res = await DemosTableApi({
82
+ ...pagination.value,
83
+ ...queryForm.value
84
+ })
85
+ tableData.value = res.list.map((item) => ({
72
86
  ...item,
73
87
  newImageFiles: item.imageDocument?.attachments ?? undefined,
74
88
  newAttachmentFile: item.attachmentDocument?.attachments ?? undefined
75
89
  }))
76
- total.value = res.length
90
+ total.value = res.count
77
91
  } catch (error) {
78
92
  console.error(error)
79
93
  }
80
- }
94
+ }, 300)
81
95
 
82
96
  // 新增和修改
83
97
  const handleEdit = (row?: ProjectItem) => {
84
- jnEditRef.value.open()
98
+ editDialogRef.value.open()
85
99
  queueMicrotask(() => {
86
100
  ruleFormRef.value?.resetFields()
87
101
  const matched = objectMatchAssign(ruleForm.value, row)
88
102
  ruleForm.value = matched
103
+ // Select 组件数据回填
104
+ if (row && 'managerId' in row && 'manager' in row) {
105
+ ruleForm.value.managerId = {
106
+ managerId: row.managerId,
107
+ manager: row.manager
108
+ }
109
+ }
89
110
  })
90
111
  }
91
112
 
@@ -94,7 +115,10 @@ const submitForm = () => {
94
115
  ruleFormRef.value?.validate(async (valid) => {
95
116
  if (valid) {
96
117
  loading.value = true
97
- const formData = objectToFormData(ruleForm.value)
118
+ const formData = objectToFormData({
119
+ ...ruleForm.value,
120
+ managerId: ruleForm.value.managerId?.managerId
121
+ })
98
122
  try {
99
123
  await DemosFormApi(formData)
100
124
  ElMessage({
@@ -117,7 +141,8 @@ onActivated(() => {
117
141
  </script>
118
142
 
119
143
  <template>
120
- <JnEdit ref="jnEditRef" title="项目管理" width="600px">
144
+ <!-- 编辑弹窗 -->
145
+ <JnDialog ref="editDialogRef" title="项目管理" width="600px">
121
146
  <el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="auto" v-loading="loading">
122
147
  <el-form-item prop="id"></el-form-item>
123
148
  <el-form-item label="项目名称" prop="name">
@@ -133,6 +158,14 @@ onActivated(() => {
133
158
  />
134
159
  </el-select>
135
160
  </el-form-item>
161
+ <el-form-item label="项目经理" prop="managerId">
162
+ <SelectManager
163
+ v-model="ruleForm.managerId"
164
+ :formRef="ruleFormRef"
165
+ validateFieldName="managerId"
166
+ :simpleValue="false"
167
+ ></SelectManager>
168
+ </el-form-item>
136
169
  <el-form-item label="预算" prop="budget">
137
170
  <el-input-number v-model="ruleForm.budget" :min="0" :precision="2" :step="10000" controls-position="right">
138
171
  <template #prefix>
@@ -171,6 +204,7 @@ onActivated(() => {
171
204
  :fileSizeMb="50"
172
205
  :limit="3"
173
206
  drag
207
+ :downloadFileFn="(file) => downloadFile(file.uniqueFileName, file.fileName)"
174
208
  />
175
209
  </el-form-item>
176
210
  <el-form-item label="上传文件" prop="newAttachmentFile">
@@ -180,20 +214,92 @@ onActivated(() => {
180
214
  <template #footer>
181
215
  <el-button type="success" icon="Select" :loading="loading" @click="submitForm()">提交</el-button>
182
216
  </template>
183
- </JnEdit>
217
+ </JnDialog>
184
218
 
185
219
  <el-card>
186
220
  <template #header>
187
- <div class="card_header">
221
+ <div style="display: flex; justify-content: space-between; align-items: center">
188
222
  <span>项目管理</span>
189
- <el-button type="primary" size="small" :icon="Plus" @click="handleEdit()">新增</el-button>
223
+ <div style="display: flex; justify-content: space-between; align-items: center">
224
+ <JnImportAndExport
225
+ :importTemplateApi="DemosImportTemplateApi"
226
+ importBtnName="导入项目"
227
+ :importApi="DemosImportDataApi"
228
+ exportBtnName="导出项目"
229
+ :exportApi="DemosExportApi"
230
+ :exportParams="{
231
+ ...dateFormatsToObject(queryForm.plannedStartDate)
232
+ }"
233
+ :exportDynamicParamsConfig="{
234
+ label: '项目编号',
235
+ prop: 'code'
236
+ }"
237
+ :exportDisabled="tableData.length === 0"
238
+ size="small"
239
+ @change="getDemosTable()"
240
+ />
241
+ <el-button type="primary" size="small" :icon="Plus" @click="handleEdit()" style="margin-left: 12px">
242
+ 新增
243
+ </el-button>
244
+ </div>
190
245
  </div>
191
246
  </template>
247
+
248
+ <!-- 查询条件 -->
249
+ <el-form :model="queryForm" size="small" inline v-loading="loading">
250
+ <el-form-item label="项目编号" prop="code">
251
+ <el-input v-model="queryForm.code" clearable style="width: 150px">
252
+ <template #append>
253
+ <el-button icon="Search" @click="getDemosTable()" />
254
+ </template>
255
+ </el-input>
256
+ </el-form-item>
257
+ <el-form-item label="项目名称" prop="projectType">
258
+ <el-select
259
+ v-model="queryForm.projectType"
260
+ filterable
261
+ placeholder=""
262
+ clearable
263
+ style="width: 150px"
264
+ @change="getDemosTable()"
265
+ >
266
+ <el-option
267
+ :label="item.label"
268
+ :value="item.value"
269
+ v-for="item in getDictList('projectType')"
270
+ :key="item.value"
271
+ />
272
+ </el-select>
273
+ </el-form-item>
274
+ <el-form-item label="项目经理" prop="manager">
275
+ <SelectManager
276
+ v-model="queryForm.manager"
277
+ :initialParams="{ role: 1 }"
278
+ size="small"
279
+ width="200px"
280
+ @change="getDemosTable()"
281
+ ></SelectManager>
282
+ </el-form-item>
283
+ <el-form-item label="计划开始时间" prop="plannedStartDate">
284
+ <el-date-picker
285
+ v-model="queryForm.plannedStartDate"
286
+ value-format="YYYY-MM-DD"
287
+ size="small"
288
+ style="width: 150px"
289
+ @change="getDemosTable()"
290
+ />
291
+ </el-form-item>
292
+ </el-form>
293
+
294
+ <!-- 数据列表 -->
192
295
  <JnTable
193
296
  :data="tableData"
194
297
  :pagination="pagination"
298
+ :autoHeight="true"
299
+ :showScrollbar="true"
195
300
  :showIndexColumn="true"
196
301
  :showSelectionColumn="true"
302
+ :showMouseSelection="true"
197
303
  @selection-change="handleSelectionChange"
198
304
  >
199
305
  <el-table-column prop="code" label="项目编号" min-width="200" sortable show-overflow-tooltip />
@@ -205,7 +311,7 @@ onActivated(() => {
205
311
  <el-table-column prop="program" label="项目集名称" min-width="200" sortable show-overflow-tooltip />
206
312
  <el-table-column prop="projectType" label="项目类型" width="100" align="center" sortable>
207
313
  <template #default="{ row }">
208
- <JnDictTag dictName="projectType" :value="row.projectType" />
314
+ <DictTag dictName="projectType" :value="row.projectType" />
209
315
  </template>
210
316
  </el-table-column>
211
317
  <el-table-column prop="manager" label="项目经理" width="100" align="center" sortable />
@@ -231,7 +337,7 @@ onActivated(() => {
231
337
  </el-table-column>
232
338
  <el-table-column prop="status" label="状态" width="100" align="center" sortable>
233
339
  <template #default="{ row }">
234
- <JnDictTag dictName="status" :value="row.status" :showColor="false" />
340
+ <DictTag dictName="status" :value="row.status" :showColor="false" />
235
341
  </template>
236
342
  </el-table-column>
237
343
  <el-table-column prop="description" label="描述" min-width="200" show-overflow-tooltip />
@@ -252,13 +358,7 @@ onActivated(() => {
252
358
  </el-table-column>
253
359
  </JnTable>
254
360
 
255
- <JnPagination :total="total" v-model="pagination" @change="handlePaginationChange" />
361
+ <!-- 表格分页 -->
362
+ <JnPagination :total="total" v-model="pagination" @change="getDemosTable" />
256
363
  </el-card>
257
364
  </template>
258
-
259
- <style lang="scss" scoped>
260
- .card_header {
261
- display: flex;
262
- justify-content: space-between;
263
- }
264
- </style>
@@ -7,7 +7,7 @@ import { NotFoundApi, NoAuth, DetailsApi } from '@/api/demos'
7
7
  import { getFileUrl } from '@/utils/file'
8
8
  import { downloadFile } from '@/utils/packages'
9
9
 
10
- import ImageView from '@/components/base/ImageView.vue'
10
+ import ImageView from '@/components/common/ImageView.vue'
11
11
 
12
12
  const squareUrl = ref()
13
13
 
@@ -5,12 +5,16 @@ import { handleRouter } from '@jnrs/vue-core/router'
5
5
  import type { MenuItem } from '@jnrs/vue-core'
6
6
  import { hasPermission } from '@/utils/permissions'
7
7
  import { MenuApi } from '@/api/system'
8
+ import { formatDateTime, formatWeekday } from '@jnrs/shared'
9
+ import { isFloatGtZero } from '@jnrs/shared/validator'
10
+ import { testI18n } from '@jnrs/shared/request'
8
11
 
9
12
  const routeOptions = ref<MenuItem[]>([])
10
13
  const currentRoute = ref('')
11
14
  const datePicker = ref(new Date())
12
-
13
- onMounted(() => {})
15
+ const datetime = ref(formatDateTime() + ' ' + formatWeekday())
16
+ const validator = ref()
17
+ const testI18nInCore = ref('')
14
18
 
15
19
  const handleMenuApi = async () => {
16
20
  try {
@@ -26,11 +30,31 @@ const handleRouteChange = () => {
26
30
  name: currentRoute.value
27
31
  })
28
32
  }
33
+
34
+ const changeI18n = () => {
35
+ datetime.value = formatDateTime() + ' ' + formatWeekday()
36
+ isFloatGtZero({}, '0', (msg) => {
37
+ validator.value = msg
38
+ })
39
+ testI18nInCore.value = testI18n()
40
+ }
41
+
42
+ onMounted(() => {
43
+ isFloatGtZero({}, '0', (msg) => {
44
+ validator.value = msg
45
+ })
46
+ testI18nInCore.value = testI18n()
47
+ })
29
48
  </script>
30
49
 
31
50
  <template>
32
51
  <div>
33
52
  <h3>Playground - 功能测试</h3>
53
+ <p>国际化测试</p>
54
+ <div>@jnrs/shared: {{ datetime }}</div>
55
+ <div>@jnrs/shared/validator: {{ validator }}</div>
56
+ <div>@jnrs/shared/request: {{ testI18nInCore }}</div>
57
+ <el-button type="primary" size="small" @click="changeI18n">切换语言后点击按钮更新国际化显示</el-button>
34
58
  <p>权限测试(admin 账号拥有全部权限,请用非 admin 账号测试该功能)</p>
35
59
  <ul>
36
60
  <li>
@@ -191,8 +191,6 @@ const submitForm = async () => {
191
191
  box-shadow: 5px 0 10px rgba(0, 0, 0, 0.5);
192
192
  // background: url('@/assets/img/common/card_bg.png') no-repeat;
193
193
  // background-size: 100% 100%;
194
- text-align: center;
195
- font-size: 22px;
196
194
 
197
195
  .card_left_mid {
198
196
  width: 50%;
@@ -204,7 +202,10 @@ const submitForm = async () => {
204
202
  }
205
203
 
206
204
  .title {
205
+ text-align: center;
207
206
  font-size: 24px;
207
+ letter-spacing: 4px;
208
+ white-space: nowrap;
208
209
  font-weight: normal;
209
210
  font-family: AlimamaShuHeiTi-Bold;
210
211
  color: rgba(255, 255, 255, 0.5);
@@ -238,6 +239,7 @@ const submitForm = async () => {
238
239
 
239
240
  .title {
240
241
  text-align: center;
242
+ text-transform: uppercase;
241
243
  color: var(--jnrs-color-primary);
242
244
  }
243
245
 
@@ -261,6 +263,7 @@ const submitForm = async () => {
261
263
  color: var(--jnrs-color-primary-06);
262
264
  font-size: 14px;
263
265
  text-align: center;
266
+ text-transform: uppercase;
264
267
 
265
268
  &::before,
266
269
  &::after {
@@ -286,6 +289,8 @@ const submitForm = async () => {
286
289
  position: absolute;
287
290
  bottom: 5px;
288
291
  font-size: 12px;
292
+ letter-spacing: 2px;
293
+ text-transform: uppercase;
289
294
  color: rgba(0, 0, 0, 0.1);
290
295
  }
291
296
  }