vue2-client 1.20.19 → 1.20.21

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 (86) hide show
  1. package/.claude/settings.local.json +30 -30
  2. package/.eslintrc.js +74 -74
  3. package/Components.md +60 -60
  4. package/index.js +31 -31
  5. package/jest-transform-stub.js +8 -8
  6. package/jest.setup.js +7 -7
  7. package/package.json +1 -1
  8. package/src/assets/img/querySlotDemo.svg +15 -15
  9. package/src/base-client/components/common/AmapMarker/AmapPointRendering.vue +120 -120
  10. package/src/base-client/components/common/CitySelect/index.js +3 -3
  11. package/src/base-client/components/common/CitySelect/index.md +109 -109
  12. package/src/base-client/components/common/FormGroupEdit/index.js +3 -3
  13. package/src/base-client/components/common/FormGroupEdit/index.md +43 -43
  14. package/src/base-client/components/common/JSONToTree/jsontotree.vue +271 -271
  15. package/src/base-client/components/common/PersonSetting/index.js +3 -3
  16. package/src/base-client/components/common/Tree/Tree.vue +149 -149
  17. package/src/base-client/components/common/Tree/index.js +2 -2
  18. package/src/base-client/components/common/Upload/index.js +3 -3
  19. package/src/base-client/components/common/XAddNativeForm/index.md +146 -146
  20. package/src/base-client/components/common/XCard/XCard.vue +64 -64
  21. package/src/base-client/components/common/XDataDrawer/XDataDrawer.vue +180 -180
  22. package/src/base-client/components/common/XDataDrawer/index.js +3 -3
  23. package/src/base-client/components/common/XDataDrawer/index.md +41 -41
  24. package/src/base-client/components/common/XDescriptions/XDescriptionsGroup.vue +671 -671
  25. package/src/base-client/components/common/XDescriptions/index.js +3 -3
  26. package/src/base-client/components/common/XDescriptions/index.md +382 -382
  27. package/src/base-client/components/common/XForm/index.md +178 -178
  28. package/src/base-client/components/common/XFormTable/XFormTable.vue +8 -0
  29. package/src/base-client/components/common/XFormTable/demo.vue +79 -37
  30. package/src/base-client/components/common/XInspectionDetailDrawer/components/CheckItems.vue +42 -17
  31. package/src/base-client/components/common/XInspectionDetailDrawer/components/HazardPhotos.vue +48 -19
  32. package/src/base-client/components/common/XInspectionDetailDrawer/services/inspectionService.js +5 -3
  33. package/src/base-client/components/common/XStepView/XStepView.vue +252 -252
  34. package/src/base-client/components/common/XStepView/index.js +3 -3
  35. package/src/base-client/components/common/XStepView/index.md +31 -31
  36. package/src/base-client/components/common/XTable/XTable.vue +20 -0
  37. package/src/base-client/components/common/XTable/index.md +255 -255
  38. package/src/base-client/components/system/DictionaryDetailsView/DictionaryDetailsView.vue +232 -232
  39. package/src/base-client/plugins/Config.js +19 -19
  40. package/src/base-client/plugins/tabs-page-plugin.js +39 -39
  41. package/src/components/Charts/Bar.vue +62 -62
  42. package/src/components/Charts/ChartCard.vue +134 -134
  43. package/src/components/Charts/Liquid.vue +67 -67
  44. package/src/components/Charts/MiniArea.vue +39 -39
  45. package/src/components/Charts/MiniBar.vue +39 -39
  46. package/src/components/Charts/MiniProgress.vue +75 -75
  47. package/src/components/Charts/MiniSmoothArea.vue +40 -40
  48. package/src/components/Charts/Radar.vue +68 -68
  49. package/src/components/Charts/RankList.vue +77 -77
  50. package/src/components/Charts/TagCloud.vue +113 -113
  51. package/src/components/Charts/TransferBar.vue +64 -64
  52. package/src/components/Charts/Trend.vue +82 -82
  53. package/src/components/Charts/chart.less +12 -12
  54. package/src/components/Charts/smooth.area.less +13 -13
  55. package/src/components/NumberInfo/NumberInfo.vue +54 -54
  56. package/src/components/NumberInfo/index.js +3 -3
  57. package/src/components/NumberInfo/index.less +54 -54
  58. package/src/components/NumberInfo/index.md +43 -43
  59. package/src/components/card/ChartCard.vue +79 -79
  60. package/src/components/chart/Bar.vue +60 -60
  61. package/src/components/chart/MiniArea.vue +67 -67
  62. package/src/components/chart/MiniBar.vue +59 -59
  63. package/src/components/chart/MiniProgress.vue +57 -57
  64. package/src/components/chart/Radar.vue +80 -80
  65. package/src/components/chart/RankingList.vue +60 -60
  66. package/src/components/chart/Trend.vue +79 -79
  67. package/src/components/chart/index.less +9 -9
  68. package/src/components/checkbox/ColorCheckbox.vue +157 -157
  69. package/src/components/input/IInput.vue +66 -66
  70. package/src/components/menu/SideMenu.vue +75 -75
  71. package/src/components/menu/menu.js +273 -273
  72. package/src/components/tool/AStepItem.vue +60 -60
  73. package/src/layouts/CommonLayout.vue +56 -56
  74. package/src/lib.js +1 -1
  75. package/src/mock/extend/index.js +84 -84
  76. package/src/mock/goods/index.js +108 -108
  77. package/src/pages/WorkflowDetail/WorkFlowDemo4.vue +127 -0
  78. package/src/pages/WorkflowDetail/WorkflowPageDetail/WorkFlowBaseInformation.vue +417 -417
  79. package/src/pages/dashboard/workplace/WorkPlace.vue +141 -141
  80. package/src/pages/system/dictionary/index.vue +44 -44
  81. package/src/pages/system/monitor/loginInfor/index.vue +37 -37
  82. package/src/pages/system/monitor/operLog/index.vue +37 -37
  83. package/src/services/api/cas.js +79 -79
  84. package/src/store/modules/setting.js +119 -119
  85. package/src/utils/errorCode.js +6 -6
  86. package//350/277/201/347/247/273/346/227/245/345/277/227.md +15 -15
