aegon-lv82 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 (148) hide show
  1. package/package.json +12 -0
  2. package/src/App.vue +44 -0
  3. package/src/api/index.ts +19 -0
  4. package/src/api/modules/build-report/reportEditor.ts +526 -0
  5. package/src/api/modules/build-report/reportPermission.ts +64 -0
  6. package/src/api/modules/index.ts +69 -0
  7. package/src/api/modules/industry/green_mortgage.ts +42 -0
  8. package/src/api/modules/user/index.ts +4 -0
  9. package/src/api/request.ts +124 -0
  10. package/src/assets/sample-access-icon.png +0 -0
  11. package/src/assets/sample-pie-chart.png +0 -0
  12. package/src/assets/vue.svg +1 -0
  13. package/src/components/CapsuleScrollbar.vue +7 -0
  14. package/src/components/Export/ExcelExport.vue +592 -0
  15. package/src/components/Export/ExcelExport2.vue +494 -0
  16. package/src/components/Export/ExcelExport3.vue +342 -0
  17. package/src/components/Export/ExcelExport4.vue +665 -0
  18. package/src/components/Export/excelExport.js +547 -0
  19. package/src/components/Export/excelExport.ts +551 -0
  20. package/src/components/GEN-AI/index.vue +140 -0
  21. package/src/components/GEN-AI/index1.vue +422 -0
  22. package/src/components/GEN-AI/index10.vue +5 -0
  23. package/src/components/GEN-AI/index2.vue +548 -0
  24. package/src/components/GEN-AI/index3.vue +605 -0
  25. package/src/components/GEN-AI/index4.vue +609 -0
  26. package/src/components/GEN-AI/index5.vue +558 -0
  27. package/src/components/GEN-AI/index6.vue +634 -0
  28. package/src/components/GEN-AI/index7.vue +688 -0
  29. package/src/components/GEN-AI/index8.vue +458 -0
  30. package/src/components/GEN-AI/index9.vue +1217 -0
  31. package/src/components/GEN-AI/types.ts +12 -0
  32. package/src/components/GEN-AI/utils.ts +42 -0
  33. package/src/components/HelloWorld.vue +41 -0
  34. package/src/components/PageCard.vue +124 -0
  35. package/src/components/PageHeader.vue +32 -0
  36. package/src/components/backup/index5 copy.vue +556 -0
  37. package/src/components/backup/index5.vue +620 -0
  38. package/src/components/backup/index9 copy.vue +1029 -0
  39. package/src/components/backup/index9-pro.vue +1065 -0
  40. package/src/components/backup/index9.vue +1057 -0
  41. package/src/directives/btnLoading.ts +455 -0
  42. package/src/directives/debounce copy.ts +670 -0
  43. package/src/directives/debounce.ts +98 -0
  44. package/src/directives/index.ts +25 -0
  45. package/src/layouts/MainLayout.vue +129 -0
  46. package/src/main.ts +76 -0
  47. package/src/router/index.ts +142 -0
  48. package/src/router/menus.ts +28 -0
  49. package/src/store/modules/gen-ai/index.ts +1 -0
  50. package/src/store/modules/gen-ai/reportBuild.ts +37 -0
  51. package/src/style.css +79 -0
  52. package/src/styles/report-config-popover.css +39 -0
  53. package/src/styles/report-icon-btn.css +19 -0
  54. package/src/test/mock.ts +101 -0
  55. package/src/test/test1.vue +402 -0
  56. package/src/test/test2.vue +1689 -0
  57. package/src/types/gen-ai/build-report/reportEditor.ts +684 -0
  58. package/src/utils/function.ts +46 -0
  59. package/src/utils/gen-ai-navigation.ts +1 -0
  60. package/src/utils/gen-ai-scroll.ts +1 -0
  61. package/src/utils/openDataLoaderWordExport.ts +33 -0
  62. package/src/utils/pageScrollbar.ts +115 -0
  63. package/src/utils/randomTranscode.ts +87 -0
  64. package/src/utils/reportPdfExport.ts +44 -0
  65. package/src/views/Blank.vue +68 -0
  66. package/src/views/Home.vue +29 -0
  67. package/src/views/TemplateCenter/Knowledge.ts +83 -0
  68. package/src/views/TemplateCenter/data.d.ts +10 -0
  69. package/src/views/TemplateCenter/index.vue +1128 -0
  70. package/src/views/TemplateCenter/service.ts +69 -0
  71. package/src/views/gen-ai/build-report/chartStreamRefs.ts +174 -0
  72. package/src/views/gen-ai/build-report/coherence-check/index.vue +559 -0
  73. package/src/views/gen-ai/build-report/components/ReportChapterWorkspace.vue +4258 -0
  74. package/src/views/gen-ai/build-report/components/ReportConfigPanel.vue +727 -0
  75. package/src/views/gen-ai/build-report/components/ReportGenerateSettingsPanel.vue +2361 -0
  76. package/src/views/gen-ai/build-report/components/ReportGeneratingPanel.vue +1765 -0
  77. package/src/views/gen-ai/build-report/components/ReportPromptPanel.vue +614 -0
  78. package/src/views/gen-ai/build-report/components/ReportSourceFileSummary.vue +656 -0
  79. package/src/views/gen-ai/build-report/components/ReportSourcesPanel.vue +1327 -0
  80. package/src/views/gen-ai/build-report/components/ReportTemplateDetail.vue +191 -0
  81. package/src/views/gen-ai/build-report/components/ReportTemplateEditorFormPanel.vue +667 -0
  82. package/src/views/gen-ai/build-report/components/ReportTemplatePicker.vue +302 -0
  83. package/src/views/gen-ai/build-report/components/ReportWorkflowSidebar.vue +148 -0
  84. package/src/views/gen-ai/build-report/components/paramsSetting.vue +886 -0
  85. package/src/views/gen-ai/build-report/components/reportEdit.vue +2283 -0
  86. package/src/views/gen-ai/build-report/index.vue +856 -0
  87. package/src/views/gen-ai/build-report/report-domain.ts +1133 -0
  88. package/src/views/gen-ai/build-report/report-template-data.ts +295 -0
  89. package/src/views/gen-ai/build-report/useReportWorkflow.ts +1408 -0
  90. package/src/views/gen-ai/common/assets/NotoSans-SC.woff2 +0 -0
  91. package/src/views/gen-ai/common/assets/NotoSans-TC.woff2 +0 -0
  92. package/src/views/gen-ai/common/assets/NotoSans.woff2 +0 -0
  93. package/src/views/gen-ai/common/assets/fonts.css +278 -0
  94. package/src/views/gen-ai/common/assets/pagination.css +163 -0
  95. package/src/views/gen-ai/common/directives/btnLoading.ts +455 -0
  96. package/src/views/gen-ai/common/directives/debounce.ts +98 -0
  97. package/src/views/gen-ai/common/directives/index.ts +30 -0
  98. package/src/views/gen-ai/common/en.md +417 -0
  99. package/src/views/gen-ai/common/index.ts +36 -0
  100. package/src/views/gen-ai/common/types/component-expose.ts +9 -0
  101. package/src/views/gen-ai/common/utils/api-res-status.ts +7 -0
  102. package/src/views/gen-ai/common/utils/navigation.ts +59 -0
  103. package/src/views/gen-ai/common/utils/remote-request.ts +45 -0
  104. package/src/views/gen-ai/common/utils/scroll.ts +577 -0
  105. package/src/views/gen-ai/components/AIExport/docx-export.ts +950 -0
  106. package/src/views/gen-ai/components/AIExport/docxExport.ts +2566 -0
  107. package/src/views/gen-ai/components/AIExport/index.ts +52 -0
  108. package/src/views/gen-ai/components/AIExport/parseMarkdownHtml.ts +649 -0
  109. package/src/views/gen-ai/components/CapsuleScrollbar.vue +149 -0
  110. package/src/views/gen-ai/components/ChapterTitleScroll.vue +468 -0
  111. package/src/views/gen-ai/components/EntryHeroNavCards.vue +379 -0
  112. package/src/views/gen-ai/components/GenAiPagination.vue +52 -0
  113. package/src/views/gen-ai/components/ModelCard.vue +1114 -0
  114. package/src/views/gen-ai/components/Preview/FilePreviewPage.vue +947 -0
  115. package/src/views/gen-ai/components/Preview/PreviewCapsuleScroll.vue +205 -0
  116. package/src/views/gen-ai/components/Preview/PreviewOutlineTree.vue +148 -0
  117. package/src/views/gen-ai/components/Preview/index.ts +11 -0
  118. package/src/views/gen-ai/components/Preview/preview.ts +722 -0
  119. package/src/views/gen-ai/components/PromptField.vue +505 -0
  120. package/src/views/gen-ai/components/RecentReportsTable.vue +974 -0
  121. package/src/views/gen-ai/components/ReportCollapsibleSection.vue +172 -0
  122. package/src/views/gen-ai/components/ReportHistoryList.vue +637 -0
  123. package/src/views/gen-ai/components/ReportSectionConfirmPopover.vue +251 -0
  124. package/src/views/gen-ai/components/editor/ChapterTiptapEditor.vue +3139 -0
  125. package/src/views/gen-ai/components/editor/StructureBlockView.vue +441 -0
  126. package/src/views/gen-ai/components/editor/TiptapToolbar.vue +1036 -0
  127. package/src/views/gen-ai/components/editor/TypewriterDocEditor.vue +398 -0
  128. package/src/views/gen-ai/components/editor/_StructureOrgNode.vue +326 -0
  129. package/src/views/gen-ai/components/editor/index.ts +12 -0
  130. package/src/views/gen-ai/components/editor/parseMarkdownHtml.ts +667 -0
  131. package/src/views/gen-ai/gen-entry/api/index.ts +32 -0
  132. package/src/views/gen-ai/gen-entry/index.vue +287 -0
  133. package/src/views/gen-ai/gen-entry/types/index.ts +4 -0
  134. package/src/views/gen-ai/i.mark +2 -0
  135. package/src/views/gen-ai/management-center/index.vue +1815 -0
  136. package/src/views/gen-ai/management-center/mockData.ts +248 -0
  137. package/src/views/gen-ai/management-center/types/index.ts +37 -0
  138. package/src/views/gen-ai/model-manager/TemplateEditorFormPanel.vue +661 -0
  139. package/src/views/gen-ai/model-manager/api/index.ts +32 -0
  140. package/src/views/gen-ai/model-manager/api/mockApi.ts +33 -0
  141. package/src/views/gen-ai/model-manager/index.vue +1583 -0
  142. package/src/views/gen-ai/model-manager/mockData.ts +177 -0
  143. package/src/views/gen-ai/model-manager/template-detail-shared.ts +154 -0
  144. package/src/views/gen-ai/model-manager/template-editor.vue +345 -0
  145. package/src/views/gen-ai/model-manager/types/index.ts +40 -0
  146. package/src/views/gen-ai/model-manager/utils.ts +25 -0
  147. package/src/views/greenMortgage.vue +1834 -0
  148. package/src/vite-env.d.ts +46 -0
