aegon-lv97 1.0.0

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 (78) hide show
  1. package/gen-ai/build-report/chartStreamRefs.ts +227 -0
  2. package/gen-ai/build-report/coherence-check/index.vue +559 -0
  3. package/gen-ai/build-report/components/ReportChapterWorkspace.vue +4571 -0
  4. package/gen-ai/build-report/components/ReportConfigPanel.vue +727 -0
  5. package/gen-ai/build-report/components/ReportGenerateSettingsPanel.vue +2361 -0
  6. package/gen-ai/build-report/components/ReportGeneratingPanel.vue +1765 -0
  7. package/gen-ai/build-report/components/ReportPromptPanel.vue +625 -0
  8. package/gen-ai/build-report/components/ReportSourceFileSummary.vue +665 -0
  9. package/gen-ai/build-report/components/ReportSourcesPanel.vue +1327 -0
  10. package/gen-ai/build-report/components/ReportTemplateDetail.vue +191 -0
  11. package/gen-ai/build-report/components/ReportTemplateEditorFormPanel.vue +667 -0
  12. package/gen-ai/build-report/components/ReportTemplatePicker.vue +302 -0
  13. package/gen-ai/build-report/components/ReportWorkflowSidebar.vue +148 -0
  14. package/gen-ai/build-report/components/paramsSetting.vue +886 -0
  15. package/gen-ai/build-report/components/reportEdit.vue +2283 -0
  16. package/gen-ai/build-report/index.vue +856 -0
  17. package/gen-ai/build-report/report-domain.ts +1133 -0
  18. package/gen-ai/build-report/report-template-data.ts +295 -0
  19. package/gen-ai/build-report/useReportWorkflow.ts +1386 -0
  20. package/gen-ai/common/assets/NotoSans-SC.woff2 +0 -0
  21. package/gen-ai/common/assets/NotoSans-TC.woff2 +0 -0
  22. package/gen-ai/common/assets/NotoSans.woff2 +0 -0
  23. package/gen-ai/common/assets/fonts.css +278 -0
  24. package/gen-ai/common/assets/pagination.css +163 -0
  25. package/gen-ai/common/directives/btnLoading.ts +455 -0
  26. package/gen-ai/common/directives/debounce.ts +98 -0
  27. package/gen-ai/common/directives/index.ts +30 -0
  28. package/gen-ai/common/en.md +417 -0
  29. package/gen-ai/common/index.ts +36 -0
  30. package/gen-ai/common/types/component-expose.ts +9 -0
  31. package/gen-ai/common/utils/api-res-status.ts +7 -0
  32. package/gen-ai/common/utils/navigation.ts +59 -0
  33. package/gen-ai/common/utils/remote-request.ts +45 -0
  34. package/gen-ai/common/utils/scroll.ts +577 -0
  35. package/gen-ai/components/AIExport/docx-export.ts +950 -0
  36. package/gen-ai/components/AIExport/docxExport.ts +2566 -0
  37. package/gen-ai/components/AIExport/index.ts +52 -0
  38. package/gen-ai/components/AIExport/parseMarkdownHtml.ts +653 -0
  39. package/gen-ai/components/CapsuleScrollbar.vue +149 -0
  40. package/gen-ai/components/ChapterTitleScroll.vue +468 -0
  41. package/gen-ai/components/EntryHeroNavCards.vue +379 -0
  42. package/gen-ai/components/GenAiPagination.vue +52 -0
  43. package/gen-ai/components/ModelCard.vue +1114 -0
  44. package/gen-ai/components/Preview/FilePreviewPage.vue +949 -0
  45. package/gen-ai/components/Preview/PreviewCapsuleScroll.vue +205 -0
  46. package/gen-ai/components/Preview/PreviewOutlineTree.vue +148 -0
  47. package/gen-ai/components/Preview/index.ts +11 -0
  48. package/gen-ai/components/Preview/preview.ts +724 -0
  49. package/gen-ai/components/PromptField.vue +505 -0
  50. package/gen-ai/components/RecentReportsTable.vue +974 -0
  51. package/gen-ai/components/ReportCollapsibleSection.vue +172 -0
  52. package/gen-ai/components/ReportHistoryList.vue +637 -0
  53. package/gen-ai/components/ReportSectionConfirmPopover.vue +251 -0
  54. package/gen-ai/components/editor/ChapterTiptapEditor.vue +3718 -0
  55. package/gen-ai/components/editor/StructureBlockView.vue +441 -0
  56. package/gen-ai/components/editor/TiptapToolbar.vue +1036 -0
  57. package/gen-ai/components/editor/TypewriterDocEditor.vue +422 -0
  58. package/gen-ai/components/editor/_StructureOrgNode.vue +326 -0
  59. package/gen-ai/components/editor/index.ts +28 -0
  60. package/gen-ai/components/editor/parseMarkdownHtml.ts +754 -0
  61. package/gen-ai/components/editor/reviewCitationTip.ts +163 -0
  62. package/gen-ai/gen-entry/api/index.ts +32 -0
  63. package/gen-ai/gen-entry/index.vue +287 -0
  64. package/gen-ai/gen-entry/types/index.ts +4 -0
  65. package/gen-ai/i.mark +2 -0
  66. package/gen-ai/management-center/index.vue +1815 -0
  67. package/gen-ai/management-center/mockData.ts +248 -0
  68. package/gen-ai/management-center/types/index.ts +37 -0
  69. package/gen-ai/model-manager/TemplateEditorFormPanel.vue +661 -0
  70. package/gen-ai/model-manager/api/index.ts +32 -0
  71. package/gen-ai/model-manager/api/mockApi.ts +33 -0
  72. package/gen-ai/model-manager/index.vue +1583 -0
  73. package/gen-ai/model-manager/mockData.ts +177 -0
  74. package/gen-ai/model-manager/template-detail-shared.ts +154 -0
  75. package/gen-ai/model-manager/template-editor.vue +345 -0
  76. package/gen-ai/model-manager/types/index.ts +40 -0
  77. package/gen-ai/model-manager/utils.ts +25 -0
  78. package/package.json +12 -0
