wui-components-v2 1.1.85 → 1.1.86
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.
|
@@ -4,10 +4,10 @@ import { useRouter } from 'uni-mini-router'
|
|
|
4
4
|
import { onLoad } from '@dcloudio/uni-app'
|
|
5
5
|
import type { ClassEditConfigs, Columns, Entities, Enums, Fields, Groups, rowActions } from '../../type'
|
|
6
6
|
import ActionPopup from '../action-popup/action-popup.vue'
|
|
7
|
-
import { actionDataSave, deleteData } from '../../api/page'
|
|
7
|
+
import { actionDataSave, deleteData, editPageConfig } from '../../api/page'
|
|
8
8
|
import { useGlobalToast } from '../../composables/useGlobalToast'
|
|
9
9
|
import { useGlobalMessage } from '../../composables/useGlobalMessage'
|
|
10
|
-
import { comparator } from '../../utils/index'
|
|
10
|
+
import { comparator, generateHighResolutionID } from '../../utils/index'
|
|
11
11
|
import ControlTypeSupportor from '../../utils/control-type-supportor'
|
|
12
12
|
import { formatItemData } from '../../utils'
|
|
13
13
|
|
|
@@ -202,7 +202,30 @@ function closeMoreButn() {
|
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
// 点击更多按钮
|
|
205
|
-
function select({ item }: { item: any }) {
|
|
205
|
+
async function select({ item }: { item: any }) {
|
|
206
|
+
// 复制操作:跳转新增页,仅复制基本信息(fieldMap),不带原 ID 和 relation 分组数据(如快递运单)
|
|
207
|
+
if (item.title.includes('复制')) {
|
|
208
|
+
// 优先用编辑同款接口拉取完整 fieldMap(含关联选择字段值如基地名称/快递公司),失败回退列表行数据
|
|
209
|
+
let fieldMapData = props.data.fieldMap
|
|
210
|
+
try {
|
|
211
|
+
const res: any = await editPageConfig(props.sourceId, props.code)
|
|
212
|
+
const entity = res?.dtmplConfig?.entity
|
|
213
|
+
if (entity?.fieldMap) fieldMapData = entity.fieldMap
|
|
214
|
+
} catch (e) {
|
|
215
|
+
console.log('[copy] 拉取完整实体失败,回退使用列表数据', e)
|
|
216
|
+
}
|
|
217
|
+
// 生成复制标识:URL 带 copyEvent 区分"复制新增";存储以 copyEvent 为 key,仅本次复制可读,不污染普通新增
|
|
218
|
+
const copyEvent = generateHighResolutionID()
|
|
219
|
+
uni.setStorageSync(copyEvent, {
|
|
220
|
+
code: '',
|
|
221
|
+
fieldMap: fieldMapData,
|
|
222
|
+
arrayMap: {}, // 不复制 relation 分组数据(快递运单等需用户重新填写)
|
|
223
|
+
})
|
|
224
|
+
router.push(
|
|
225
|
+
`/pages/edit-page/index?sourceId=${props.sourceId}&id=&title=${props.item.title}&pageType=${props.pageType}&addEvent=${props.addEvent}©Event=${copyEvent}`
|
|
226
|
+
)
|
|
227
|
+
return
|
|
228
|
+
}
|
|
206
229
|
if (item.title.includes('评价') && item.actionType === 'rowActions') {
|
|
207
230
|
return action(item)
|
|
208
231
|
}
|
|
@@ -58,6 +58,11 @@ const addEvent = ref('')
|
|
|
58
58
|
const editEvent = ref('')
|
|
59
59
|
const rowAddEvent = ref('')
|
|
60
60
|
const sendRowAddEvent = ref('')
|
|
61
|
+
const copyEvent = ref('') // 复制场景:携带源行数据的事件名
|
|
62
|
+
const copyData = ref<any>(null) // 复制场景:源行数据(已剥离 ID)
|
|
63
|
+
const copyApplied = ref(false) // 复制数据是否已写入 entity
|
|
64
|
+
// 复制场景下,需等复制数据写入 entity 后再渲染表单,否则 FormControl 在 onBeforeMount 时读不到值
|
|
65
|
+
const formReady = computed(() => !!pageConfig.value?.groups?.length && (!copyEvent.value || copyApplied.value))
|
|
61
66
|
const smartPaste = ref(false)
|
|
62
67
|
// 折叠面板
|
|
63
68
|
const collapses = ref('')
|
|
@@ -96,6 +101,15 @@ onLoad((option: any) => {
|
|
|
96
101
|
pageType.value = option.pageType || ''
|
|
97
102
|
rowAddEvent.value = option.rowAddEvent
|
|
98
103
|
sendRowAddEvent.value = option.sendRowAddEvent
|
|
104
|
+
copyEvent.value = option.copyEvent
|
|
105
|
+
// 复制场景:仅当 URL 带 copyEvent 标识(即"复制新增")才读取预填数据;
|
|
106
|
+
// 普通新增不带该标识,绝不读取存储,避免复制残留数据污染普通新增
|
|
107
|
+
if (copyEvent.value) {
|
|
108
|
+
copyData.value = uni.getStorageSync(copyEvent.value) || null
|
|
109
|
+
if (copyData.value) {
|
|
110
|
+
console.log('[copy] 读取到复制数据:', JSON.parse(JSON.stringify(copyData.value)))
|
|
111
|
+
}
|
|
112
|
+
}
|
|
99
113
|
getEditPageConfig()
|
|
100
114
|
})
|
|
101
115
|
|
|
@@ -106,6 +120,7 @@ onUnmounted(() => {
|
|
|
106
120
|
// uni.$off(addEvent.value)
|
|
107
121
|
uni.$off(editEvent.value)
|
|
108
122
|
uni.$off(sendRowAddEvent.value)
|
|
123
|
+
uni.$off(copyEvent.value)
|
|
109
124
|
})
|
|
110
125
|
|
|
111
126
|
onBeforeMount(() => {
|
|
@@ -113,6 +128,49 @@ onBeforeMount(() => {
|
|
|
113
128
|
hydrocarbonProgramToken.value = uni.getStorageSync('HYDROCARBON_PROGRAM_TOKEN')
|
|
114
129
|
token.value = uni.getStorageSync('TOKEN')
|
|
115
130
|
})
|
|
131
|
+
|
|
132
|
+
// 复制场景:将源行数据写入 entity,且强制 code 为空(新增,不带原 ID)
|
|
133
|
+
function applyCopyData() {
|
|
134
|
+
pageConfig.value.entity = {
|
|
135
|
+
...pageConfig.value.entity,
|
|
136
|
+
code: '',
|
|
137
|
+
fieldMap: copyData.value.fieldMap || {},
|
|
138
|
+
arrayMap: copyData.value.arrayMap || {},
|
|
139
|
+
}
|
|
140
|
+
copyApplied.value = true
|
|
141
|
+
console.log('[copy] 已预填 entity:', JSON.parse(JSON.stringify(pageConfig.value.entity)))
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// 根据已加载的 entity 初始化关联(勾选/行)数据
|
|
145
|
+
function initRelationData() {
|
|
146
|
+
pageConfig.value.groups.forEach((item: Groups) => {
|
|
147
|
+
// 初始化勾选数据
|
|
148
|
+
if (item.type === 'relation' && (item.buttons.includes('dtmplAdd') || item.buttons.includes('selectAdd'))) {
|
|
149
|
+
selectData.value[item.id] = {
|
|
150
|
+
data:
|
|
151
|
+
(pageConfig.value.entity &&
|
|
152
|
+
pageConfig.value.entity.arrayMap[item.id]?.map((sebitem: any) => {
|
|
153
|
+
return `${sebitem.code}`
|
|
154
|
+
})) ||
|
|
155
|
+
[],
|
|
156
|
+
loading: false,
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// 初始化行数据
|
|
160
|
+
if (item.type === 'relation' && item.buttons.includes('rowAdd')) {
|
|
161
|
+
rowData.value[item.id] =
|
|
162
|
+
(pageConfig.value.entity &&
|
|
163
|
+
pageConfig.value.entity.arrayMap[item.id]?.map((sebitem: any) => {
|
|
164
|
+
return {
|
|
165
|
+
id: sebitem.code,
|
|
166
|
+
...sebitem.fieldMap,
|
|
167
|
+
}
|
|
168
|
+
})) ||
|
|
169
|
+
[]
|
|
170
|
+
}
|
|
171
|
+
})
|
|
172
|
+
}
|
|
173
|
+
|
|
116
174
|
// 获取编辑页面配置
|
|
117
175
|
async function getEditPageConfig() {
|
|
118
176
|
// 判断是否为行新增事件
|
|
@@ -158,35 +216,19 @@ async function getEditPageConfig() {
|
|
|
158
216
|
title: `${res.dtmplConfig.title}`,
|
|
159
217
|
})
|
|
160
218
|
pageConfig.value = res.dtmplConfig
|
|
219
|
+
// 复制场景:用携带的行数据预填表单,但不带原记录 ID(保持新增)
|
|
220
|
+
if (copyEvent.value && copyData.value) {
|
|
221
|
+
applyCopyData()
|
|
222
|
+
} else if (copyEvent.value) {
|
|
223
|
+
// 兜底:复制数据迟到或丢失时,最多等待 800ms 后渲染空表单,避免页面空白卡死
|
|
224
|
+
setTimeout(() => {
|
|
225
|
+
if (!copyApplied.value) copyApplied.value = true
|
|
226
|
+
}, 800)
|
|
227
|
+
}
|
|
161
228
|
const visibleGroups = pageConfig.value.groups.filter((item: Groups) => item.displayConfig.includes('displayed'))
|
|
162
229
|
collapses.value = visibleGroups.length > 0 ? visibleGroups[0].id : ''
|
|
163
230
|
|
|
164
|
-
|
|
165
|
-
// 初始化勾选数据
|
|
166
|
-
if (item.type === 'relation' && (item.buttons.includes('dtmplAdd') || item.buttons.includes('selectAdd'))) {
|
|
167
|
-
selectData.value[item.id] = {
|
|
168
|
-
data:
|
|
169
|
-
(pageConfig.value.entity &&
|
|
170
|
-
pageConfig.value.entity.arrayMap[item.id]?.map((sebitem: any) => {
|
|
171
|
-
return `${sebitem.code}`
|
|
172
|
-
})) ||
|
|
173
|
-
[],
|
|
174
|
-
loading: false,
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
// 初始化行数据
|
|
178
|
-
if (item.type === 'relation' && item.buttons.includes('rowAdd')) {
|
|
179
|
-
rowData.value[item.id] =
|
|
180
|
-
(pageConfig.value.entity &&
|
|
181
|
-
pageConfig.value.entity.arrayMap[item.id]?.map((sebitem: any) => {
|
|
182
|
-
return {
|
|
183
|
-
id: sebitem.code,
|
|
184
|
-
...sebitem.fieldMap,
|
|
185
|
-
}
|
|
186
|
-
})) ||
|
|
187
|
-
[]
|
|
188
|
-
}
|
|
189
|
-
})
|
|
231
|
+
initRelationData()
|
|
190
232
|
getEnums()
|
|
191
233
|
console.log(pageConfig.value, 'pageConfig.value')
|
|
192
234
|
}
|
|
@@ -342,6 +384,9 @@ async function save() {
|
|
|
342
384
|
// ★ 通知 wui-select-popup 刷新列表数据
|
|
343
385
|
uni.$emit('selectPopup:refresh', sourceId.value)
|
|
344
386
|
|
|
387
|
+
// 复制场景:保存成功后清除本次复制数据(按 copyEvent key),避免残留
|
|
388
|
+
if (copyEvent.value) uni.removeStorageSync(copyEvent.value)
|
|
389
|
+
|
|
345
390
|
subLoading.value = false
|
|
346
391
|
router.back()
|
|
347
392
|
} catch (error) {
|
|
@@ -877,7 +922,7 @@ console.log(pageConfig, 'props111')
|
|
|
877
922
|
</template>
|
|
878
923
|
|
|
879
924
|
<FormControl
|
|
880
|
-
v-if="group.type === 'fieldGroup'"
|
|
925
|
+
v-if="group.type === 'fieldGroup' && formReady"
|
|
881
926
|
ref="formControlRef"
|
|
882
927
|
:field-group="group"
|
|
883
928
|
:entity="pageConfig?.entity?.fieldMap"
|
|
@@ -40,51 +40,74 @@ export function useCompanyFieldFilter(
|
|
|
40
40
|
)
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (
|
|
48
|
-
|
|
49
|
-
...item,
|
|
50
|
-
hidden: isHidden,
|
|
51
|
-
}
|
|
52
|
-
} else {
|
|
53
|
-
return {
|
|
54
|
-
...item,
|
|
55
|
-
hidden: values.some(v => v.includes(company)) ? false : item.hidden,
|
|
56
|
-
}
|
|
57
|
-
}
|
|
43
|
+
// 判断值是否为空(依赖字段无数据)
|
|
44
|
+
const isEmptyValue = (v: any) => {
|
|
45
|
+
if (v == null) return true
|
|
46
|
+
if (typeof v === 'string') return v.trim() === ''
|
|
47
|
+
if (Array.isArray(v)) return v.length === 0
|
|
48
|
+
return false
|
|
58
49
|
}
|
|
50
|
+
|
|
51
|
+
// 评估单条可用规则(usableRuleCriteria)的就绪/命中状态
|
|
52
|
+
// criterion 通过 mstrucId 关联同一分组内的其它字段,再拿该字段在 model 中的实时值与 transDefaultValue 比对
|
|
53
|
+
// 返回值:'empty'(依赖字段无数据)| 'match'(命中)| 'unmatch'(未命中)
|
|
54
|
+
const evaluateCriterion = (criterion: any, fieldsMap: Map<string, any>, modelValue: any): 'empty' | 'match' | 'unmatch' => {
|
|
55
|
+
const target = criterion?.mstrucId ? fieldsMap.get(criterion.mstrucId) : null
|
|
56
|
+
// 找不到被关联字段时 fail-open,视为命中,避免误隐藏
|
|
57
|
+
if (!target) return 'match'
|
|
58
|
+
const refValue = modelValue[target.sourceId]
|
|
59
|
+
// 依赖字段无数据:该项隐藏
|
|
60
|
+
if (isEmptyValue(refValue)) return 'empty'
|
|
61
|
+
const expected = (criterion?.transDefaultValue || '')
|
|
62
|
+
.split(',')
|
|
63
|
+
.map((v: string) => v.trim())
|
|
64
|
+
.filter(Boolean)
|
|
65
|
+
if (expected.length === 0) return 'match'
|
|
66
|
+
const rv = String(refValue)
|
|
67
|
+
// include_anyone:被关联字段值 与 规则值 任一方包含对方即视为命中(兼容"顺丰"匹配"顺丰速运"这类模糊场景)
|
|
68
|
+
const matched = expected.some((e: string) => {
|
|
69
|
+
const ev = String(e)
|
|
70
|
+
return ev === rv || ev.includes(rv) || rv.includes(ev)
|
|
71
|
+
})
|
|
72
|
+
return matched ? 'match' : 'unmatch'
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 计算字段是否隐藏:依据 usableRuleCriteria 关联其它字段实时值
|
|
76
|
+
// - 无可用规则:保持字段自身 unusableMode 决定的显隐
|
|
77
|
+
// - 有可用规则:
|
|
78
|
+
// 1) 任一依赖字段无数据 -> 隐藏该项
|
|
79
|
+
// 2) 依赖均有数据后,所有规则命中才显示,否则隐藏
|
|
80
|
+
const computeHidden = (item: any, fieldsMap: Map<string, any>, modelValue: any, isEnabled: boolean) => {
|
|
81
|
+
const baseHidden = item?.unusableMode === 'hidden'
|
|
82
|
+
if (!isEnabled) return baseHidden
|
|
83
|
+
const criteria = item?.usableRuleCriteria
|
|
84
|
+
if (!criteria || criteria.length === 0) return baseHidden
|
|
85
|
+
// 任一依赖字段无数据 -> 隐藏
|
|
86
|
+
if (criteria.some((c: any) => evaluateCriterion(c, fieldsMap, modelValue) === 'empty')) return true
|
|
87
|
+
// 依赖就绪后:所有规则命中才显示
|
|
88
|
+
const usable = criteria.every((c: any) => evaluateCriterion(c, fieldsMap, modelValue) === 'match')
|
|
89
|
+
return usable ? false : true
|
|
90
|
+
}
|
|
91
|
+
|
|
59
92
|
const filteredFields = computed(() => {
|
|
60
|
-
const company = selectedCompany.value
|
|
61
93
|
const allFields = fieldGroup()?.fields
|
|
62
94
|
if (!allFields) return []
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
// 检查 usableRuleCriteria 是否存在且有值
|
|
69
|
-
if (!item.usableRuleCriteria || item.usableRuleCriteria.length === 0) {
|
|
70
|
-
return true
|
|
71
|
-
}
|
|
72
|
-
// 获取 transDefaultValue 并检查是否包含选中的公司
|
|
73
|
-
const transDefaultValue = item.usableRuleCriteria?.[0]?.transDefaultValue
|
|
74
|
-
if (typeof transDefaultValue === 'string') {
|
|
75
|
-
const values = transDefaultValue.split(',').map(v => v.trim())
|
|
76
|
-
// console.log('transDefaultValue', company, 'values', values,values.includes(company))
|
|
77
|
-
return values.some(v => v.includes(company))
|
|
78
|
-
}
|
|
79
|
-
return true
|
|
95
|
+
// 建立 mstrucId -> field 映射,供可用规则关联同分组内其它字段
|
|
96
|
+
const fieldsMap = new Map<string, any>()
|
|
97
|
+
allFields.forEach((f: any) => {
|
|
98
|
+
if (f?.mstrucId) fieldsMap.set(f.mstrucId, f)
|
|
80
99
|
})
|
|
81
|
-
|
|
82
|
-
|
|
100
|
+
const modelValue = model.value
|
|
101
|
+
// 保留全部字段(监听所有数据),仅通过 hidden 控制显隐,规则随 model 实时联动
|
|
102
|
+
return allFields.map((item: any) => ({
|
|
103
|
+
...item,
|
|
104
|
+
hidden: computeHidden(item, fieldsMap, modelValue, enabled),
|
|
105
|
+
}))
|
|
83
106
|
})
|
|
84
107
|
watch(
|
|
85
108
|
filteredFields,
|
|
86
|
-
|
|
87
|
-
//
|
|
109
|
+
() => {
|
|
110
|
+
// 字段显隐随 model 实时变化,可在此做监听/埋点
|
|
88
111
|
},
|
|
89
112
|
{ immediate: true }
|
|
90
113
|
)
|