@@ -0,0 +1,614 @@
1
+ <template>
2
+ <aside class="report-prompt-panel" :class="{ 'is-compact': !promptOpen && !chapterHistoryOpen }">
3
+ <ReportCollapsibleSection v-model:open="promptOpen" title="Prompt">
4
+ <div :key="promptFormRenderKey" class="report-prompt-panel__content">
5
+ <div class="report-prompt-panel__prompt">
6
+ <PromptField
7
+ v-model="promptChapterForm.prompt"
8
+ label="Prompt"
9
+ layout="stack"
10
+ :required="false"
11
+ :rows="8"
12
+ min-height="180px"
13
+ :maxlength="1300"
14
+ :disabled="!chapterEditMode"
15
+ @ai-assist="handleAiAssist"
16
+ enable-ai-dialog
17
+ />
18
+ </div>
19
+
20
+ <div class="report-prompt-panel__options">
21
+ <label class="report-prompt-panel__option report-prompt-panel__option--inline">
22
+ <input
23
+ v-model="promptChapterForm.enableBodyContent"
24
+ type="checkbox"
25
+ class="report-prompt-panel__checkbox"
26
+ :disabled="!chapterEditMode"
27
+ />
28
+ <span class="report-prompt-panel__option-label">正文內容</span>
29
+ <input
30
+ v-model.number="promptChapterForm.bodyWordLimit"
31
+ type="number"
32
+ class="report-prompt-panel__number-input"
33
+ :disabled="!chapterEditMode || !promptChapterForm.enableBodyContent"
34
+ min="1"
35
+ max="5000"
36
+ />
37
+ <span class="report-prompt-panel__option-suffix">字以內</span>
38
+ </label>
39
+
40
+ <div class="report-prompt-panel__option-group">
41
+ <div class="report-prompt-panel__option-header">
42
+ <label class="report-prompt-panel__option">
43
+ <input
44
+ v-model="promptChapterForm.enableTable"
45
+ type="checkbox"
46
+ class="report-prompt-panel__checkbox"
47
+ :disabled="!chapterEditMode"
48
+ />
49
+ <span class="report-prompt-panel__option-label">生成表格</span>
50
+ </label>
51
+ <button
52
+ type="button"
53
+ class="report-prompt-panel__fold-toggle"
54
+ aria-label="展開或收起生成設置"
55
+ @click="optionsDetailsOpen = !optionsDetailsOpen"
56
+ >
57
+ <span
58
+ class="report-prompt-panel__fold-arrow"
59
+ :class="{ 'is-open': optionsDetailsOpen }"
60
+ aria-hidden="true"
61
+ />
62
+ </button>
63
+ </div>
64
+
65
+ <div v-show="optionsDetailsOpen" class="report-prompt-panel__details">
66
+ <div v-if="promptChapterForm.enableTable" class="report-prompt-panel__nested">
67
+ <label class="report-prompt-panel__field">
68
+ <span class="report-prompt-panel__field-label">表格標題</span>
69
+ <el-input
70
+ v-model="promptChapterForm.tableTitle"
71
+ class="report-prompt-panel__input"
72
+ :disabled="!chapterEditMode"
73
+ />
74
+ </label>
75
+ <label class="report-prompt-panel__field">
76
+ <span class="report-prompt-panel__field-label">列標籤</span>
77
+ <el-input
78
+ v-model="promptChapterForm.tableRowLabels"
79
+ type="textarea"
80
+ :rows="3"
81
+ resize="none"
82
+ class="report-prompt-panel__textarea"
83
+ :disabled="!chapterEditMode"
84
+ />
85
+ </label>
86
+ <label class="report-prompt-panel__field">
87
+ <span class="report-prompt-panel__field-label">欄標籤</span>
88
+ <el-input
89
+ v-model="promptChapterForm.tableColumnLabels"
90
+ type="textarea"
91
+ :rows="3"
92
+ resize="none"
93
+ class="report-prompt-panel__textarea"
94
+ :disabled="!chapterEditMode"
95
+ />
96
+ </label>
97
+ <label class="report-prompt-panel__field">
98
+ <span class="report-prompt-panel__field-label">內容</span>
99
+ <el-input
100
+ v-model="promptChapterForm.tableContent"
101
+ type="textarea"
102
+ :rows="3"
103
+ resize="none"
104
+ class="report-prompt-panel__textarea"
105
+ :disabled="!chapterEditMode"
106
+ />
107
+ </label>
108
+ </div>
109
+
110
+ <div
111
+ class="report-prompt-panel__option-group report-prompt-panel__option-group--nested"
112
+ >
113
+ <label class="report-prompt-panel__option">
114
+ <input
115
+ v-model="promptChapterForm.enableSourceChart"
116
+ type="checkbox"
117
+ class="report-prompt-panel__checkbox"
118
+ :disabled="!chapterEditMode"
119
+ />
120
+ <span class="report-prompt-panel__option-label">引用資訊源圖表</span>
121
+ </label>
122
+
123
+ <div v-if="promptChapterForm.enableSourceChart" class="report-prompt-panel__nested">
124
+ <label class="report-prompt-panel__field">
125
+ <span class="report-prompt-panel__field-label">圖表描述</span>
126
+ <el-input
127
+ v-model="promptChapterForm.chartDescription"
128
+ type="textarea"
129
+ :rows="4"
130
+ resize="none"
131
+ class="report-prompt-panel__textarea"
132
+ :disabled="!chapterEditMode"
133
+ />
134
+ </label>
135
+ </div>
136
+ </div>
137
+
138
+ <div class="report-prompt-panel__actions">
139
+ <button
140
+ type="button"
141
+ class="app-btn app-btn--wide report-prompt-generate-btn"
142
+ :disabled="!chapterEditMode"
143
+ v-aiDebounce
144
+ v-aiBtnLoading
145
+ @click="handleGenerateChapter"
146
+ >
147
+ 生成章節內容
148
+ </button>
149
+ </div>
150
+ </div>
151
+ </div>
152
+ </div>
153
+ </div>
154
+ </ReportCollapsibleSection>
155
+
156
+ <ReportCollapsibleSection v-model:open="chapterHistoryOpen" title="章節歷史">
157
+ <ReportHistoryList
158
+ v-model:active-key="activeChapterHistoryKey"
159
+ :items="chapterHistoryItems"
160
+ :show-title="false"
161
+ @continue-draft="handleContinueDraft"
162
+ />
163
+ </ReportCollapsibleSection>
164
+ </aside>
165
+ </template>
166
+
167
+ <script lang="ts">
168
+ export interface PromptLibraryItem {
169
+ id: string
170
+ label: string
171
+ content: string
172
+ }
173
+ </script>
174
+
175
+ <script setup lang="ts">
176
+ import genAiReportEditorApi from '@/api/modules/build-report/reportEditor'
177
+ import { useGenAiBuildReportStore } from '@/store/modules/gen-ai'
178
+ import type { GenAiChartAsStreamParams } from '@/types/gen-ai/build-report/reportEditor'
179
+ import { ElInput, ElMessage } from 'element-plus'
180
+ import { nextTick, onBeforeUnmount, ref, watch } from 'vue'
181
+ import { closeAiBtnLoading } from '../../common/directives'
182
+ import {
183
+ PromptField,
184
+ ReportCollapsibleSection,
185
+ ReportHistoryList,
186
+ type ReportHistoryItem,
187
+ } from '../../common'
188
+ import { useReportWorkflow } from '../useReportWorkflow'
189
+
190
+ const genAiBuildReportStore = useGenAiBuildReportStore()
191
+
192
+ const {
193
+ draft,
194
+ promptChapterForm,
195
+ chapterEditMode,
196
+ chapterHistoryItems,
197
+ activeChapterHistoryKey,
198
+ chapterHistoryOpen,
199
+ chapterHistoryPreviewBody,
200
+ chapterHistoryApplyToken,
201
+ sourceFiles,
202
+ startChapterContentTypewriter,
203
+ stopChapterContentTypewriter,
204
+ markChapterContentFirstChunk,
205
+ chapterContentStreamEpoch,
206
+ requestOpenAiPromptDialog,
207
+ enterChapterEditMode,
208
+ setChapterChartAuditEventId,
209
+ clearChapterChartAuditEventId,
210
+ upsertChapterChartStreamRef,
211
+ clearChapterChartStreamRefs,
212
+ } = useReportWorkflow()
213
+
214
+ const promptOpen = ref(true)
215
+ const optionsDetailsOpen = ref(false)
216
+ /** 歷史反顯時遞增,強制 Prompt 區 checkbox/input 重掛載 */
217
+ const promptFormRenderKey = ref(0)
218
+
219
+ /** 無章節歷史時默認收起 */
220
+ watch(
221
+ chapterHistoryItems,
222
+ (items) => {
223
+ if (!items.length) chapterHistoryOpen.value = false
224
+ },
225
+ { deep: true, immediate: true }
226
+ )
227
+
228
+ /** 版本套用後刷新 Prompt UI:展開詳情並重掛表單,保證全量反顯 */
229
+ watch(chapterHistoryApplyToken, async () => {
230
+ if (!activeChapterHistoryKey.value) return
231
+ promptOpen.value = true
232
+ optionsDetailsOpen.value = true
233
+ await nextTick()
234
+ promptFormRenderKey.value += 1
235
+ })
236
+
237
+ /** 草稿「繼續編輯」:反顯該版本 Prompt / 正文 / 資訊源(靜態無打字機),並進入編輯模式 */
238
+ function handleContinueDraft(item: ReportHistoryItem) {
239
+ const key = item.key
240
+ if (!key) return
241
+ // 已選中同一草稿時強制再觸發一次 watch,確保三塊數據按該版本回填
242
+ if (activeChapterHistoryKey.value === key) {
243
+ activeChapterHistoryKey.value = ''
244
+ }
245
+ activeChapterHistoryKey.value = key
246
+ enterChapterEditMode()
247
+ }
248
+
249
+ function handleAiAssist() {
250
+ if (!chapterEditMode.value) return
251
+ requestOpenAiPromptDialog('prompt-panel')
252
+ }
253
+
254
+ let chapterContentGenerateSeq = 0
255
+ let chapterContentAbort: AbortController | null = null
256
+
257
+ /** 切章時中止進行中的 chartAsStream,避免寫入錯章 */
258
+ watch(chapterContentStreamEpoch, () => {
259
+ chapterContentAbort?.abort()
260
+ chapterContentAbort = null
261
+ chapterContentGenerateSeq += 1
262
+ })
263
+
264
+ /** Prompt 面板 → ChartAsStreamDTO 全量入參 */
265
+ function buildChartAsStreamParams(): GenAiChartAsStreamParams {
266
+ const form = promptChapterForm
267
+ return {
268
+ // 報告配置「模型」value;未選時為空字串
269
+ modelName: String(draft.model || '').trim(),
270
+ promptDetail: form.prompt.trim() || 'who are you?',
271
+ promptType: 'INSTANCE_PROMPT_DETAIL',
272
+ contentLengthLimit: form.enableBodyContent ? form.bodyWordLimit || 500 : null,
273
+ tableInfo: {
274
+ enableTable: form.enableTable ? 'Y' : 'N',
275
+ tableTitle: form.tableTitle,
276
+ columnLabel: form.tableRowLabels,
277
+ barLabel: form.tableColumnLabels,
278
+ content: form.tableContent,
279
+ },
280
+ chartInfo: {
281
+ enableChart: form.enableSourceChart ? 'Y' : 'N',
282
+ chartDesc: form.chartDescription,
283
+ },
284
+ // 資訊源當前勾選列表(全選 / 全不選 / 部分)
285
+ fileIdList: sourceFiles.value.filter((file) => file.selected).map((file) => file.id),
286
+ instanceId: String(genAiBuildReportStore.instanceId ?? '').trim(),
287
+ categoryId: 1,
288
+ temperature: null,
289
+ maxTokens: null,
290
+ stream: true,
291
+ }
292
+ }
293
+
294
+ /** 生成章節內容 chartAsStream:先清空標題外正文並繪出標題,再流式續打 */
295
+ async function generateGenAiSectionContent() {
296
+ const seq = ++chapterContentGenerateSeq
297
+ chapterContentAbort?.abort()
298
+ chapterContentAbort = new AbortController()
299
+ const signal = chapterContentAbort.signal
300
+ const previousBody = chapterHistoryPreviewBody.value
301
+ clearChapterChartAuditEventId()
302
+ clearChapterChartStreamRefs()
303
+ startChapterContentTypewriter()
304
+ // 先讓中欄只保留章節標題(正文已清空),再關 loading、開始收流
305
+ await nextTick()
306
+ if (seq !== chapterContentGenerateSeq) return
307
+ markChapterContentFirstChunk()
308
+ await nextTick()
309
+ if (seq !== chapterContentGenerateSeq) return
310
+
311
+ let received = false
312
+
313
+ try {
314
+ for await (const chunk of genAiReportEditorApi.streamChartAsStream(
315
+ buildChartAsStreamParams(),
316
+ signal,
317
+ {
318
+ onAuditEvent: (auditEventId) => setChapterChartAuditEventId(auditEventId),
319
+ onRefEvent: (ref) => upsertChapterChartStreamRef(ref),
320
+ }
321
+ )) {
322
+ if (seq !== chapterContentGenerateSeq) return
323
+ received = true
324
+ chapterHistoryPreviewBody.value = `${chapterHistoryPreviewBody.value ?? ''}${chunk}`
325
+ if (String(chapterHistoryPreviewBody.value).trim()) markChapterContentFirstChunk()
326
+ }
327
+ try {
328
+ const stored = String(
329
+ sessionStorage.getItem('gen-ai-chapter-chart-audit-event-id') ?? ''
330
+ ).trim()
331
+ if (stored) setChapterChartAuditEventId(stored)
332
+ } catch {
333
+ /* ignore */
334
+ }
335
+ if (seq !== chapterContentGenerateSeq) return
336
+ if (!received || !String(chapterHistoryPreviewBody.value ?? '').trim()) {
337
+ stopChapterContentTypewriter()
338
+ chapterHistoryPreviewBody.value = previousBody
339
+ return false
340
+ }
341
+ return true
342
+ } catch (err) {
343
+ if (signal.aborted || seq !== chapterContentGenerateSeq) return
344
+ console.error('接口异常', err)
345
+ stopChapterContentTypewriter()
346
+ chapterHistoryPreviewBody.value = previousBody
347
+ return err instanceof Error && err.message.trim() ? err.message : false
348
+ } finally {
349
+ if (seq === chapterContentGenerateSeq) markChapterContentFirstChunk()
350
+ }
351
+ }
352
+
353
+ onBeforeUnmount(() => {
354
+ chapterContentAbort?.abort()
355
+ chapterContentAbort = null
356
+ })
357
+
358
+ function handleGenerateChapter() {
359
+ if (!chapterEditMode.value) {
360
+ closeAiBtnLoading('.report-prompt-generate-btn')
361
+ return
362
+ }
363
+ if (!promptChapterForm.prompt.trim()) {
364
+ ElMessage.warning('請先填寫 Prompt')
365
+ closeAiBtnLoading('.report-prompt-generate-btn')
366
+ return
367
+ }
368
+ ElMessage.success('章節內容生成中')
369
+ void generateGenAiSectionContent()
370
+ .then((ok) => {
371
+ if (ok === false) ElMessage.warning('接口异常')
372
+ else if (typeof ok === 'string') ElMessage.warning(ok)
373
+ })
374
+ .finally(() => {
375
+ closeAiBtnLoading('.report-prompt-generate-btn')
376
+ })
377
+ }
378
+ </script>
379
+
380
+ <style scoped>
381
+ .report-prompt-panel {
382
+ display: flex;
383
+ flex-direction: column;
384
+ gap: 14px;
385
+ min-width: 0;
386
+ height: 100%;
387
+ box-sizing: border-box;
388
+ overflow: visible;
389
+ }
390
+
391
+ .report-prompt-panel.is-compact {
392
+ height: auto;
393
+ align-self: flex-start;
394
+ }
395
+
396
+ .report-prompt-panel > :deep(.report-collapsible-section:last-child:not(.is-collapsed)) {
397
+ flex: 1;
398
+ display: flex;
399
+ flex-direction: column;
400
+ min-height: 0;
401
+ }
402
+
403
+ .report-prompt-panel
404
+ > :deep(
405
+ .report-collapsible-section:last-child:not(.is-collapsed) .report-collapsible-section__body
406
+ ) {
407
+ flex: 1;
408
+ display: flex;
409
+ flex-direction: column;
410
+ min-height: 0;
411
+ }
412
+
413
+ .report-prompt-panel :deep(.report-collapsible-section__toggle) {
414
+ border-bottom: none;
415
+ }
416
+
417
+ .report-prompt-panel
418
+ :deep(.report-collapsible-section.is-collapsed .report-collapsible-section__toggle) {
419
+ padding-bottom: 0;
420
+ }
421
+
422
+ .report-prompt-panel__content {
423
+ display: flex;
424
+ flex-direction: column;
425
+ gap: 8px;
426
+ min-width: 0;
427
+ }
428
+
429
+ .report-prompt-panel__prompt :deep(.gen-ai-prompt-field__label) {
430
+ display: none;
431
+ }
432
+
433
+ .report-prompt-panel__prompt :deep(.gen-ai-prompt-field--row) {
434
+ grid-template-columns: minmax(0, 1fr);
435
+ }
436
+
437
+ .report-prompt-panel__prompt :deep(.gen-ai-prompt-field__count) {
438
+ margin-top: 2px;
439
+ }
440
+
441
+ .report-prompt-panel__options {
442
+ display: flex;
443
+ flex-direction: column;
444
+ gap: 8px;
445
+ }
446
+
447
+ .report-prompt-panel__option-group {
448
+ display: flex;
449
+ flex-direction: column;
450
+ gap: 6px;
451
+ }
452
+
453
+ .report-prompt-panel__option-header {
454
+ display: flex;
455
+ align-items: center;
456
+ justify-content: space-between;
457
+ gap: 8px;
458
+ min-width: 0;
459
+ }
460
+
461
+ .report-prompt-panel__fold-toggle {
462
+ display: inline-flex;
463
+ align-items: center;
464
+ justify-content: center;
465
+ flex-shrink: 0;
466
+ width: 24px;
467
+ height: 24px;
468
+ margin: 0;
469
+ padding: 0;
470
+ border: 0;
471
+ background: none;
472
+ cursor: pointer;
473
+ }
474
+
475
+ .report-prompt-panel__fold-arrow {
476
+ display: inline-block;
477
+ width: 0;
478
+ height: 0;
479
+ border-left: 5px solid transparent;
480
+ border-right: 5px solid transparent;
481
+ border-bottom: 7px solid #c53355;
482
+ transition: transform 0.2s ease;
483
+ }
484
+
485
+ .report-prompt-panel__fold-arrow.is-open {
486
+ transform: rotate(180deg);
487
+ }
488
+
489
+ .report-prompt-panel__option {
490
+ display: inline-flex;
491
+ align-items: center;
492
+ gap: 8px;
493
+ cursor: pointer;
494
+ user-select: none;
495
+ }
496
+
497
+ .report-prompt-panel__option--inline {
498
+ flex-wrap: wrap;
499
+ }
500
+
501
+ .report-prompt-panel__checkbox {
502
+ width: 14px;
503
+ height: 14px;
504
+ margin: 0;
505
+ accent-color: #c53355;
506
+ flex-shrink: 0;
507
+ }
508
+
509
+ .report-prompt-panel__option-label {
510
+ font-size: 13px;
511
+ font-weight: 500;
512
+ color: #303133;
513
+ }
514
+
515
+ .report-prompt-panel__option-suffix {
516
+ font-size: 13px;
517
+ color: #606266;
518
+ }
519
+
520
+ .report-prompt-panel__number-input {
521
+ width: 64px;
522
+ height: 28px;
523
+ padding: 2px 8px;
524
+ border: 1px solid #dcdfe6;
525
+ border-radius: 4px;
526
+ font-size: 13px;
527
+ color: #303133;
528
+ box-sizing: border-box;
529
+ }
530
+
531
+ .report-prompt-panel__number-input:disabled {
532
+ background: #f5f7fa;
533
+ color: #c0c4cc;
534
+ cursor: not-allowed;
535
+ }
536
+
537
+ .report-prompt-panel__nested {
538
+ display: flex;
539
+ flex-direction: column;
540
+ gap: 8px;
541
+ }
542
+
543
+ .report-prompt-panel__details {
544
+ display: flex;
545
+ flex-direction: column;
546
+ gap: 8px;
547
+ }
548
+
549
+ .report-prompt-panel__option-group--nested {
550
+ margin-top: 0;
551
+ }
552
+
553
+ .report-prompt-panel__field {
554
+ display: flex;
555
+ flex-direction: column;
556
+ gap: 4px;
557
+ }
558
+
559
+ .report-prompt-panel__field-label {
560
+ font-size: 13px;
561
+ color: #606266;
562
+ }
563
+
564
+ .report-prompt-panel__input :deep(.el-input__wrapper),
565
+ .report-prompt-panel__textarea :deep(.el-textarea__inner) {
566
+ border-radius: 4px;
567
+ font-size: 13px;
568
+ }
569
+
570
+ .report-prompt-panel__textarea :deep(.el-textarea__inner) {
571
+ min-height: 72px;
572
+ line-height: 1.6;
573
+ }
574
+
575
+ .report-prompt-panel__actions {
576
+ display: flex;
577
+ justify-content: center;
578
+ padding-top: 8px;
579
+ }
580
+
581
+ .app-btn {
582
+ display: inline-flex;
583
+ align-items: center;
584
+ justify-content: center;
585
+ box-sizing: border-box;
586
+ width: 160px;
587
+ height: 39px;
588
+ min-width: 160px;
589
+ padding: 0;
590
+ border: 1px solid #c53355;
591
+ border-radius: 4px;
592
+ background: #c53355;
593
+ color: #fff;
594
+ font-size: 14px;
595
+ font-weight: 600;
596
+ line-height: 1;
597
+ cursor: pointer;
598
+ }
599
+
600
+ .app-btn:hover:not(:disabled) {
601
+ background: #fff;
602
+ color: #c53355;
603
+ }
604
+
605
+ .app-btn:disabled {
606
+ opacity: 0.45;
607
+ cursor: not-allowed;
608
+ }
609
+
610
+ .app-btn--wide {
611
+ width: 160px;
612
+ min-width: 160px;
613
+ }
614
+ </style>