@@ -1,178 +1,178 @@
1
- # XForm
2
-
3
- 动态表单控件,根据JSON配置生成一个完整的动态表单
4
-
5
-
6
- ## 何时使用
7
-
8
- 当需要一个动态生成的表单时
9
-
10
-
11
- 引用方式:
12
-
13
- ```javascript
14
- import XForm from '@vue2-client/base-client/components/XForm/XForm'
15
-
16
- export default {
17
- components: {
18
- XForm
19
- }
20
- }
21
- ```
22
-
23
-
24
-
25
- ## 代码演示
26
-
27
- ```html
28
- <x-form
29
- :json-data="json"
30
- :isExports="true"
31
- @onSubmit="onSubmit">
32
- </x-form>
33
- ```
34
-
35
- ## API
36
-
37
- | 参数 | 说明 | 类型 | 默认值 |
38
- |-----------|--------------------------|---------|------|
39
- | jsonData | JSON配置,根据[工具>查询配置生成]功能生成 | Object | {} |
40
- | isExports | 是否显示导出按钮 | Boolean | true |
41
- | getDataParams | 调用logic获取数据源的追加参数 | Object | - |
42
- | @onSubmit | 表单的提交事件 | event | - |
43
-
44
- ## 例子1
45
- ----
46
- (基础使用)
47
-
48
- ```vue
49
- <template>
50
- <x-form
51
- v-if="loaded"
52
- :json-data="formItemJson"
53
- :isExports="false"
54
- @onSubmit="onSubmit">
55
- </x-form>
56
- </template>
57
-
58
- <script>
59
- import XForm from '@vue2-client/base-client/components/XForm/XForm'
60
-
61
- export default {
62
- components: {
63
- XForm
64
- },
65
- data () {
66
- return {
67
- // 加载查询参数JSON配置文件是否完成
68
- loaded: false,
69
- // 从查询参数JSON配置中得到的生成表单的JSON
70
- formItemJson: undefined,
71
- // 表单
72
- form: {}
73
- }
74
- },
75
- created () {
76
- this.getQueryJson()
77
- },
78
- methods: {
79
- // 加载查询参数JSON配置文件
80
- getQueryJson () {
81
- this.formItemJson = [
82
- {
83
- "name":"燃气公司",
84
- "keyName":"orgList",
85
- "model":"orgName",
86
- "placeholder":"请选择",
87
- "type":"select"
88
- },
89
- {
90
- "name":"用户地址",
91
- "model":"f_address",
92
- "type":"input"
93
- },
94
- {
95
- "name":"指令类型",
96
- "keyName":"指令类型",
97
- "model":"f_instruct_type",
98
- "placeholder":"请选择",
99
- "type":"select"
100
- },
101
- {
102
- "name":"指令说明",
103
- "model":"f_instruct_title",
104
- "placeholder":"请输入指令说明",
105
- "type":"input"
106
- },
107
- {
108
- "name":"指令状态",
109
- "keyName":"指令状态",
110
- "model":"f_instruct_state",
111
- "placeholder":"请选择",
112
- "type":"select"
113
- },
114
- {
115
- "name":"响应结果",
116
- "model":"f_receive_state",
117
- "placeholder":"请输入响应结果",
118
- "type":"input"
119
- },
120
- {
121
- "name":"生成时间",
122
- "model":"f_instruct_date",
123
- "type":"rangePicker"
124
- },
125
- {
126
- "name":"操作人",
127
- "model":"f_inputtor",
128
- "placeholder":"请输入操作人员",
129
- "type":"input"
130
- }
131
- ]
132
- this.loaded = true
133
- },
134
- // 表单提交方法
135
- onSubmit (res) {
136
- // 如果通过校验
137
- if (res.valid) {
138
- // 表单赋值
139
- this.form = res.form
140
- } else {
141
- return false
142
- }
143
- }
144
- }
145
- }
146
- </script>
147
- ```
148
-
149
- 注意事项
150
- ----
151
-
152
- > 本组件已经实现了自适应布局,在不同分辨率下的设备均可得到基本理想的展示效果
153
- >
154
- > 以上示例查询参数配置为后台生成后的结果,此处为了方便调试,所以直接写在了代码中,实际使用请通过发起请求获取查询参数配置,如下:
155
- ```vue
156
- <script>
157
- import { commonApi } from '@vue2-client/base-client/api/common'
158
- import Vue from 'vue'
159
-
160
- export default {
161
- data () {
162
- return {
163
- // 查询配置文件名
164
- queryParamsName: 'instructQueryParams'
165
- }
166
- },
167
- methods: {
168
- getConfig () {
169
- Vue.resetpost(commonApi.getConfig, {str: this.queryParamsName}).then((res) => {
170
- this.formItemJson = res.formJson
171
- this.columnItemJson = res.columnJson
172
- this.loaded = true
173
- })
174
- }
175
- }
176
- }
177
- </script>
178
- ```
1
+ # XForm
2
+
3
+ 动态表单控件,根据JSON配置生成一个完整的动态表单
4
+
5
+
6
+ ## 何时使用
7
+
8
+ 当需要一个动态生成的表单时
9
+
10
+
11
+ 引用方式:
12
+
13
+ ```javascript
14
+ import XForm from '@vue2-client/base-client/components/XForm/XForm'
15
+
16
+ export default {
17
+ components: {
18
+ XForm
19
+ }
20
+ }
21
+ ```
22
+
23
+
24
+
25
+ ## 代码演示
26
+
27
+ ```html
28
+ <x-form
29
+ :json-data="json"
30
+ :isExports="true"
31
+ @onSubmit="onSubmit">
32
+ </x-form>
33
+ ```
34
+
35
+ ## API
36
+
37
+ | 参数 | 说明 | 类型 | 默认值 |
38
+ |-----------|--------------------------|---------|------|
39
+ | jsonData | JSON配置,根据[工具>查询配置生成]功能生成 | Object | {} |
40
+ | isExports | 是否显示导出按钮 | Boolean | true |
41
+ | getDataParams | 调用logic获取数据源的追加参数 | Object | - |
42
+ | @onSubmit | 表单的提交事件 | event | - |
43
+
44
+ ## 例子1
45
+ ----
46
+ (基础使用)
47
+
48
+ ```vue
49
+ <template>
50
+ <x-form
51
+ v-if="loaded"
52
+ :json-data="formItemJson"
53
+ :isExports="false"
54
+ @onSubmit="onSubmit">
55
+ </x-form>
56
+ </template>
57
+
58
+ <script>
59
+ import XForm from '@vue2-client/base-client/components/XForm/XForm'
60
+
61
+ export default {
62
+ components: {
63
+ XForm
64
+ },
65
+ data () {
66
+ return {
67
+ // 加载查询参数JSON配置文件是否完成
68
+ loaded: false,
69
+ // 从查询参数JSON配置中得到的生成表单的JSON
70
+ formItemJson: undefined,
71
+ // 表单
72
+ form: {}
73
+ }
74
+ },
75
+ created () {
76
+ this.getQueryJson()
77
+ },
78
+ methods: {
79
+ // 加载查询参数JSON配置文件
80
+ getQueryJson () {
81
+ this.formItemJson = [
82
+ {
83
+ "name":"燃气公司",
84
+ "keyName":"orgList",
85
+ "model":"orgName",
86
+ "placeholder":"请选择",
87
+ "type":"select"
88
+ },
89
+ {
90
+ "name":"用户地址",
91
+ "model":"f_address",
92
+ "type":"input"
93
+ },
94
+ {
95
+ "name":"指令类型",
96
+ "keyName":"指令类型",
97
+ "model":"f_instruct_type",
98
+ "placeholder":"请选择",
99
+ "type":"select"
100
+ },
101
+ {
102
+ "name":"指令说明",
103
+ "model":"f_instruct_title",
104
+ "placeholder":"请输入指令说明",
105
+ "type":"input"
106
+ },
107
+ {
108
+ "name":"指令状态",
109
+ "keyName":"指令状态",
110
+ "model":"f_instruct_state",
111
+ "placeholder":"请选择",
112
+ "type":"select"
113
+ },
114
+ {
115
+ "name":"响应结果",
116
+ "model":"f_receive_state",
117
+ "placeholder":"请输入响应结果",
118
+ "type":"input"
119
+ },
120
+ {
121
+ "name":"生成时间",
122
+ "model":"f_instruct_date",
123
+ "type":"rangePicker"
124
+ },
125
+ {
126
+ "name":"操作人",
127
+ "model":"f_inputtor",
128
+ "placeholder":"请输入操作人员",
129
+ "type":"input"
130
+ }
131
+ ]
132
+ this.loaded = true
133
+ },
134
+ // 表单提交方法
135
+ onSubmit (res) {
136
+ // 如果通过校验
137
+ if (res.valid) {
138
+ // 表单赋值
139
+ this.form = res.form
140
+ } else {
141
+ return false
142
+ }
143
+ }
144
+ }
145
+ }
146
+ </script>
147
+ ```
148
+
149
+ 注意事项
150
+ ----
151
+
152
+ > 本组件已经实现了自适应布局,在不同分辨率下的设备均可得到基本理想的展示效果
153
+ >
154
+ > 以上示例查询参数配置为后台生成后的结果,此处为了方便调试,所以直接写在了代码中,实际使用请通过发起请求获取查询参数配置,如下:
155
+ ```vue
156
+ <script>
157
+ import { commonApi } from '@vue2-client/base-client/api/common'
158
+ import Vue from 'vue'
159
+
160
+ export default {
161
+ data () {
162
+ return {
163
+ // 查询配置文件名
164
+ queryParamsName: 'instructQueryParams'
165
+ }
166
+ },
167
+ methods: {
168
+ getConfig () {
169
+ Vue.resetpost(commonApi.getConfig, {str: this.queryParamsName}).then((res) => {
170
+ this.formItemJson = res.formJson
171
+ this.columnItemJson = res.columnJson
172
+ this.loaded = true
173
+ })
174
+ }
175
+ }
176
+ }
177
+ </script>
178
+ ```
@@ -561,6 +561,14 @@ export default {
561
561
  handler () {
562
562
  this.initConfig()
563
563
  }
564
+ },
565
+ extraData: {
566
+ handler (newVal) {
567
+ if (this.$refs.xTable) {
568
+ this.$refs.xTable.updateExtraData(newVal)
569
+ }
570
+ },
571
+ deep: true
564
572
  }
