aegon-dangerious 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 (32) hide show
  1. package/build-report/components/AiPromptGenerateDialog.vue +349 -0
  2. package/build-report/components/CapsuleScrollbar.vue +145 -0
  3. package/build-report/components/ChapterTitleScroll.vue +292 -0
  4. package/build-report/components/PromptField.vue +314 -0
  5. package/build-report/components/RecentReportsTable.vue +408 -0
  6. package/build-report/components/ReportChapterPreview.vue +437 -0
  7. package/build-report/components/ReportChapterWorkspace.vue +923 -0
  8. package/build-report/components/ReportCollapsibleSection.vue +132 -0
  9. package/build-report/components/ReportConfigPanel.vue +609 -0
  10. package/build-report/components/ReportGenerateSettingsPanel.vue +403 -0
  11. package/build-report/components/ReportGeneratingPanel.vue +908 -0
  12. package/build-report/components/ReportHistoryList.vue +157 -0
  13. package/build-report/components/ReportHistoryPanel.vue +140 -0
  14. package/build-report/components/ReportPromptPanel.vue +445 -0
  15. package/build-report/components/ReportSectionConfirmPopover.vue +232 -0
  16. package/build-report/components/ReportSourceFileSummary.vue +544 -0
  17. package/build-report/components/ReportSourcesMoreOverlay.vue +279 -0
  18. package/build-report/components/ReportSourcesPanel.vue +1055 -0
  19. package/build-report/components/ReportTemplateDetail.vue +176 -0
  20. package/build-report/components/ReportTemplateEditorFormPanel.vue +602 -0
  21. package/build-report/components/ReportTemplatePicker.vue +802 -0
  22. package/build-report/components/ReportTemplatePromptField.vue +314 -0
  23. package/build-report/components/ReportWorkflowSidebar.vue +104 -0
  24. package/build-report/components/reportEdit.vue +334 -0
  25. package/build-report/index.vue +646 -0
  26. package/build-report/report-list.vue +407 -0
  27. package/build-report/report-template-data.ts +248 -0
  28. package/build-report/styles/report-workflow-dialog.css +33 -0
  29. package/build-report/useReportWorkflow.ts +343 -0
  30. package/build-report/utils/report-edit-route.ts +109 -0
  31. package/build-report/utils/scroll.ts +361 -0
  32. package/package.json +12 -0
