vue2-client 1.22.3 → 1.22.4

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 (88) hide show
  1. package/.env.his +19 -19
  2. package/.idea/.name +1 -0
  3. package/.idea/MarsCodeWorkspaceAppSettings.xml +8 -0
  4. package/.idea/deployment.xml +14 -0
  5. package/.idea/gradle.xml +7 -0
  6. package/.idea/inspectionProfiles/Project_Default.xml +6 -0
  7. package/.idea/libraries/contour_plot.xml +9 -0
  8. package/.idea/material_theme_project_new.xml +18 -0
  9. package/.idea/misc.xml +87 -5
  10. package/package.json +1 -1
  11. package/src/base-client/components/common/HIS/HForm/HForm.vue +1186 -1186
  12. package/src/base-client/components/common/XMarkdownViewer/demo.vue +102 -102
  13. package/src/base-client/components/his/HAi/HAi.vue +1177 -1177
  14. package/src/base-client/components/his/XTransfer/index.md +327 -327
  15. package/src/base-client/plugins/GetLoginInfoService.js +4 -4
  16. package/src/utils/login.js +11 -11
  17. package/.history/.eslintrc_20260521171150.js +0 -74
  18. package/.history/.eslintrc_20260521171213.js +0 -74
  19. package/.history/src/base-client/components/common/HIS/HAddNativeForm/HAddNativeForm_20260601154443.vue +0 -726
  20. package/.history/src/base-client/components/common/HIS/HAddNativeForm/HAddNativeForm_20260601154700.vue +0 -478
  21. package/.history/src/base-client/components/common/HIS/HButtons/HButtons_20260512175435.vue +0 -706
  22. package/.history/src/base-client/components/common/HIS/HButtons/HButtons_20260512175450.vue +0 -694
  23. package/.history/src/base-client/components/common/HIS/HButtons/HButtons_20260611152602.vue +0 -755
  24. package/.history/src/base-client/components/common/HIS/HForm/HForm_20260513145941.vue +0 -524
  25. package/.history/src/base-client/components/common/HIS/HForm/HForm_20260513153133.vue +0 -731
  26. package/.history/src/base-client/components/common/HIS/HForm/HForm_20260513160316.vue +0 -525
  27. package/.history/src/base-client/components/common/HIS/HForm/HForm_20260601144150.vue +0 -1046
  28. package/.history/src/base-client/components/common/HIS/HFormTable/HFormTable_20260310142713.vue +0 -512
  29. package/.history/src/base-client/components/common/HIS/HFormTable/HFormTable_20260310145118.vue +0 -511
  30. package/.history/src/base-client/components/common/HIS/HFormTable/HFormTable_20260311094834.vue +0 -696
  31. package/.history/src/base-client/components/common/HIS/HFormTable/HFormTable_20260320143028.vue +0 -693
  32. package/.history/src/base-client/components/common/HIS/HFormTable/HFormTable_20260409101450.vue +0 -677
  33. package/.history/src/base-client/components/common/HIS/HTab/HTab_20260508164645.vue +0 -758
  34. package/.history/src/base-client/components/common/HIS/HTab/HTab_20260508164714.vue +0 -693
  35. package/.history/src/base-client/components/common/HIS/HTab/HTab_20260508171651.vue +0 -716
  36. package/.history/src/base-client/components/common/HIS/HTab/HTab_20260509133717.vue +0 -695
  37. package/.history/src/base-client/components/common/HIS/HTab/HTab_20260509171115.vue +0 -664
  38. package/.history/src/base-client/components/common/XAddNativeForm/XAddNativeForm_20260513140637.vue +0 -1455
  39. package/.history/src/base-client/components/common/XAddNativeForm/XAddNativeForm_20260513140935.vue +0 -1441
  40. package/.history/src/base-client/components/common/XAddNativeForm/XAddNativeForm_20260513150818.vue +0 -1441
  41. package/.history/src/base-client/components/common/XAddNativeForm/XAddNativeForm_20260513153119.vue +0 -1442
  42. package/.history/src/base-client/components/common/XAddNativeForm/XAddNativeForm_20260513153126.vue +0 -1486
  43. package/.history/src/base-client/components/common/XForm/XFormItem_20260513140854.vue +0 -1607
  44. package/.history/src/base-client/components/common/XMarkdownViewer/XMarkdownViewer_20260519140403.vue +0 -643
  45. package/.history/src/base-client/components/common/XMarkdownViewer/XMarkdownViewer_20260519140829.vue +0 -628
  46. package/.history/src/base-client/components/common/XMarkdownViewer/demo_20260519142824.vue +0 -104
  47. package/.history/src/base-client/components/common/XMarkdownViewer/demo_20260519143155.vue +0 -102
  48. package/.history/src/base-client/components/common/XReportGrid/XReport_20260309171231.vue +0 -1241
  49. package/.history/src/base-client/components/common/XReportGrid/XReport_20260309171441.vue +0 -1223
  50. package/.history/src/base-client/components/his/HAi/HAi_20260612174826.vue +0 -472
  51. package/.history/src/base-client/components/his/HAi/HAi_20260612175839.vue +0 -538
  52. package/.history/src/base-client/components/his/HAi/HAi_20260615103331.vue +0 -650
  53. package/.history/src/base-client/components/his/XHDescriptions/XHDescriptions_20260424134504.vue +0 -1469
  54. package/.history/src/base-client/components/his/XSidebar/XSidebar_20260610171133.vue +0 -788
  55. package/.history/src/base-client/components/his/XSidebar/XSidebar_20260610171151.vue +0 -780
  56. package/.history/src/base-client/components/his/XTransfer/XTransfer_20260511170841.vue +0 -585
  57. package/.history/src/base-client/components/his/XTransfer/XTransfer_20260511171138.vue +0 -787
  58. package/.history/src/base-client/components/his/XTransfer/XTransfer_20260512141830.vue +0 -739
  59. package/.history/src/components/STable/index_20260409155138.js +0 -806
  60. package/.history/src/components/STable/index_20260409155218.js +0 -814
  61. package/.history/src/expression/core/Expression_20260305164427.js +0 -1371
  62. package/.history/src/expression/core/Expression_20260305170258.js +0 -1358
  63. package/.history/src/expression/core/Program_20260305111830.js +0 -944
  64. package/.history/src/expression/core/Program_20260305112041.js +0 -931
  65. package/.history/src/logic/LogicRunner_20260304154306.js +0 -170
  66. package/.history/src/logic/LogicRunner_20260304155553.js +0 -112
  67. package/.history/src/logic/LogicRunner_20260305105834.js +0 -112
  68. package/.history/src/logic/LogicRunner_20260305112718.js +0 -129
  69. package/.history/src/logic/LogicRunner_20260305182436.js +0 -133
  70. package/.history/src/logic/LogicRunner_20260306151301.js +0 -213
  71. package/.history/src/logic/LogicRunner_20260306152419.js +0 -213
  72. package/.history/src/logic/plugins/common/DateTools_20260305154159.js +0 -61
  73. package/.history/src/logic/plugins/common/DateTools_20260305154217.js +0 -44
  74. package/.history/src/logic/plugins/common/DateTools_20260305161014.js +0 -44
  75. package/.history/src/logic/plugins/common/HttpTools_20260305164352.js +0 -80
  76. package/.history/src/logic/plugins/common/HttpTools_20260305170258.js +0 -75
  77. package/.history/src/logic/plugins/common/HttpTools_20260305171634.js +0 -75
  78. package/.history/src/logic/plugins/common/HttpTools_20260306152419.js +0 -72
  79. package/.history/src/services/api/restTools_20260427142149.js +0 -245
  80. package/.history/src/services/api/restTools_20260427142853.js +0 -230
  81. package/.history/src/services/api/restTools_20260519135558.js +0 -230
  82. package/.history/src/services/api/restTools_20260519140825.js +0 -230
  83. package/.history/src/services/api/restTools_20260519151223.js +0 -230
  84. package/.history/src/utils/indexedDB_20260306150918.js +0 -593
  85. package/.history/src/utils/indexedDB_20260306151301.js +0 -586
  86. package/.idea/codeStyles/Project.xml +0 -62
  87. package/.idea/codeStyles/codeStyleConfig.xml +0 -5
  88. package/preview-input-box.html +0 -180
