adtec-core-package 3.3.0 → 3.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adtec-core-package",
3
- "version": "3.3.0",
3
+ "version": "3.3.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "exports": {
@@ -82,6 +82,28 @@ ElSelect.props.fitInputWidth = {
82
82
  type: Boolean,
83
83
  default: false,
84
84
  }
85
+ const isWujieSubApp =
86
+ typeof window !== 'undefined' && !!(window as Window & { __POWERED_BY_WUJIE__?: boolean }).__POWERED_BY_WUJIE__
87
+ /**
88
+ * 无界 iframe 内 Popper 坐标修正。
89
+ * ElSelect / ElDatePicker 等须保持 teleported 默认 true(vxe 单元格挂 body + popperClass 防 clearEdit),
90
+ * 仅通过 strategy/modifiers 修正偏移,避免各子应用逐页 v-bind。
91
+ */
92
+ const wujiePopperOptions = {
93
+ strategy: 'fixed' as const,
94
+ modifiers: [
95
+ {
96
+ name: 'computeStyles',
97
+ options: { adaptive: false, gpuAcceleration: false },
98
+ },
99
+ ],
100
+ }
101
+ if (isWujieSubApp) {
102
+ ElSelect.props.popperOptions = { type: Object, default: () => wujiePopperOptions }
103
+ ElDatePicker.props.popperOptions = { type: Object, default: () => wujiePopperOptions }
104
+ ElTreeSelect.props.popperOptions = { type: Object, default: () => wujiePopperOptions }
105
+ ElCascader.props.popperOptions = { type: Object, default: () => wujiePopperOptions }
106
+ }
85
107
  ElSelect.props.popperClass = {
86
108
  type: String,
87
109
  default: VXE_IGNORE_CLEAR_POPPER,
@@ -7,6 +7,39 @@ import { storeToRefs } from 'pinia'
7
7
  import { userInfoStore } from '../stores/userInfoStore.ts'
8
8
  import frameworkUtils from '../utils/FrameworkUtils.ts'
9
9
 
10
+ /**
11
+ * 后端在带 orgId 且 Redis 未命中时,可能返回带 parentId 的扁平列表(未 buildTree)。
12
+ * 前端按 parentId 重建 children,恢复领域/项目类型等树形字典。
13
+ */
14
+ const ensureDictTree = (list?: ISysDictDataCacheVo[]): ISysDictDataCacheVo[] => {
15
+ if (!list?.length) return list ?? []
16
+ if (list.some((item) => Array.isArray(item.children) && item.children.length > 0)) {
17
+ return list
18
+ }
19
+ const nodeMap = new Map<string, ISysDictDataCacheVo>()
20
+ list.forEach((item) => {
21
+ if (!item?.id) return
22
+ nodeMap.set(item.id, { ...item, children: undefined })
23
+ })
24
+ if (!nodeMap.size) return list
25
+
26
+ const roots: ISysDictDataCacheVo[] = []
27
+ let linked = 0
28
+ nodeMap.forEach((node) => {
29
+ const parentId = node.parentId
30
+ if (parentId && parentId !== '0' && nodeMap.has(parentId)) {
31
+ const parent = nodeMap.get(parentId)!
32
+ if (!parent.children) parent.children = []
33
+ parent.children.push(node)
34
+ linked += 1
35
+ } else {
36
+ roots.push(node)
37
+ }
38
+ })
39
+ if (!linked) return list
40
+ return roots
41
+ }
42
+
10
43
  export default function useDictHooks(dictTypes?: string[], orgId?: string) {
11
44
  const userInfo = userInfoStore()
12
45
  const dictStores = dictStore()
@@ -19,38 +52,133 @@ export default function useDictHooks(dictTypes?: string[], orgId?: string) {
19
52
  return userInfo.user?.orgId
20
53
  }
21
54
 
55
+ const hasDictList = (list?: ISysDictDataCacheVo[]) => Array.isArray(list) && list.length > 0
56
+
57
+ const hasDictCache = (dictType: string, oid?: string): boolean => {
58
+ if (oid && hasDictList(dictMap.value[`${oid}:${dictType}`])) return true
59
+ if (hasDictList(dictMap.value[dictType])) return true
60
+ return Object.keys(dictMap.value).some(
61
+ (key) => key.endsWith(`:${dictType}`) && hasDictList(dictMap.value[key]),
62
+ )
63
+ }
64
+
65
+ const resolveDictMapKey = (dictType: string, orgId?: string): string | undefined => {
66
+ const tenantOrgId = resolveOrgId()
67
+ const scopedOrgId = orgId ?? tenantOrgId
68
+ if (scopedOrgId && hasDictList(dictMap.value[`${scopedOrgId}:${dictType}`])) {
69
+ return `${scopedOrgId}:${dictType}`
70
+ }
71
+ if (hasDictList(dictMap.value[dictType])) return dictType
72
+ const fallback = Object.keys(dictMap.value).find(
73
+ (key) => key.endsWith(`:${dictType}`) && hasDictList(dictMap.value[key]),
74
+ )
75
+ return fallback
76
+ }
77
+
78
+ const resolveDictDataKey = (dictType: string, orgId?: string): string | undefined => {
79
+ const tenantOrgId = resolveOrgId()
80
+ const scopedOrgId = orgId ?? tenantOrgId
81
+ if (scopedOrgId) {
82
+ const scopedKey = `${scopedOrgId}:${dictType}`
83
+ if (dictDataMap.value[scopedKey] && Object.keys(dictDataMap.value[scopedKey]).length) {
84
+ return scopedKey
85
+ }
86
+ }
87
+ if (dictDataMap.value[dictType] && Object.keys(dictDataMap.value[dictType]).length) {
88
+ return dictType
89
+ }
90
+ return Object.keys(dictDataMap.value).find(
91
+ (key) => key.endsWith(`:${dictType}`) && Object.keys(dictDataMap.value[key]).length > 0,
92
+ )
93
+ }
94
+
95
+ const repairCachedDictTrees = (): boolean => {
96
+ let repaired = false
97
+ for (const key of Object.keys(dictMap.value)) {
98
+ const list = dictMap.value[key]
99
+ if (!hasDictList(list)) continue
100
+ const tree = ensureDictTree(list)
101
+ if (tree !== list && tree.some((item) => item.children?.length)) {
102
+ dictMap.value[key] = tree
103
+ repaired = true
104
+ }
105
+ }
106
+ return repaired
107
+ }
108
+
22
109
  const getDict = async (dictTypes?: string[], orgId?: string): Promise<void> => {
23
110
  try {
24
111
  if (!dictTypes || !dictTypes.length) return
25
112
  await userInfo.ensureUserHydrated()
26
113
  const tenantOrgId = resolveOrgId(orgId)
27
- const dictKeySet = new Set(Object.keys(dictMap.value))
28
- let uncachedDictTypes: string[] = []
29
- if (orgId || tenantOrgId) {
30
- const oid = orgId ?? tenantOrgId!
31
- uncachedDictTypes = dictTypes.filter((dictType) => !dictKeySet.has(`${oid}:${dictType}`))
32
- } else {
33
- uncachedDictTypes = dictTypes.filter((dictType) => !dictKeySet.has(dictType))
114
+ // orgId 就绪后清理 session 里「有 key 无数据」的脏缓存,避免误判已命中
115
+ let cacheDirty = false
116
+ if (tenantOrgId) {
117
+ const oid = orgId ?? tenantOrgId
118
+ for (const key of Object.keys(dictMap.value)) {
119
+ if (
120
+ (key.startsWith(`${oid}:`) || !key.includes(':')) &&
121
+ Array.isArray(dictMap.value[key]) &&
122
+ dictMap.value[key].length === 0
123
+ ) {
124
+ delete dictMap.value[key]
125
+ delete dictDataMap.value[key]
126
+ delete dictDefaultValueMap.value[key]
127
+ cacheDirty = true
128
+ }
129
+ }
130
+ }
131
+ // 修复「扁平但含 parentId」的脏缓存(带 orgId 后后端未 buildTree 的历史数据)
132
+ if (repairCachedDictTrees()) {
133
+ cacheDirty = true
34
134
  }
135
+ if (cacheDirty) {
136
+ dictStores.publishToSharedCache()
137
+ }
138
+ const uncachedDictTypes = dictTypes.filter(
139
+ (dictType) => !hasDictCache(dictType, orgId ?? tenantOrgId),
140
+ )
35
141
  if (!uncachedDictTypes.length) return
36
142
  const data = await SysDictCacheApi.batchGetSysDictDataCacheVo(uncachedDictTypes, orgId ?? tenantOrgId)
37
- dictMap.value = { ...dictMap.value, ...data }
38
- const promises = Object.keys(data).map(async (item: string) => {
143
+ const normalized: typeof data = {}
144
+ Object.entries(data).forEach(([key, value]) => {
145
+ if (!value?.length) return
146
+ const tree = ensureDictTree(value)
147
+ normalized[key] = tree
148
+ const colon = key.indexOf(':')
149
+ if (colon > 0) {
150
+ const bare = key.slice(colon + 1)
151
+ if (!normalized[bare]?.length) {
152
+ normalized[bare] = tree
153
+ }
154
+ } else if (tenantOrgId) {
155
+ const scoped = `${tenantOrgId}:${key}`
156
+ if (!normalized[scoped]?.length) {
157
+ normalized[scoped] = tree
158
+ }
159
+ }
160
+ })
161
+ dictMap.value = { ...dictMap.value, ...normalized }
162
+ const nextDataMap = { ...dictDataMap.value }
163
+ const nextDefaultMap = { ...dictDefaultValueMap.value }
164
+ const promises = Object.keys(normalized).map(async (item: string) => {
39
165
  const dataMap: dictDataMapVoType = {}
40
166
  const defaultList: ISysDictDataCacheVo[] = []
41
- await packageDictDataMap(dataMap, defaultList, data[item])
167
+ await packageDictDataMap(dataMap, defaultList, normalized[item])
42
168
  return { item, dataMap, defaultList }
43
169
  })
44
170
  const results = await Promise.allSettled(promises)
45
171
  results.forEach((result, index) => {
46
172
  if (result.status === 'fulfilled') {
47
173
  const { item, dataMap, defaultList } = result.value
48
- dictDataMap.value[item] = dataMap
49
- dictDefaultValueMap.value[item] = defaultList
174
+ nextDataMap[item] = dataMap
175
+ nextDefaultMap[item] = defaultList
50
176
  } else {
51
- ElMessage.error(`处理键 ${Object.keys(data)[index]} 时出错:`, result.reason)
177
+ ElMessage.error(`处理键 ${Object.keys(normalized)[index]} 时出错:`, result.reason)
52
178
  }
53
179
  })
180
+ dictDataMap.value = nextDataMap
181
+ dictDefaultValueMap.value = nextDefaultMap
54
182
  dictStores.publishToSharedCache()
55
183
  } catch (error: any) {
56
184
  frameworkUtils.messageError(error)
@@ -76,13 +204,8 @@ export default function useDictHooks(dictTypes?: string[], orgId?: string) {
76
204
  }
77
205
 
78
206
  const getDictName = (value?: string, dictType?: string, orgId?: string): string | undefined => {
79
- let key = orgId ? `${orgId}:${dictType}` : dictType
80
- if (dictDataMap.value[key!]) return dictDataMap.value[key!][value!]?.label || value
81
- const tenantOrgId = resolveOrgId()
82
- if (tenantOrgId) {
83
- key = `${tenantOrgId}:${dictType}`
84
- if (dictDataMap.value[key!]) return dictDataMap.value[key!][value!]?.label || value
85
- }
207
+ const key = resolveDictDataKey(dictType!, orgId)
208
+ if (key && dictDataMap.value[key]) return dictDataMap.value[key][value!]?.label || value
86
209
  return value
87
210
  }
88
211
 
@@ -91,39 +214,38 @@ export default function useDictHooks(dictTypes?: string[], orgId?: string) {
91
214
  dictType: string,
92
215
  orgId?: string,
93
216
  ): ISysDictDataCacheVo | {} => {
94
- let key = orgId ? `${orgId}:${dictType}` : dictType
95
- if (dictDataMap.value[key!] && dictDataMap.value[key!][value!])
96
- return dictDataMap.value[key!][value!]
97
- const tenantOrgId = resolveOrgId()
98
- if (tenantOrgId) {
99
- key = `${tenantOrgId}:${dictType}`
100
- if (dictDataMap.value[key!] && dictDataMap.value[key!][value!])
101
- return dictDataMap.value[key!][value!]
102
- }
217
+ const key = resolveDictDataKey(dictType, orgId)
218
+ if (key && dictDataMap.value[key]?.[value]) return dictDataMap.value[key][value]
103
219
  return {}
104
220
  }
105
221
  const getDictDefaultValue = (
106
222
  dictType: string,
107
223
  orgId?: string
108
224
  ): ISysDictDataCacheVo[] => {
109
- let key = orgId ? `${orgId}:${dictType}` : dictType
110
- if (dictDefaultValueMap.value[key!]) return dictDefaultValueMap.value[key!]
111
225
  const tenantOrgId = resolveOrgId()
112
- if (tenantOrgId) {
113
- key = `${tenantOrgId}:${dictType}`
114
- if (dictDefaultValueMap.value[key!]) return dictDefaultValueMap.value[key!]
226
+ const scopedOrgId = orgId ?? tenantOrgId
227
+ if (scopedOrgId) {
228
+ const scoped = dictDefaultValueMap.value[`${scopedOrgId}:${dictType}`]
229
+ if (scoped?.length) return scoped
115
230
  }
116
- return []
231
+ return dictDefaultValueMap.value[dictType] ?? []
117
232
  }
118
233
  const getDictTypeData = (dictType: string, orgId?: string): ISysDictDataCacheVo[] => {
119
- let key = orgId ? `${orgId}:${dictType}` : dictType
120
- if (dictMap.value[key!]) return dictMap.value[key!]
121
- const tenantOrgId = resolveOrgId()
122
- if (tenantOrgId) {
123
- key = `${tenantOrgId}:${dictType}`
124
- if (dictMap.value[key!]) return dictMap.value[key!]
234
+ const key = resolveDictMapKey(dictType, orgId)
235
+ if (!key) return []
236
+ const list = dictMap.value[key]
237
+ const tree = ensureDictTree(list)
238
+ if (tree !== list && tree.some((item) => item.children?.length)) {
239
+ dictMap.value[key] = tree
240
+ const bare = key.includes(':') ? key.slice(key.indexOf(':') + 1) : key
241
+ const tenantOrgId = resolveOrgId(orgId)
242
+ if (tenantOrgId && !key.includes(':')) {
243
+ dictMap.value[`${tenantOrgId}:${bare}`] = tree
244
+ } else if (key.includes(':') && !dictMap.value[bare]?.some((i) => i.children?.length)) {
245
+ dictMap.value[bare] = tree
246
+ }
125
247
  }
126
- return []
248
+ return tree
127
249
  }
128
250
  const clearDict = (dictType?: string[], orgId?: string, all?: Boolean) => {
129
251
  clearDictCache(dictType, resolveOrgId(), orgId, all)
@@ -142,6 +264,9 @@ export default function useDictHooks(dictTypes?: string[], orgId?: string) {
142
264
  getDict,
143
265
  userReady,
144
266
  dictReady,
267
+ dictMap,
268
+ dictDataMap,
269
+ dictDefaultValueMap,
145
270
  getDictName,
146
271
  getDictData,
147
272
  getDictTypeData,