@@ -0,0 +1,923 @@
1
+ <template>
2
+ <section class="report-chapter-workspace">
3
+ <header class="report-chapter-workspace__toolbar">
4
+ <div v-if="isReportSettingsMode" class="report-chapter-workspace__chapter-box">
5
+ <el-button class="chatbot-report-btn-outline" @click="handleBackToChapterEdit">
6
+ 返回章节编辑
7
+ </el-button>
8
+ </div>
9
+
10
+ <div v-else ref="chapterBoxRef" class="report-chapter-workspace__chapter-box">
11
+ <div class="report-chapter-workspace__trigger-wrap">
12
+ <button type="button" class="report-chapter-workspace__chapter-trigger"
13
+ :class="{ 'is-open': chapterPanelOpen }" @click="toggleChapterPanel">
14
+ <span class="report-chapter-workspace__chapter-trigger-text">{{ activeChapterTitle }}</span>
15
+ <el-icon class="report-chapter-workspace__chapter-trigger-arrow">
16
+ <ArrowDown />
17
+ </el-icon>
18
+ </button>
19
+
20
+ <div v-show="chapterPanelOpen" class="report-chapter-workspace__chapter-panel">
21
+ <div class="report-chapter-workspace__chapter-list-wrap">
22
+ <ul class="report-chapter-workspace__chapter-list">
23
+ <li v-for="(title, index) in chapterTitles" :key="`${title}-${index}`"
24
+ class="report-chapter-workspace__chapter-item">
25
+ <button type="button" class="report-chapter-workspace__chapter-item-btn"
26
+ @click="selectChapterFromList(index)">
27
+ <span class="report-chapter-workspace__chapter-item-title"
28
+ :class="{ 'is-active': index === activeChapterIndex }">
29
+ {{ title }}
30
+ </span>
31
+ <span class="report-chapter-workspace__chapter-item-status">{{ getChapterStatus(index) }}</span>
32
+ </button>
33
+ </li>
34
+ </ul>
35
+ </div>
36
+
37
+ <div class="report-chapter-workspace__chapter-list-footer">
38
+ <button type="button" class="report-chapter-workspace__chapter-list-action" @click="openAddChapterDialog">
39
+ + 新增章節
40
+ </button>
41
+ <button type="button" class="report-chapter-workspace__chapter-list-action" @click="openSortChapterDialog">
42
+ 章節排序
43
+ </button>
44
+ </div>
45
+ </div>
46
+ </div>
47
+ </div>
48
+
49
+ <div class="report-chapter-workspace__toolbar-right">
50
+ <template v-if="isReportSettingsMode">
51
+ <el-button class="chatbot-report-btn-primary" @click="handleApplyCreateTemplate">
52
+ 申请创建模板
53
+ </el-button>
54
+ <el-button class="chatbot-report-btn-primary chatbot-report-btn-primary--wide" @click="handleViewCoherenceCheck">
55
+ 查看报告连贯性检查结果
56
+ </el-button>
57
+ <el-button class="chatbot-report-btn-primary" @click="handleExportWord">
58
+ 导出为 word
59
+ </el-button>
60
+ </template>
61
+
62
+ <template v-else>
63
+ <button
64
+ v-if="chapterEditMode"
65
+ type="button"
66
+ class="template-center-toolbar-btn gen-ai-action-btn template-center-toolbar-btn--outline template-center-toolbar-btn--wide"
67
+ @click="handleCancelEdit"
68
+ >
69
+ 取消
70
+ </button>
71
+ <button
72
+ type="button"
73
+ class="template-center-toolbar-btn gen-ai-action-btn template-center-toolbar-btn--primary template-center-toolbar-btn--wide"
74
+ :disabled="!canEditReport"
75
+ @click="handleEditSave"
76
+ >
77
+ {{ chapterEditMode ? '保存' : '編輯/保存' }}
78
+ </button>
79
+ <button
80
+ type="button"
81
+ class="template-center-toolbar-btn gen-ai-action-btn template-center-toolbar-btn--primary template-center-toolbar-btn--wide"
82
+ @click="handleGenerateReport"
83
+ >
84
+ 生成報告
85
+ </button>
86
+ </template>
87
+ </div>
88
+ </header>
89
+
90
+ <div class="report-chapter-workspace__editor">
91
+ <ReportChapterPreview
92
+ :key="editorKey"
93
+ :chapter-title="activeChapterTitle"
94
+ :chapter-intro="activeChapterIntro"
95
+ />
96
+ </div>
97
+
98
+ <el-dialog v-model="chapterDialogVisible" width="60%" append-to-body :show-close="false"
99
+ modal-class="report-workflow-dialog-overlay" class="report-workflow-dialog report-chapter-dialog"
100
+ header-class="report-chapter-dialog__header" @closed="handleChapterDialogClosed">
101
+ <template #header>
102
+ <span class="report-chapter-dialog__title">{{ chapterDialogTitle }}</span>
103
+ </template>
104
+
105
+ <div v-if="chapterDialogMode === 'add'" class="report-chapter-dialog__form">
106
+ <label class="report-chapter-dialog__field report-chapter-dialog__field--row">
107
+ <span class="report-chapter-dialog__label">
108
+ 章節標題<span class="report-chapter-dialog__required">*</span>
109
+ </span>
110
+ <div class="report-chapter-dialog__control">
111
+ <el-input v-model="newChapterForm.title" :maxlength="CHAPTER_TITLE_MAX" show-word-limit
112
+ class="report-chapter-dialog__input" />
113
+ </div>
114
+ </label>
115
+
116
+ <label class="report-chapter-dialog__field report-chapter-dialog__field--row report-chapter-dialog__field--textarea">
117
+ <span class="report-chapter-dialog__label">
118
+ 章節描述<span class="report-chapter-dialog__required">*</span>
119
+ </span>
120
+ <div class="report-chapter-dialog__control">
121
+ <el-input v-model="newChapterForm.description" type="textarea" :rows="4" :maxlength="CHAPTER_DESC_MAX"
122
+ show-word-limit resize="none" class="report-chapter-dialog__textarea" />
123
+ </div>
124
+ </label>
125
+
126
+ <ReportTemplatePromptField v-model="newChapterForm.prompt" :maxlength="CHAPTER_PROMPT_MAX" :rows="6"
127
+ label-width="100px" field-gap="16px" layout="row" :chapter-title="newChapterForm.title"
128
+ :chapter-description="newChapterForm.description" />
129
+ </div>
130
+
131
+ <div v-else class="report-chapter-dialog__sort">
132
+ <div class="report-chapter-workspace__sort-list-wrap report-chapter-dialog__sort-list-wrap">
133
+ <ul ref="sortListRef" class="report-chapter-workspace__sort-list">
134
+ <li v-for="(title, index) in draftChapterTitles" :key="`${title}-${index}`"
135
+ class="report-chapter-workspace__sort-item">
136
+ <span class="report-chapter-workspace__sort-handle" aria-hidden="true">
137
+ <el-icon>
138
+ <Sort />
139
+ </el-icon>
140
+ </span>
141
+ <div class="report-chapter-workspace__sort-label" @click="draftActiveIndex = index">
142
+ <ChapterTitleScroll root-tag="div" :title="title" :active="index === draftActiveIndex" />
143
+ </div>
144
+ </li>
145
+ </ul>
146
+ </div>
147
+ </div>
148
+
149
+ <template #footer>
150
+ <div class="report-chapter-dialog__footer">
151
+ <button type="button"
152
+ class="template-center-toolbar-btn gen-ai-action-btn template-center-toolbar-btn--outline report-chapter-dialog__footer-btn"
153
+ @click="closeChapterDialog">
154
+ 取消
155
+ </button>
156
+ <button v-if="chapterDialogMode === 'add'" type="button"
157
+ class="template-center-toolbar-btn gen-ai-action-btn template-center-toolbar-btn--primary report-chapter-dialog__footer-btn"
158
+ @click="handleAddChapterSubmit">
159
+ 提交並生成章節內容
160
+ </button>
161
+ <button v-else type="button"
162
+ class="template-center-toolbar-btn gen-ai-action-btn template-center-toolbar-btn--primary report-chapter-dialog__footer-btn"
163
+ @click="handleSortConfirm">
164
+ 確定
165
+ </button>
166
+ </div>
167
+ </template>
168
+ </el-dialog>
169
+ </section>
170
+ </template>
171
+
172
+ <script setup lang="ts">
173
+ import { ArrowDown, Sort } from '@element-plus/icons-vue'
174
+ import { onClickOutside } from '@vueuse/core'
175
+ import { ElButton, ElDialog, ElIcon, ElInput, ElMessage, ElMessageBox } from 'element-plus'
176
+ import Sortable from 'sortablejs'
177
+ import { computed, nextTick, reactive, ref, watch } from 'vue'
178
+ import ReportChapterPreview from './ReportChapterPreview.vue'
179
+ import ChapterTitleScroll from './ChapterTitleScroll.vue'
180
+ import ReportTemplatePromptField from './ReportTemplatePromptField.vue'
181
+ import { useReportWorkflow } from '../useReportWorkflow'
182
+
183
+ const CHAPTER_PANEL_MAX_ROWS = 14
184
+ const CHAPTER_PANEL_ROW_HEIGHT = 40
185
+ const DEMO_EDITING_CHAPTER_INDEX = 2
186
+ const CHAPTER_TITLE_MAX = 100
187
+ const CHAPTER_DESC_MAX = 1000
188
+ const CHAPTER_PROMPT_MAX = 1300
189
+
190
+ const INITIAL_CHAPTER_TITLES = [
191
+ '摘要與本年結論',
192
+ '行業概覽與景氣判斷',
193
+ '核心風險指標快照',
194
+ '驅動因素拆解',
195
+ '風險點與預警信號',
196
+ '風控建議與跟進清單',
197
+ '附錄:參考資料與口徑',
198
+ ]
199
+
200
+ type ChapterDialogMode = 'add' | 'sort'
201
+
202
+ const {
203
+ draft,
204
+ generatedChapterBodies,
205
+ canEditReport,
206
+ sourceFiles,
207
+ promptRightPanel,
208
+ chapterEditMode,
209
+ enterChapterEditMode,
210
+ commitChapterEdit,
211
+ exitChapterEditMode,
212
+ isChapterEditDirty,
213
+ } = useReportWorkflow()
214
+
215
+ const isReportSettingsMode = computed(() => promptRightPanel.value === 'settings')
216
+
217
+ const emit = defineEmits<{
218
+ 'generate-report': []
219
+ 'back-to-chapter-edit': []
220
+ }>()
221
+
222
+ const chapterTitles = ref<string[]>([...INITIAL_CHAPTER_TITLES])
223
+ const activeChapterIndex = ref(0)
224
+
225
+ const chapterBoxRef = ref<HTMLElement | null>(null)
226
+ const chapterPanelOpen = ref(false)
227
+ const chapterDialogVisible = ref(false)
228
+ const chapterDialogMode = ref<ChapterDialogMode>('add')
229
+ const draftChapterTitles = ref<string[]>([])
230
+ const draftActiveIndex = ref(0)
231
+ const sortListRef = ref<HTMLElement | null>(null)
232
+ const newChapterForm = reactive({
233
+ title: '',
234
+ description: '',
235
+ prompt: '',
236
+ })
237
+ let sortableInstance: Sortable | null = null
238
+
239
+ const chapterDialogTitle = computed(() =>
240
+ chapterDialogMode.value === 'add' ? '新增章節' : '章節排序',
241
+ )
242
+
243
+ onClickOutside(chapterBoxRef, () => {
244
+ if (chapterPanelOpen.value) closeChapterPanel()
245
+ })
246
+
247
+ watch(
248
+ () => chapterTitles.value.length,
249
+ (length) => {
250
+ if (activeChapterIndex.value >= length) {
251
+ activeChapterIndex.value = Math.max(0, length - 1)
252
+ }
253
+ },
254
+ )
255
+
256
+ const activeChapterTitle = computed(
257
+ () => chapterTitles.value[activeChapterIndex.value] ?? '章節內容',
258
+ )
259
+
260
+ function stripHtml(value: string) {
261
+ return value.replace(/<[^>]+>/g, '').trim()
262
+ }
263
+
264
+ const activeChapterIntro = computed(() => {
265
+ const index = activeChapterIndex.value
266
+ const generated = generatedChapterBodies.value[index]
267
+ if (generated) return stripHtml(generated)
268
+
269
+ if (index === 0) {
270
+ return `本報告基於「${draft.industry || '目標行業'}」${draft.year}年度調研,從${draft.researchFocus || '核心視角'}出發,對行業風險進行系統性梳理。整體風險可控,但需持續關注景氣波動與政策調整帶來的傳導效應。`
271
+ }
272
+
273
+ return '本章節內容將根據右側 Prompt 配置與資訊源生成。當前展示為演示 Mock 正文,用於預覽打字機輸出與表格排版效果。'
274
+ })
275
+
276
+ const editorKey = computed(
277
+ () => `${activeChapterIndex.value}-${activeChapterTitle.value}-${chapterEditMode.value ? 'edit' : 'view'}`,
278
+ )
279
+
280
+ const sortListMaxHeight = `${CHAPTER_PANEL_MAX_ROWS * CHAPTER_PANEL_ROW_HEIGHT}px`
281
+
282
+ function destroySortable() {
283
+ sortableInstance?.destroy()
284
+ sortableInstance = null
285
+ }
286
+
287
+ function initSortable() {
288
+ destroySortable()
289
+ if (!sortListRef.value) return
290
+
291
+ sortableInstance = Sortable.create(sortListRef.value, {
292
+ handle: '.report-chapter-workspace__sort-handle',
293
+ animation: 150,
294
+ onEnd({ oldIndex, newIndex }) {
295
+ if (oldIndex == null || newIndex == null || oldIndex === newIndex) return
296
+
297
+ const next = [...draftChapterTitles.value]
298
+ const [moved] = next.splice(oldIndex, 1)
299
+ next.splice(newIndex, 0, moved!)
300
+ draftChapterTitles.value = next
301
+
302
+ if (draftActiveIndex.value === oldIndex) {
303
+ draftActiveIndex.value = newIndex
304
+ return
305
+ }
306
+
307
+ if (oldIndex < draftActiveIndex.value && newIndex >= draftActiveIndex.value) {
308
+ draftActiveIndex.value -= 1
309
+ } else if (oldIndex > draftActiveIndex.value && newIndex <= draftActiveIndex.value) {
310
+ draftActiveIndex.value += 1
311
+ }
312
+ },
313
+ })
314
+ }
315
+
316
+ async function openChapterPanel() {
317
+ draftChapterTitles.value = [...chapterTitles.value]
318
+ draftActiveIndex.value = activeChapterIndex.value
319
+ chapterPanelOpen.value = true
320
+ }
321
+
322
+ function closeChapterPanel() {
323
+ chapterPanelOpen.value = false
324
+ }
325
+
326
+ async function toggleChapterPanel() {
327
+ if (chapterPanelOpen.value) {
328
+ closeChapterPanel()
329
+ return
330
+ }
331
+ await openChapterPanel()
332
+ }
333
+
334
+ function getChapterStatus(index: number) {
335
+ if (index === activeChapterIndex.value && chapterEditMode.value) {
336
+ return '編輯中'
337
+ }
338
+ if (index === DEMO_EDITING_CHAPTER_INDEX) {
339
+ return '編輯中'
340
+ }
341
+ return '已生成'
342
+ }
343
+
344
+ function selectChapterFromList(index: number) {
345
+ activeChapterIndex.value = index
346
+ closeChapterPanel()
347
+ }
348
+
349
+ function resetNewChapterForm() {
350
+ newChapterForm.title = ''
351
+ newChapterForm.description = ''
352
+ newChapterForm.prompt = ''
353
+ }
354
+
355
+ function openAddChapterDialog() {
356
+ closeChapterPanel()
357
+ resetNewChapterForm()
358
+ chapterDialogMode.value = 'add'
359
+ chapterDialogVisible.value = true
360
+ }
361
+
362
+ async function openSortChapterDialog() {
363
+ closeChapterPanel()
364
+ chapterDialogMode.value = 'sort'
365
+ draftChapterTitles.value = [...chapterTitles.value]
366
+ draftActiveIndex.value = activeChapterIndex.value
367
+ chapterDialogVisible.value = true
368
+ await nextTick()
369
+ initSortable()
370
+ }
371
+
372
+ function closeChapterDialog() {
373
+ chapterDialogVisible.value = false
374
+ }
375
+
376
+ function handleChapterDialogClosed() {
377
+ destroySortable()
378
+ if (chapterDialogMode.value === 'add') {
379
+ resetNewChapterForm()
380
+ }
381
+ }
382
+
383
+ function handleAddChapterSubmit() {
384
+ const title = newChapterForm.title.trim()
385
+ const description = newChapterForm.description.trim()
386
+ const prompt = newChapterForm.prompt.trim()
387
+
388
+ if (!title) {
389
+ ElMessage.warning('請輸入章節標題')
390
+ return
391
+ }
392
+ if (!description) {
393
+ ElMessage.warning('請輸入章節描述')
394
+ return
395
+ }
396
+ if (!prompt) {
397
+ ElMessage.warning('請輸入 Prompt')
398
+ return
399
+ }
400
+
401
+ chapterTitles.value = [...chapterTitles.value, title]
402
+ activeChapterIndex.value = chapterTitles.value.length - 1
403
+ closeChapterDialog()
404
+ ElMessage.success('章節已提交並生成內容(演示)')
405
+ }
406
+
407
+ function handleSortConfirm() {
408
+ chapterTitles.value = [...draftChapterTitles.value]
409
+ activeChapterIndex.value = draftActiveIndex.value
410
+ closeChapterDialog()
411
+ ElMessage.success('章節順序已更新')
412
+ }
413
+
414
+ function handleGenerateReport() {
415
+ if (!sourceFiles.value.length) {
416
+ ElMessage.warning('請至少添加一個信息源文件')
417
+ return
418
+ }
419
+ emit('generate-report')
420
+ }
421
+
422
+ function handleBackToChapterEdit() {
423
+ emit('back-to-chapter-edit')
424
+ }
425
+
426
+ function handleApplyCreateTemplate() {
427
+ ElMessage.info('申請創建模板(演示)')
428
+ }
429
+
430
+ function handleViewCoherenceCheck() {
431
+ ElMessage.info('查看報告連貫性檢查結果(演示)')
432
+ }
433
+
434
+ function handleExportWord() {
435
+ ElMessage.info('導出為 Word(演示)')
436
+ }
437
+
438
+ async function handleCancelEdit() {
439
+ if (!chapterEditMode.value) return
440
+
441
+ if (!isChapterEditDirty()) {
442
+ exitChapterEditMode(true)
443
+ return
444
+ }
445
+
446
+ try {
447
+ await ElMessageBox.confirm(
448
+ '您已修改部分內容且未保存,確定要進行「取消」的操作嗎?',
449
+ '提示',
450
+ {
451
+ confirmButtonText: '確定',
452
+ cancelButtonText: '取消',
453
+ type: 'warning',
454
+ },
455
+ )
456
+ exitChapterEditMode(true)
457
+ } catch {
458
+ // 用戶取消操作,保持編輯狀態
459
+ }
460
+ }
461
+
462
+ function handleEditSave() {
463
+ if (!chapterEditMode.value) {
464
+ enterChapterEditMode()
465
+ return
466
+ }
467
+ commitChapterEdit()
468
+ ElMessage.success('章節內容已保存')
469
+ }
470
+ </script>
471
+
472
+ <style scoped>
473
+ .report-chapter-workspace {
474
+ --report-accent: #c53355;
475
+ --report-accent-soft: #fdf0f2;
476
+ display: flex;
477
+ flex-direction: column;
478
+ gap: 12px;
479
+ min-width: 0;
480
+ flex: 1;
481
+ min-height: 0;
482
+ height: 100%;
483
+ }
484
+
485
+ .report-chapter-workspace__toolbar {
486
+ flex-shrink: 0;
487
+ display: flex;
488
+ align-items: flex-start;
489
+ justify-content: space-between;
490
+ gap: 12px;
491
+ box-sizing: border-box;
492
+ }
493
+
494
+ .report-chapter-workspace__chapter-box {
495
+ position: relative;
496
+ min-width: 0;
497
+ }
498
+
499
+ .report-chapter-workspace__toolbar-right {
500
+ display: flex;
501
+ align-items: center;
502
+ gap: 12px;
503
+ flex-shrink: 0;
504
+ }
505
+
506
+ .report-chapter-workspace__trigger-wrap {
507
+ position: relative;
508
+ min-width: 0;
509
+ }
510
+
511
+ .report-chapter-workspace__chapter-trigger {
512
+ display: inline-flex;
513
+ align-items: center;
514
+ justify-content: space-between;
515
+ gap: 12px;
516
+ width: 220px;
517
+ min-width: 180px;
518
+ height: 39px;
519
+ margin: 0;
520
+ padding: 0 12px;
521
+ border: 1px solid #dcdfe6;
522
+ border-radius: 4px;
523
+ background: #fff;
524
+ cursor: pointer;
525
+ box-sizing: border-box;
526
+ transition: border-color 0.2s ease, color 0.2s ease;
527
+ }
528
+
529
+ .report-chapter-workspace__chapter-trigger-text {
530
+ flex: 1;
531
+ min-width: 0;
532
+ overflow: hidden;
533
+ text-overflow: ellipsis;
534
+ white-space: nowrap;
535
+ text-align: left;
536
+ font-size: 14px;
537
+ font-weight: 400;
538
+ color: #606266;
539
+ transition: color 0.2s ease;
540
+ }
541
+
542
+ .report-chapter-workspace__chapter-trigger-arrow {
543
+ flex-shrink: 0;
544
+ font-size: 14px;
545
+ color: #c53355;
546
+ transition: transform 0.2s ease;
547
+ }
548
+
549
+ .report-chapter-workspace__chapter-trigger:hover,
550
+ .report-chapter-workspace__chapter-trigger.is-open {
551
+ border-color: #c53355;
552
+ }
553
+
554
+ .report-chapter-workspace__chapter-trigger:hover .report-chapter-workspace__chapter-trigger-text,
555
+ .report-chapter-workspace__chapter-trigger.is-open .report-chapter-workspace__chapter-trigger-text {
556
+ color: #c53355;
557
+ }
558
+
559
+ .report-chapter-workspace__chapter-trigger.is-open .report-chapter-workspace__chapter-trigger-arrow {
560
+ transform: rotate(180deg);
561
+ }
562
+
563
+ .report-chapter-workspace__chapter-panel {
564
+ position: absolute;
565
+ top: calc(100% + 8px);
566
+ left: 0;
567
+ z-index: 20;
568
+ width: 220px;
569
+ padding: 8px 0 10px;
570
+ border: 1px solid #dcdfe6;
571
+ border-radius: 4px;
572
+ background: #fff;
573
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
574
+ box-sizing: border-box;
575
+ }
576
+
577
+ .report-chapter-workspace__chapter-list-wrap {
578
+ max-height: v-bind(sortListMaxHeight);
579
+ overflow-y: auto;
580
+ overflow-x: hidden;
581
+ }
582
+
583
+ .report-chapter-workspace__chapter-list {
584
+ margin: 0;
585
+ padding: 0;
586
+ list-style: none;
587
+ }
588
+
589
+ .report-chapter-workspace__chapter-item {
590
+ margin: 0;
591
+ padding: 0;
592
+ }
593
+
594
+ .report-chapter-workspace__chapter-item-btn {
595
+ display: flex;
596
+ align-items: center;
597
+ justify-content: space-between;
598
+ gap: 8px;
599
+ width: 100%;
600
+ min-height: 36px;
601
+ margin: 0;
602
+ padding: 6px 12px;
603
+ border: 0;
604
+ background: transparent;
605
+ cursor: pointer;
606
+ box-sizing: border-box;
607
+ text-align: left;
608
+ transition: background-color 0.2s ease;
609
+ }
610
+
611
+ .report-chapter-workspace__chapter-item-btn:hover {
612
+ background: #f5f7fa;
613
+ }
614
+
615
+ .report-chapter-workspace__chapter-item-title {
616
+ flex: 1;
617
+ min-width: 0;
618
+ overflow: hidden;
619
+ text-overflow: ellipsis;
620
+ white-space: nowrap;
621
+ font-size: 14px;
622
+ color: #303133;
623
+ }
624
+
625
+ .report-chapter-workspace__chapter-item-title.is-active {
626
+ color: var(--report-accent);
627
+ font-weight: 600;
628
+ }
629
+
630
+ .report-chapter-workspace__chapter-item-status {
631
+ flex-shrink: 0;
632
+ font-size: 13px;
633
+ color: #909399;
634
+ white-space: nowrap;
635
+ }
636
+
637
+ .report-chapter-workspace__chapter-list-footer {
638
+ display: flex;
639
+ align-items: center;
640
+ justify-content: space-between;
641
+ gap: 8px;
642
+ margin-top: 4px;
643
+ padding: 8px 12px 0;
644
+ border-top: 1px solid #ebeef5;
645
+ }
646
+
647
+ .report-chapter-workspace__chapter-list-action {
648
+ padding: 0;
649
+ border: 0;
650
+ background: none;
651
+ font-size: 13px;
652
+ color: #409eff;
653
+ cursor: pointer;
654
+ white-space: nowrap;
655
+ }
656
+
657
+ .report-chapter-workspace__chapter-list-action:hover {
658
+ color: #66b1ff;
659
+ }
660
+
661
+ .report-chapter-workspace__sort-list-wrap {
662
+ max-height: v-bind(sortListMaxHeight);
663
+ overflow-y: auto;
664
+ overflow-x: hidden;
665
+ }
666
+
667
+ .report-chapter-dialog__sort-list-wrap {
668
+ padding: 0;
669
+ max-height: min(560px, 60vh);
670
+ }
671
+
672
+ .report-chapter-workspace__sort-list {
673
+ margin: 0;
674
+ padding: 0;
675
+ list-style: none;
676
+ }
677
+
678
+ .report-chapter-workspace__sort-item {
679
+ display: flex;
680
+ align-items: center;
681
+ gap: 10px;
682
+ min-height: 36px;
683
+ padding: 2px 0;
684
+ }
685
+
686
+ .report-chapter-workspace__sort-handle {
687
+ display: inline-flex;
688
+ align-items: center;
689
+ justify-content: center;
690
+ flex-shrink: 0;
691
+ width: 20px;
692
+ color: #909399;
693
+ cursor: grab;
694
+ }
695
+
696
+ .report-chapter-workspace__sort-handle:active {
697
+ cursor: grabbing;
698
+ }
699
+
700
+ .report-chapter-workspace__sort-label {
701
+ flex: 1;
702
+ min-width: 0;
703
+ cursor: pointer;
704
+ }
705
+
706
+ .report-chapter-workspace__sort-label :deep(.chapter-title-scroll) {
707
+ width: 100%;
708
+ }
709
+
710
+ .report-chapter-workspace__editor {
711
+ flex: 1;
712
+ min-height: 420px;
713
+ border-radius: 8px;
714
+ overflow: hidden;
715
+ display: flex;
716
+ flex-direction: column;
717
+ background: #fff;
718
+ }
719
+
720
+ .gen-ai-action-btn,
721
+ .template-center-toolbar-btn {
722
+ font-size: 15px;
723
+ font-family: Arial, sans-serif;
724
+ font-weight: 400;
725
+ }
726
+
727
+ .template-center-toolbar-btn {
728
+ display: inline-flex;
729
+ align-items: center;
730
+ justify-content: center;
731
+ gap: 6px;
732
+ box-sizing: border-box;
733
+ height: 32px;
734
+ min-width: 120px;
735
+ padding: 0 14px;
736
+ border-radius: 4px;
737
+ line-height: 1;
738
+ white-space: nowrap;
739
+ cursor: pointer;
740
+ transition: all 0.2s ease;
741
+ }
742
+
743
+ .template-center-toolbar-btn--wide {
744
+ min-width: 160px;
745
+ }
746
+
747
+ .template-center-toolbar-btn:disabled {
748
+ opacity: 0.45;
749
+ cursor: not-allowed;
750
+ }
751
+
752
+ .template-center-toolbar-btn--primary {
753
+ border: 1px solid var(--report-accent);
754
+ background: var(--report-accent);
755
+ color: #fff;
756
+ }
757
+
758
+ .template-center-toolbar-btn--primary:hover:not(:disabled) {
759
+ background: #fff;
760
+ border-color: var(--report-accent);
761
+ color: var(--report-accent);
762
+ }
763
+
764
+ .template-center-toolbar-btn--outline {
765
+ border: 1px solid var(--report-accent);
766
+ color: var(--report-accent);
767
+ background: #fff;
768
+ }
769
+
770
+ .template-center-toolbar-btn--outline:hover:not(:disabled) {
771
+ border-color: var(--report-accent);
772
+ color: var(--report-accent);
773
+ background: var(--report-accent-soft);
774
+ }
775
+
776
+ .chatbot-report-btn-outline.el-button,
777
+ .chatbot-report-btn-primary.el-button {
778
+ height: 32px !important;
779
+ padding-inline: 14px !important;
780
+ border-radius: 4px !important;
781
+ font-size: 15px !important;
782
+ font-family: Arial, sans-serif !important;
783
+ font-weight: 400;
784
+ }
785
+
786
+ .chatbot-report-btn-outline.el-button {
787
+ border: 1px solid var(--report-accent) !important;
788
+ color: var(--report-accent) !important;
789
+ background: #fff !important;
790
+ }
791
+
792
+ .chatbot-report-btn-outline.el-button:hover {
793
+ background: var(--report-accent-soft) !important;
794
+ color: var(--report-accent) !important;
795
+ border-color: var(--report-accent) !important;
796
+ }
797
+
798
+ .chatbot-report-btn-outline--wide.el-button {
799
+ min-width: 0;
800
+ max-width: 220px;
801
+ white-space: normal;
802
+ line-height: 1.3;
803
+ height: auto !important;
804
+ min-height: 32px;
805
+ padding-block: 6px !important;
806
+ }
807
+
808
+ .chatbot-report-btn-primary.el-button {
809
+ border: 1px solid var(--report-accent) !important;
810
+ background: var(--report-accent) !important;
811
+ color: #fff !important;
812
+ }
813
+
814
+ .chatbot-report-btn-primary.el-button:hover {
815
+ background: #fff !important;
816
+ color: var(--report-accent) !important;
817
+ border-color: var(--report-accent) !important;
818
+ }
819
+
820
+ .chatbot-report-btn-primary--wide.el-button {
821
+ min-width: 0;
822
+ max-width: 220px;
823
+ white-space: normal;
824
+ line-height: 1.3;
825
+ height: auto !important;
826
+ min-height: 32px;
827
+ padding-block: 6px !important;
828
+ }
829
+ </style>
830
+
831
+ <style>
832
+ .report-chapter-dialog.el-dialog {
833
+ --el-dialog-padding-primary: 0;
834
+ border-radius: 4px;
835
+ overflow: hidden;
836
+ }
837
+
838
+ .report-chapter-dialog .el-dialog__header,
839
+ .report-chapter-dialog__header {
840
+ display: flex;
841
+ align-items: center;
842
+ justify-content: center;
843
+ margin: 0;
844
+ padding: 14px 20px;
845
+ background: #4a5f7a;
846
+ }
847
+
848
+ .report-chapter-dialog__title,
849
+ .report-chapter-dialog .el-dialog__title {
850
+ color: #fff;
851
+ font-size: 16px;
852
+ font-weight: 600;
853
+ line-height: 1.4;
854
+ }
855
+
856
+ .report-chapter-dialog .el-dialog__body {
857
+ padding: 24px 20px;
858
+ background: #fff;
859
+ }
860
+
861
+ .report-chapter-dialog .el-dialog__footer {
862
+ padding: 12px 16px 16px;
863
+ background: #fff;
864
+ display: flex;
865
+ justify-content: center;
866
+ }
867
+
868
+ .report-chapter-dialog__form {
869
+ display: flex;
870
+ flex-direction: column;
871
+ gap: 18px;
872
+ }
873
+
874
+ .report-chapter-dialog__field {
875
+ margin: 0;
876
+ }
877
+
878
+ .report-chapter-dialog__field--row {
879
+ display: grid;
880
+ grid-template-columns: 100px minmax(0, 1fr);
881
+ gap: 16px;
882
+ align-items: start;
883
+ }
884
+
885
+ .report-chapter-dialog__field--textarea {
886
+ align-items: start;
887
+ }
888
+
889
+ .report-chapter-dialog__label {
890
+ padding-top: 8px;
891
+ font-size: 14px;
892
+ color: #303133;
893
+ line-height: 1.4;
894
+ white-space: nowrap;
895
+ }
896
+
897
+ .report-chapter-dialog__required {
898
+ color: #c53355;
899
+ }
900
+
901
+ .report-chapter-dialog__control {
902
+ min-width: 0;
903
+ }
904
+
905
+ .report-chapter-dialog__input :deep(.el-input__wrapper),
906
+ .report-chapter-dialog__textarea :deep(.el-textarea__inner) {
907
+ border-radius: 2px;
908
+ }
909
+
910
+ .report-chapter-dialog__footer {
911
+ display: flex;
912
+ align-items: center;
913
+ justify-content: center;
914
+ gap: 16px;
915
+ width: 100%;
916
+ }
917
+
918
+ .report-chapter-dialog__footer-btn {
919
+ min-width: 140px;
920
+ }
921
+ </style>
922
+
923
+ <style src="../styles/report-workflow-dialog.css"></style>