af-mobile-client-vue3 1.1.22 → 1.1.24

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,111 +1,100 @@
1
- {
2
- "name": "af-mobile-client-vue3",
3
- "type": "module",
4
- "version": "1.1.22",
5
- "description": "Vue + Vite component lib",
6
- "license": "MIT",
7
- "engines": {
8
- "node": ">=18.12.0",
9
- "pnpm": ">=8.15.0"
10
- },
11
- "scripts": {
12
- "dev": "cross-env MOCK_SERVER_PORT=8086 vite",
13
- "build": "vue-tsc --noEmit && vite build",
14
- "build:dev": "vue-tsc --noEmit && vite build --mode=development",
15
- "preview": "vite preview",
16
- "lint": "eslint . && vue-tsc --noEmit",
17
- "lint:fix": "eslint . --fix",
18
- "test": "vitest",
19
- "release": "bumpp --commit --push --tag"
20
- },
21
- "dependencies": {
22
- "@micro-zoe/micro-app": "1.0.0-rc.24",
23
- "@vant/area-data": "^2.0.0",
24
- "@unhead/vue": "^2.0.5",
25
- "@vant/touch-emulator": "^1.4.0",
26
- "@vant/use": "^1.6.0",
27
- "@vueuse/core": "^13.1.0",
28
- "@iconify/vue": "4.3.0",
29
- "animate.css": "^4.1.1",
30
- "axios": "^1.8.4",
31
- "crypto-js": "^4.2.0",
32
- "echarts": "^5.6.0",
33
- "lodash-es": "^4.17.21",
34
- "nprogress": "^0.2.0",
35
- "ol": "^10.5.0",
36
- "pinia": "^3.0.2",
37
- "pinia-plugin-persistedstate": "^4.2.0",
38
- "qs": "^6.14.0",
39
- "resize-detector": "^0.3.0",
40
- "store": "^2.0.12",
41
- "vant": "^4.9.18",
42
- "vconsole": "^3.15.1",
43
- "vue": "^3.5.13",
44
- "vue-router": "^4.5.0"
45
- },
46
- "devDependencies": {
47
- "@antfu/eslint-config": "^4.12.0",
48
- "@iconify/json": "2.2.318",
49
- "@types/crypto-js": "^4.2.2",
50
- "@types/lodash-es": "^4.17.12",
51
- "@types/node": "^22.14.1",
52
- "@types/nprogress": "^0.2.3",
53
- "@types/store": "^2.0.5",
54
- "@unocss/eslint-plugin": "^66.1.0-beta.11",
55
- "@unocss/preset-rem-to-px": "66.1.0-beta.11",
56
- "@vitejs/plugin-legacy": "^6.0.2",
57
- "@vitejs/plugin-vue": "^5.2.3",
58
- "autoprefixer": "^10.4.21",
59
- "bumpp": "^10.1.0",
60
- "commitizen": "^4.3.1",
61
- "consola": "^3.4.2",
62
- "cross-env": "^7.0.3",
63
- "cz-emoji-chinese": "^0.3.1",
64
- "eslint": "^9.24.0",
65
- "eslint-ts-patch": "^8.57.0-0",
66
- "husky": "^9.1.7",
67
- "less": "^4.3.0",
68
- "mockjs": "^1.1.0",
69
- "postcss-mobile-forever": "^5.0.0",
70
- "rollup": "^4.40.0",
71
- "terser": "^5.39.0",
72
- "typescript": "^5.8.3",
73
- "unocss": "^66.1.0-beta.11",
74
- "unplugin-auto-import": "^19.1.2",
75
- "unplugin-vue-components": "^28.4.1",
76
- "unplugin-vue-router": "^0.12.0",
77
- "vite": "^6.2.6",
78
- "vite-plugin-compression": "^0.5.1",
79
- "vite-plugin-mock-dev-server": "^1.8.5",
80
- "vite-plugin-pwa": "^1.0.0",
81
- "vite-plugin-sitemap": "^0.7.1",
82
- "vite-plugin-svg-icons": "^2.0.1",
83
- "vite-plugin-vconsole": "^2.1.1",
84
- "vite-plugin-vue-devtools": "^7.7.2",
85
- "vite-plugin-vue-layouts": "^0.11.0",
86
- "vitest": "^3.1.1",
87
- "vue-tsc": "^2.2.8"
88
- },
89
- "pnpm": {
90
- "peerDependencyRules": {
91
- "ignoreMissing": [
92
- "postcss",
93
- "esbuild"
94
- ],
95
- "allowedVersions": {
96
- "rollup": "^4.x"
97
- }
98
- }
99
- },
100
- "config": {
101
- "commitizen": {
102
- "path": "./node_modules/cz-emoji-chinese"
103
- },
104
- "cz-emoji-chinese": {
105
- "skipQuestions": [
106
- "body",
107
- "scope"
108
- ]
109
- }
110
- }
111
- }
1
+ {
2
+ "name": "af-mobile-client-vue3",
3
+ "type": "module",
4
+ "version": "1.1.24",
5
+ "description": "Vue + Vite component lib",
6
+ "license": "MIT",
7
+ "engines": {
8
+ "node": ">=18.12.0",
9
+ "pnpm": ">=8.15.0"
10
+ },
11
+ "dependencies": {
12
+ "@micro-zoe/micro-app": "1.0.0-rc.24",
13
+ "@vant/area-data": "^2.0.0",
14
+ "@unhead/vue": "^2.0.5",
15
+ "@vant/touch-emulator": "^1.4.0",
16
+ "@vant/use": "^1.6.0",
17
+ "@vueuse/core": "^13.1.0",
18
+ "@iconify/vue": "4.3.0",
19
+ "animate.css": "^4.1.1",
20
+ "axios": "^1.8.4",
21
+ "crypto-js": "^4.2.0",
22
+ "echarts": "^5.6.0",
23
+ "lodash-es": "^4.17.21",
24
+ "nprogress": "^0.2.0",
25
+ "ol": "^10.5.0",
26
+ "pinia": "^3.0.2",
27
+ "pinia-plugin-persistedstate": "^4.2.0",
28
+ "qs": "^6.14.0",
29
+ "resize-detector": "^0.3.0",
30
+ "store": "^2.0.12",
31
+ "vant": "^4.9.18",
32
+ "vconsole": "^3.15.1",
33
+ "vue": "^3.5.13",
34
+ "vue-router": "^4.5.0"
35
+ },
36
+ "devDependencies": {
37
+ "@antfu/eslint-config": "^4.12.0",
38
+ "@iconify/json": "2.2.318",
39
+ "@types/crypto-js": "^4.2.2",
40
+ "@types/lodash-es": "^4.17.12",
41
+ "@types/node": "^22.14.1",
42
+ "@types/nprogress": "^0.2.3",
43
+ "@types/store": "^2.0.5",
44
+ "@unocss/eslint-plugin": "^66.1.0-beta.11",
45
+ "@unocss/preset-rem-to-px": "66.1.0-beta.11",
46
+ "@vitejs/plugin-legacy": "^6.0.2",
47
+ "@vitejs/plugin-vue": "^5.2.3",
48
+ "autoprefixer": "^10.4.21",
49
+ "bumpp": "^10.1.0",
50
+ "commitizen": "^4.3.1",
51
+ "consola": "^3.4.2",
52
+ "cross-env": "^7.0.3",
53
+ "cz-emoji-chinese": "^0.3.1",
54
+ "eslint": "^9.24.0",
55
+ "eslint-ts-patch": "^8.57.0-0",
56
+ "husky": "^9.1.7",
57
+ "less": "^4.3.0",
58
+ "mockjs": "^1.1.0",
59
+ "postcss-mobile-forever": "^5.0.0",
60
+ "rollup": "^4.40.0",
61
+ "terser": "^5.39.0",
62
+ "typescript": "^5.8.3",
63
+ "unocss": "^66.1.0-beta.11",
64
+ "unplugin-auto-import": "^19.1.2",
65
+ "unplugin-vue-components": "^28.4.1",
66
+ "unplugin-vue-router": "^0.12.0",
67
+ "vite": "^6.2.6",
68
+ "vite-plugin-compression": "^0.5.1",
69
+ "vite-plugin-mock-dev-server": "^1.8.5",
70
+ "vite-plugin-pwa": "^1.0.0",
71
+ "vite-plugin-sitemap": "^0.7.1",
72
+ "vite-plugin-svg-icons": "^2.0.1",
73
+ "vite-plugin-vconsole": "^2.1.1",
74
+ "vite-plugin-vue-devtools": "^7.7.2",
75
+ "vite-plugin-vue-layouts": "^0.11.0",
76
+ "vitest": "^3.1.1",
77
+ "vue-tsc": "^2.2.8"
78
+ },
79
+ "config": {
80
+ "commitizen": {
81
+ "path": "./node_modules/cz-emoji-chinese"
82
+ },
83
+ "cz-emoji-chinese": {
84
+ "skipQuestions": [
85
+ "body",
86
+ "scope"
87
+ ]
88
+ }
89
+ },
90
+ "scripts": {
91
+ "dev": "cross-env MOCK_SERVER_PORT=8086 vite",
92
+ "build": "vue-tsc --noEmit && vite build",
93
+ "build:dev": "vue-tsc --noEmit && vite build --mode=development",
94
+ "preview": "vite preview",
95
+ "lint": "eslint . && vue-tsc --noEmit",
96
+ "lint:fix": "eslint . --fix",
97
+ "test": "vitest",
98
+ "release": "bumpp --commit --push --tag"
99
+ }
100
+ }
@@ -76,32 +76,28 @@ function valueChange(value: string | string[]) {
76
76
  <div id="XGridDropOption">
77
77
  <template v-if="props.multiple">
78
78
  <VanCheckboxGroup v-model="checked as string[]" direction="horizontal" @change="valueChange">
79
- <VanGrid :gutter="props.gutter" :border="false" :column-num="props.columnNum">
80
- <VanGridItem v-for="colRow in props.columns" :key="colRow[props.columnsFieldNames.text]">
81
- <template #default>
82
- <VanCheckbox :name="colRow[props.columnsFieldNames.value]">
83
- <VanButton type="default" size="small" :class="{ 'select-text-col': classSel(colRow) }">
84
- {{ colRow[props.columnsFieldNames.text] }}
85
- </VanButton>
86
- </VanCheckbox>
87
- </template>
88
- </VanGridItem>
89
- </VanGrid>
79
+ <div class="option-container">
80
+ <div v-for="colRow in props.columns" :key="colRow[props.columnsFieldNames.text]" class="option-item">
81
+ <VanCheckbox :name="colRow[props.columnsFieldNames.value]">
82
+ <VanButton type="default" size="small" :class="{ 'select-text-col': classSel(colRow) }">
83
+ {{ colRow[props.columnsFieldNames.text] }}
84
+ </VanButton>
85
+ </VanCheckbox>
86
+ </div>
87
+ </div>
90
88
  </VanCheckboxGroup>
91
89
  </template>
92
90
  <template v-else>
93
91
  <VanRadioGroup v-model="checked" direction="horizontal" @change="valueChange">
94
- <VanGrid :gutter="props.gutter" :border="false" :column-num="props.columnNum">
95
- <VanGridItem v-for="colRow in props.columns" :key="colRow[props.columnsFieldNames.text]">
96
- <template #default>
97
- <VanRadio :name="colRow[props.columnsFieldNames.value]">
98
- <VanButton type="default" size="small" :class="{ 'select-text-col': classSel(colRow) }">
99
- {{ colRow[props.columnsFieldNames.text] }}
100
- </VanButton>
101
- </VanRadio>
102
- </template>
103
- </VanGridItem>
104
- </VanGrid>
92
+ <div class="option-container">
93
+ <div v-for="colRow in props.columns" :key="colRow[props.columnsFieldNames.text]" class="option-item">
94
+ <VanRadio :name="colRow[props.columnsFieldNames.value]">
95
+ <VanButton type="default" size="small" :class="{ 'select-text-col': classSel(colRow) }">
96
+ {{ colRow[props.columnsFieldNames.text] }}
97
+ </VanButton>
98
+ </VanRadio>
99
+ </div>
100
+ </div>
105
101
  </VanRadioGroup>
106
102
  </template>
107
103
  </div>
@@ -116,10 +112,18 @@ function valueChange(value: string | string[]) {
116
112
  --van-radio-label-margin: 0px;
117
113
  --van-button-default-border-color: 'rgb(247,248,250)';
118
114
 
119
- .van-grid {
115
+ .option-container {
116
+ display: flex;
117
+ flex-wrap: wrap;
118
+ gap: 8px;
120
119
  width: 100%;
121
120
  }
122
121
 
122
+ .option-item {
123
+ flex: 0 1 auto;
124
+ min-width: fit-content;
125
+ }
126
+
123
127
  .select-text-col {
124
128
  color: blue;
125
129
  }
@@ -140,6 +144,7 @@ function valueChange(value: string | string[]) {
140
144
  :deep(.van-button) {
141
145
  width: 100%;
142
146
  background-color: rgb(247,248,250);
147
+ white-space: nowrap;
143
148
  }
144
149
  :deep(.van-checkbox__label) {
145
150
  width: 100%;
@@ -2,6 +2,8 @@
2
2
  import XBadge from '@af-mobile-client-vue3/components/data/XBadge/index.vue'
3
3
  import XCellListFilter from '@af-mobile-client-vue3/components/data/XCellListFilter/index.vue'
4
4
  import { getConfigByName, query } from '@af-mobile-client-vue3/services/api/common'
5
+ import { getRangeByType } from '@af-mobile-client-vue3/utils/queryFormDefaultRangePicker'
6
+ import { executeStrFunctionByContext } from '@af-mobile-client-vue3/utils/runEvalFunction'
5
7
  import LoadError from '@af-mobile-client-vue3/views/common/LoadError.vue'
6
8
  import {
7
9
  showConfirmDialog,
@@ -17,7 +19,7 @@ import {
17
19
  Space as VanSpace,
18
20
  Tag as VanTag,
19
21
  } from 'vant'
20
- import { computed, defineEmits, defineProps, onBeforeMount, ref, watch } from 'vue'
22
+ import { computed, defineEmits, defineProps, getCurrentInstance, onBeforeMount, ref, useSlots, watch } from 'vue'
21
23
  import { useRouter } from 'vue-router'
22
24
 
23
25
  const { configName, serviceName, fixQueryForm } = withDefaults(defineProps<{
@@ -38,7 +40,14 @@ const { configName, serviceName, fixQueryForm } = withDefaults(defineProps<{
38
40
  scanOptions: undefined,
39
41
  })
40
42
 
41
- const emit = defineEmits(['toDetail', 'update', 'deleteRow', 'add'])
43
+ const emit = defineEmits<{
44
+ (e: 'toDetail', item: any): void
45
+ (e: 'update', item: any, handledByParent: any): void
46
+ (e: 'deleteRow', item: any): void
47
+ (e: 'add'): void
48
+ (e: string, item: any): void
49
+ (e: 'updateCondition', params: any): void
50
+ }>()
42
51
 
43
52
  const router = useRouter()
44
53
 
@@ -108,8 +117,12 @@ const finishedText = ref('加载完成')
108
117
  // 避免查询多次
109
118
  const isLastPage = ref(false)
110
119
 
120
+ // 条件参数(查询框)
111
121
  const conditionParams = ref(undefined)
112
122
 
123
+ // 查询参数(配置自带的默认值)
124
+ const queryDefaultParams = ref({})
125
+
113
126
  // 主要按钮的状态
114
127
  const buttonState = ref(undefined)
115
128
 
@@ -117,6 +130,11 @@ const buttonState = ref(undefined)
117
130
  const groupFormItems = ref({})
118
131
  const title = ref('')
119
132
 
133
+ const slots = useSlots()
134
+
135
+ // 当前组件实例(不推荐使用,可能会在后续的版本更迭中调整,暂时用来绑定函数的上下文)
136
+ const currInst = getCurrentInstance()
137
+
120
138
  onBeforeMount(() => {
121
139
  initComponent()
122
140
  })
@@ -178,9 +196,47 @@ function initComponent() {
178
196
  allActions.value.push({ text: '删除', func: 'deleteRow' })
179
197
  }
180
198
  splitArrayAt(allActions.value, 3)
199
+
200
+ // 初始化条件参数(从表单默认值中获取)
201
+ initConditionParams(result.formJson)
181
202
  }, serviceName)
182
203
  }
183
204
 
205
+ // 初始化条件参数
206
+ function initConditionParams(formItems) {
207
+ if (!formItems || !Array.isArray(formItems) || formItems.length === 0)
208
+ return
209
+
210
+ const defaultParams = {}
211
+ let hasDefaults = false
212
+
213
+ // 从表单配置中获取所有默认值
214
+ formItems.forEach((item) => {
215
+ if (item.model) {
216
+ // 根据查询模式获取对应的默认值
217
+ if (item.queryFormDefault !== undefined && item.queryFormDefault !== null) {
218
+ if (item.type === 'rangePicker' && item.queryType === 'BETWEEN') {
219
+ defaultParams[item.model] = getRangeByType(item.queryFormDefault, false)
220
+ }
221
+ else {
222
+ defaultParams[item.model] = item.queryFormDefault
223
+ }
224
+ hasDefaults = true
225
+ }
226
+ }
227
+ })
228
+
229
+ // 如果有默认值,则设置到条件参数中并立即执行查询
230
+ if (hasDefaults) {
231
+ queryDefaultParams.value = defaultParams
232
+
233
+ // 延迟执行第一次查询,确保组件完全加载
234
+ setTimeout(() => {
235
+ onRefresh()
236
+ }, 100)
237
+ }
238
+ }
239
+
184
240
  // 刷新数据
185
241
  function onRefresh() {
186
242
  isError.value = false
@@ -197,6 +253,8 @@ function onRefresh() {
197
253
 
198
254
  // 加载数据
199
255
  function onLoad() {
256
+ if (!refreshing.value)
257
+ return
200
258
  if (refreshing.value) {
201
259
  list.value = []
202
260
  pageNo.value = 1
@@ -206,6 +264,23 @@ function onLoad() {
206
264
  let searchVal = searchValue.value
207
265
  if (searchVal === '')
208
266
  searchVal = undefined
267
+
268
+ // 确保conditionParams不是undefined
269
+ if (conditionParams.value === undefined)
270
+ conditionParams.value = {}
271
+ const mergedParams = mergeParams(queryDefaultParams.value, conditionParams.value)
272
+
273
+ // 输出查询条件,便于调试
274
+ console.log('查询条件:', {
275
+ pageNo: pageNo.value,
276
+ pageSize,
277
+ conditionParams: {
278
+ $queryValue: searchVal,
279
+ ...fixQueryForm,
280
+ ...mergedParams,
281
+ },
282
+ })
283
+
209
284
  query({
210
285
  queryParamsName: configName,
211
286
  pageNo: pageNo.value,
@@ -213,7 +288,7 @@ function onLoad() {
213
288
  conditionParams: {
214
289
  $queryValue: searchVal,
215
290
  ...fixQueryForm,
216
- ...conditionParams.value,
291
+ ...mergedParams,
217
292
  },
218
293
  sortField: orderVal?.value,
219
294
  sortOrder: sortordVal?.value,
@@ -240,6 +315,18 @@ function onLoad() {
240
315
  }
241
316
  }
242
317
 
318
+ // 合并参数
319
+ function mergeParams(defaultParams: object, overrideParams: object) {
320
+ const result = { ...defaultParams }
321
+ for (const [key, value] of Object.entries(overrideParams)) {
322
+ // 只有当overrideParams中的值不是undefined或空字符串时才覆盖
323
+ if (value !== undefined) {
324
+ result[key] = value
325
+ }
326
+ }
327
+ return result
328
+ }
329
+
243
330
  // 区分主要操作列与其他操作列
244
331
  function splitArrayAt<T>(array: T[], index: number) {
245
332
  mainActions.value = array.slice(0, index)
@@ -251,23 +338,24 @@ watch(() => searchValue.value, (newVal) => {
251
338
  onRefresh()
252
339
  })
253
340
 
254
- function handleFunctionStyle(funcString, param) {
255
- try {
256
- if (!funcString || funcString === '')
257
- return {}
258
-
259
- // 匹配参数名、函数体
260
- const innerFuncRegex = /function\s+\w*\((\w+)\)\s*\{([\s\S]*)\}/
261
- const matches = funcString.match(innerFuncRegex)
262
-
263
- const paramName = matches[1] // 提取参数名
264
-
265
- // eslint-disable-next-line no-new-func
266
- const func = new Function(paramName, matches[2])
341
+ // 配置中心->表单项展示函数
342
+ function handleFunctionStyle(funcString, record) {
343
+ if (!funcString) {
344
+ return {}
345
+ }
267
346
 
268
- return func(param)
347
+ try {
348
+ // 同步执行函数
349
+ const obj = executeStrFunctionByContext(currInst, funcString, [record])
350
+ // 如果返回的是对象,则直接返回
351
+ if (obj && typeof obj === 'object') {
352
+ return obj
353
+ }
354
+ // 其他情况返回空对象
355
+ return {}
269
356
  }
270
- catch {
357
+ catch (error) {
358
+ console.error('Error in handleFunctionStyle:', error)
271
359
  return {}
272
360
  }
273
361
  }
@@ -388,12 +476,39 @@ function evaluateCustomFunction(funcString: string | undefined, record: any, ind
388
476
  return true
389
477
  }
390
478
  }
479
+
480
+ // 更新查询条件并刷新
481
+ function updateConditionAndRefresh(params: any) {
482
+ // 更新 conditionParams
483
+ if (!conditionParams.value) {
484
+ conditionParams.value = {}
485
+ }
486
+ if (params) {
487
+ // 遍历参数,更新对应的表单值
488
+ Object.entries(params).forEach(([key, value]) => {
489
+ // 找到对应的表单项
490
+ const formItem = formQueryList.value.find(item => item.model === key)
491
+ if (formItem) {
492
+ // 更新表单项的值
493
+ conditionParams.value[key] = value
494
+ }
495
+ })
496
+ }
497
+
498
+ // 触发刷新
499
+ onRefresh()
500
+ }
501
+
502
+ // 暴露方法给父组件
503
+ defineExpose({
504
+ updateConditionAndRefresh,
505
+ })
391
506
  </script>
392
507
 
393
508
  <template>
394
509
  <div id="XCellList">
395
510
  <VanRow class="filter-condition">
396
- <VanCol>
511
+ <VanCol class="search-col">
397
512
  <VanSearch
398
513
  v-model="searchValue"
399
514
  class="title-search"
@@ -403,6 +518,14 @@ function evaluateCustomFunction(funcString: string | undefined, record: any, ind
403
518
  @search="onRefresh"
404
519
  />
405
520
  </VanCol>
521
+ <!-- 动态插槽区域 -->
522
+ <template v-for="(_, name) in slots" :key="name">
523
+ <template v-if="typeof name === 'string' && name.startsWith('search-right-')">
524
+ <div class="filter-icon-box">
525
+ <slot :name="name" />
526
+ </div>
527
+ </template>
528
+ </template>
406
529
  <VanCol class="search-icon">
407
530
  <XCellListFilter
408
531
  v-model:sortord-val="sortordVal"
@@ -437,7 +560,7 @@ function evaluateCustomFunction(funcString: string | undefined, record: any, ind
437
560
  <div v-for="(column) in mainColumns" :key="`main_${column.dataIndex}`" class="main-title">
438
561
  <p
439
562
  class="card_item_title"
440
- :style="handleFunctionStyle(column.styleFunctionForValue, item[column.dataIndex])"
563
+ :style="handleFunctionStyle(column.styleFunctionForValue, item)"
441
564
  >
442
565
  {{ item[column.dataIndex] ? item[column.dataIndex] : '--' }}
443
566
  </p>
@@ -445,10 +568,10 @@ function evaluateCustomFunction(funcString: string | undefined, record: any, ind
445
568
  <div v-for="(column) in subTitleColumns" :key="`subtitle_${column.dataIndex}`" class="sub-title">
446
569
  <p
447
570
  class="card_item_subtitle"
448
- :style="handleFunctionStyle(column.styleFunctionForValue, item[column.dataIndex])"
571
+ :style="handleFunctionStyle(column.styleFunctionForValue, item)"
449
572
  >
450
573
  <XBadge
451
- :style="handleFunctionStyle(column.styleFunctionForValue, item[column.dataIndex])"
574
+ :style="handleFunctionStyle(column.styleFunctionForValue, item)"
452
575
  :dict-name="column.dictName" :dict-value="item[column.dataIndex]"
453
576
  :service-name="serviceName"
454
577
  />
@@ -472,7 +595,7 @@ function evaluateCustomFunction(funcString: string | undefined, record: any, ind
472
595
  <p>
473
596
  {{ `${column.title}: ` }}
474
597
  <XBadge
475
- :style="handleFunctionStyle(column.styleFunctionForValue, item[column.dataIndex])"
598
+ :style="handleFunctionStyle(column.styleFunctionForValue, item)"
476
599
  :dict-name="column.dictName" :dict-value="item[column.dataIndex]"
477
600
  :service-name="serviceName"
478
601
  />
@@ -514,11 +637,11 @@ function evaluateCustomFunction(funcString: string | undefined, record: any, ind
514
637
  <VanRow gutter="20" class="card_item_footer" @click="emit('toDetail', item)">
515
638
  <VanCol v-for="column of footColumns" :key="`foot_${column.dataIndex}`" :span="12">
516
639
  <p>
517
- <span :style="handleFunctionStyle(column.styleFunctionForTitle, item[column.dataIndex])">
640
+ <span :style="handleFunctionStyle(column.styleFunctionForTitle, item)">
518
641
  {{ column.title }}:
519
642
  </span>
520
643
  <XBadge
521
- :style="handleFunctionStyle(column.styleFunctionForValue, item[column.dataIndex])"
644
+ :style="handleFunctionStyle(column.styleFunctionForValue, item)"
522
645
  :dict-name="column.dictName" :dict-value="item[column.dataIndex]"
523
646
  :service-name="serviceName"
524
647
  />
@@ -576,8 +699,8 @@ function evaluateCustomFunction(funcString: string | undefined, record: any, ind
576
699
  <style scoped lang="less">
577
700
  #XCellList {
578
701
  height: calc(94vh - var(--van-nav-bar-height) - 5px);
579
- --van-search-padding:5px;
580
- --van-dropdown-menu-title-padding: 5px;
702
+ --van-search-padding: 3px;
703
+ --van-dropdown-menu-title-padding: 3px;
581
704
  --van-cell-vertical-padding: 0px;
582
705
  .main {
583
706
  overflow-y: auto;
@@ -736,6 +859,7 @@ function evaluateCustomFunction(funcString: string | undefined, record: any, ind
736
859
  align-items: center;
737
860
  padding: 8px 12px;
738
861
  background-color: #fff;
862
+ gap: 5px;
739
863
  :deep(.van-search) {
740
864
  width: 100%;
741
865
  padding: var(--van-search-padding);
@@ -757,20 +881,31 @@ function evaluateCustomFunction(funcString: string | undefined, record: any, ind
757
881
  font-size: 14px;
758
882
  }
759
883
  .van-col {
760
- &:first-child {
884
+ display: flex;
885
+ align-items: center;
886
+ &.search-col {
761
887
  flex: 1;
762
888
  min-width: 0;
763
889
  }
764
- &:last-child {
890
+ &.search-icon {
765
891
  flex-shrink: 0;
892
+ padding: 0;
766
893
  }
767
894
  }
768
- .search-icon {
895
+ .filter-icon-box {
769
896
  display: flex;
770
897
  align-items: center;
771
- justify-content: flex-end;
772
- height: 100%;
773
- padding: 0;
898
+ justify-content: center;
899
+ width: 40px;
900
+ height: 40px;
901
+ border-radius: 10px;
902
+ background-color: rgba(245,245,245);
903
+ cursor: pointer;
904
+ position: relative;
905
+ z-index: 1;
906
+ &:active {
907
+ opacity: 0.7;
908
+ }
774
909
  }
775
910
  }
776
911
 
@@ -11,6 +11,7 @@ import { runLogic } from '@af-mobile-client-vue3/services/api/common'
11
11
  import { searchToListOption, searchToOption } from '@af-mobile-client-vue3/services/v3Api'
12
12
  import { useUserStore } from '@af-mobile-client-vue3/stores/modules/user'
13
13
  import { getDict } from '@af-mobile-client-vue3/utils/dictUtil'
14
+ import { getRangeByType } from '@af-mobile-client-vue3/utils/queryFormDefaultRangePicker'
14
15
  import { executeStrFunctionByContext } from '@af-mobile-client-vue3/utils/runEvalFunction'
15
16
  import { areaList } from '@vant/area-data'
16
17
  import { debounce } from 'lodash-es'
@@ -187,7 +188,7 @@ function getDefaultValue() {
187
188
  if (props.modelValue && Array.isArray(props.modelValue) && props.modelValue.length > 1)
188
189
  return `${props.modelValue[0]} ~ ${props.modelValue[1]}`
189
190
  else
190
- return props.modelValue
191
+ return props.modelValue !== undefined ? props.modelValue : querySelectDefaultValue.value
191
192
  case 'addressSearch':
192
193
  return props.modelValue
193
194
  default:
@@ -205,9 +206,14 @@ watch(() => props.modelValue, (newVal) => {
205
206
  localValue.value = Array.isArray(newVal) ? newVal : []
206
207
  }
207
208
  else {
208
- localValue.value = newVal !== undefined ? newVal : getDefaultValue()
209
209
  if (attr.type === 'rangePicker') {
210
- pickerValue.value = newVal !== undefined ? `${newVal[0]} ~ ${newVal[1]}` : ''
210
+ console.log('newVal', newVal)
211
+ pickerValue.value = newVal !== undefined ? `${newVal[0]} ~ ${newVal[1]}` : getDefaultValue()
212
+ console.log('11111111111', getDefaultValue())
213
+ }
214
+ else {
215
+ console.log('newVal', newVal)
216
+ localValue.value = newVal !== undefined ? newVal : getDefaultValue()
211
217
  }
212
218
  }
213
219
  })
@@ -459,6 +465,16 @@ function init() {
459
465
  // querySelectDefaultValue.value = attr.queryFormDefault
460
466
  }
461
467
  }
468
+
469
+ if (attr.type === 'rangePicker') {
470
+ if (attr.formDefault)
471
+ formSelectDefaultValue.value = attr.formDefault
472
+ if (attr.queryFormDefault) {
473
+ const dateArray = getRangeByType(attr.queryFormDefault, true)
474
+ pickerValue.value = `${dateArray[0]} ~ ${dateArray[1]}`
475
+ querySelectDefaultValue.value = pickerValue.value
476
+ }
477
+ }
462
478
  }
463
479
 
464
480
  function getDataCallback(res) {
@@ -1,33 +1,33 @@
1
- <script setup lang="ts">
2
- import { onMounted, ref } from 'vue'
3
- import XReport from './XReport.vue'
4
-
5
- const mainRef = ref()
6
-
7
- onMounted(() => {
8
- // 初始化逻辑
9
- })
10
- </script>
11
-
12
- <template>
13
- <div id="test">
14
- <van-card :bordered="false">
15
- <XReport
16
- ref="mainRef"
17
- :use-oss-for-img="false"
18
- config-name="nurseWorkstationCover"
19
- server-name="af-his"
20
- :show-img-in-cell="true"
21
- :display-only="true"
22
- :edit-mode="false"
23
- :show-save-button="false"
24
- :no-padding="true"
25
- :dont-format="true"
26
- />
27
- </van-card>
28
- </div>
29
- </template>
30
-
31
- <style scoped>
32
-
33
- </style>
1
+ <script setup lang="ts">
2
+ import { onMounted, ref } from 'vue'
3
+ import XReport from './XReport.vue'
4
+
5
+ const mainRef = ref()
6
+
7
+ onMounted(() => {
8
+ // 初始化逻辑
9
+ })
10
+ </script>
11
+
12
+ <template>
13
+ <div id="test">
14
+ <van-card :bordered="false">
15
+ <XReport
16
+ ref="mainRef"
17
+ :use-oss-for-img="false"
18
+ config-name="nurseWorkstationCover"
19
+ server-name="af-his"
20
+ :show-img-in-cell="true"
21
+ :display-only="true"
22
+ :edit-mode="false"
23
+ :show-save-button="false"
24
+ :no-padding="true"
25
+ :dont-format="true"
26
+ />
27
+ </van-card>
28
+ </div>
29
+ </template>
30
+
31
+ <style scoped>
32
+
33
+ </style>
@@ -1,184 +1,184 @@
1
- // print.js
2
-
3
- export function printElement(elementToPrint) {
4
- // 创建一个新的浏览器窗口
5
- const printWindow = window.open('', '_blank', 'height=1024,width=768')
6
- // 设置新窗口的文档内容
7
- printWindow.document.write(`
8
- <html>
9
- <head>
10
- <title>Print</title>
11
- <style>
12
- @page {
13
- size: auto;
14
- margin: 0mm;
15
- }
16
- html, body {
17
- margin: 0;
18
- padding: 0;
19
- width: 100%;
20
- height: 100%;
21
- }
22
- #print-container {
23
- display: none
24
- }
25
- .img{
26
- width: 95%;
27
- height: 180px;
28
- object-fit: cover;
29
- }
30
- .reportMain {
31
- text-align: center;
32
- margin: 0 auto;
33
- font-size: 16px;
34
- color: #000;
35
- background-color: #fff;
36
- border-radius: 8px;
37
-
38
- .reportTitle {
39
- font-weight: bold;
40
- }
41
-
42
- .subTitle {
43
- display: flex;
44
- justify-content: space-between;
45
- margin-bottom: 1%;
46
-
47
- .subTitleItems {
48
- max-width: 30%;
49
- }
50
- }
51
-
52
- .inputsDiv {
53
- display: flex;
54
- justify-content: space-between;
55
- .inputsDivItem {
56
- display: flex;
57
- align-items: center;
58
- padding: 0 4px;
59
- white-space: nowrap;
60
- .inputsDivItemLabel {
61
- padding: 0 4px;
62
- }
63
- }
64
- }
65
-
66
- .reportTable {
67
- width: 100%;
68
- border-collapse: collapse;
69
- table-layout:fixed;
70
- word-break:break-all;
71
- text-align: center;
72
- }
73
- }
74
- .reportMainForDisplay {
75
- text-align: center;
76
- margin: 10% auto;
77
- font-size: 16px;
78
- color: #000;
79
- background-color: #fff;
80
- border-radius: 8px;
81
-
82
- .reportTitle {
83
- font-weight: bold;
84
- }
85
-
86
- .subTitle {
87
- display: flex;
88
- justify-content: space-between;
89
-
90
- .subTitleItems {
91
- max-width: 30%;
92
- }
93
- }
94
-
95
- .inputsDiv {
96
- display: flex;
97
- justify-content: space-around;
98
- .inputsDivItem {
99
- display: flex;
100
- align-items: center;
101
- padding: 0 4px;
102
- white-space: nowrap;
103
- .inputsDivItemLabel {
104
- padding: 0 4px;
105
- }
106
- }
107
- }
108
-
109
- .reportTable {
110
- width: 100%;
111
- border-collapse: collapse;
112
- table-layout:fixed;
113
- word-break:break-all;
114
- }
115
- }
116
- .reportMainNoPadding {
117
- text-align: center;
118
- margin: 0 auto;
119
- font-size: 16px;
120
- color: #000;
121
- background-color: #fff;
122
- border-radius: 8px;
123
-
124
- .reportTitle {
125
- font-weight: bold;
126
- }
127
-
128
- .subTitle {
129
- display: flex;
130
- justify-content: space-between;
131
-
132
- .subTitleItems {
133
- max-width: 30%;
134
- }
135
- }
136
-
137
- .inputsDiv {
138
- display: flex;
139
- justify-content: space-between;
140
- .inputsDivItem {
141
- display: flex;
142
- align-items: center;
143
- padding: 0 4px;
144
- white-space: nowrap;
145
- .inputsDivItemLabel {
146
- padding: 0 4px;
147
- }
148
- }
149
- }
150
-
151
- .reportTable {
152
- width: 100%;
153
- border-collapse: collapse;
154
- table-layout:fixed;
155
- word-break:break-all;
156
- }
157
- }
158
- .tools{
159
- position: fixed;
160
- right: 2%;
161
- text-align: right;
162
- width: 60%;
163
- cursor: pointer;
164
- .toolsItem{
165
- width: 15%;
166
- margin-right: 3%;
167
- display: inline-block;
168
- }
169
- }
170
- </style>
171
- </head>
172
- <body>
173
- <!-- 将需要打印的元素内容复制到新窗口中 -->
174
- ${elementToPrint.innerHTML}
175
- </body>
176
- </html>
177
- `)
178
- // 延迟执行打印,以确保新窗口的内容已加载完成
179
- printWindow.document.close() // 关闭文档流,确保内容完全加载
180
- setTimeout(() => {
181
- printWindow.print() // 调用打印方法
182
- printWindow.close()
183
- }, 500) // 延迟500毫秒后执行打印
184
- }
1
+ // print.js
2
+
3
+ export function printElement(elementToPrint) {
4
+ // 创建一个新的浏览器窗口
5
+ const printWindow = window.open('', '_blank', 'height=1024,width=768')
6
+ // 设置新窗口的文档内容
7
+ printWindow.document.write(`
8
+ <html>
9
+ <head>
10
+ <title>Print</title>
11
+ <style>
12
+ @page {
13
+ size: auto;
14
+ margin: 0mm;
15
+ }
16
+ html, body {
17
+ margin: 0;
18
+ padding: 0;
19
+ width: 100%;
20
+ height: 100%;
21
+ }
22
+ #print-container {
23
+ display: none
24
+ }
25
+ .img{
26
+ width: 95%;
27
+ height: 180px;
28
+ object-fit: cover;
29
+ }
30
+ .reportMain {
31
+ text-align: center;
32
+ margin: 0 auto;
33
+ font-size: 16px;
34
+ color: #000;
35
+ background-color: #fff;
36
+ border-radius: 8px;
37
+
38
+ .reportTitle {
39
+ font-weight: bold;
40
+ }
41
+
42
+ .subTitle {
43
+ display: flex;
44
+ justify-content: space-between;
45
+ margin-bottom: 1%;
46
+
47
+ .subTitleItems {
48
+ max-width: 30%;
49
+ }
50
+ }
51
+
52
+ .inputsDiv {
53
+ display: flex;
54
+ justify-content: space-between;
55
+ .inputsDivItem {
56
+ display: flex;
57
+ align-items: center;
58
+ padding: 0 4px;
59
+ white-space: nowrap;
60
+ .inputsDivItemLabel {
61
+ padding: 0 4px;
62
+ }
63
+ }
64
+ }
65
+
66
+ .reportTable {
67
+ width: 100%;
68
+ border-collapse: collapse;
69
+ table-layout:fixed;
70
+ word-break:break-all;
71
+ text-align: center;
72
+ }
73
+ }
74
+ .reportMainForDisplay {
75
+ text-align: center;
76
+ margin: 10% auto;
77
+ font-size: 16px;
78
+ color: #000;
79
+ background-color: #fff;
80
+ border-radius: 8px;
81
+
82
+ .reportTitle {
83
+ font-weight: bold;
84
+ }
85
+
86
+ .subTitle {
87
+ display: flex;
88
+ justify-content: space-between;
89
+
90
+ .subTitleItems {
91
+ max-width: 30%;
92
+ }
93
+ }
94
+
95
+ .inputsDiv {
96
+ display: flex;
97
+ justify-content: space-around;
98
+ .inputsDivItem {
99
+ display: flex;
100
+ align-items: center;
101
+ padding: 0 4px;
102
+ white-space: nowrap;
103
+ .inputsDivItemLabel {
104
+ padding: 0 4px;
105
+ }
106
+ }
107
+ }
108
+
109
+ .reportTable {
110
+ width: 100%;
111
+ border-collapse: collapse;
112
+ table-layout:fixed;
113
+ word-break:break-all;
114
+ }
115
+ }
116
+ .reportMainNoPadding {
117
+ text-align: center;
118
+ margin: 0 auto;
119
+ font-size: 16px;
120
+ color: #000;
121
+ background-color: #fff;
122
+ border-radius: 8px;
123
+
124
+ .reportTitle {
125
+ font-weight: bold;
126
+ }
127
+
128
+ .subTitle {
129
+ display: flex;
130
+ justify-content: space-between;
131
+
132
+ .subTitleItems {
133
+ max-width: 30%;
134
+ }
135
+ }
136
+
137
+ .inputsDiv {
138
+ display: flex;
139
+ justify-content: space-between;
140
+ .inputsDivItem {
141
+ display: flex;
142
+ align-items: center;
143
+ padding: 0 4px;
144
+ white-space: nowrap;
145
+ .inputsDivItemLabel {
146
+ padding: 0 4px;
147
+ }
148
+ }
149
+ }
150
+
151
+ .reportTable {
152
+ width: 100%;
153
+ border-collapse: collapse;
154
+ table-layout:fixed;
155
+ word-break:break-all;
156
+ }
157
+ }
158
+ .tools{
159
+ position: fixed;
160
+ right: 2%;
161
+ text-align: right;
162
+ width: 60%;
163
+ cursor: pointer;
164
+ .toolsItem{
165
+ width: 15%;
166
+ margin-right: 3%;
167
+ display: inline-block;
168
+ }
169
+ }
170
+ </style>
171
+ </head>
172
+ <body>
173
+ <!-- 将需要打印的元素内容复制到新窗口中 -->
174
+ ${elementToPrint.innerHTML}
175
+ </body>
176
+ </html>
177
+ `)
178
+ // 延迟执行打印,以确保新窗口的内容已加载完成
179
+ printWindow.document.close() // 关闭文档流,确保内容完全加载
180
+ setTimeout(() => {
181
+ printWindow.print() // 调用打印方法
182
+ printWindow.close()
183
+ }, 500) // 延迟500毫秒后执行打印
184
+ }
@@ -5,7 +5,7 @@ import { showToast } from 'vant'
5
5
  // 不需要登录拦截的路由配置
6
6
  const loginIgnore = {
7
7
  names: ['404', '403'], // 根据路由名称匹配
8
- paths: ['/login', '/XReportFormIframeView', '/invoiceShow'], // 根据路由fullPath匹配
8
+ paths: ['/login', '/XReportFormIframeView', '/invoiceShow', '/user-appointment', '/appointment-form', '/appointment-history'], // 根据路由fullPath匹配
9
9
  /**
10
10
  * 判断路由是否包含在该配置中
11
11
  * @param route vue-router 的 route 对象
@@ -0,0 +1,57 @@
1
+ /**
2
+ * 根据类型获取日期区间字符串
3
+ * @param type '当年' | 'curMonth' | '当日'
4
+ * @param show 区分实际值还是显示值, true为实际值, false为显示值
5
+ * @returns [start, end] 例:['2024-01-01 00:00:00', '2024-12-31 23:59:59']
6
+ */
7
+ export function getRangeByType(type: string, show: boolean): [string, string] {
8
+ const now = new Date()
9
+ const year = now.getFullYear()
10
+ const month = (now.getMonth() + 1).toString().padStart(2, '0')
11
+ const day = now.getDate().toString().padStart(2, '0')
12
+
13
+ if (!show) {
14
+ if (type === 'curYear') {
15
+ return [
16
+ `${year}-01-01 00:00:00`,
17
+ `${year}-12-31 23:59:59`,
18
+ ]
19
+ }
20
+ if (type === 'curMonth') {
21
+ const lastDay = new Date(year, now.getMonth() + 1, 0).getDate()
22
+ return [
23
+ `${year}-${month}-01 00:00:00`,
24
+ `${year}-${month}-${lastDay.toString().padStart(2, '0')} 23:59:59`,
25
+ ]
26
+ }
27
+ if (type === 'curDay') {
28
+ return [
29
+ `${year}-${month}-${day} 00:00:00`,
30
+ `${year}-${month}-${day} 23:59:59`,
31
+ ]
32
+ }
33
+ }
34
+ if (show) {
35
+ if (type === 'curYear') {
36
+ return [
37
+ `${year}-01-01`,
38
+ `${year}-12-31`,
39
+ ]
40
+ }
41
+ if (type === 'curMonth') {
42
+ const lastDay = new Date(year, now.getMonth() + 1, 0).getDate()
43
+ return [
44
+ `${year}-${month}-01`,
45
+ `${year}-${month}-${lastDay.toString().padStart(2, '0')}`,
46
+ ]
47
+ }
48
+ if (type === 'curDay') {
49
+ return [
50
+ `${year}-${month}-${day}`,
51
+ `${year}-${month}-${day}`,
52
+ ]
53
+ }
54
+ }
55
+ // 兜底返回空字符串数组
56
+ return ['', '']
57
+ }
package/tsconfig.json CHANGED
@@ -1,43 +1,43 @@
1
- {
2
- "compilerOptions": {
3
- "target": "esnext",
4
- "jsx": "preserve",
5
- "lib": ["esnext", "dom", "dom.iterable", "scripthost"],
6
- "experimentalDecorators": true,
7
- "baseUrl": ".",
8
- "module": "esnext",
9
- "moduleResolution": "Bundler",
10
- "paths": {
11
- "@af-mobile-client-vue3/*": ["src/*"]
12
- },
13
- "types": [
14
- "node",
15
- "unplugin-vue-router/client",
16
- "vite-plugin-vue-layouts/client",
17
- "vite-plugin-pwa/client"
18
- ],
19
- "allowJs": true,
20
- "strictNullChecks": false,
21
- "noImplicitAny": false,
22
- "noUnusedLocals": false,
23
- "noUnusedParameters": false,
24
- "importHelpers": true,
25
- "sourceMap": true,
26
- "allowSyntheticDefaultImports": true,
27
- "esModuleInterop": true,
28
- "verbatimModuleSyntax": true,
29
- "skipLibCheck": true
30
- },
31
- "include": [
32
- "src/App.vue",
33
- "src/**/*.ts",
34
- "src/**/*.tsx",
35
- "src/**/*.vue",
36
- "tests/**/*.ts",
37
- "tests/**/*.tsx",
38
- "src/components.d.ts",
39
- "src/auto-imports.d.ts",
40
- "src/typed-router.d.ts",
41
- "tests/*.ts"
42
- ]
43
- }
1
+ {
2
+ "compilerOptions": {
3
+ "target": "esnext",
4
+ "jsx": "preserve",
5
+ "lib": ["esnext", "dom", "dom.iterable", "scripthost"],
6
+ "experimentalDecorators": true,
7
+ "baseUrl": ".",
8
+ "module": "esnext",
9
+ "moduleResolution": "Bundler",
10
+ "paths": {
11
+ "@af-mobile-client-vue3/*": ["src/*"]
12
+ },
13
+ "types": [
14
+ "node",
15
+ "unplugin-vue-router/client",
16
+ "vite-plugin-vue-layouts/client",
17
+ "vite-plugin-pwa/client"
18
+ ],
19
+ "allowJs": true,
20
+ "strictNullChecks": false,
21
+ "noImplicitAny": false,
22
+ "noUnusedLocals": false,
23
+ "noUnusedParameters": false,
24
+ "importHelpers": true,
25
+ "sourceMap": true,
26
+ "allowSyntheticDefaultImports": true,
27
+ "esModuleInterop": true,
28
+ "verbatimModuleSyntax": true,
29
+ "skipLibCheck": true
30
+ },
31
+ "include": [
32
+ "src/App.vue",
33
+ "src/**/*.ts",
34
+ "src/**/*.tsx",
35
+ "src/**/*.vue",
36
+ "tests/**/*.ts",
37
+ "tests/**/*.tsx",
38
+ "src/components.d.ts",
39
+ "src/auto-imports.d.ts",
40
+ "src/typed-router.d.ts",
41
+ "tests/*.ts"
42
+ ]
43
+ }
package/vite.config.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import type { ConfigEnv, UserConfig } from 'vite'
2
2
  import path from 'node:path'
3
3
  import process from 'node:process'
4
- import autoprefixer from 'autoprefixer'
5
- import viewport from 'postcss-mobile-forever'
4
+ // import autoprefixer from 'autoprefixer'
5
+ // import viewport from 'postcss-mobile-forever'
6
6
  import { loadEnv } from 'vite'
7
7
  import { createVitePlugins } from './build/vite'
8
8
 
@@ -95,15 +95,15 @@ export default ({ mode }: ConfigEnv): UserConfig => {
95
95
  postcss: {
96
96
  plugins: [
97
97
  // 自动获取浏览器的流行度和能够支持的属性,并为 CSS 规则添加前缀
98
- autoprefixer(),
99
- viewport({
100
- appSelector: '#system-app',
101
- viewportWidth: 375,
102
- maxDisplayWidth: 800,
103
- appContainingBlock: 'auto',
104
- necessarySelectorWhenAuto: '.app-wrapper',
105
- rootContainingBlockSelectorList: ['van-tabbar', 'van-popup'],
106
- }),
98
+ // autoprefixer(),
99
+ // viewport({
100
+ // appSelector: '#system-app',
101
+ // viewportWidth: 375,
102
+ // maxDisplayWidth: 800,
103
+ // appContainingBlock: 'auto',
104
+ // necessarySelectorWhenAuto: '.app-wrapper',
105
+ // rootContainingBlockSelectorList: ['van-tabbar', 'van-popup'],
106
+ // }),
107
107
  ],
108
108
  },
109
109
  },