@@ -0,0 +1,422 @@
1
+ <template>
2
+ <div ref="rootRef" class="report-typewriter-doc">
3
+ <template v-if="ready && chapters.length">
4
+ <ReportChapterTiptapEditor
5
+ v-for="chapter in revealedChapters"
6
+ :key="chapter.key"
7
+ class="report-typewriter-doc__chapter"
8
+ :data-chapter-key="chapter.key"
9
+ :chapter-title="chapter.title"
10
+ :chapter-intro="chapter.intro"
11
+ :content-identity="chapter.key"
12
+ :typewriter-phase="phaseOf(chapter.key)"
13
+ :editable="false"
14
+ :show-review-markers="false"
15
+ :typewriter-settle-ms="typewriterSettleMs"
16
+ :disable-typewriter="disableTypewriter"
17
+ plain-content
18
+ @typewriter-complete="onChapterComplete(chapter.key)"
19
+ />
20
+ </template>
21
+ <p v-else-if="ready" class="report-typewriter-doc__empty">
22
+ {{ emptyText }}
23
+ </p>
24
+ <div v-else class="report-typewriter-doc__shell" aria-hidden="true">
25
+ <div class="report-typewriter-doc__shell-title" />
26
+ <div class="report-typewriter-doc__shell-line" />
27
+ <div class="report-typewriter-doc__shell-line is-short" />
28
+ <div class="report-typewriter-doc__shell-line" />
29
+ </div>
30
+ </div>
31
+ </template>
32
+
33
+ <script setup lang="ts">
34
+ import { computed, nextTick, ref, watch } from 'vue'
35
+ import ReportChapterTiptapEditor from './ChapterTiptapEditor.vue'
36
+
37
+ export interface TypewriterDocChapter {
38
+ key: string
39
+ title: string
40
+ intro: string
41
+ }
42
+
43
+ const props = withDefaults(
44
+ defineProps<{
45
+ /** 按展示順序的章節(已過濾勾選) */
46
+ chapters: TypewriterDocChapter[]
47
+ /** 內容區是否可掛載編輯器 */
48
+ ready?: boolean
49
+ emptyText?: string
50
+ /** 拖拽排序後重播:從該章起重新列印 */
51
+ replayKey?: string | null
52
+ replayToken?: number
53
+ /**
54
+ * 流式斷續 settle:追平緩衝後等待多久無新內容才進入下一章。
55
+ * 傳給 ChapterTiptapEditor;空緩衝會一直等首包。
56
+ */
57
+ typewriterSettleMs?: number
58
+ /** 需求 2026-08-13 16:58:settings 頁直接滿內容,不打字 */
59
+ disableTypewriter?: boolean
60
+ }>(),
61
+ {
62
+ ready: false,
63
+ emptyText: '請勾選至少一個章節',
64
+ replayKey: null,
65
+ replayToken: 0,
66
+ typewriterSettleMs: 1500,
67
+ disableTypewriter: false,
68
+ }
69
+ )
70
+
71
+ const emit = defineEmits<{
72
+ /** 當前正在打字的章節 key(供外側列表等鬆耦合聯動) */
73
+ 'typing-change': [key: string | null]
74
+ /** 是否仍在整篇列印流程中(含章間切換;全部打完為 false) */
75
+ 'printing-change': [printing: boolean]
76
+ 'chapter-complete': [key: string]
77
+ }>()
78
+
79
+ const rootRef = ref<HTMLElement | null>(null)
80
+ const typedKeys = ref<string[]>([])
81
+ const typingKey = ref<string | null>(null)
82
+
83
+ const chapterKeys = computed(() => props.chapters.map((c) => c.key))
84
+
85
+ const isPrinting = computed(() => {
86
+ if (props.disableTypewriter) return false
87
+ const keys = chapterKeys.value
88
+ if (!keys.length || !props.ready) return false
89
+ return typedKeys.value.length < keys.length || typingKey.value !== null
90
+ })
91
+
92
+ function phaseOf(key: string): 'idle' | 'typing' | 'done' {
93
+ if (props.disableTypewriter) return 'done'
94
+ if (typedKeys.value.includes(key)) return 'done'
95
+ if (typingKey.value === key) return 'typing'
96
+ return 'idle'
97
+ }
98
+
99
+ const revealedChapters = computed(() =>
100
+ props.disableTypewriter
101
+ ? props.chapters
102
+ : props.chapters.filter((chapter) => phaseOf(chapter.key) !== 'idle')
103
+ )
104
+
105
+ function syncQueue() {
106
+ if (props.disableTypewriter) {
107
+ typingKey.value = null
108
+ typedKeys.value = [...chapterKeys.value]
109
+ return
110
+ }
111
+ const keys = chapterKeys.value
112
+ const typed = typedKeys.value.filter((key) => keys.includes(key))
113
+ if (typed.length !== typedKeys.value.length) {
114
+ typedKeys.value = typed
115
+ }
116
+
117
+ if (typingKey.value && !keys.includes(typingKey.value)) {
118
+ typingKey.value = null
119
+ }
120
+
121
+ if (typingKey.value && keys.includes(typingKey.value) && !typed.includes(typingKey.value)) {
122
+ return
123
+ }
124
+
125
+ const next = keys.find((key) => !typed.includes(key)) ?? null
126
+ if (typingKey.value !== next) {
127
+ typingKey.value = next
128
+ }
129
+ }
130
+
131
+ //0918:disableTypewriter true→false 必须 reset typedKeys,否则整段灌文 / 跟滚失效
132
+ watch(
133
+ () => props.disableTypewriter,
134
+ (disabled, wasDisabled) => {
135
+ if (disabled) {
136
+ syncQueue()
137
+ return
138
+ }
139
+ if (wasDisabled === true) {
140
+ reset()
141
+ void nextTick(() => syncQueue())
142
+ }
143
+ }
144
+ )
145
+ //0918
146
+
147
+ function onChapterComplete(key: string) {
148
+ if (!typedKeys.value.includes(key)) {
149
+ typedKeys.value = [...typedKeys.value, key]
150
+ }
151
+ if (typingKey.value === key) {
152
+ typingKey.value = null
153
+ }
154
+ emit('chapter-complete', key)
155
+ syncQueue()
156
+
157
+ // 全部打完:滾到文檔最底(表格等高塊佈局穩定後)
158
+ const keys = chapterKeys.value
159
+ if (keys.length && keys.every((k) => typedKeys.value.includes(k))) {
160
+ scrollDocToBottom()
161
+ }
162
+ }
163
+
164
+ //0918:滚动父级回落(迁移后无 report-edit class 时仍能跟滚)
165
+ function findDocScrollParent(from: HTMLElement): HTMLElement | null {
166
+ const col =
167
+ (from.closest('.report-edit-page__col-scroll') as HTMLElement | null) ||
168
+ (from.closest('.report-edit-page__main--anchored') as HTMLElement | null) ||
169
+ (from.closest('.report-edit-page__main') as HTMLElement | null) ||
170
+ (from.closest('[data-report-main-scroll]') as HTMLElement | null)
171
+ const wrap =
172
+ (col?.querySelector('.el-scrollbar__wrap') as HTMLElement | null) ||
173
+ (from.closest('.el-scrollbar__wrap') as HTMLElement | null)
174
+ if (wrap) return wrap
175
+
176
+ let node: HTMLElement | null = from.parentElement
177
+ let fallback: HTMLElement | null = null
178
+ while (node && node !== document.body) {
179
+ if (node.classList.contains('el-scrollbar__wrap')) fallback = node
180
+ const { overflowY } = getComputedStyle(node)
181
+ const canOverflow =
182
+ overflowY === 'auto' ||
183
+ overflowY === 'scroll' ||
184
+ overflowY === 'overlay' ||
185
+ node.classList.contains('el-scrollbar__wrap')
186
+ if (canOverflow && node.scrollHeight > node.clientHeight + 1) {
187
+ return node
188
+ }
189
+ node = node.parentElement
190
+ }
191
+ return fallback
192
+ }
193
+ //0918
194
+
195
+ /** 僅滾動本組件所在滾動容器,不查詢左右欄 DOM */
196
+ function scrollTypingChapterIntoView(key: string | null) {
197
+ if (!key || !rootRef.value) return
198
+ void nextTick(() => {
199
+ const el = rootRef.value?.querySelector(
200
+ `.report-typewriter-doc__chapter[data-chapter-key="${CSS.escape(key)}"]`
201
+ ) as HTMLElement | null
202
+ if (!el) return
203
+ // 僅在章節頂部超出視口時輕推,避免與 DeepSeek 跟滾搶控制權
204
+ const scrollParent = findDocScrollParent(el)
205
+ if (!scrollParent) {
206
+ el.scrollIntoView({ block: 'nearest', behavior: 'auto', inline: 'nearest' })
207
+ return
208
+ }
209
+ const parentRect = scrollParent.getBoundingClientRect()
210
+ const rect = el.getBoundingClientRect()
211
+ if (rect.top < parentRect.top + 24) {
212
+ scrollParent.scrollTop += rect.top - parentRect.top - 24
213
+ }
214
+ })
215
+ }
216
+
217
+ function scrollDocToBottom() {
218
+ void nextTick(() => {
219
+ requestAnimationFrame(() => {
220
+ requestAnimationFrame(() => {
221
+ const root = rootRef.value
222
+ if (!root) return
223
+ const scrollParent = findDocScrollParent(root)
224
+ if (!scrollParent) return
225
+ scrollParent.scrollTop = scrollParent.scrollHeight - scrollParent.clientHeight
226
+ })
227
+ })
228
+ })
229
+ }
230
+
231
+ function replayFromKey(key: string) {
232
+ const keys = chapterKeys.value
233
+ const idx = keys.indexOf(key)
234
+ if (idx < 0) return
235
+
236
+ typedKeys.value = keys.slice(0, idx)
237
+ typingKey.value = null
238
+ void nextTick(() => {
239
+ typingKey.value = key
240
+ scrollTypingChapterIntoView(key)
241
+ })
242
+ }
243
+
244
+ function reset() {
245
+ typedKeys.value = []
246
+ typingKey.value = null
247
+ }
248
+
249
+ watch(
250
+ chapterKeys,
251
+ () => {
252
+ syncQueue()
253
+ },
254
+ { immediate: true }
255
+ )
256
+
257
+ /**
258
+ * 接口正文晚到:當前章仍在打 / 已 done 但 intro 從空→有 → 重播該章
259
+ * (子編輯器在 phase=done 時只能靜態灌入,必須由隊列拉回 typing)
260
+ */
261
+ watch(
262
+ () =>
263
+ props.chapters.map((chapter) => ({
264
+ key: chapter.key,
265
+ title: (chapter.title || '').trim(),
266
+ intro: (chapter.intro || '').trim(),
267
+ })),
268
+ (next, prev) => {
269
+ if (props.disableTypewriter) return
270
+ if (!props.ready || !prev?.length) return
271
+ for (const chapter of next) {
272
+ const before = prev.find((item) => item.key === chapter.key)
273
+ if (!before) continue
274
+ const introArrived = !before.intro && !!chapter.intro
275
+ const titleArrived = !before.title && !!chapter.title
276
+ const introGrew = !!before.intro && chapter.intro.startsWith(before.intro) && chapter.intro.length > before.intro.length
277
+ if (!introArrived && !titleArrived && !introGrew) continue
278
+
279
+ const alreadyDone = typedKeys.value.includes(chapter.key)
280
+ const isCurrent = typingKey.value === chapter.key
281
+ // 增長中的當前章:交給子編輯器 onStreamContentUpdated 續打
282
+ if (isCurrent && introGrew && !introArrived) continue
283
+ if (alreadyDone || (isCurrent && (introArrived || titleArrived))) {
284
+ replayFromKey(chapter.key)
285
+ return
286
+ }
287
+ }
288
+ },
289
+ { deep: true }
290
+ )
291
+
292
+ watch(typingKey, (key) => {
293
+ emit('typing-change', key)
294
+ scrollTypingChapterIntoView(key)
295
+ })
296
+
297
+ watch(
298
+ isPrinting,
299
+ (printing) => {
300
+ emit('printing-change', printing)
301
+ },
302
+ { immediate: true }
303
+ )
304
+
305
+ watch(
306
+ () => [props.replayToken ?? 0, props.replayKey ?? null] as const,
307
+ ([token, key]) => {
308
+ if (props.disableTypewriter) return
309
+ if (!token || !key) return
310
+ replayFromKey(key)
311
+ }
312
+ )
313
+
314
+ defineExpose({
315
+ reset,
316
+ replayFromKey,
317
+ typingKey,
318
+ })
319
+ </script>
320
+
321
+ <style scoped>
322
+ .report-typewriter-doc {
323
+ flex: 1 1 auto;
324
+ min-height: 0;
325
+ display: flex;
326
+ flex-direction: column;
327
+ gap: 0;
328
+ padding-bottom: 24px;
329
+ background: #fff;
330
+ box-sizing: border-box;
331
+ }
332
+
333
+ .report-typewriter-doc
334
+ :deep(.ProseMirror > *:first-child:not(h1):not(h2):not(h3):not(h4):not(h5):not(h6)) {
335
+ margin-top: 0 !important;
336
+ }
337
+
338
+ .report-typewriter-doc :deep(.ProseMirror h2) {
339
+ margin: 24px 0 !important;
340
+ }
341
+
342
+ .report-typewriter-doc__chapter + .report-typewriter-doc__chapter :deep(.ProseMirror > h2:first-child) {
343
+ margin-top: 24px !important;
344
+ }
345
+
346
+ .report-typewriter-doc :deep(.report-tiptap-editor__toolbar) {
347
+ display: none;
348
+ }
349
+
350
+ .report-typewriter-doc__chapter {
351
+ flex-shrink: 0;
352
+ }
353
+
354
+ .report-typewriter-doc__chapter :deep(.report-tiptap-editor__content),
355
+ .report-typewriter-doc__chapter :deep(.report-tiptap-editor__body),
356
+ .report-typewriter-doc__chapter :deep(.report-tiptap-editor) {
357
+ min-height: 0 !important;
358
+ height: auto !important;
359
+ }
360
+
361
+ .report-typewriter-doc__chapter :deep(.ProseMirror),
362
+ .report-typewriter-doc__chapter :deep(.report-tiptap-editor__prose) {
363
+ min-height: 0 !important;
364
+ height: auto !important;
365
+ padding-bottom: 0 !important;
366
+ }
367
+
368
+ .report-typewriter-doc :deep(.ProseMirror > p:empty),
369
+ .report-typewriter-doc :deep(.ProseMirror > p:has(> br.ProseMirror-trailingBreak:only-child)) {
370
+ display: none !important;
371
+ margin: 0 !important;
372
+ height: 0 !important;
373
+ }
374
+
375
+ .report-typewriter-doc__empty {
376
+ margin: 48px 0;
377
+ text-align: center;
378
+ color: #606266;
379
+ font-size: 16px;
380
+ font-weight: 500;
381
+ font-family: var(--gen-ai-font-family, 'Noto Sans', 'Noto Sans TC', sans-serif);
382
+ }
383
+
384
+ .report-typewriter-doc__shell {
385
+ display: flex;
386
+ flex-direction: column;
387
+ gap: 14px;
388
+ min-height: 280px;
389
+ padding-top: 8px;
390
+ }
391
+
392
+ .report-typewriter-doc__shell-title {
393
+ width: min(420px, 70%);
394
+ height: 28px;
395
+ border-radius: 4px;
396
+ background: linear-gradient(90deg, #f2f3f5 25%, #e9ebef 37%, #f2f3f5 63%);
397
+ background-size: 400% 100%;
398
+ animation: report-typewriter-doc-shimmer 1.2s ease-in-out infinite;
399
+ }
400
+
401
+ .report-typewriter-doc__shell-line {
402
+ width: 100%;
403
+ height: 14px;
404
+ border-radius: 4px;
405
+ background: linear-gradient(90deg, #f5f6f8 25%, #eceef2 37%, #f5f6f8 63%);
406
+ background-size: 400% 100%;
407
+ animation: report-typewriter-doc-shimmer 1.2s ease-in-out infinite;
408
+ }
409
+
410
+ .report-typewriter-doc__shell-line.is-short {
411
+ width: 62%;
412
+ }
413
+
414
+ @keyframes report-typewriter-doc-shimmer {
415
+ 0% {
416
+ background-position: 100% 0;
417
+ }
418
+ 100% {
419
+ background-position: 0 0;
420
+ }
421
+ }
422
+ </style>