vue2-client 1.15.92 → 1.15.94

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue2-client",
3
- "version": "1.15.92",
3
+ "version": "1.15.94",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "serve": "SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve --no-eslint",
@@ -25,7 +25,7 @@
25
25
  </template>
26
26
  <template v-else-if="cell.type === 'slot'">
27
27
  <template
28
- v-if="['x-form-table','x-add-native-form','x-tree-pro', 'x-his-editor', 'x-tab', 'x-form-group', 'x-report', 'x-buttons', 'x-label-select', 'x-conversation', 'x-check-list', 'x-cardSet', 'x-collapse','x-h-descriptions', 'x-sidebar', 'x-list','x-input','x-time-line', 'x-radio','x-calendar', 'x-time-select' ,'x-checkbox', 'x-title', 'x-select', 'x-tree-rows', 'x-three-test-orders', 'x-shift-schedule','x-charge','x-questionnaire'].includes(cell.slotType)">
28
+ v-if="['x-form-table','x-add-native-form','x-tree-pro', 'x-his-editor', 'x-tab', 'x-form-group', 'x-report', 'x-buttons', 'x-label-select', 'x-conversation', 'x-check-list', 'x-cardSet', 'x-collapse','x-h-descriptions', 'x-sidebar', 'x-list','x-input','x-time-line', 'x-radio','x-calendar', 'x-time-select' ,'x-checkbox', 'x-title', 'x-select', 'x-tree-rows', 'x-three-test-orders', 'x-shift-schedule','x-charge','x-questionnaire','x-import-excel-button'].includes(cell.slotType)">
29
29
  <component
30
30
  :is="getComponentName(cell.slotConfig, cell.serviceName, cell.slotType)"
31
31
  :key="cellIndex"
@@ -63,7 +63,7 @@
63
63
  </template>
64
64
  <template v-else-if="cell.type === 'slot'">
65
65
  <template
66
- v-if="['x-form-table','x-add-native-form','x-tree-pro', 'x-his-editor', 'x-tab', 'x-form-group', 'x-report', 'x-buttons', 'x-label-select', 'x-conversation', 'x-check-list', 'x-cardSet', 'x-collapse', 'x-h-descriptions', 'x-sidebar', 'x-list','x-input','x-time-line', 'x-radio','x-calendar', 'x-time-select','x-checkbox', 'x-title', 'x-select', 'x-tree-rows', 'x-three-test-orders', 'x-shift-schedule','x-charge','x-questionnaire'].includes(cell.slotType)">
66
+ v-if="['x-form-table','x-add-native-form','x-tree-pro', 'x-his-editor', 'x-tab', 'x-form-group', 'x-report', 'x-buttons', 'x-label-select', 'x-conversation', 'x-check-list', 'x-cardSet', 'x-collapse', 'x-h-descriptions', 'x-sidebar', 'x-list','x-input','x-time-line', 'x-radio','x-calendar', 'x-time-select','x-checkbox', 'x-title', 'x-select', 'x-tree-rows', 'x-three-test-orders', 'x-shift-schedule','x-charge','x-questionnaire','x-import-excel-button'].includes(cell.slotType)">
67
67
  <component
68
68
  :is="getComponentName(cell.slotConfig, cell.serviceName, cell.slotType)"
69
69
  :key="cellIndex"
@@ -127,7 +127,8 @@ export default {
127
127
  XThreeTestOrders: () => import('@vue2-client/base-client/components/his/threeTestOrders/threeTestOrders.vue'),
128
128
  XShiftSchedule: () => import('@vue2-client/base-client/components/his/XShiftSchedule/XShiftSchedule.vue'),
129
129
  XCharge: () => import('@vue2-client/base-client/components/his/XCharge/XCharge.vue'),
130
- XQuestionnaire: () => import('@vue2-client/base-client/components/his/XQuestionnaire/XQuestionnaire.vue')
130
+ XQuestionnaire: () => import('@vue2-client/base-client/components/his/XQuestionnaire/XQuestionnaire.vue'),
131
+ XImportExcelButton: () => import('@vue2-client/base-client/components/his/XImportExcelButton/XImportExcelButton.vue')
131
132
  },
