adtec-core-package 3.0.3 → 3.0.5
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/AGENTS.md +1 -1
- package/CLAUDE.md +1 -1
- package/package.json +21 -4
- package/prebuilt/umo-editor/umo-editor.css +1 -1
- package/prebuilt/umo-editor/umo-editor.js +13739 -15052
- package/prebuilt/umo-editor/umo-editor.js.map +1 -1
- package/src/components/RichTextEditor/RichTextEditor.vue +62 -9
- package/src/components/RichTextEditor/installUmoEditorApp.ts +20 -0
- package/src/components/editor-main/src/components/index.vue +2 -1
- package/src/components/editor-main/src/components/menus/button.vue +30 -3
- package/src/components/editor-main/src/components/menus/toolbar/base/color.vue +12 -5
- package/src/components/editor-main/src/components/menus/toolbar/base/font-family.vue +6 -4
- package/src/components/editor-main/src/components/menus/toolbar/base/font-size.vue +42 -25
- package/src/components/editor-main/src/components/menus/toolbar/base/heading.vue +6 -8
- package/src/components/editor-main/src/composables/toolbarSelection.js +233 -0
- package/src/components/editor-main/src/locales/bo.json +2 -2
- package/src/components/editor-main/src/locales/en-US.json +2 -2
- package/src/components/editor-main/src/locales/it-IT.json +2 -2
- package/src/components/editor-main/src/locales/ru-RU.json +2 -2
- package/src/components/editor-main/src/locales/zh-CN.json +2 -2
- package/src/components/editor-main/src/utils/editor-scroll.js +39 -15
- package/src/components/vxeGrid/index.vue +11 -4
- package/src/stores/dictStore.ts +72 -5
|
@@ -1,8 +1,17 @@
|
|
|
1
|
+
import { ref } from 'vue'
|
|
2
|
+
|
|
1
3
|
/** 工具栏 t-select 等抢焦点时缓存的非空文本选区 */
|
|
2
4
|
let cachedRange = null
|
|
3
5
|
/** 当前 t-select 弹层会话内快照(打开下拉时锁定,避免误恢复旧选区) */
|
|
4
6
|
let pendingSelectRange = null
|
|
5
7
|
|
|
8
|
+
/** ProseMirror 选区/mark 变化时递增,供 Vue computed 订阅 */
|
|
9
|
+
export const toolbarEditorTick = ref(0)
|
|
10
|
+
|
|
11
|
+
export function bumpToolbarEditorState() {
|
|
12
|
+
toolbarEditorTick.value += 1
|
|
13
|
+
}
|
|
14
|
+
|
|
6
15
|
export function cacheEditorTextSelection(editor) {
|
|
7
16
|
if (!editor?.state) return
|
|
8
17
|
const { from, to, empty } = editor.state.selection
|
|
@@ -17,11 +26,13 @@ export function syncCacheOnEditorSelectionUpdate(editor) {
|
|
|
17
26
|
if (!empty && from !== to) {
|
|
18
27
|
cachedRange = { from, to }
|
|
19
28
|
}
|
|
29
|
+
bumpToolbarEditorState()
|
|
20
30
|
}
|
|
21
31
|
|
|
22
32
|
export function beginSelectMenuInteraction(editor) {
|
|
23
33
|
if (!editor?.state) {
|
|
24
34
|
pendingSelectRange = cachedRange ? { ...cachedRange } : null
|
|
35
|
+
bumpToolbarEditorState()
|
|
25
36
|
return
|
|
26
37
|
}
|
|
27
38
|
const { from, to, empty } = editor.state.selection
|
|
@@ -33,10 +44,12 @@ export function beginSelectMenuInteraction(editor) {
|
|
|
33
44
|
} else {
|
|
34
45
|
pendingSelectRange = null
|
|
35
46
|
}
|
|
47
|
+
bumpToolbarEditorState()
|
|
36
48
|
}
|
|
37
49
|
|
|
38
50
|
export function endSelectMenuInteraction() {
|
|
39
51
|
pendingSelectRange = null
|
|
52
|
+
bumpToolbarEditorState()
|
|
40
53
|
}
|
|
41
54
|
|
|
42
55
|
function applyTextRange(editor, range) {
|
|
@@ -65,4 +78,224 @@ export function refreshCachedTextSelection(editor) {
|
|
|
65
78
|
if (!empty && from !== to) {
|
|
66
79
|
cachedRange = { from, to }
|
|
67
80
|
}
|
|
81
|
+
bumpToolbarEditorState()
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function clampRange(editor, range) {
|
|
85
|
+
if (!editor?.state || !range) return null
|
|
86
|
+
const docSize = editor.state.doc.content.size
|
|
87
|
+
const from = Math.max(0, Math.min(range.from, docSize))
|
|
88
|
+
const to = Math.max(from, Math.min(range.to, docSize))
|
|
89
|
+
if (to <= from) return null
|
|
90
|
+
return { from, to }
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Word 中文字号 pt/px 对照(与 richTextHtmlUtils 一致) */
|
|
94
|
+
const CHINESE_FONT_SIZE_PT_PX = [
|
|
95
|
+
{ pt: 42, px: 49 },
|
|
96
|
+
{ pt: 36, px: 42 },
|
|
97
|
+
{ pt: 26, px: 30 },
|
|
98
|
+
{ pt: 24, px: 28 },
|
|
99
|
+
{ pt: 22, px: 26 },
|
|
100
|
+
{ pt: 18, px: 21 },
|
|
101
|
+
{ pt: 16, px: 19 },
|
|
102
|
+
{ pt: 15, px: 18 },
|
|
103
|
+
{ pt: 14, px: 16 },
|
|
104
|
+
{ pt: 12, px: 14 },
|
|
105
|
+
{ pt: 10.5, px: 12 },
|
|
106
|
+
{ pt: 9, px: 11 },
|
|
107
|
+
{ pt: 7.5, px: 9 },
|
|
108
|
+
{ pt: 6.5, px: 8 },
|
|
109
|
+
]
|
|
110
|
+
|
|
111
|
+
function normalizeFontSizeValue(raw) {
|
|
112
|
+
if (!raw) return null
|
|
113
|
+
const value = String(raw).trim()
|
|
114
|
+
const pxMatch = value.match(/^(\d+(?:\.\d+)?)px$/i)
|
|
115
|
+
if (pxMatch) {
|
|
116
|
+
return `${Math.round(parseFloat(pxMatch[1]))}px`
|
|
117
|
+
}
|
|
118
|
+
const ptMatch = value.match(/^(\d+(?:\.\d+)?)pt$/i)
|
|
119
|
+
if (ptMatch) {
|
|
120
|
+
return `${parseFloat(ptMatch[1])}pt`
|
|
121
|
+
}
|
|
122
|
+
return value
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** 将 DOM/浏览器读到的 px 映射回 pt 选项值,供 t-select 显示中文标签 */
|
|
126
|
+
function resolveFontSizeForToolbarDisplay(raw) {
|
|
127
|
+
const normalized = normalizeFontSizeValue(raw)
|
|
128
|
+
if (!normalized) return null
|
|
129
|
+
if (/pt$/i.test(normalized)) return normalized
|
|
130
|
+
|
|
131
|
+
const pxMatch = normalized.match(/^(\d+(?:\.\d+)?)px$/i)
|
|
132
|
+
if (!pxMatch) return normalized
|
|
133
|
+
|
|
134
|
+
const px = Math.round(parseFloat(pxMatch[1]))
|
|
135
|
+
// 14px 为编辑器「默认」,勿映射为 12pt(小四)
|
|
136
|
+
if (px === 14) return '14px'
|
|
137
|
+
|
|
138
|
+
const byWordPx = CHINESE_FONT_SIZE_PT_PX.find((entry) => entry.px === px)
|
|
139
|
+
if (byWordPx) return `${byWordPx.pt}pt`
|
|
140
|
+
|
|
141
|
+
// 浏览器按 CSS 换算的 px(如 36pt → 48px)
|
|
142
|
+
const cssPt = (px * 72) / 96
|
|
143
|
+
const byCssPt = CHINESE_FONT_SIZE_PT_PX.find(
|
|
144
|
+
(entry) => Math.abs(entry.pt - cssPt) < 0.6,
|
|
145
|
+
)
|
|
146
|
+
if (byCssPt) return `${byCssPt.pt}pt`
|
|
147
|
+
|
|
148
|
+
return normalized
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function readTextStyleMarkAtPos(editor, pos, attr) {
|
|
152
|
+
const $pos = editor.state.doc.resolve(pos)
|
|
153
|
+
const activeMarks = $pos.marks()
|
|
154
|
+
const storedMarks = editor.state.storedMarks ?? []
|
|
155
|
+
const marks = activeMarks.length ? activeMarks : storedMarks
|
|
156
|
+
const textStyle = marks.find((mark) => mark.type.name === 'textStyle')
|
|
157
|
+
return textStyle?.attrs?.[attr] ?? null
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function readFontSizeFromDom(editor, pos) {
|
|
161
|
+
if (typeof window === 'undefined') return null
|
|
162
|
+
const view = editor.view
|
|
163
|
+
if (!view?.dom) return null
|
|
164
|
+
|
|
165
|
+
try {
|
|
166
|
+
const domPos = view.domAtPos(pos)
|
|
167
|
+
let node = domPos.node
|
|
168
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
169
|
+
node = node.parentElement
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
while (node && node !== view.dom) {
|
|
173
|
+
const inlineSize = node.style?.fontSize
|
|
174
|
+
const computedSize =
|
|
175
|
+
inlineSize && inlineSize !== 'inherit'
|
|
176
|
+
? inlineSize
|
|
177
|
+
: window.getComputedStyle(node).fontSize
|
|
178
|
+
const normalized = normalizeFontSizeValue(computedSize)
|
|
179
|
+
if (normalized) {
|
|
180
|
+
return normalized
|
|
181
|
+
}
|
|
182
|
+
node = node.parentElement
|
|
183
|
+
}
|
|
184
|
+
} catch {
|
|
185
|
+
return null
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return null
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function readFontSizeAtRange(editor, range) {
|
|
192
|
+
const clamped = clampRange(editor, range)
|
|
193
|
+
if (!clamped) return null
|
|
194
|
+
|
|
195
|
+
const { from, to } = clamped
|
|
196
|
+
let fontSize = null
|
|
197
|
+
|
|
198
|
+
editor.state.doc.nodesBetween(from, to, (node, pos) => {
|
|
199
|
+
if (fontSize || !node.isText) return
|
|
200
|
+
const mark = node.marks.find(
|
|
201
|
+
(item) => item.type.name === 'textStyle' && item.attrs?.fontSize,
|
|
202
|
+
)
|
|
203
|
+
if (mark) {
|
|
204
|
+
fontSize = mark.attrs.fontSize
|
|
205
|
+
}
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
if (!fontSize) {
|
|
209
|
+
const readPos = Math.min(from + 1, to - 1, editor.state.doc.content.size - 1)
|
|
210
|
+
fontSize = readTextStyleMarkAtPos(editor, Math.max(from, readPos), 'fontSize')
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (!fontSize) {
|
|
214
|
+
fontSize = readFontSizeFromDom(editor, from)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return resolveFontSizeForToolbarDisplay(fontSize)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function readFontFamilyAtRange(editor, range) {
|
|
221
|
+
const clamped = clampRange(editor, range)
|
|
222
|
+
if (!clamped) return null
|
|
223
|
+
|
|
224
|
+
const { from, to } = clamped
|
|
225
|
+
let fontFamily = null
|
|
226
|
+
|
|
227
|
+
editor.state.doc.nodesBetween(from, to, (node) => {
|
|
228
|
+
if (fontFamily || !node.isText) return
|
|
229
|
+
const mark = node.marks.find(
|
|
230
|
+
(item) => item.type.name === 'textStyle' && item.attrs?.fontFamily,
|
|
231
|
+
)
|
|
232
|
+
if (mark) {
|
|
233
|
+
fontFamily = mark.attrs.fontFamily
|
|
234
|
+
}
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
if (!fontFamily) {
|
|
238
|
+
const readPos = Math.min(from + 1, to - 1, editor.state.doc.content.size - 1)
|
|
239
|
+
fontFamily = readTextStyleMarkAtPos(
|
|
240
|
+
editor,
|
|
241
|
+
Math.max(from, readPos),
|
|
242
|
+
'fontFamily',
|
|
243
|
+
)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return fontFamily ? fontFamily.replace(/"/g, '') : null
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function getActiveTextRange(editor) {
|
|
250
|
+
if (!editor?.state) return null
|
|
251
|
+
const { from, to, empty } = editor.state.selection
|
|
252
|
+
if (!empty && from !== to) {
|
|
253
|
+
return { from, to }
|
|
254
|
+
}
|
|
255
|
+
return pendingSelectRange ?? cachedRange
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/** t-select 抢焦点导致选区折叠时,仍从缓存选区读取字号供下拉框展示 */
|
|
259
|
+
export function getToolbarFontSize(editor) {
|
|
260
|
+
if (!editor?.state) return null
|
|
261
|
+
|
|
262
|
+
const { from, to, empty } = editor.state.selection
|
|
263
|
+
if (!empty && from !== to) {
|
|
264
|
+
return (
|
|
265
|
+
readFontSizeAtRange(editor, { from, to }) ??
|
|
266
|
+
resolveFontSizeForToolbarDisplay(
|
|
267
|
+
editor.getAttributes('textStyle').fontSize,
|
|
268
|
+
) ??
|
|
269
|
+
resolveFontSizeForToolbarDisplay(readFontSizeFromDom(editor, from))
|
|
270
|
+
)
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const range = getActiveTextRange(editor)
|
|
274
|
+
return (
|
|
275
|
+
readFontSizeAtRange(editor, range) ??
|
|
276
|
+
resolveFontSizeForToolbarDisplay(
|
|
277
|
+
editor.getAttributes('textStyle').fontSize,
|
|
278
|
+
) ??
|
|
279
|
+
(range
|
|
280
|
+
? resolveFontSizeForToolbarDisplay(readFontSizeFromDom(editor, range.from))
|
|
281
|
+
: null)
|
|
282
|
+
)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/** t-select 抢焦点导致选区折叠时,仍从缓存选区读取字体供下拉框展示 */
|
|
286
|
+
export function getToolbarFontFamily(editor) {
|
|
287
|
+
if (!editor?.state) return null
|
|
288
|
+
|
|
289
|
+
const { from, to, empty } = editor.state.selection
|
|
290
|
+
if (!empty && from !== to) {
|
|
291
|
+
return readFontFamilyAtRange(editor, { from, to })
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const range = getActiveTextRange(editor)
|
|
295
|
+
return (
|
|
296
|
+
readFontFamilyAtRange(editor, range) ??
|
|
297
|
+
(editor.getAttributes('textStyle').fontFamily
|
|
298
|
+
? editor.getAttributes('textStyle').fontFamily.replace(/"/g, '')
|
|
299
|
+
: null)
|
|
300
|
+
)
|
|
68
301
|
}
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
"12pt": "Sotto livello quattro",
|
|
52
52
|
"10_5pt": "Quinto livello",
|
|
53
53
|
"9pt": "Sotto livello cinque",
|
|
54
|
-
"7_5pt": "
|
|
55
|
-
"6_5pt": "
|
|
54
|
+
"7_5pt": "Sesto livello",
|
|
55
|
+
"6_5pt": "Sotto livello sei"
|
|
56
56
|
},
|
|
57
57
|
"formatPainter": {
|
|
58
58
|
"text": "Copia formato",
|
|
@@ -57,8 +57,8 @@
|
|
|
57
57
|
"12pt": "Под-четвертый уровень",
|
|
58
58
|
"10_5pt": "Пятый уровень",
|
|
59
59
|
"9pt": "Под-пятый уровень",
|
|
60
|
-
"7_5pt": "
|
|
61
|
-
"6_5pt": "
|
|
60
|
+
"7_5pt": "Шестой уровень",
|
|
61
|
+
"6_5pt": "Под-шестой уровень"
|
|
62
62
|
},
|
|
63
63
|
"formatPainter": {
|
|
64
64
|
"text": "Формат по образцу",
|
|
@@ -1,35 +1,59 @@
|
|
|
1
|
+
/** TipTap focus 选项:不触发 ProseMirror scrollIntoView */
|
|
2
|
+
export const FOCUS_WITHOUT_SCROLL = { scrollIntoView: false }
|
|
3
|
+
|
|
4
|
+
function pushScrollPosition(positions, seen, el) {
|
|
5
|
+
if (!el || seen.has(el)) return
|
|
6
|
+
seen.add(el)
|
|
7
|
+
positions.push({
|
|
8
|
+
el,
|
|
9
|
+
top: el.scrollTop,
|
|
10
|
+
left: el.scrollLeft,
|
|
11
|
+
})
|
|
12
|
+
}
|
|
13
|
+
|
|
1
14
|
/**
|
|
2
|
-
* 保存/恢复编辑器及外层滚动位置,避免 setBlockType
|
|
15
|
+
* 保存/恢复编辑器及外层滚动位置,避免 toolbar focus / setBlockType 等触发 scrollIntoView 导致页面跳动。
|
|
3
16
|
*/
|
|
4
17
|
export function captureScrollPositions(container) {
|
|
5
18
|
const positions = []
|
|
19
|
+
const seen = new Set()
|
|
6
20
|
const pageContainer = document.querySelector(
|
|
7
21
|
`${container} .umo-zoomable-container`,
|
|
8
22
|
)
|
|
9
|
-
|
|
10
|
-
positions.push({
|
|
11
|
-
el: pageContainer,
|
|
12
|
-
top: pageContainer.scrollTop,
|
|
13
|
-
left: pageContainer.scrollLeft,
|
|
14
|
-
})
|
|
15
|
-
}
|
|
23
|
+
pushScrollPosition(positions, seen, pageContainer)
|
|
16
24
|
|
|
17
|
-
let node =
|
|
25
|
+
let node =
|
|
26
|
+
pageContainer?.parentElement ??
|
|
27
|
+
document.querySelector(container)?.parentElement ??
|
|
28
|
+
null
|
|
18
29
|
while (node && node !== document.documentElement) {
|
|
19
30
|
if (node.classList?.contains('el-scrollbar__wrap')) {
|
|
20
|
-
positions
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
31
|
+
pushScrollPosition(positions, seen, node)
|
|
32
|
+
} else {
|
|
33
|
+
const style = getComputedStyle(node)
|
|
34
|
+
const overflow = `${style.overflow}${style.overflowY}${style.overflowX}`
|
|
35
|
+
if (/auto|scroll/.test(overflow)) {
|
|
36
|
+
pushScrollPosition(positions, seen, node)
|
|
37
|
+
}
|
|
26
38
|
}
|
|
27
39
|
node = node.parentElement
|
|
28
40
|
}
|
|
29
41
|
|
|
42
|
+
pushScrollPosition(positions, seen, document.documentElement)
|
|
43
|
+
pushScrollPosition(positions, seen, document.body)
|
|
44
|
+
|
|
30
45
|
return positions
|
|
31
46
|
}
|
|
32
47
|
|
|
48
|
+
export function runPreservingScroll(container, fn) {
|
|
49
|
+
const scrollPositions = captureScrollPositions(container)
|
|
50
|
+
try {
|
|
51
|
+
return fn()
|
|
52
|
+
} finally {
|
|
53
|
+
restoreScrollPositions(scrollPositions)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
33
57
|
export function restoreScrollPositions(positions) {
|
|
34
58
|
if (!positions.length) return
|
|
35
59
|
const apply = () => {
|
|
@@ -7,14 +7,15 @@
|
|
|
7
7
|
<script setup lang="ts">
|
|
8
8
|
//@ts-ignore
|
|
9
9
|
import { components, initVxeTableInPage } from 'adtec-core-package/src/config/VxeTableConfig'
|
|
10
|
-
// 导入默认的语言
|
|
11
10
|
import { defineComponent, getCurrentInstance, h } from 'vue'
|
|
11
|
+
|
|
12
12
|
const { VxeGrid } = components
|
|
13
13
|
defineComponent({
|
|
14
14
|
components: {
|
|
15
15
|
VxeGrid,
|
|
16
16
|
},
|
|
17
17
|
})
|
|
18
|
+
|
|
18
19
|
const { renderComponent = { enableElementPlus: true, enableExcel: false, enablePdf: false } } =
|
|
19
20
|
defineProps<{
|
|
20
21
|
renderComponent?: {
|
|
@@ -24,12 +25,18 @@ const { renderComponent = { enableElementPlus: true, enableExcel: false, enableP
|
|
|
24
25
|
}
|
|
25
26
|
}>()
|
|
26
27
|
|
|
27
|
-
initVxeTableInPage(
|
|
28
|
+
initVxeTableInPage(
|
|
29
|
+
renderComponent.enableExcel,
|
|
30
|
+
renderComponent.enablePdf,
|
|
31
|
+
renderComponent.enableElementPlus ?? true,
|
|
32
|
+
)
|
|
28
33
|
|
|
29
34
|
const vm = getCurrentInstance()
|
|
30
35
|
|
|
31
|
-
const changeRef = (exposed:
|
|
32
|
-
|
|
36
|
+
const changeRef = (exposed: unknown) => {
|
|
37
|
+
if (vm) {
|
|
38
|
+
vm.exposed = exposed
|
|
39
|
+
}
|
|
33
40
|
}
|
|
34
41
|
</script>
|
|
35
42
|
|
package/src/stores/dictStore.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { defineStore } from 'pinia'
|
|
2
|
-
import { ref } from 'vue'
|
|
2
|
+
import { ref, type Ref } from 'vue'
|
|
3
|
+
import Base64 from 'crypto-js/enc-base64'
|
|
4
|
+
import Utf8 from 'crypto-js/enc-utf8'
|
|
3
5
|
import type { ISysDictDataCacheVo } from '../interface/ISysDictDataCacheVo'
|
|
6
|
+
|
|
4
7
|
// 定义包含map的整体类型
|
|
5
8
|
export interface dictMapType {
|
|
6
9
|
[key: string]: ISysDictDataCacheVo[]
|
|
@@ -14,12 +17,76 @@ export interface dictDataMapType {
|
|
|
14
17
|
[key: string]: { [key: string]: ISysDictDataCacheVo }
|
|
15
18
|
}
|
|
16
19
|
|
|
20
|
+
const DICT_STORAGE_KEY = 'dictStore'
|
|
21
|
+
|
|
22
|
+
export interface SharedDictState {
|
|
23
|
+
dictMap: Ref<dictMapType>
|
|
24
|
+
dictDataMap: Ref<dictDataMapType>
|
|
25
|
+
dictDefaultValueMap: Ref<dictMapType>
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
declare global {
|
|
29
|
+
interface Window {
|
|
30
|
+
__ADTEC_SHARED_DICT__?: SharedDictState
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** wujie 子应用走 parent,宿主/独立 dev 走自身 window —— 全应用共享同一份 ref */
|
|
35
|
+
function getRootWindow(): Window {
|
|
36
|
+
if (typeof window === 'undefined') return window
|
|
37
|
+
const w = window as Window & { __POWERED_BY_WUJIE__?: boolean }
|
|
38
|
+
return w.__POWERED_BY_WUJIE__ ? window.parent : window
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function hydrateFromSessionStorage(state: SharedDictState) {
|
|
42
|
+
const raw = sessionStorage.getItem(DICT_STORAGE_KEY)
|
|
43
|
+
if (!raw) return
|
|
44
|
+
try {
|
|
45
|
+
const parsed = JSON.parse(Base64.parse(raw).toString(Utf8)) as {
|
|
46
|
+
dictMap?: dictMapType
|
|
47
|
+
dictDataMap?: dictDataMapType
|
|
48
|
+
dictDefaultValueMap?: dictMapType
|
|
49
|
+
}
|
|
50
|
+
if (parsed.dictMap) {
|
|
51
|
+
state.dictMap.value = { ...parsed.dictMap, ...state.dictMap.value }
|
|
52
|
+
}
|
|
53
|
+
if (parsed.dictDataMap) {
|
|
54
|
+
state.dictDataMap.value = { ...parsed.dictDataMap, ...state.dictDataMap.value }
|
|
55
|
+
}
|
|
56
|
+
if (parsed.dictDefaultValueMap) {
|
|
57
|
+
state.dictDefaultValueMap.value = {
|
|
58
|
+
...parsed.dictDefaultValueMap,
|
|
59
|
+
...state.dictDefaultValueMap.value,
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
} catch {
|
|
63
|
+
// ignore corrupt session data
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** 宿主 window 单例:alive 子应用与宿主读写同一组 Vue ref(刷新时仍由 sessionStorage 恢复) */
|
|
68
|
+
export function getSharedDictRefs(): SharedDictState {
|
|
69
|
+
const root = getRootWindow()
|
|
70
|
+
if (!root.__ADTEC_SHARED_DICT__) {
|
|
71
|
+
root.__ADTEC_SHARED_DICT__ = {
|
|
72
|
+
dictMap: ref<dictMapType>({}),
|
|
73
|
+
dictDataMap: ref<dictDataMapType>({}),
|
|
74
|
+
dictDefaultValueMap: ref<dictMapType>({}),
|
|
75
|
+
}
|
|
76
|
+
hydrateFromSessionStorage(root.__ADTEC_SHARED_DICT__)
|
|
77
|
+
}
|
|
78
|
+
return root.__ADTEC_SHARED_DICT__
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** @deprecated 已由 getSharedDictRefs 在初始化时 hydrate;保留兼容旧调用 */
|
|
82
|
+
export function syncDictFromSessionStorage(target: SharedDictState) {
|
|
83
|
+
hydrateFromSessionStorage(target)
|
|
84
|
+
}
|
|
85
|
+
|
|
17
86
|
export const dictStore = defineStore('dictStore', () => {
|
|
18
|
-
const dictMap =
|
|
19
|
-
const dictDataMap = ref<dictDataMapType>({})
|
|
20
|
-
const dictDefaultValueMap = ref<dictMapType>({})
|
|
87
|
+
const { dictMap, dictDataMap, dictDefaultValueMap } = getSharedDictRefs()
|
|
21
88
|
|
|
22
|
-
const clearDictCache = (dictType?: string[],userOrgId?: string, orgId?: string, all?: Boolean) => {
|
|
89
|
+
const clearDictCache = (dictType?: string[], userOrgId?: string, orgId?: string, all?: Boolean) => {
|
|
23
90
|
if (dictType && dictType.length > 0) {
|
|
24
91
|
dictType.forEach((item) => {
|
|
25
92
|
if (orgId) {
|