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,505 @@
1
+ <template>
2
+ <label
3
+ class="gen-ai-prompt-field"
4
+ :class="{ 'gen-ai-prompt-field--row': layout === 'row' }"
5
+ :style="fieldStyle"
6
+ >
7
+ <span class="gen-ai-prompt-field__label">
8
+ {{ label }}<span v-if="required" class="gen-ai-prompt-field__required">*</span>
9
+ </span>
10
+ <div class="gen-ai-prompt-field__control" :style="controlStyle">
11
+ <div
12
+ class="gen-ai-prompt-field__box"
13
+ :class="{ 'gen-ai-prompt-field__box--constrained': isConstrained }"
14
+ :style="boxStyle"
15
+ >
16
+ <div
17
+ ref="bodyRef"
18
+ class="gen-ai-prompt-field__body"
19
+ :class="{ 'gen-ai-prompt-field__body--scroll': isConstrained }"
20
+ >
21
+ <el-input
22
+ ref="inputRef"
23
+ :model-value="modelValue"
24
+ type="textarea"
25
+ :autosize="textareaAutosize"
26
+ :rows="isConstrained ? rows : undefined"
27
+ :maxlength="maxlength"
28
+ :placeholder="placeholder"
29
+ :disabled="disabled"
30
+ resize="none"
31
+ :class="[
32
+ 'gen-ai-prompt-field__textarea',
33
+ { 'gen-ai-prompt-field__textarea--fill': isConstrained },
34
+ ]"
35
+ @update:model-value="onModelUpdate"
36
+ />
37
+ <!-- 自定義滾動條:滑塊固定 50px(原生 scrollbar 無法鎖定高度) -->
38
+ <div
39
+ v-show="scrollbarVisible"
40
+ ref="trackRef"
41
+ class="gen-ai-prompt-field__scrollbar"
42
+ @mousedown.prevent="onTrackMouseDown"
43
+ >
44
+ <div
45
+ class="gen-ai-prompt-field__scrollbar-thumb"
46
+ :style="{ transform: `translateY(${thumbTop}px)` }"
47
+ @mousedown.stop.prevent="onThumbMouseDown"
48
+ />
49
+ </div>
50
+ </div>
51
+ <div class="gen-ai-prompt-field__toolbar">
52
+ <button
53
+ type="button"
54
+ class="gen-ai-prompt-field__ai"
55
+ :disabled="disabled"
56
+ @click="openAiDialog"
57
+ >
58
+ AI+
59
+ </button>
60
+ </div>
61
+ </div>
62
+ <p class="gen-ai-prompt-field__count">{{ wordCountText }}</p>
63
+ </div>
64
+ </label>
65
+ </template>
66
+
67
+ <script setup lang="ts">
68
+ import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch, type StyleValue } from 'vue'
69
+ import type { InputInstance } from 'element-plus'
70
+
71
+ const THUMB_HEIGHT = 50
72
+
73
+ const props = withDefaults(
74
+ defineProps<{
75
+ modelValue: string
76
+ label?: string
77
+ required?: boolean
78
+ maxlength?: number
79
+ rows?: number
80
+ maxRows?: number
81
+ /** 外層可指定寬度,默認隨父級撐滿 */
82
+ width?: string
83
+ /** 外層可指定整體高度(含底欄),內部文字區域滾動 */
84
+ height?: string
85
+ minHeight?: string
86
+ /** 外層可指定最大高度,超出後內部滾動 */
87
+ maxHeight?: string
88
+ placeholder?: string
89
+ disabled?: boolean
90
+ layout?: 'row' | 'stack'
91
+ labelWidth?: string
92
+ fieldGap?: string
93
+ rootStyle?: StyleValue
94
+ }>(),
95
+ {
96
+ label: 'Prompt',
97
+ required: true,
98
+ maxlength: 1300,
99
+ rows: 8,
100
+ maxRows: 16,
101
+ placeholder: '',
102
+ disabled: false,
103
+ layout: 'row',
104
+ }
105
+ )
106
+
107
+ const emit = defineEmits<{
108
+ 'update:modelValue': [value: string]
109
+ 'ai-assist': []
110
+ }>()
111
+
112
+ const inputRef = ref<InputInstance | null>(null)
113
+ const bodyRef = ref<HTMLElement | null>(null)
114
+ const trackRef = ref<HTMLElement | null>(null)
115
+ const scrollbarVisible = ref(false)
116
+ const thumbTop = ref(0)
117
+
118
+ let dragStartY = 0
119
+ let dragStartTop = 0
120
+ let dragging = false
121
+ let resizeObserver: ResizeObserver | null = null
122
+
123
+ function openAiDialog() {
124
+ if (props.disabled) return
125
+ emit('ai-assist')
126
+ }
127
+
128
+ function onModelUpdate(value: string) {
129
+ emit('update:modelValue', value)
130
+ void nextTick(updateScrollbar)
131
+ }
132
+
133
+ /** 指定 height / maxHeight 時改為固定容器 + 內部滾動 */
134
+ const isConstrained = computed(() => !!(props.height || props.maxHeight))
135
+
136
+ const textareaAutosize = computed(() => {
137
+ if (isConstrained.value) return false
138
+ return {
139
+ minRows: props.rows,
140
+ maxRows: props.maxRows,
141
+ }
142
+ })
143
+
144
+ const wordCountText = computed(() => `${props.modelValue.length} / ${props.maxlength}`)
145
+
146
+ function pickSizeStyle(
147
+ width?: string,
148
+ height?: string,
149
+ minHeight?: string,
150
+ maxHeight?: string
151
+ ): StyleValue {
152
+ const style: Record<string, string> = {}
153
+ if (width) style.width = width
154
+ if (height) style.height = height
155
+ if (minHeight) style.minHeight = minHeight
156
+ if (maxHeight) style.maxHeight = maxHeight
157
+ return style
158
+ }
159
+
160
+ const fieldStyle = computed((): StyleValue => {
161
+ const style: Record<string, string> = {}
162
+ if (props.labelWidth) style['--gen-ai-prompt-field-label-w'] = props.labelWidth
163
+ if (props.fieldGap) style['--gen-ai-prompt-field-gap'] = props.fieldGap
164
+ if (!props.rootStyle) return style
165
+ if (typeof props.rootStyle === 'string') return [style, props.rootStyle]
166
+ if (Array.isArray(props.rootStyle)) return [style, ...props.rootStyle]
167
+ return { ...style, ...props.rootStyle }
168
+ })
169
+
170
+ const controlStyle = computed(() => pickSizeStyle(props.width))
171
+ const boxStyle = computed(() =>
172
+ pickSizeStyle(props.width, props.height, props.minHeight, props.maxHeight)
173
+ )
174
+
175
+ function getTextarea(): HTMLTextAreaElement | null {
176
+ const root = inputRef.value?.$el as HTMLElement | undefined
177
+ return root?.querySelector?.('textarea.el-textarea__inner') ?? null
178
+ }
179
+
180
+ function trackHeight(): number {
181
+ return trackRef.value?.clientHeight ?? 0
182
+ }
183
+
184
+ function maxThumbTop(): number {
185
+ return Math.max(0, trackHeight() - THUMB_HEIGHT)
186
+ }
187
+
188
+ function updateScrollbar() {
189
+ const el = getTextarea()
190
+ if (!el) {
191
+ scrollbarVisible.value = false
192
+ return
193
+ }
194
+ const { scrollTop, scrollHeight, clientHeight } = el
195
+ const needs = scrollHeight > clientHeight + 1
196
+ scrollbarVisible.value = needs
197
+ if (!needs) {
198
+ thumbTop.value = 0
199
+ return
200
+ }
201
+ const maxScroll = scrollHeight - clientHeight
202
+ const maxTop = maxThumbTop()
203
+ thumbTop.value = maxScroll > 0 ? (scrollTop / maxScroll) * maxTop : 0
204
+ }
205
+
206
+ function scrollToThumbTop(nextTop: number) {
207
+ const el = getTextarea()
208
+ if (!el) return
209
+ const maxTop = maxThumbTop()
210
+ const clamped = Math.min(maxTop, Math.max(0, nextTop))
211
+ thumbTop.value = clamped
212
+ const maxScroll = el.scrollHeight - el.clientHeight
213
+ if (maxScroll <= 0 || maxTop <= 0) return
214
+ el.scrollTop = (clamped / maxTop) * maxScroll
215
+ }
216
+
217
+ function onTrackMouseDown(e: MouseEvent) {
218
+ const track = trackRef.value
219
+ if (!track) return
220
+ const rect = track.getBoundingClientRect()
221
+ const clickY = e.clientY - rect.top
222
+ scrollToThumbTop(clickY - THUMB_HEIGHT / 2)
223
+ onThumbMouseDown(e)
224
+ }
225
+
226
+ function onThumbMouseDown(e: MouseEvent) {
227
+ dragging = true
228
+ dragStartY = e.clientY
229
+ dragStartTop = thumbTop.value
230
+ window.addEventListener('mousemove', onDragMove)
231
+ window.addEventListener('mouseup', onDragEnd)
232
+ }
233
+
234
+ function onDragMove(e: MouseEvent) {
235
+ if (!dragging) return
236
+ scrollToThumbTop(dragStartTop + (e.clientY - dragStartY))
237
+ }
238
+
239
+ function onDragEnd() {
240
+ dragging = false
241
+ window.removeEventListener('mousemove', onDragMove)
242
+ window.removeEventListener('mouseup', onDragEnd)
243
+ }
244
+
245
+ function bindTextareaScroll() {
246
+ const el = getTextarea()
247
+ if (!el) return
248
+ el.removeEventListener('scroll', updateScrollbar)
249
+ el.addEventListener('scroll', updateScrollbar, { passive: true })
250
+ updateScrollbar()
251
+ }
252
+
253
+ onMounted(() => {
254
+ void nextTick(() => {
255
+ bindTextareaScroll()
256
+ const el = getTextarea()
257
+ if (el && typeof ResizeObserver !== 'undefined') {
258
+ resizeObserver = new ResizeObserver(() => updateScrollbar())
259
+ resizeObserver.observe(el)
260
+ if (bodyRef.value) resizeObserver.observe(bodyRef.value)
261
+ }
262
+ })
263
+ })
264
+
265
+ onBeforeUnmount(() => {
266
+ const el = getTextarea()
267
+ el?.removeEventListener('scroll', updateScrollbar)
268
+ resizeObserver?.disconnect()
269
+ resizeObserver = null
270
+ onDragEnd()
271
+ })
272
+
273
+ watch(
274
+ () => props.modelValue,
275
+ () => {
276
+ void nextTick(() => {
277
+ bindTextareaScroll()
278
+ updateScrollbar()
279
+ })
280
+ }
281
+ )
282
+
283
+ watch(
284
+ () => [props.height, props.maxHeight, props.rows, props.maxRows, isConstrained.value] as const,
285
+ () => {
286
+ void nextTick(() => {
287
+ bindTextareaScroll()
288
+ updateScrollbar()
289
+ })
290
+ }
291
+ )
292
+
293
+ export interface PromptFieldLayoutBind {
294
+ labelWidth?: string
295
+ fieldGap?: string
296
+ width?: string
297
+ height?: string
298
+ minHeight?: string
299
+ maxHeight?: string
300
+ rootStyle?: StyleValue
301
+ }
302
+ </script>
303
+
304
+ <style scoped>
305
+ .gen-ai-prompt-field {
306
+ margin: 0;
307
+ }
308
+
309
+ .gen-ai-prompt-field--row {
310
+ --gen-ai-prompt-field-label-w: 100px;
311
+ --gen-ai-prompt-field-gap: 16px;
312
+ display: grid;
313
+ grid-template-columns: var(--gen-ai-prompt-field-label-w) minmax(0, 1fr);
314
+ column-gap: var(--gen-ai-prompt-field-gap);
315
+ align-items: start;
316
+ }
317
+
318
+ .gen-ai-prompt-field__label {
319
+ flex-shrink: 0;
320
+ padding-top: 8px;
321
+ font-size: 15px;
322
+ font-weight: 500;
323
+ font-family: var(--gen-ai-font-family, 'Noto Sans', 'Noto Sans TC', sans-serif);
324
+ color: #303133;
325
+ white-space: nowrap;
326
+ }
327
+
328
+ .gen-ai-prompt-field__required {
329
+ margin-left: 2px;
330
+ color: #f56c6c;
331
+ }
332
+
333
+ .gen-ai-prompt-field__control {
334
+ min-width: 0;
335
+ width: 100%;
336
+ }
337
+
338
+ .gen-ai-prompt-field__box {
339
+ display: flex;
340
+ flex-direction: column;
341
+ width: 100%;
342
+ border: 1px solid #dcdfe6;
343
+ border-radius: 8px;
344
+ background: #fff;
345
+ overflow: hidden;
346
+ transition: border-color 0.2s ease;
347
+ }
348
+
349
+ .gen-ai-prompt-field__box--constrained {
350
+ min-height: 0;
351
+ }
352
+
353
+ .gen-ai-prompt-field__box:focus-within {
354
+ border-color: #c53355;
355
+ }
356
+
357
+ .gen-ai-prompt-field__body {
358
+ position: relative;
359
+ flex: 1 1 auto;
360
+ min-height: 0;
361
+ padding: 12px 14px 4px 12px;
362
+ }
363
+
364
+ .gen-ai-prompt-field__body--scroll {
365
+ display: flex;
366
+ flex-direction: column;
367
+ overflow: hidden;
368
+ }
369
+
370
+ .gen-ai-prompt-field__textarea {
371
+ width: 100%;
372
+ }
373
+
374
+ .gen-ai-prompt-field__textarea :deep(.el-textarea),
375
+ .gen-ai-prompt-field__textarea :deep(.el-textarea__wrapper),
376
+ .gen-ai-prompt-field__textarea :deep(.el-textarea__wrapper.is-focus) {
377
+ padding: 0;
378
+ margin: 0;
379
+ border: none;
380
+ outline: none;
381
+ box-shadow: none !important;
382
+ background: transparent;
383
+ }
384
+
385
+ .gen-ai-prompt-field__textarea :deep(.el-textarea__inner) {
386
+ padding: 0 4px 0 0;
387
+ margin: 0;
388
+ border: none;
389
+ outline: none;
390
+ box-shadow: none !important;
391
+ background: transparent;
392
+ font-size: 14px;
393
+ line-height: 1.6;
394
+ color: #303133;
395
+ resize: none;
396
+ box-sizing: border-box;
397
+ /* 隱藏原生滾動條,改用自定義 50px 滑塊 */
398
+ scrollbar-width: none;
399
+ -ms-overflow-style: none;
400
+ }
401
+
402
+ .gen-ai-prompt-field__textarea :deep(.el-textarea__inner::-webkit-scrollbar) {
403
+ width: 0 !important;
404
+ height: 0 !important;
405
+ display: none !important;
406
+ }
407
+
408
+ .gen-ai-prompt-field__textarea :deep(.el-textarea__inner:focus) {
409
+ border: none;
410
+ outline: none;
411
+ box-shadow: none !important;
412
+ }
413
+
414
+ .gen-ai-prompt-field__textarea--fill {
415
+ flex: 1 1 auto;
416
+ min-height: 0;
417
+ height: 100%;
418
+ display: flex;
419
+ flex-direction: column;
420
+ }
421
+
422
+ .gen-ai-prompt-field__textarea--fill :deep(.el-textarea) {
423
+ flex: 1 1 auto;
424
+ min-height: 0;
425
+ height: 100%;
426
+ display: flex;
427
+ flex-direction: column;
428
+ }
429
+
430
+ .gen-ai-prompt-field__textarea--fill :deep(.el-textarea__inner) {
431
+ flex: 1 1 auto;
432
+ min-height: 0 !important;
433
+ height: 100% !important;
434
+ overflow-y: auto !important;
435
+ }
436
+
437
+ /* 與章節下拉同款:寬 8px、滑塊固定高 50px */
438
+ .gen-ai-prompt-field__scrollbar {
439
+ position: absolute;
440
+ top: 12px;
441
+ right: 4px;
442
+ bottom: 4px;
443
+ width: 8px;
444
+ z-index: 2;
445
+ }
446
+
447
+ .gen-ai-prompt-field__scrollbar-thumb {
448
+ position: absolute;
449
+ top: 0;
450
+ left: 0;
451
+ width: 8px;
452
+ height: 50px;
453
+ border-radius: 4px;
454
+ background-color: #999;
455
+ cursor: default;
456
+ will-change: transform;
457
+ }
458
+
459
+ .gen-ai-prompt-field__toolbar {
460
+ flex-shrink: 0;
461
+ display: flex;
462
+ justify-content: flex-end;
463
+ align-items: center;
464
+ padding: 0 12px 10px;
465
+ }
466
+
467
+ .gen-ai-prompt-field__ai {
468
+ flex-shrink: 0;
469
+ width: 40px;
470
+ height: 40px;
471
+ padding: 0;
472
+ border: none;
473
+ border-radius: 50%;
474
+ background: linear-gradient(135deg, #7b61ff 0%, #5b8def 100%);
475
+ color: #fff;
476
+ font-size: 12px;
477
+ font-weight: 700;
478
+ line-height: 1;
479
+ cursor: pointer;
480
+ box-shadow: 0 2px 8px rgba(91, 141, 239, 0.35);
481
+ transition:
482
+ transform 0.2s ease,
483
+ box-shadow 0.2s ease;
484
+ }
485
+
486
+ .gen-ai-prompt-field__ai:hover:not(:disabled) {
487
+ transform: translateY(-1px);
488
+ box-shadow: 0 4px 12px rgba(91, 141, 239, 0.45);
489
+ }
490
+
491
+ .gen-ai-prompt-field__ai:disabled {
492
+ opacity: 0.45;
493
+ cursor: not-allowed;
494
+ transform: none;
495
+ box-shadow: 0 2px 8px rgba(91, 141, 239, 0.35);
496
+ }
497
+
498
+ .gen-ai-prompt-field__count {
499
+ margin: 4px 0 0;
500
+ text-align: right;
501
+ font-size: 12px;
502
+ color: #909399;
503
+ line-height: 1;
504
+ }
505
+ </style>