132
133
  props: {
133
134
  // 每一行的配置
@@ -0,0 +1,214 @@
1
+ <template>
2
+ <a-modal
3
+ title="数据导入"
4
+ :visible="open"
5
+ :zIndex="1001"
6
+ :confirm-loading="uploading"
7
+ @cancel="importExcelHandleCancel"
8
+ >
9
+ <a-spin tip="上传中..." :spinning="uploading">
10
+ <a-upload-dragger
11
+ name="file"
12
+ accept=".xlsx, .xls"
13
+ :file-list="fileList"
14
+ :multiple="false"
15
+ :remove="handleRemove"
16
+ :before-upload="beforeUpload"
17
+ >
18
+ <p class="ant-upload-drag-icon">
19
+ <a-icon type="inbox" />
20
+ </p>
21
+ <p class="ant-upload-text">
22
+ 请将文件拖拽到此处上传
23
+ </p>
24
+ <p class="ant-upload-hint">
25
+ 支持单个上传,也可以点击后选择文件上传
26
+ </p>
27
+ </a-upload-dragger>
28
+ <a-divider v-if="$slots.importExcelSlot"/>
29
+ <a-collapse :bordered="false" v-if="$slots.importExcelSlot">
30
+ <a-collapse-panel key="0" header="查看导入说明">
31
+ <slot name="importExcelSlot"></slot>
32
+ </a-collapse-panel>
33
+ </a-collapse>
34
+ </a-spin>
35
+ <template slot="footer">
36
+ <a-row>
37
+ <a-button type="link" icon="download" v-if="queryParamsName !== 'none'" @click="importTemplate">
38
+ 下载导入模板
39
+ </a-button>
40
+ <a-button key="back" @click="importExcelHandleCancel">
41
+ 取消
42
+ </a-button>
43
+ <a-button key="submit" type="primary" :loading="uploading" @click="importExcelHandleChange">
44
+ 导入
45
+ </a-button>
46
+ </a-row>
47
+ </template>
48
+ </a-modal>
49
+ </template>
50
+
51
+ <script>
52
+
53
+ import { importData, downloadImportExcel, getConfigByName } from '@vue2-client/services/api/common'
54
+ import { excleParseArrays } from '@vue2-client/utils/excel/Export2Excel'
55
+ import { mapState } from 'vuex'
56
+
57
+ export default {
58
+ name: 'XImportExcel',
59
+ props: {
60
+ serviceName: {
61
+ type: String,
62
+ default: undefined
63
+ },
64
+ importType: {
65
+ type: String,
66
+ default: undefined
67
+ },
68
+ env: {
69
+ type: String,
70
+ default: 'prod'
71
+ },
72
+ queryParamsName: {
73
+ type: String,
74
+ default: 'none'
75
+ },
76
+ // 业务名称
77
+ title: {
78
+ type: String,
79
+ default: ''
80
+ },
81
+ extraData: {
82
+ type: Object,
83
+ default: () => {
84
+ return {}
85
+ }
86
+ }
87
+ },
88
+ components: {
89
+ },
90
+ data () {
91
+ return {
92
+ open: false,
93
+ uploadStatus: '',
94
+ fileList: [],
95
+ // 是否禁用上传
96
+ uploading: false,
97
+ excelImportTemplate: [],
98
+ }
99
+ },
100
+ filters: {
101
+ },
102
+ created () {
103
+ },
104
+ computed: {
105
+ ...mapState('account', { currUser: 'user' })
106
+ },
107
+ watch: {
108
+ },
109
+ methods: {
110
+ /** 导入excel窗体关闭 */
111
+ importExcelHandleCancel (e) {
112
+ this.open = false
113
+ this.fileList = []
114
+ // 关闭后刷新列表
115
+ this.$emit('ok')
116
+ },
117
+ /** 下载模板操作 */
118
+ importTemplate () {
119
+ downloadImportExcel({
120
+ queryParamsName: this.queryParamsName
121
+ }, this.serviceName, this.env === 'dev').then(res => {
122
+ if (!res || !res.value) {
123
+ this.$message.warn('导入模板不存在,请检查配置')
124
+ return
125
+ }
126
+ window.open(res.value)
127
+ })
128
+ },
129
+ /** 导入excel窗体开启 */
130
+ importExcelHandleOpen (e) {
131
+ this.open = true
132
+ console.log(this.importType)
133
+ if (this.importType == 'former') {
134
+ this.readTemplateConfig()
135
+ }
136
+ },
137
+ /** 读取excle导入模板 */
138
+ readTemplateConfig () {
139
+ getConfigByName(this.queryParamsName, 'af-his', res => {
140
+ console.log('res2=====>', res)
141
+ if (res != null && res != undefined) {
142
+ this.excelImportTemplate = res.excelImportTemplate[0]?.column
143
+ }
144
+ })
145
+ },
146
+ beforeUpload (file) {
147
+ this.fileList = [file]
148
+ return false
149
+ },
150
+ /** 导入excel */
151
+ importExcelHandleChange () {
152
+ const { fileList } = this
153
+ const formData = new FormData()
154
+ if (!fileList[0]) {
155
+ this.$message.warn('请选择需要上传的文件')
156
+ return
157
+ }
158
+ this.uploading = true
159
+ if (this.importType == 'former') {
160
+ try {
161
+ const parsedData = excleParseArrays(fileList[0], this.excelImportTemplate)
162
+ this.$emit('frontImport', parsedData, () => {
163
+ this.open = false
164
+ this.uploading = false
165
+ })
166
+ } catch (error) {
167
+ this.$message.error('Excel 解析失败,请检查文件格式')
168
+ } finally {
169
+ this.open = false
170
+ this.uploading = false
171
+ }
172
+ } else if (this.importType == 'customization') {
173
+ // this.$emit('customization', fileList[0]) // 自定义处理方式
174
+ } else {
175
+ const userData = {
176
+ currUserName: this.currUser.name,
177
+ currUserId: this.currUser.id,
178
+ orgId: this.currUser.orgid,
179
+ orgName: this.currUser.orgs,
180
+ depId: this.currUser.depids,
181
+ depName: this.currUser.deps
182
+ }
183
+ formData.append('file', fileList[0])
184
+ formData.append('queryParamsName', this.queryParamsName)
185
+ formData.append('userData', JSON.stringify(userData))
186
+ formData.append('otherParams', JSON.stringify(this.extraData))
187
+ importData(formData, this.serviceName, this.env === 'dev').then(res => {
188
+ this.fileList = []
189
+ const msg = res.msg || '导入成功'
190
+ if (res?.successLen && !res?.msg) {
191
+ this.$message.success(`${msg},成功导入${res.successLen}条数据`)
192
+ } else {
193
+ this.$message.success(msg)
194
+ }
195
+ this.open = false
196
+ this.$emit('ok', res)
197
+ }).catch(e => {
198
+ this.$message.error(e)
199
+ }).finally(() => {
200
+ this.uploading = false
201
+ })
202
+ }
203
+ },
204
+ handleRemove () {
205
+ this.fileList = []
206
+ this.uploading = false
207
+ },
208
+ excleParse () {
209
+ return []
210
+ }
211
+
212
+ }
213
+ }
214
+ </script>
@@ -0,0 +1,21 @@
1
+ <script>
2
+ import XImportExcelButton from './XImportExcelButton.vue'
3
+ export default {
4
+ name: 'XFrontImportExcelDemo',
5
+ components: {
6
+ XImportExcelButton,
7
+ },
8
+ data () {
9
+ return {
10
+ queryParamsName: 'testImprot'
11
+ }
12
+ }
13
+ }
14
+ </script>
15
+
16
+ <template>
17
+ <x-import-excel-button :queryParamsName="queryParamsName"></x-import-excel-button>
18
+ </template>
19
+
20
+ <style scoped>
21
+ </style>
@@ -0,0 +1,103 @@
1
+ <template>
2
+ <div class="import-button">
3
+ <a-button
4
+ type="type"
5
+ ref="importExcelButton"
6
+ @click="importData">
7
+ <a-icon :style="iconStyle" type="import"/>{{ this.label }}
8
+ </a-button>
9
+ <x-front-import-excel
10
+ ref="importExcel"
11
+ :title="title"
12
+ :extraData="extraData"
13
+ :service-name="serviceName"
14
+ :import-type="importType"
15
+ :env="env"
16
+ @frontImport="fronImport"
17
+ :query-params-name="crudQueryParamsName"
18
+ >
19
+ </x-front-import-excel>
20
+ </div>
21
+ </template>
22
+
23
+ <script>
24
+
25
+ import { getConfigByName } from '@vue2-client/services/api/common'
26
+ import XFrontImportExcel from './XFrontImportExcel.vue'
27
+
28
+ export default {
29
+ name: 'XImportExcelButton',
30
+ props: {
31
+ queryParamsName: {
32
+ type: Object,
33
+ default: null
34
+ }
35
+ },
36
+ inject: ['getComponentByName'],
37
+ components: {
38
+ XFrontImportExcel
39
+ },
40
+ data () {
41
+ return {
42
+ // 图标样式
43
+ iconStyle: {
44
+ position: 'relative',
45
+ top: '1px'
46
+ },
47
+ type: 'primary',
48
+ label: '导入',
49
+ title: '',
50
+ extraData: '',
51
+ serviceName: '',
52
+ env: 'dev',
53
+ crudQueryParamsName: '',
54
+ importType: undefined,
55
+ fronImportEvent: 'fronImport'
56
+ }
57
+ },
58
+ created () {
59
+ this.getData(this.queryParamsName)
60
+ },
61
+ methods: {
62
+ // 获取配置
63
+ async getData (queryParamsName) {
64
+ getConfigByName(queryParamsName, 'af-his', res => {
65
+ if (res != null) {
66
+ this.crudQueryParamsName = res.queryParamsName
67
+ this.env = res.env || 'dev'
68
+ this.serviceName = res.serviceName || ''
69
+ this.title = res.title || ''
70
+ this.extraData = res.extraData || ''
71
+ this.label = res.label || '导入'
72
+ this.importType = res.importType
73
+ this.fronImportEvent = res.fronImportEvent || 'fronImport'
74
+ this.type = res.type || 'primary'
75
+ }
76
+ })
77
+ },
78
+ // 导入业务
79
+ importData () {
80
+ this.$refs.importExcel.importExcelHandleOpen()
81
+ },
82
+ // 导入操作
83
+ fronImport (dataList, callback) {
84
+ console.log('条件事件', dataList)
85
+ console.log('条件事件', this.fronImportEvent)
86
+ if (this.$listeners[this.fronImportEvent]) {
87
+ // 交由父级处理
88
+ this.$emit(this.fronImportEvent, dataList, callback)
89
+ } else {
90
+ this.defaultAction(this.fronImportEvent, { key: '导入' }, callback)
91
+ }
92
+ },
93
+ defaultAction (clickEventName, item, callback) {
94
+ setTimeout(() => {
95
+ this.$message.warn(`已触发按钮 [${item.key}],注册事件名 [${clickEventName}],未实现事件函数`)
96
+ callback()
97
+ }, 200)
98
+ },
99
+ },
100
+ }
101
+ </script>
102
+ <style scoped>
103
+ </style>
@@ -26,9 +26,9 @@ export default {
26
26
  ...mapState('setting', ['cachePage', 'animate'])
27
27
  },
28
28
  created () {
29
- this.loadCacheConfig(this.$router?.options?.routes)
30
29
  },
31
30
  mounted () {
31
+ this.loadCacheConfig(this.$router?.options?.routes)
32
32
  if (window.__MICRO_APP_ENVIRONMENT__) {
33
33
  this.isMicroAppEnv = true
34
34
  window.microApp.addDataListener((data) => {
@@ -44,9 +44,11 @@ export default {
44
44
  // 加载需要排除缓存的路由配置
45
45
  loadCacheConfig (routes, pCache = true) {
46
46
  routes.forEach(item => {
47
- const cacheAble = item.meta?.page?.cacheAble ?? pCache ?? true
47
+ const cacheAble = item.meta?.keepAlive ?? pCache ?? true
48
48
  if (!cacheAble) {
49
- this.excludeKeys.push(new RegExp(`${item.path.replace(/:[^/]*/g, '[^/]*')}(\\?.*)?\\d*$`))
49
+ // 确保路径以 / 开头
50
+ const path = item.path.startsWith('/') ? item.path : '/' + item.path
51
+ this.excludeKeys.push(new RegExp(`^${path.replace(/:[^/]*/g, '[^/]*')}(\\?.*)?\\d*::.+$`))
50
52
  }
51
53
  if (item.children) {
52
54
  this.loadCacheConfig(item.children, cacheAble)
@@ -60,12 +60,13 @@ path: 'example',
60
60
  // component: () => import('@vue2-client/base-client/components/common/XAddNativeForm/demo.vue'),
61
61
  // component: () => import('@vue2-client/base-client/components/common/XFormGroup/demo.vue'),
62
62
  // component: () => import('@vue2-client/base-client/components/common/XReport/XReportDemo.vue'),
63
- component: () => import('@vue2-client/base-client/components/common/XFormTable/demo.vue'),
63
+ // component: () => import('@vue2-client/base-client/components/common/XFormTable/demo.vue'),
64
64
  // component: () => import('@vue2-client/base-client/components/common/XDatePicker/demo.vue'),
65
65
  // component: () => import('@vue2-client/base-client/components/common/XTab/XTabDemo.vue'),
66
66
  // component: () => import('@vue2-client/base-client/components/common/XRate/demo.vue'),
67
67
  // component: () => import('@vue2-client/base-client/components/common/XForm/demo.vue'),
68
68
  // component: () => import('@vue2-client/base-client/components/his/XTimeSelect/XTimeSelectDemo.vue'),
69
+ component: () => import('@vue2-client/base-client/components/his/XImportExcelButton/XFrontImportExcelDemo.vue'),
69
70
  // component: () => import('@vue2-client/pages/WorkflowDetail/WorkFlowDemo.vue'),
70
71
  // component: () => import('@vue2-client/pages/WorkflowDetail/WorkFlowDemo.vue'),
71
72
  // component: () => import('@vue2-client/pages/XPageViewExample/index.vue'),
@@ -139,3 +139,46 @@ export function exportJson(th, jsonData, defaultTitle) {
139
139
  const title = defaultTitle || '列表';
140
140
  saveAs(new Blob([s2ab(wbout)], {type: "application/octet-stream"}), title + ".xlsx")
141
141
  }
142
+
143
+ export function excleParseArrays(file, configs) {
144
+ return new Promise((resolve, reject) => {
145
+ const reader = new FileReader();
146
+ reader.onload = (e) => {
147
+ try {
148
+ const data = new Uint8Array(e.target.result);
149
+ const workbook = XLSX.read(data, { type: 'array' });
150
+
151
+ // 获取第一个工作表
152
+ const firstSheetName = workbook.SheetNames[0];
153
+ const worksheet = workbook.Sheets[firstSheetName];
154
+
155
+ // 转换为 JSON 数组(行数据)
156
+ const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
157
+
158
+ // 提取表头(第一行)
159
+ const headers = jsonData[0] || [];
160
+
161
+ // 验证字段匹配
162
+ if (headers.length !== configs.length) {
163
+ console.warn('Excel列数与配置字段数不一致', headers, configs);
164
+ }
165
+
166
+ // 转换数据行为对象数组
167
+ const result = jsonData.slice(1).map(row => {
168
+ const obj = {};
169
+ configs.forEach((field, index) => {
170
+ // 处理列数超出配置的情况
171
+ obj[field] = index < row.length ? row[index] : null;
172
+ });
173
+ return obj;
174
+ });
175
+
176
+ resolve(result);
177
+ } catch (error) {
178
+ reject(`解析失败: ${error.message}`);
179
+ }
180
+ };
181
+ reader.onerror = (error) => reject(`文件读取错误: ${error}`);
182
+ reader.readAsArrayBuffer(file);
183
+ });
184
+ }
@@ -449,7 +449,14 @@ function parsefunc (func) {
449
449
  try {
450
450
  const params = new URLSearchParams(queryString)
451
451
  for (const [key, value] of params.entries()) {
452
- route.meta[key] = value
452
+ // 转换字符串布尔值为实际的布尔值
453
+ if (value === 'true') {
454
+ route.meta[key] = true
455
+ } else if (value === 'false') {
456
+ route.meta[key] = false
457
+ } else {
458
+ route.meta[key] = value
459
+ }
453
460
  }
454
461
  if (route.meta.path) {
455
462
  route.path = route.meta.path
@@ -533,7 +540,14 @@ function parsefuncOA (func) {
533
540
  try {
534
541
  const params = new URLSearchParams(queryString)
535
542
  for (const [key, value] of params.entries()) {
536
- route.meta[key] = value
543
+ // 转换字符串布尔值为实际的布尔值
544
+ if (value === 'true') {
545
+ route.meta[key] = true
546
+ } else if (value === 'false') {
547
+ route.meta[key] = false
548
+ } else {
549
+ route.meta[key] = value
550
+ }
537
551
  }
538
552
  if (route.meta.path) {
539
553
  route.path = route.meta.path