565
573
  },
566
574
  methods: {
@@ -2,32 +2,51 @@
2
2
  <a-card :bordered="false">
3
3
  <x-form-table
4
4
  title="示例表单"
5
- :queryParamsName="queryParamsName"
5
+ queryParamsName="scanCodeAndNFCRUD"
6
6
  :fixedAddForm="fixedAddForm"
7
7
  :externalSelectedRowKeys="selectedKeys"
8
+ :defaultPageSize="100"
9
+ :pageSizeArray="['100','200']"
8
10
  @action="action"
9
11
  @selectRow="selectRow"
10
12
  @columnClick="columnClick"
11
13
  @ceshi="ceshi"
12
- @rowDblClick="rowDblClick"
13
- :defaultPageSize="5"
14
- serviceName="af-revenue"
14
+ @startService="startService"
15
+ serviceName="af-safecheck"
15
16
  ref="xFormTable"
16
17
  :reserveSpaceForButtons="true"
17
- @addFormSubmit="addFormSubmit"
18
- ></x-form-table>
18
+ >
19
+ </x-form-table>
20
+ <a-modal
21
+ v-model="formModalVisible"
22
+ title="工单回访"
23
+ :zIndex="1002"
24
+ width="50vw"
25
+ :destroy-on-close="true"
26
+ @cancel="formModalVisible = false"
27
+ @ok="ok"
28
+ >
29
+ <x-add-native-form
30
+ ref="xForm"
31
+ />
32
+ </a-modal>
33
+ <button @click="backDealData">提交</button>
19
34
  </a-card>
20
35
  </template>
21
36
 
22
37
  <script>
23
38
  import XFormTable from '@vue2-client/base-client/components/common/XFormTable/XFormTable.vue'
39
+ import XAddNativeForm from '@vue2-client/base-client/components/common/XAddNativeForm/XAddNativeForm.vue'
24
40
  import { microDispatch } from '@vue2-client/utils/microAppUtils'
41
+ import {getConfigByNameAsync, runLogic} from '@vue2-client/services/api/common'
42
+
25
43
  export default {
26
44
  name: 'Demo',
27
45
  components: {
28
- XFormTable
46
+ XFormTable,
47
+ XAddNativeForm,
29
48
  },
30
- data() {
49
+ data () {
31
50
  return {
32
51
  // 查询配置文件名
33
52
  queryParamsName: 'ceshiCRUD',
@@ -43,26 +62,32 @@ export default {
43
62
  selectedKeys: [],
44
63
  selected: {
45
64
  keys: [],
46
- rows: []
47
- }
65
+ rows: [],
66
+ },
67
+ formModalVisible: false,
48
68
  }
49
69
  },
50
-
51
70
  methods: {
52
- handleCustomQuery() {
53
- this.$refs.xFormTable.queryTable({
54
- uf_f_alias: 'XianFeng',
55
- uf_f_card_id: '10500030'
71
+ backDealData () {
72
+ this.$refs.xFormTable.$refs.xForm.backDealData().then(data => {
73
+ console.log('backDealData', data)
74
+ console.log('selected', this.$refs.xFormTable.$refs.xForm?.form)
56
75
  })
57
76
  },
58
- rowDblClick(record) {
59
- console.log('rowDblClick', record)
60
- },
61
77
  // input框 行編輯參數傳遞
62
- ceshi(...args) {
78
+ ceshi (...args) {
63
79
  // attr, value, currentRecord, currentIndex, nextRecord, nextIndex
64
- const [attr, value, currentRecord, currentIndex, nextRecord, nextIndex] = args
65
- console.log('ceshi', attr, value, currentRecord, currentIndex, nextRecord, nextIndex)
80
+ const [attr, value, currentRecord, currentIndex, nextRecord, nextIndex] =
81
+ args
82
+ console.log(
83
+ 'ceshi',
84
+ attr,
85
+ value,
86
+ currentRecord,
87
+ currentIndex,
88
+ nextRecord,
89
+ nextIndex
90
+ )
66
91
  // 示例:当按下 Enter 键且有下一行时,跳转到下一行的同一列
67
92
  // 可以在这里执行业务逻辑(例如:保存数据)
68
93
  console.log('当前行:', currentIndex, '下一行:', nextIndex)
@@ -73,44 +98,61 @@ export default {
73
98
  // 跳转到下一行的同一列
74
99
  this.$refs.xFormTable.$refs.xTable.focusInput(nextIndex, attr.model)
75
100
  },
76
- test() {
101
+ test () {
77
102
  this.$refs.xFormTable.setTableData([])
78
103
  },
79
- defaultF() {
104
+ defaultF () {
80
105
  this.$refs.xFormTable.setTableSize('default')
81
106
  },
82
- middleF() {
107
+ middleF () {
83
108
  this.$refs.xFormTable.setTableSize('middle')
84
109
  },
85
- smallF() {
110
+ smallF () {
86
111
  this.$refs.xFormTable.setTableSize('small')
87
112
  },
88
- columnClick(key, value, record) {
113
+ columnClick (key, value, record) {
89
114
  microDispatch({
90
115
  type: 'v3route',
91
116
  path: '/bingliguanli/dianzibingliluru',
92
- props: { selected: arguments[0].his_f_admission_id }
117
+ props: { selected: arguments[0].his_f_admission_id },
93
118
  })
94
119
  },
95
- action(record, id, actionType) {
96
- this.detailVisible = true
97
- console.log('触发了详情操作', record, id, actionType)
120
+ startService (record, id, actionType) {
121
+ getConfigByNameAsync('测试Form', 'af-safecheck').then(config => {
122
+ this.formModalVisible = true
123
+ this.$nextTick(
124
+ () => {
125
+ this.formModalVisible = true
126
+ this.$refs.xForm.init({
127
+ formItems: config.formJson,
128
+ title: '工单回访',
129
+ businessType: '新增',
130
+ ...config,
131
+ modifyModelData: { data: { id: 1 } },
132
+ })
133
+ })
134
+ })
135
+ // this.detailVisible = true
136
+ // console.log('触发了详情操作', record, id, actionType)
137
+ },
138
+ async ok () {
139
+ const res = await this.$refs.xForm.asyncSubmit()
140
+ await runLogic('ceshwewei', res.realForm)
98
141
  },
99
- onClose() {
142
+ onClose () {
100
143
  this.detailVisible = false
101
144
  // 关闭详情之后重新查询表单
102
145
  this.$refs.xFormTable.refreshTable(true)
103
146
  },
104
- selectRow(selectedRowKeys, selectedRows) {
147
+ selectRow (selectedRowKeys, selectedRows) {
105
148
  this.selected = {
106
149
  keys: selectedRowKeys,
107
- rows: selectedRows
150
+ rows: selectedRows,
108
151
  }
152
+ console.log('selectedDemo', this.selected)
109
153
  },
110
- addFormSubmit(params, callback){
111
- callback()
112
- }
113
- }
154
+ },
155
+ computed: {},
114
156
  }
115
157
  </script>
116
158
 
@@ -79,9 +79,9 @@
79
79
  >
80
80
  <!-- 有 fileId 时通过 img 展示加载中/错误/图片 -->
81
81
  <template v-if="photo.fileId">
82
- <a-spin v-if="getThumbState(photo.fileId) === 'loading'" size="small" />
83
- <a-icon v-else-if="getThumbState(photo.fileId) === 'error'" type="picture" class="thumb-error-icon" />
84
- <img v-else :src="thumbUrlMap[photo.fileId]" :alt="photo.title || '照片'" />
82
+ <a-spin v-if="getThumbState(photo) === 'loading'" size="small" />
83
+ <a-icon v-else-if="getThumbState(photo) === 'error'" type="picture" class="thumb-error-icon" />
84
+ <img v-else :src="thumbUrlMap[thumbCacheKey(photo)]" :alt="photo.title || '照片'" />
85
85
  </template>
86
86
  <!-- 直接有 url 时展示 -->
87
87
  <img v-else-if="photo.url" :src="photo.url" :alt="photo.title || '照片'" />
@@ -162,7 +162,8 @@ export default {
162
162
  if (!this.currentPhoto) return ''
163
163
  if (this.currentPhoto.url) return this.currentPhoto.url
164
164
  if (this.currentPhoto.fileId) {
165
- return this.thumbUrlMap[this.currentPhoto.fileId] || ''
165
+ const key = this.thumbCacheKey(this.currentPhoto)
166
+ return this.thumbUrlMap[key] || ''
166
167
  }
167
168
  return ''
168
169
  },
@@ -184,37 +185,61 @@ export default {
184
185
  */
185
186
  preloadThumbnails () {
186
187
  if (!this.checkItems || !this.injectedServiceName) return
188
+ this.thumbUrlMap = {}
189
+ this.thumbStateMap = {}
187
190
  this.checkItems.forEach(category => {
188
191
  if (!category.items) return
189
192
  category.items.forEach(item => {
190
193
  if (!item.photos) return
191
194
  item.photos.forEach(photo => {
192
- if (photo.fileId && !this.thumbStateMap[photo.fileId]) {
193
- this.loadThumb(photo.fileId)
194
- }
195
+ if (photo.fileId) this.loadThumb(photo)
195
196
  })
196
197
  })
197
198
  })
198
199
  },
199
200
 
200
- async loadThumb (fileId) {
201
- this.$set(this.thumbStateMap, fileId, 'loading')
201
+ /**
202
+ * 缩略图缓存必须用字符串键。若用对象作 fileId,JS 会统一变成 "[object Object]",导致所有缩略图共用一张图。
203
+ * 优先使用业务侧已生成的 photo.id,其次从 fileId 上解析 id。
204
+ */
205
+ thumbCacheKey (photo) {
206
+ if (!photo) return ''
207
+ if (photo.id != null && photo.id !== '') return String(photo.id)
208
+ const raw = photo.fileId
209
+ if (raw == null || raw === '') return ''
210
+ if (typeof raw !== 'object') return String(raw)
211
+ const id = raw.id ?? raw.f_id
212
+ if (id != null && typeof id !== 'object') return String(id)
213
+ return JSON.stringify(raw)
214
+ },
215
+
216
+ async loadThumb (photo) {
217
+ const key = this.thumbCacheKey(photo)
218
+ if (!key || !photo.fileId) return
219
+ if (this.thumbStateMap[key] === 'loading' || this.thumbStateMap[key] === 'done') return
220
+ this.$set(this.thumbStateMap, key, 'loading')
202
221
  try {
203
222
  const svc = createFileImageService({ serviceName: this.injectedServiceName })
204
- const url = await svc.getImageUrl(fileId)
205
- this.$set(this.thumbUrlMap, fileId, url)
206
- this.$set(this.thumbStateMap, fileId, 'done')
207
- } catch {
208
- this.$set(this.thumbStateMap, fileId, 'error')
223
+ const url = await svc.getImageUrl(photo.fileId)
224
+ if (this.thumbStateMap[key] === 'loading') {
225
+ this.$set(this.thumbUrlMap, key, url)
226
+ this.$set(this.thumbStateMap, key, 'done')
227
+ }
228
+ } catch (e) {
229
+ console.warn(`[CheckItems] 加载缩略图失败 key=${key}:`, e.message)
230
+ if (this.thumbStateMap[key] === 'loading') {
231
+ this.$set(this.thumbStateMap, key, 'error')
232
+ }
209
233
  }
210
234
  },
211
235
 
212
- getThumbState (fileId) {
213
- return this.thumbStateMap[fileId] || 'loading'
236
+ getThumbState (photo) {
237
+ const key = this.thumbCacheKey(photo)
238
+ return this.thumbStateMap[key] || 'loading'
214
239
  },
215
240
 
216
241
  getPhotoKey (photo, index) {
217
- return photo.fileId || photo.id || index
242
+ return this.thumbCacheKey(photo) || photo.id || index
218
243
  },
219
244
 
220
245
  /**