@@ -1,787 +0,0 @@
1
- <script setup>
2
- import { ref, computed, watch, onMounted } from 'vue'
3
- import { query, runLogic, getConfigByName } from '@vue2-client/services/api/common'
4
-
5
- const props = defineProps({
6
- // 配置名称 - 用于通过 getConfigByName 获取配置
7
- queryParamsName: { type: String, default: '' },
8
- configName: { type: String, default: '' },
9
- // 服务名
10
- serverName: { type: String, default: 'af-his' },
11
- // 直接属性(优先级高于 config)
12
- logicName: { type: String, default: '' },
13
- parameter: { type: Object, default: () => ({}) },
14
- rowKey: { type: String, default: 'key' },
15
- displayKey: { type: String, default: 'title' },
16
- descriptionKey: { type: String, default: '' },
17
- groupKey: { type: String, default: 'group' },
18
- groupLabelKey: { type: String, default: 'label' },
19
- groupCountKey: { type: String, default: 'count' },
20
- groupItemsKey: { type: String, default: 'items' },
21
- leftTitle: { type: String, default: '' },
22
- rightTitle: { type: String, default: '' },
23
- allText: { type: String, default: 'All' },
24
- addHint: { type: String, default: '双击添加' },
25
- removeHint: { type: String, default: '双击移除' },
26
- leftWidth: { type: String, default: '260px' },
27
- rightWidth: { type: String, default: '260px' },
28
- height: { type: String, default: '300px' },
29
- initialValue: { type: Array, default: () => [] },
30
- disabled: { type: Boolean, default: false },
31
- // 静态数据
32
- data: { type: Array, default: null },
33
- // config 对象
34
- config: { type: Object, default: null },
35
- // 环境
36
- env: { type: String, default: 'prod' }
37
- })
38
-
39
- const emit = defineEmits(['update:value', 'change', 'loaded'])
40
-
41
- const loading = ref(false)
42
- const localValue = ref([])
43
- const localDataSource = ref([])
44
- const localGroupDataSource = ref([])
45
- const localConfig = ref(null)
46
-
47
- // 是否是开发环境
48
- const isDev = computed(() => props.env === 'prod' ? false : true)
49
-
50
- // 获取配置值(支持多层级)
51
- const getConfig = (key, defaultValue) => {
52
- // 1. 优先从 config 对象读取
53
- if (props.config && props.config[key] !== undefined) {
54
- return props.config[key]
55
- }
56
- // 2. 从本地配置读取
57
- if (localConfig.value && localConfig.value[key] !== undefined) {
58
- return localConfig.value[key]
59
- }
60
- // 3. 从直接属性读取
61
- if (props[key] !== undefined) {
62
- return props[key]
63
- }
64
- return defaultValue
65
- }
66
-
67
- // UI 配置
68
- const logicName = computed(() => getConfig('logicName', props.logicName || ''))
69
- const queryParamsName = computed(() => getConfig('queryParamsName', props.queryParamsName || props.configName || ''))
70
- const parameter = computed(() => getConfig('parameter', props.parameter || {}))
71
- const pageSize = computed(() => getConfig('pageSize', 500))
72
-
73
- // 默认宽度和高度
74
- const leftWidth = computed(() => getConfig('leftWidth', '324px'))
75
- const rightWidth = computed(() => getConfig('rightWidth', '324px'))
76
- const height = computed(() => getConfig('height', '143px'))
77
- const allText = computed(() => getConfig('allText', 'All'))
78
- const addHint = computed(() => getConfig('addHint', '双击添加'))
79
- const removeHint = computed(() => getConfig('removeHint', '双击移除'))
80
- const leftTitle = computed(() => getConfig('leftTitle', ''))
81
- const rightTitle = computed(() => getConfig('rightTitle', ''))
82
- const disabled = computed(() => getConfig('disabled', false))
83
- const initialValue = computed(() => getConfig('initialValue', []))
84
-
85
- const totalCount = computed(() => localDataSource.value.length)
86
-
87
- // 监听外部 value 变化
88
- watch(() => getConfig('value', undefined), (newVal) => {
89
- if (newVal !== undefined && JSON.stringify(newVal) !== JSON.stringify(localValue.value)) {
90
- localValue.value = [...newVal]
91
- }
92
- }, { immediate: true })
93
-
94
- watch(localValue, (newVal) => {
95
- emit('update:value', newVal)
96
- })
97
-
98
- // ============ 数据加载 ============
99
- const loadData = async () => {
100
- loading.value = true
101
- try {
102
- let data = []
103
-
104
- // 1. 优先使用静态 data 属性
105
- if (props.data && Array.isArray(props.data)) {
106
- console.log('[XTransfer] using props.data')
107
- data = props.data
108
- }
109
- // 2. 使用 logicName 直接加载
110
- else if (logicName.value) {
111
- console.log('[XTransfer] using logicName:', logicName.value)
112
- data = await loadByLogic()
113
- }
114
- // 3. 使用 queryParamsName 获取配置后再加载
115
- else if (queryParamsName.value) {
116
- console.log('[XTransfer] using queryParamsName:', queryParamsName.value)
117
- await loadByConfig()
118
- // loadByConfig 会设置 localConfig 并重新触发 loadData
119
- return
120
- }
121
-
122
- parseData(data)
123
-
124
- if (initialValue.value.length > 0) {
125
- localValue.value = [...initialValue.value]
126
- }
127
-
128
- emit('loaded', {
129
- dataSource: localDataSource.value,
130
- groupDataSource: localGroupDataSource.value
131
- })
132
- } catch (e) {
133
- console.error('[XTransfer] Load error:', e)
134
- } finally {
135
- loading.value = false
136
- }
137
- }
138
-
139
- // 通过 queryParamsName 获取配置
140
- const loadByConfig = () => {
141
- return new Promise((resolve, reject) => {
142
- console.log('[XTransfer] getConfigByName:', queryParamsName.value, props.serverName)
143
- getConfigByName(queryParamsName.value, props.serverName, async (config) => {
144
- console.log('[XTransfer] config loaded:', config)
145
- if (!config) {
146
- console.error('[XTransfer] config is null')
147
- loading.value = false
148
- resolve()
149
- return
150
- }
151
-
152
- // 保存配置
153
- localConfig.value = config
154
-
155
- // 用配置中的 logicName 加载数据
156
- if (config.logicName) {
157
- try {
158
- const data = await loadByLogicWithConfig(config)
159
- parseData(data)
160
- if (initialValue.value.length > 0) {
161
- localValue.value = [...initialValue.value]
162
- }
163
- emit('loaded', {
164
- dataSource: localDataSource.value,
165
- groupDataSource: localGroupDataSource.value
166
- })
167
- } catch (e) {
168
- console.error('[XTransfer] Load error:', e)
169
- }
170
- } else if (config.data && Array.isArray(config.data)) {
171
- parseData(config.data)
172
- }
173
-
174
- loading.value = false
175
- resolve()
176
- }, isDev.value)
177
- })
178
- }
179
-
180
- // 使用配置的 logicName 加载数据
181
- const loadByLogicWithConfig = async (config) => {
182
- const logic = config.logicName || logicName.value
183
- const params = config.parameter || parameter.value
184
- const server = config.serverName || props.serverName
185
-
186
- console.log('[XTransfer] loadByLogic:', logic, params, server)
187
-
188
- try {
189
- const res = await runLogic(logic, params, server, isDev.value)
190
- console.log('[XTransfer] logic result:', res)
191
- if (res) {
192
- return Array.isArray(res) ? res : (res.data || res.result || [])
193
- }
194
- } catch (e) {
195
- console.error('[XTransfer] logic error:', e)
196
- }
197
- return []
198
- }
199
-
200
- // 直接使用 logicName 加载数据
201
- const loadByLogic = async () => {
202
- const logic = logicName.value
203
- const params = parameter.value
204
- const server = props.serverName
205
-
206
- console.log('[XTransfer] loadByLogic:', logic, params, server)
207
-
208
- try {
209
- const res = await runLogic(logic, params, server, isDev.value)
210
- console.log('[XTransfer] logic result:', res)
211
- if (res) {
212
- return Array.isArray(res) ? res : (res.data || res.result || [])
213
- }
214
- } catch (e) {
215
- console.error('[XTransfer] logic error:', e)
216
- }
217
- return []
218
- }
219
-
220
- // ============ 数据解析 ============
221
- const parseData = (data) => {
222
- if (!data || !Array.isArray(data)) {
223
- localDataSource.value = []
224
- localGroupDataSource.value = []
225
- return
226
- }
227
-
228
- const rowKey = getConfig('rowKey', 'key')
229
- const displayKey = getConfig('displayKey', 'title')
230
- const descriptionKey = getConfig('descriptionKey', '')
231
- const groupKey = getConfig('groupKey', 'group')
232
- const groupLabelKey = getConfig('groupLabelKey', 'label')
233
- const groupCountKey = getConfig('groupCountKey', 'count')
234
- const groupItemsKey = getConfig('groupItemsKey', 'items')
235
-
236
- const firstItem = data[0]
237
- const hasGroup = firstItem && (firstItem[groupKey] || firstItem[groupLabelKey])
238
-
239
- console.log('[XTransfer] parseData hasGroup:', hasGroup)
240
-
241
- if (hasGroup) {
242
- localGroupDataSource.value = data.map(group => ({
243
- key: group[rowKey] || group.key,
244
- label: group[groupLabelKey] || group.label || '未命名',
245
- count: group[groupCountKey] || (group[groupItemsKey]?.length || 0),
246
- items: transformItems(group[groupItemsKey] || group.items || []),
247
- _rawData: group
248
- }))
249
-
250
- localDataSource.value = []
251
- data.forEach(group => {
252
- const items = group[groupItemsKey] || group.items || []
253
- localDataSource.value.push(...transformItems(items))
254
- })
255
- } else {
256
- localDataSource.value = transformItems(data)
257
- localGroupDataSource.value = []
258
- }
259
- }
260
-
261
- const transformItems = (items) => {
262
- if (!items || !Array.isArray(items)) return []
263
-
264
- const rowKey = getConfig('rowKey', 'key')
265
- const displayKey = getConfig('displayKey', 'title')
266
- const descriptionKey = getConfig('descriptionKey', '')
267
-
268
- return items.map((item, index) => ({
269
- key: String(getNestedValue(item, rowKey) || item.key || `item-${index}`),
270
- title: String(getNestedValue(item, displayKey) || item.title || `选项${index + 1}`),
271
- description: descriptionKey ? String(getNestedValue(item, descriptionKey) || '') : '',
272
- disabled: item.disabled === true,
273
- _rawData: item
274
- }))
275
- }
276
-
277
- const getNestedValue = (obj, path) => {
278
- if (!path || !obj) return null
279
- return path.split('.').reduce((acc, part) => {
280
- if (acc === null || acc === undefined) return null
281
- return acc[part]
282
- }, obj)
283
- }
284
-
285
- // ============ 交互操作 ============
286
- const addItem = (key) => {
287
- if (disabled.value) return
288
- if (!localValue.value.includes(key)) {
289
- localValue.value = [...localValue.value, key]
290
- emitChange()
291
- }
292
- }
293
-
294
- const removeItem = (key) => {
295
- if (disabled.value) return
296
- localValue.value = localValue.value.filter(k => k !== key)
297
- emitChange()
298
- }
299
-
300
- const selectAll = () => {
301
- if (disabled.value) return
302
- const allKeys = localDataSource.value.map(item => item.key)
303
- localValue.value = [...allKeys]
304
- emitChange()
305
- }
306
-
307
- const clearAll = () => {
308
- if (disabled.value) return
309
- localValue.value = []
310
- emitChange()
311
- }
312
-
313
- const emitChange = () => {
314
- emit('change', {
315
- value: localValue.value,
316
- data: getSelectedData()
317
- })
318
- }
319
-
320
- const getSelectedData = () => {
321
- return localValue.value.map(key => {
322
- const item = localDataSource.value.find(d => d.key === key)
323
- return item?._rawData
324
- }).filter(Boolean)
325
- }
326
-
327
- const getItemTitle = (key) => {
328
- const item = localDataSource.value.find(d => d.key === key)
329
- return item?.title || key
330
- }
331
-
332
- const getItemDesc = (key) => {
333
- const item = localDataSource.value.find(d => d.key === key)
334
- return item?.description || ''
335
- }
336
-
337
- // 暴露方法
338
- const init = (config) => {
339
- console.log('[XTransfer] init with config:', config)
340
- if (config) {
341
- localConfig.value = config
342
- loadData()
343
- }
344
- }
345
-
346
- const refresh = () => {
347
- loadData()
348
- }
349
-
350
- defineExpose({
351
- loadData,
352
- init,
353
- refresh,
354
- getSelectedData,
355
- getSelectedKeys: () => [...localValue.value],
356
- clear: clearAll,
357
- setValue: (keys) => { localValue.value = keys }
358
- })
359
-
360
- onMounted(() => {
361
- console.log('[XTransfer] mounted, queryParamsName:', props.queryParamsName, 'logicName:', props.logicName)
362
- loadData()
363
- })
364
-
365
- // 监听配置变化
366
- watch(() => [props.queryParamsName, props.logicName, props.config, props.data], () => {
367
- loadData()
368
- }, { deep: true })
369
- </script>
370
-
371
- <template>
372
- <div class="x-transfer-component">
373
- <a-spin :spinning="loading">
374
- <div class="x-transfer-container">
375
- <!-- 左侧:可选项列表 -->
376
- <div class="transfer-panel left-panel" :style="{ width: leftWidth }">
377
- <div class="panel-header">
378
- <span v-if="leftTitle" class="panel-title">{{ leftTitle }}</span>
379
- </div>
380
- <div class="panel-body" :style="{ maxHeight: height }">
381
- <!-- 分组列表 -->
382
- <template v-if="localGroupDataSource.length > 0">
383
- <div
384
- v-for="group in localGroupDataSource"
385
- :key="group.key"
386
- class="group-section"
387
- >
388
- <div class="group-label-row">
389
- <span class="group-label">{{ group.label }}</span>
390
- <span class="group-count" v-if="group.count > 0">{{ group.count }}</span>
391
- </div>
392
- <div class="group-items">
393
- <div
394
- v-for="item in group.items"
395
- :key="item.key"
396
- class="item-row"
397
- :class="{ selected: localValue.includes(item.key) }"
398
- :title="item.title"
399
- @dblclick="addItem(item.key)"
400
- >
401
- <span class="item-title">{{ item.title }}</span>
402
- <span v-if="item.description" class="item-desc">{{ item.description }}</span>
403
- <span class="item-arrow">
404
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
405
- <path d="M9 18l6-6-6-6"/>
406
- </svg>
407
- </span>
408
- </div>
409
- </div>
410
- </div>
411
- </template>
412
-
413
- <!-- 简单列表 -->
414
- <template v-else>
415
- <div
416
- v-for="item in localDataSource"
417
- :key="item.key"
418
- class="item-row"
419
- :class="{ selected: localValue.includes(item.key) }"
420
- :title="item.title"
421
- @dblclick="addItem(item.key)"
422
- >
423
- <span class="item-title">{{ item.title }}</span>
424
- <span v-if="item.description" class="item-desc">{{ item.description }}</span>
425
- <span class="item-arrow">
426
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
427
- <path d="M9 18l6-6-6-6"/>
428
- </svg>
429
- </span>
430
- </div>
431
- </template>
432
-
433
- <a-empty v-if="localDataSource.length === 0 && !loading" />
434
- </div>
435
- </div>
436
-
437
- <!-- 中间:操作按钮 -->
438
- <div class="transfer-actions">
439
- <div class="action-row">
440
- <span class="action-text">{{ allText }}</span>
441
- <span
442
- class="action-arrow"
443
- :class="{ disabled: disabled || totalCount === 0 }"
444
- @click="selectAll"
445
- >
446
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
447
- <path d="M9 18l6-6-6-6"/>
448
- </svg>
449
- </span>
450
- </div>
451
- <div class="action-row">
452
- <span class="action-text">{{ allText }}</span>
453
- <span
454
- class="action-arrow left"
455
- :class="{ disabled: disabled || localValue.length === 0 }"
456
- @click="clearAll"
457
- >
458
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
459
- <path d="M15 18l-6-6 6-6"/>
460
- </svg>
461
- </span>
462
- </div>
463
- </div>
464
-
465
- <!-- 右侧:已选列表 -->
466
- <div class="transfer-panel right-panel" :style="{ width: rightWidth }">
467
- <div class="panel-header">
468
- <span v-if="rightTitle" class="panel-title">{{ rightTitle }}</span>
469
- <span class="panel-count selected" v-if="localValue.length > 0">{{ localValue.length }}</span>
470
- </div>
471
- <div class="panel-body" :style="{ maxHeight: height }">
472
- <div
473
- v-for="key in localValue"
474
- :key="key"
475
- class="item-row selected-item"
476
- :title="getItemTitle(key)"
477
- @dblclick="removeItem(key)"
478
- >
479
- <span class="item-arrow left-arrow">
480
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
481
- <path d="M15 18l-6-6 6-6"/>
482
- </svg>
483
- </span>
484
- <span class="item-title">{{ getItemTitle(key) }}</span>
485
- <span v-if="getItemDesc(key)" class="item-desc">{{ getItemDesc(key) }}</span>
486
- </div>
487
- <a-empty v-if="localValue.length === 0" />
488
- </div>
489
- </div>
490
- </div>
491
- </a-spin>
492
- </div>
493
- </template>
494
-
495
- <style scoped>
496
- /* 思源黑体字体 */
497
- @font-face {
498
- font-family: 'Source Han Sans';
499
- src: local('Source Han Sans'),
500
- local('思源黑体'),
501
- local('Noto Sans CJK SC'),
502
- local('Microsoft YaHei'),
503
- local('SimHei');
504
- font-weight: normal;
505
- }
506
-
507
- .x-transfer-component {
508
- width: 100%;
509
- font-family: 'Source Han Sans', 'Noto Sans CJK SC', 'Microsoft YaHei', sans-serif;
510
- }
511
-
512
- .x-transfer-container {
513
- display: flex !important;
514
- flex-direction: row !important;
515
- gap: 12px;
516
- align-items: flex-start;
517
- width: 100%;
518
- }
519
-
520
- .transfer-panel {
521
- width: 324px;
522
- height: 143px;
523
- border: 1px solid #E5E9F0;
524
- border-radius: 6px;
525
- background: #fff;
526
- flex: 0 0 auto;
527
- box-sizing: border-box;
528
- display: flex;
529
- flex-direction: column;
530
- }
531
-
532
- .panel-header {
533
- padding: 0 12px;
534
- background: #fafafa;
535
- border-bottom: 1px solid #E5E9F0;
536
- display: flex;
537
- align-items: center;
538
- gap: 8px;
539
- height: 37px;
540
- box-sizing: border-box;
541
- flex-shrink: 0;
542
- }
543
-
544
- .panel-title {
545
- font-family: 'Source Han Sans', 'Noto Sans CJK SC', 'Microsoft YaHei', sans-serif;
546
- font-size: 16px;
547
- font-weight: normal;
548
- line-height: 37px;
549
- letter-spacing: 0em;
550
- font-feature-settings: "kern" on;
551
- color: #313131;
552
- }
553
-
554
- .panel-count {
555
- font-family: 'Source Han Sans', 'Noto Sans CJK SC', 'Microsoft YaHei', sans-serif;
556
- font-size: 16px;
557
- font-weight: normal;
558
- line-height: 37px;
559
- letter-spacing: 0em;
560
- font-feature-settings: "kern" on;
561
- color: #313131;
562
- background: #f0f0f0;
563
- padding: 0 8px;
564
- border-radius: 10px;
565
- }
566
-
567
- .panel-count.selected {
568
- background: #1890ff;
569
- color: #fff;
570
- }
571
-
572
- .hint {
573
- font-family: 'Source Han Sans', 'Noto Sans CJK SC', 'Microsoft YaHei', sans-serif;
574
- font-size: 16px;
575
- font-weight: normal;
576
- line-height: 37px;
577
- letter-spacing: 0em;
578
- font-feature-settings: "kern" on;
579
- color: #94979E;
580
- width: 100%;
581
- text-align: center;
582
- }
583
-
584
- /* 中间操作区域 */
585
- .transfer-actions {
586
- display: flex;
587
- flex-direction: column;
588
- justify-content: center;
589
- align-items: center;
590
- gap: 8px;
591
- width: 68px;
592
- height: 143px;
593
- flex-shrink: 0;
594
- border: 1px solid #E5E9F0;
595
- border-radius: 6px;
596
- background: #FFFFFF;
597
- box-sizing: border-box;
598
- }
599
-
600
- .action-row {
601
- display: flex;
602
- align-items: center;
603
- justify-content: center;
604
- gap: 6px;
605
- }
606
-
607
- .action-text {
608
- font-family: 'Source Han Sans', 'Noto Sans CJK SC', 'Microsoft YaHei', sans-serif;
609
- font-size: 16px;
610
- font-weight: normal;
611
- line-height: 37px;
612
- letter-spacing: 0em;
613
- font-feature-settings: "kern" on;
614
- color: #313131;
615
- text-align: center;
616
- }
617
-
618
- .action-arrow {
619
- width: 9.51px;
620
- height: 12.26px;
621
- color: #94979E;
622
- flex-shrink: 0;
623
- cursor: pointer;
624
- transition: opacity 0.2s;
625
- }
626
-
627
- .action-arrow.left {
628
- transform: rotate(180deg);
629
- }
630
-
631
- .action-arrow:hover {
632
- opacity: 0.7;
633
- }
634
-
635
- .action-arrow.disabled {
636
- opacity: 0.3;
637
- cursor: not-allowed;
638
- }
639
-
640
- .action-arrow.disabled:hover {
641
- opacity: 0.3;
642
- }
643
-
644
- .panel-body {
645
- padding: 0;
646
- overflow-y: auto;
647
- flex: 1;
648
- min-height: 0;
649
- }
650
-
651
- .group-section {
652
- margin-bottom: 12px;
653
- }
654
-
655
- .group-section:last-child {
656
- margin-bottom: 0;
657
- }
658
-
659
- .group-label-row {
660
- display: flex;
661
- align-items: center;
662
- gap: 6px;
663
- padding: 0 12px;
664
- height: 37px;
665
- box-sizing: border-box;
666
- }
667
-
668
- .group-label {
669
- font-family: 'Source Han Sans', 'Noto Sans CJK SC', 'Microsoft YaHei', sans-serif;
670
- font-size: 16px;
671
- font-weight: normal;
672
- line-height: 37px;
673
- letter-spacing: 0em;
674
- font-feature-settings: "kern" on;
675
- color: #313131;
676
- }
677
-
678
- .group-count {
679
- font-family: 'Source Han Sans', 'Noto Sans CJK SC', 'Microsoft YaHei', sans-serif;
680
- font-size: 16px;
681
- font-weight: normal;
682
- line-height: 37px;
683
- letter-spacing: 0em;
684
- color: #94979E;
685
- }
686
-
687
- .group-items {
688
- border: 1px solid #E5E9F0;
689
- border-radius: 6px;
690
- overflow: hidden;
691
- margin: 0 12px 12px 12px;
692
- }
693
-
694
- .item-row {
695
- padding: 0 12px;
696
- border-bottom: 1px solid #E5E9F0;
697
- cursor: pointer;
698
- display: flex;
699
- align-items: center;
700
- transition: background-color 0.15s;
701
- user-select: none;
702
- height: 37px;
703
- box-sizing: border-box;
704
- }
705
-
706
- .item-row:last-child {
707
- border-bottom: none;
708
- }
709
-
710
- .item-row:hover {
711
- background: #f5f5f5;
712
- }
713
-
714
- .item-row.selected {
715
- background: #e6f7ff;
716
- }
717
-
718
- .item-row.selected:hover {
719
- background: #bae7ff;
720
- }
721
-
722
- .item-title {
723
- font-family: 'Source Han Sans', 'Noto Sans CJK SC', 'Microsoft YaHei', sans-serif;
724
- font-size: 16px;
725
- font-weight: normal;
726
- line-height: 37px;
727
- letter-spacing: 0em;
728
- font-feature-settings: "kern" on;
729
- color: #313131;
730
- flex-shrink: 0;
731
- }
732
-
733
- .item-desc {
734
- font-family: 'Source Han Sans', 'Noto Sans CJK SC', 'Microsoft YaHei', sans-serif;
735
- font-size: 16px;
736
- font-weight: normal;
737
- line-height: 37px;
738
- letter-spacing: 0em;
739
- color: #94979E;
740
- margin-left: 8px;
741
- flex: 1;
742
- overflow: hidden;
743
- text-overflow: ellipsis;
744
- white-space: nowrap;
745
- }
746
-
747
- /* 数据项箭头 */
748
- .item-arrow {
749
- width: 16px;
750
- height: 16px;
751
- color: #94979E;
752
- flex-shrink: 0;
753
- margin-left: auto;
754
- display: flex;
755
- align-items: center;
756
- justify-content: center;
757
- }
758
-
759
- .item-arrow svg {
760
- width: 100%;
761
- height: 100%;
762
- }
763
-
764
- .item-arrow.left-arrow {
765
- margin-left: 0;
766
- margin-right: 8px;
767
- }
768
-
769
- .remove-icon {
770
- color: #94979E;
771
- font-weight: normal;
772
- margin-right: 4px;
773
- flex-shrink: 0;
774
- font-family: 'Source Han Sans', 'Noto Sans CJK SC', 'Microsoft YaHei', sans-serif;
775
- font-size: 16px;
776
- line-height: 37px;
777
- }
778
-
779
- .selected-item {
780
- background: #fff;
781
- border-color: #E5E9F0;
782
- }
783
-
784
- .selected-item:hover {
785
- background: #f5f5f5 !important;
786
- }
787
- </style>