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,2283 @@
1
+ <template>
2
+ <div
3
+ ref="pageRef"
4
+ class="report-edit-page"
5
+ :class="{
6
+ 'is-generating': pageContentOpen && flowShowGenerating,
7
+ 'is-prompt': pageContentOpen && flowShowPromptWorkspace,
8
+ 'is-select': pageContentOpen && flowStep === 'select',
9
+ 'is-detail': pageContentOpen && flowStep === 'detail',
10
+ 'is-sidebar-collapsed': sidebarCollapsed && !isStackedLayout,
11
+ 'is-prompt-collapsed': promptCollapsed && !isStackedLayout,
12
+ 'is-stacked': isStackedLayout,
13
+ 'is-content-closed': !pageContentOpen,
14
+ }"
15
+ >
16
+ <!-- pageContentOpen / remountKey:流程點擊後強制整樹重掛,與路由對齊 -->
17
+ <div v-if="pageContentOpen" :key="remountKey" class="report-edit-page__surface">
18
+ <ReportGeneratingPanel
19
+ v-if="flowShowGenerating"
20
+ class="report-edit-page__generating"
21
+ @enter-editing="handleEnterEditing"
22
+ />
23
+
24
+ <!-- 側欄常駐:生成步驟僅隱藏,避免反覆掛載重拉組件資訊 -->
25
+ <div
26
+ v-show="!flowShowGenerating"
27
+ ref="sidebarSlotRef"
28
+ class="report-edit-page__sidebar-slot"
29
+ :class="{
30
+ 'is-collapsed': sidebarCollapsed && !isStackedLayout,
31
+ 'is-col-overflow': sidebarOverflow,
32
+ }"
33
+ @mouseenter="onSidebarSlotEnter"
34
+ @mouseleave="onSidebarSlotLeave"
35
+ >
36
+ <el-scrollbar
37
+ v-show="!sidebarCollapsed || isStackedLayout"
38
+ class="report-edit-page__col-scroll"
39
+ :min-size="50"
40
+ >
41
+ <ReportWorkflowSidebar
42
+ class="report-edit-page__sidebar"
43
+ :collapsed="sidebarCollapsed && !isStackedLayout"
44
+ />
45
+ </el-scrollbar>
46
+ <div
47
+ class="report-edit-page__side-thumb-track"
48
+ :class="{ 'is-visible': sidebarThumbShow }"
49
+ aria-hidden="true"
50
+ >
51
+ <div
52
+ class="report-edit-page__side-thumb"
53
+ :style="{
54
+ height: `${sidebarThumbH}px`,
55
+ transform: `translateY(${sidebarThumbY}px)`,
56
+ }"
57
+ @mousedown.prevent="onSideThumbDown('sidebar', $event)"
58
+ />
59
+ </div>
60
+ </div>
61
+
62
+ <template v-if="!flowShowGenerating">
63
+ <main
64
+ ref="mainRef"
65
+ class="report-edit-page__main report-edit-page__main--anchored"
66
+ :class="{
67
+ 'is-typewriting': mainColScrollbarAlways,
68
+ 'is-main-scrollbar-visible': mainCustomThumbShow,
69
+ }"
70
+ @mouseenter="onMainColEnter"
71
+ @mouseleave="onMainColLeave"
72
+ >
73
+ <!-- 左/右開關:窄屏堆疊時隱藏 -->
74
+ <button
75
+ v-show="!isStackedLayout"
76
+ type="button"
77
+ class="report-edit-page__col-divider report-edit-page__col-divider--left"
78
+ :aria-expanded="!sidebarCollapsed"
79
+ :aria-label="sidebarCollapsed ? '展開左側欄' : '收起左側欄'"
80
+ @click="sidebarCollapsed = !sidebarCollapsed"
81
+ >
82
+ <el-icon :size="14">
83
+ <DArrowLeft v-if="!sidebarCollapsed" />
84
+ <DArrowRight v-else />
85
+ </el-icon>
86
+ </button>
87
+
88
+ <button
89
+ v-if="flowShowPromptWorkspace"
90
+ v-show="!isStackedLayout"
91
+ type="button"
92
+ class="report-edit-page__col-divider report-edit-page__col-divider--right"
93
+ :aria-expanded="!promptCollapsed"
94
+ :aria-label="promptCollapsed ? '展開右側欄' : '收起右側欄'"
95
+ @click="promptCollapsed = !promptCollapsed"
96
+ >
97
+ <el-icon :size="14">
98
+ <DArrowRight v-if="!promptCollapsed" />
99
+ <DArrowLeft v-else />
100
+ </el-icon>
101
+ </button>
102
+
103
+ <el-scrollbar class="report-edit-page__col-scroll">
104
+ <KeepAlive>
105
+ <ReportTemplatePicker v-if="flowShowSelect" @select="handleSelectTemplate" />
106
+ </KeepAlive>
107
+
108
+ <ReportTemplateDetail
109
+ v-if="flowShowDetail"
110
+ :template="selectedTemplate!"
111
+ @back="goBackToSelect"
112
+ @generate="enterChapterEdit"
113
+ />
114
+
115
+ <!-- prompt:先畫與實頁一致的工具列靜態內容,再掛載重型工作區 -->
116
+ <template v-if="flowShowPromptWorkspace">
117
+ <Suspense v-if="promptHeavyReady">
118
+ <ReportChapterWorkspace
119
+ @back-to-chapter-edit="backToChapterEdit"
120
+ @generate-report="handleGenerateReportNavigate"
121
+ />
122
+ <template #fallback>
123
+ <section
124
+ class="report-edit-prompt-shell report-edit-prompt-shell--main"
125
+ aria-hidden="true"
126
+ >
127
+ <header class="report-edit-prompt-shell__toolbar">
128
+ <div class="report-edit-prompt-shell__select" tabindex="-1">
129
+ <span class="report-edit-prompt-shell__select-text">{{
130
+ promptShellChapterLabel
131
+ }}</span>
132
+ <span class="report-edit-prompt-shell__select-caret" aria-hidden="true" />
133
+ </div>
134
+ <div class="report-edit-prompt-shell__actions">
135
+ <button
136
+ type="button"
137
+ class="report-edit-prompt-shell__action-btn"
138
+ disabled
139
+ tabindex="-1"
140
+ >
141
+ 編輯/儲存
142
+ </button>
143
+ <button
144
+ type="button"
145
+ class="report-edit-prompt-shell__action-btn"
146
+ disabled
147
+ tabindex="-1"
148
+ >
149
+ 生成報告
150
+ </button>
151
+ </div>
152
+ </header>
153
+ <div class="report-edit-prompt-shell__editor">
154
+ <div class="report-edit-prompt-shell__title" />
155
+ <div class="report-edit-prompt-shell__line" />
156
+ <div
157
+ class="report-edit-prompt-shell__line report-edit-prompt-shell__line--short"
158
+ />
159
+ <div class="report-edit-prompt-shell__line" />
160
+ <div
161
+ class="report-edit-prompt-shell__line report-edit-prompt-shell__line--mid"
162
+ />
163
+ </div>
164
+ </section>
165
+ </template>
166
+ </Suspense>
167
+ <section
168
+ v-else
169
+ class="report-edit-prompt-shell report-edit-prompt-shell--main"
170
+ aria-hidden="true"
171
+ >
172
+ <header class="report-edit-prompt-shell__toolbar">
173
+ <div class="report-edit-prompt-shell__select" tabindex="-1">
174
+ <span class="report-edit-prompt-shell__select-text">{{
175
+ promptShellChapterLabel
176
+ }}</span>
177
+ <span class="report-edit-prompt-shell__select-caret" aria-hidden="true" />
178
+ </div>
179
+ <div class="report-edit-prompt-shell__actions">
180
+ <button
181
+ type="button"
182
+ class="report-edit-prompt-shell__action-btn"
183
+ disabled
184
+ tabindex="-1"
185
+ >
186
+ 編輯/儲存
187
+ </button>
188
+ <button
189
+ type="button"
190
+ class="report-edit-prompt-shell__action-btn"
191
+ disabled
192
+ tabindex="-1"
193
+ >
194
+ 生成報告
195
+ </button>
196
+ </div>
197
+ </header>
198
+ <div class="report-edit-prompt-shell__editor">
199
+ <div class="report-edit-prompt-shell__title" />
200
+ <div class="report-edit-prompt-shell__line" />
201
+ <div
202
+ class="report-edit-prompt-shell__line report-edit-prompt-shell__line--short"
203
+ />
204
+ <div class="report-edit-prompt-shell__line" />
205
+ <div class="report-edit-prompt-shell__line report-edit-prompt-shell__line--mid" />
206
+ </div>
207
+ </section>
208
+ </template>
209
+ </el-scrollbar>
210
+ <div
211
+ ref="mainThumbTrackRef"
212
+ class="report-edit-page__main-thumb-track"
213
+ :class="{ 'is-visible': mainCustomThumbShow }"
214
+ aria-hidden="true"
215
+ >
216
+ <div
217
+ class="report-edit-page__main-thumb"
218
+ :style="{
219
+ height: `${mainThumbH}px`,
220
+ transform: `translateY(${mainThumbY}px)`,
221
+ }"
222
+ @mousedown.prevent="onMainCustomThumbDown"
223
+ />
224
+ </div>
225
+ </main>
226
+
227
+ <div
228
+ v-if="flowShowPromptWorkspace"
229
+ ref="promptSlotRef"
230
+ class="report-edit-page__prompt-slot"
231
+ :class="{
232
+ 'is-collapsed': promptCollapsed && !isStackedLayout,
233
+ 'is-col-overflow': promptOverflow,
234
+ }"
235
+ @mouseenter="onPromptSlotEnter"
236
+ @mouseleave="onPromptSlotLeave"
237
+ >
238
+ <el-scrollbar
239
+ v-show="!promptCollapsed || isStackedLayout"
240
+ class="report-edit-page__col-scroll"
241
+ :min-size="50"
242
+ >
243
+ <Suspense v-if="promptHeavyReady">
244
+ <ReportPromptPanel
245
+ v-if="flowShowPromptPanel"
246
+ :key="`right-prompt-${remountKey}`"
247
+ class="report-edit-page__prompt"
248
+ />
249
+ <ReportGenerateSettingsPanel
250
+ v-else-if="flowShowSettingsPanel"
251
+ :key="`right-settings-${remountKey}`"
252
+ class="report-edit-page__prompt"
253
+ @generated="handleSettingsGenerated"
254
+ />
255
+ <template #fallback>
256
+ <aside
257
+ class="report-edit-page__prompt report-edit-prompt-shell report-edit-prompt-shell--right"
258
+ aria-hidden="true"
259
+ >
260
+ <template v-if="flowShowSettingsPanel">
261
+ <ReportCollapsibleSection :open="true" title="生成報告設置" card-hover>
262
+ <div
263
+ class="report-edit-prompt-shell__pulse report-edit-prompt-shell__pulse--tall"
264
+ />
265
+ </ReportCollapsibleSection>
266
+ <ReportCollapsibleSection :open="true" title="報告歷史" card-hover>
267
+ <div class="report-edit-prompt-shell__pulse" />
268
+ </ReportCollapsibleSection>
269
+ </template>
270
+ <template v-else>
271
+ <ReportCollapsibleSection :open="true" title="Prompt" card-hover>
272
+ <div
273
+ class="report-edit-prompt-shell__pulse report-edit-prompt-shell__pulse--tall"
274
+ />
275
+ </ReportCollapsibleSection>
276
+ <ReportCollapsibleSection :open="true" title="章節歷史" card-hover>
277
+ <div class="report-edit-prompt-shell__pulse" />
278
+ </ReportCollapsibleSection>
279
+ </template>
280
+ </aside>
281
+ </template>
282
+ </Suspense>
283
+ <aside
284
+ v-else
285
+ class="report-edit-page__prompt report-edit-prompt-shell report-edit-prompt-shell--right"
286
+ aria-hidden="true"
287
+ >
288
+ <template v-if="flowShowSettingsPanel">
289
+ <ReportCollapsibleSection :open="true" title="生成報告設置" card-hover>
290
+ <div
291
+ class="report-edit-prompt-shell__pulse report-edit-prompt-shell__pulse--tall"
292
+ />
293
+ </ReportCollapsibleSection>
294
+ <ReportCollapsibleSection :open="true" title="報告歷史" card-hover>
295
+ <div class="report-edit-prompt-shell__pulse" />
296
+ </ReportCollapsibleSection>
297
+ </template>
298
+ <template v-else>
299
+ <ReportCollapsibleSection :open="true" title="Prompt" card-hover>
300
+ <div
301
+ class="report-edit-prompt-shell__pulse report-edit-prompt-shell__pulse--tall"
302
+ />
303
+ </ReportCollapsibleSection>
304
+ <ReportCollapsibleSection :open="true" title="章節歷史" card-hover>
305
+ <div class="report-edit-prompt-shell__pulse" />
306
+ </ReportCollapsibleSection>
307
+ </template>
308
+ </aside>
309
+ </el-scrollbar>
310
+ <div
311
+ class="report-edit-page__side-thumb-track"
312
+ :class="{ 'is-visible': promptThumbShow }"
313
+ aria-hidden="true"
314
+ >
315
+ <div
316
+ class="report-edit-page__side-thumb"
317
+ :style="{
318
+ height: `${promptThumbH}px`,
319
+ transform: `translateY(${promptThumbY}px)`,
320
+ }"
321
+ @mousedown.prevent="onSideThumbDown('prompt', $event)"
322
+ />
323
+ </div>
324
+ </div>
325
+ </template>
326
+ </div>
327
+ </div>
328
+ </template>
329
+
330
+ <script setup lang="ts">
331
+ import { DArrowLeft, DArrowRight } from '@element-plus/icons-vue'
332
+ import { ElIcon, ElMessage, ElScrollbar } from 'element-plus'
333
+ import {
334
+ computed,
335
+ defineAsyncComponent,
336
+ nextTick,
337
+ onBeforeUnmount,
338
+ onMounted,
339
+ ref,
340
+ watch,
341
+ } from 'vue'
342
+ import { hiddenLayoutScroll } from '@/utils/gen-ai-scroll'
343
+ import { useRoute, useRouter } from 'vue-router'
344
+ import { ReportCollapsibleSection } from '../../common'
345
+ import {
346
+ createReportEditRouteSyncActions,
347
+ lockDocumentScroll,
348
+ matchReportModelStep,
349
+ navigateToReportEdit,
350
+ parsePromptRightPanel,
351
+ parseReportEditStep,
352
+ syncWorkflowFromReportEditRoute,
353
+ } from '../report-domain'
354
+ import type { ReportTemplateCard } from '../report-template-data'
355
+ import { resolveReportTemplateById } from '../report-template-data'
356
+ import type { ReportModelStep } from '../useReportWorkflow'
357
+ import { useReportWorkflow } from '../useReportWorkflow'
358
+ import ReportGeneratingPanel from './ReportGeneratingPanel.vue'
359
+ import ReportTemplateDetail from './ReportTemplateDetail.vue'
360
+ import ReportTemplatePicker from './ReportTemplatePicker.vue'
361
+ import ReportWorkflowSidebar from './ReportWorkflowSidebar.vue'
362
+
363
+ const router = useRouter()
364
+ const route = useRoute()
365
+ const workflow = useReportWorkflow()
366
+ const routeSyncActions = createReportEditRouteSyncActions(workflow)
367
+
368
+ const {
369
+ loadDraftFromSession,
370
+ loadTemplateFromSession,
371
+ restoreReportEditSession,
372
+ setSelectedTemplate,
373
+ selectedTemplate,
374
+ sourceFiles,
375
+ settingsTypewriterPrinting,
376
+ chapterTypewriterActive,
377
+ modelStep,
378
+ stopChapterContentTypewriter,
379
+ } = workflow
380
+
381
+ // 子組件 mount 前先恢復 session,避免刷新後首屏空白
382
+ restoreReportEditSession()
383
+
384
+ /**
385
+ * 從路由關鍵字解析步驟(支援 path 段與 query `step=`)。
386
+ * modelStep 必須與此一致,v-if 才會切到正確頁面。
387
+ */
388
+ const currentStep = computed<ReportModelStep>(() => {
389
+ const fromRoute = parseReportEditStep(route)
390
+ if (fromRoute) return fromRoute
391
+ const path = route.fullPath.toLowerCase()
392
+ if (path.includes('/generating') || path.includes('step=generating')) return 'generating'
393
+ if (
394
+ path.includes('/prompt') ||
395
+ path.includes('step=prompt') ||
396
+ path.includes('generate-settings')
397
+ ) {
398
+ return 'prompt'
399
+ }
400
+ if (path.includes('/detail') || path.includes('step=detail')) return 'detail'
401
+ return matchReportModelStep(path)
402
+ })
403
+
404
+ /** 頁面內容開關 + 重掛計數:每次流程點擊強制關→寫路由→開→重掛 */
405
+ const pageContentOpen = ref(true)
406
+ const remountKey = ref(0)
407
+
408
+ /**
409
+ * 流程視圖開關(模組級,父級 remount 不丟)
410
+ * - flowStep:select | detail | generating | prompt
411
+ * - flowRightPanel:prompt(Prompt+章節歷史)| settings(生成報告設置+報告歷史)
412
+ */
413
+ const flowStep = workflow.flowStep
414
+ const flowRightPanel = workflow.flowRightPanel
415
+ const flowShowGenerating = computed(() => flowStep.value === 'generating')
416
+ const flowShowSelect = computed(() => flowStep.value === 'select')
417
+ const flowShowDetail = computed(() => flowStep.value === 'detail' && !!selectedTemplate.value)
418
+ const flowShowPromptWorkspace = computed(() => flowStep.value === 'prompt')
419
+ const flowShowPromptPanel = computed(
420
+ () => flowShowPromptWorkspace.value && flowRightPanel.value === 'prompt'
421
+ )
422
+ const flowShowSettingsPanel = computed(
423
+ () => flowShowPromptWorkspace.value && flowRightPanel.value === 'settings'
424
+ )
425
+
426
+ /** 將流程目標寫入模組級開關 + workflow store(頁面與路由對齊的唯一寫入口) */
427
+ function applyFlowView(step: ReportModelStep, rightPanel: 'prompt' | 'settings' = 'prompt') {
428
+ flowStep.value = step
429
+ flowRightPanel.value = step === 'prompt' ? rightPanel : 'prompt'
430
+ routeSyncActions.openReportEdit(step)
431
+ if (step === 'prompt' && rightPanel === 'settings') {
432
+ routeSyncActions.showPromptSettingsPanel()
433
+ } else if (step === 'prompt') {
434
+ routeSyncActions.showPromptEditorPanel()
435
+ }
436
+ }
437
+
438
+ /**
439
+ * 一鍵生成 / 進入編輯 / 返回章節編輯 / 生成報告:
440
+ * 關內容 → 鎖目標 → 寫路由 → 寫開關 → 僅重掛內層 surface(不銷毀本組件,避免點兩次)→ 解鎖再對齊。
441
+ */
442
+ async function forceNavigateAndRefresh(
443
+ step: ReportModelStep,
444
+ rightPanel: 'prompt' | 'settings' | undefined = undefined,
445
+ templateId?: string
446
+ ) {
447
+ const panel: 'prompt' | 'settings' | undefined =
448
+ step === 'prompt' ? (rightPanel ?? 'prompt') : undefined
449
+ const tid = templateId ?? selectedTemplate.value?.id
450
+
451
+ pageContentOpen.value = false
452
+ await nextTick()
453
+
454
+ workflow.beginReportEditNavigation(step, panel)
455
+ try {
456
+ applyFlowView(step, panel ?? 'prompt')
457
+
458
+ const instanceId =
459
+ step === 'generating' && typeof route.query.instanceId === 'string'
460
+ ? route.query.instanceId
461
+ : undefined
462
+
463
+ await navigateToReportEdit(router, step, tid, true, panel, instanceId)
464
+ applyFlowView(step, panel ?? 'prompt')
465
+
466
+ // 只重掛內層內容樹;勿 remountReportEditPage(會銷毀本實例,finally 寫入失效,需點兩次)
467
+ remountKey.value += 1
468
+ pageContentOpen.value = true
469
+ await nextTick()
470
+ } finally {
471
+ workflow.endReportEditNavigation()
472
+ applyFlowView(step, panel ?? 'prompt')
473
+ }
474
+ }
475
+
476
+ /**
477
+ * 監聽路由:僅在非鎖定期把 URL 同步進 flow* + store,避免主動跳轉被中間態打回。
478
+ */
479
+ watch(
480
+ () => [currentStep.value, parsePromptRightPanel(route)] as const,
481
+ ([step, rightPanel]) => {
482
+ if (workflow.isReportEditNavLocked()) return
483
+ applyFlowView(step, step === 'prompt' ? rightPanel : 'prompt')
484
+ },
485
+ { immediate: true }
486
+ )
487
+
488
+ /** 右側欄展示以本地 flow 開關為準 */
489
+ const currentRightPanel = computed(() => flowRightPanel.value)
490
+ /** 左 / 右欄 Divider 收起狀態(收起後不佔佈局) */
491
+ const sidebarCollapsed = ref(false)
492
+ const promptCollapsed = ref(false)
493
+ /** ≤1024:左中右自上而下堆疊,強制展開並隱藏收起箭頭 */
494
+ const STACKED_MAX_WIDTH = 1024
495
+ const isStackedLayout = ref(
496
+ typeof window !== 'undefined' ? window.innerWidth <= STACKED_MAX_WIDTH : false
497
+ )
498
+
499
+ function syncStackedLayout() {
500
+ const stacked = window.innerWidth <= STACKED_MAX_WIDTH
501
+ isStackedLayout.value = stacked
502
+ if (stacked) {
503
+ // 窄屏一律展開三欄,避免收起態絕對定位造成重疊亂版
504
+ sidebarCollapsed.value = false
505
+ promptCollapsed.value = false
506
+ }
507
+ }
508
+
509
+ const pageRef = ref<HTMLElement | null>(null)
510
+ const mainRef = ref<HTMLElement | null>(null)
511
+ const sidebarSlotRef = ref<HTMLElement | null>(null)
512
+ const promptSlotRef = ref<HTMLElement | null>(null)
513
+
514
+ /**
515
+ * 事件流:
516
+ * TypewriterDocEditor @printing-change(printing)
517
+ * 章節「生成章節內容」→ chapterTypewriterActive
518
+ * 設置頁(不打字、全文)→ flowShowSettingsPanel
519
+ * → mainColScrollbarAlways → main.is-typewriting(僅禁 overflow-anchor)
520
+ * 三欄滾動條:默認隱藏;移入 card 且內容溢出再顯示,可拖動
521
+ */
522
+ const mainColScrollbarAlways = computed(
523
+ () =>
524
+ settingsTypewriterPrinting.value || chapterTypewriterActive.value || flowShowSettingsPanel.value
525
+ )
526
+
527
+ /** 側欄 / 右欄:自繪短膠囊(固定 50px),hover 且溢出顯示 */
528
+ const SIDE_THUMB_H = 50
529
+ const sidebarOverflow = ref(false)
530
+ const promptOverflow = ref(false)
531
+ const sidebarHovered = ref(false)
532
+ const promptHovered = ref(false)
533
+ const sidebarThumbDragging = ref(false)
534
+ const promptThumbDragging = ref(false)
535
+ const sidebarThumbH = ref(SIDE_THUMB_H)
536
+ const promptThumbH = ref(SIDE_THUMB_H)
537
+ const sidebarThumbY = ref(0)
538
+ const promptThumbY = ref(0)
539
+ const sidebarThumbShow = computed(
540
+ () => sidebarOverflow.value && (sidebarHovered.value || sidebarThumbDragging.value)
541
+ )
542
+ const promptThumbShow = computed(
543
+ () => promptOverflow.value && (promptHovered.value || promptThumbDragging.value)
544
+ )
545
+ let sideColOverflowRo: ResizeObserver | null = null
546
+ const sideColScrollUnbinds: Array<() => void> = []
547
+ let sideThumbDragCleanup: (() => void) | undefined
548
+
549
+ function getSideWrap(slot: HTMLElement | null) {
550
+ return slot?.querySelector('.el-scrollbar__wrap') as HTMLElement | null
551
+ }
552
+
553
+ function updateSideCustomThumb(which: 'sidebar' | 'prompt') {
554
+ const slot = which === 'sidebar' ? sidebarSlotRef.value : promptSlotRef.value
555
+ const wrap = getSideWrap(slot)
556
+ const hovered = which === 'sidebar' ? sidebarHovered.value : promptHovered.value
557
+ const dragging = which === 'sidebar' ? sidebarThumbDragging.value : promptThumbDragging.value
558
+ const overflowFlag = which === 'sidebar' ? sidebarOverflow : promptOverflow
559
+ const thumbHRef = which === 'sidebar' ? sidebarThumbH : promptThumbH
560
+ const thumbYRef = which === 'sidebar' ? sidebarThumbY : promptThumbY
561
+
562
+ if (!slot || !wrap) {
563
+ overflowFlag.value = false
564
+ return
565
+ }
566
+
567
+ const trackH = Math.max(0, Math.round(wrap.clientHeight))
568
+ const { scrollTop, scrollHeight, clientHeight } = wrap
569
+ const needsScroll = scrollHeight > clientHeight + 1 && trackH > 0
570
+ overflowFlag.value = needsScroll
571
+
572
+ // 0914:與中欄一致;hover 移出只隱藏,保留 thumbY 讓淡出留在當前滾動位置
573
+ if (!needsScroll) {
574
+ thumbHRef.value = SIDE_THUMB_H
575
+ thumbYRef.value = 0
576
+ return
577
+ }
578
+ if (!(hovered || dragging)) {
579
+ return
580
+ }
581
+ // 0914
582
+
583
+ const thumbH = Math.min(SIDE_THUMB_H, trackH)
584
+ const maxScroll = scrollHeight - clientHeight
585
+ const maxOffset = Math.max(0, trackH - thumbH)
586
+ const y =
587
+ maxScroll > 0
588
+ ? Math.min(maxOffset, Math.max(0, Math.round((scrollTop / maxScroll) * maxOffset)))
589
+ : 0
590
+ thumbHRef.value = thumbH
591
+ thumbYRef.value = y
592
+ }
593
+
594
+ function onSidebarSlotEnter() {
595
+ sidebarHovered.value = true
596
+ updateSideCustomThumb('sidebar')
597
+ }
598
+
599
+ function onSidebarSlotLeave() {
600
+ if (sidebarThumbDragging.value) return
601
+ sidebarHovered.value = false
602
+ updateSideCustomThumb('sidebar')
603
+ }
604
+
605
+ function onPromptSlotEnter() {
606
+ promptHovered.value = true
607
+ updateSideCustomThumb('prompt')
608
+ }
609
+
610
+ function onPromptSlotLeave() {
611
+ if (promptThumbDragging.value) return
612
+ promptHovered.value = false
613
+ updateSideCustomThumb('prompt')
614
+ }
615
+
616
+ function onSideThumbDown(which: 'sidebar' | 'prompt', event: MouseEvent) {
617
+ const slot = which === 'sidebar' ? sidebarSlotRef.value : promptSlotRef.value
618
+ const wrap = getSideWrap(slot)
619
+ if (!wrap) return
620
+ event.preventDefault()
621
+ if (which === 'sidebar') sidebarThumbDragging.value = true
622
+ else promptThumbDragging.value = true
623
+ updateSideCustomThumb(which)
624
+
625
+ const startY = event.clientY
626
+ const startScrollTop = wrap.scrollTop
627
+ const trackH = wrap.clientHeight
628
+ const thumbH = which === 'sidebar' ? sidebarThumbH.value : promptThumbH.value
629
+ const maxScroll = wrap.scrollHeight - wrap.clientHeight
630
+ const maxOffset = Math.max(0, trackH - thumbH)
631
+
632
+ const onMove = (ev: MouseEvent) => {
633
+ if (maxOffset <= 0 || maxScroll <= 0) return
634
+ wrap.scrollTop = startScrollTop + ((ev.clientY - startY) / maxOffset) * maxScroll
635
+ }
636
+ const onUp = () => {
637
+ document.removeEventListener('mousemove', onMove)
638
+ document.removeEventListener('mouseup', onUp)
639
+ sideThumbDragCleanup = undefined
640
+ if (which === 'sidebar') {
641
+ sidebarThumbDragging.value = false
642
+ if (!sidebarHovered.value) updateSideCustomThumb('sidebar')
643
+ } else {
644
+ promptThumbDragging.value = false
645
+ if (!promptHovered.value) updateSideCustomThumb('prompt')
646
+ }
647
+ }
648
+ document.addEventListener('mousemove', onMove)
649
+ document.addEventListener('mouseup', onUp)
650
+ sideThumbDragCleanup = onUp
651
+ }
652
+
653
+ function bindSideColOverflowWatch() {
654
+ sideColOverflowRo?.disconnect()
655
+ sideColOverflowRo = null
656
+ while (sideColScrollUnbinds.length) sideColScrollUnbinds.pop()?.()
657
+
658
+ updateSideCustomThumb('sidebar')
659
+ updateSideCustomThumb('prompt')
660
+
661
+ if (typeof ResizeObserver === 'undefined') return
662
+ sideColOverflowRo = new ResizeObserver(() => {
663
+ updateSideCustomThumb('sidebar')
664
+ updateSideCustomThumb('prompt')
665
+ })
666
+ const observeSlot = (which: 'sidebar' | 'prompt') => {
667
+ const slot = which === 'sidebar' ? sidebarSlotRef.value : promptSlotRef.value
668
+ if (!slot) return
669
+ const wrap = getSideWrap(slot)
670
+ const view = slot.querySelector('.el-scrollbar__view') as HTMLElement | null
671
+ sideColOverflowRo?.observe(slot)
672
+ if (wrap) {
673
+ sideColOverflowRo?.observe(wrap)
674
+ const onScroll = () => updateSideCustomThumb(which)
675
+ wrap.addEventListener('scroll', onScroll, { passive: true })
676
+ sideColScrollUnbinds.push(() => wrap.removeEventListener('scroll', onScroll))
677
+ }
678
+ if (view) sideColOverflowRo?.observe(view)
679
+ }
680
+ observeSlot('sidebar')
681
+ observeSlot('prompt')
682
+ }
683
+
684
+ function unbindSideColOverflowWatch() {
685
+ sideColOverflowRo?.disconnect()
686
+ sideColOverflowRo = null
687
+ while (sideColScrollUnbinds.length) sideColScrollUnbinds.pop()?.()
688
+ sideThumbDragCleanup?.()
689
+ sideThumbDragCleanup = undefined
690
+ sidebarOverflow.value = false
691
+ promptOverflow.value = false
692
+ sidebarHovered.value = false
693
+ promptHovered.value = false
694
+ sidebarThumbDragging.value = false
695
+ promptThumbDragging.value = false
696
+ }
697
+
698
+ let mainScrollWrapEl: HTMLElement | null = null
699
+
700
+ function onMainScrollWrapScroll() {
701
+ updateMainCustomThumb()
702
+ }
703
+
704
+ function bindMainScrollbarAutoHide() {
705
+ unbindMainScrollbarAutoHide()
706
+ const wrap = mainRef.value?.querySelector(
707
+ '.report-edit-page__col-scroll .el-scrollbar__wrap'
708
+ ) as HTMLElement | null
709
+ if (!wrap) return
710
+ mainScrollWrapEl = wrap
711
+ wrap.addEventListener('scroll', onMainScrollWrapScroll, { passive: true })
712
+ mainThumbRo = new ResizeObserver(() => updateMainCustomThumb())
713
+ mainThumbRo.observe(wrap)
714
+ if (mainRef.value) mainThumbRo.observe(mainRef.value)
715
+ void nextTick(() => {
716
+ if (mainThumbTrackRef.value) mainThumbRo?.observe(mainThumbTrackRef.value)
717
+ const toolbar = mainRef.value?.querySelector(
718
+ '.report-chapter-workspace__toolbar, .report-edit-prompt-shell__toolbar'
719
+ ) as HTMLElement | null
720
+ if (toolbar) mainThumbRo?.observe(toolbar)
721
+ updateMainCustomThumb()
722
+ })
723
+ }
724
+
725
+ function unbindMainScrollbarAutoHide() {
726
+ mainThumbRo?.disconnect()
727
+ mainThumbRo = null
728
+ if (mainScrollWrapEl) {
729
+ mainScrollWrapEl.removeEventListener('scroll', onMainScrollWrapScroll)
730
+ mainScrollWrapEl = null
731
+ }
732
+ mainCustomThumbShow.value = false
733
+ }
734
+
735
+ /** 中欄自繪滑塊:固定 50px;僅 hover / 拖動且溢出時顯示;軌道避開 toolbar */
736
+ const MAIN_THUMB_H = 50
737
+ const mainThumbTrackRef = ref<HTMLElement | null>(null)
738
+ const mainThumbH = ref(MAIN_THUMB_H)
739
+ const mainThumbY = ref(0)
740
+ const mainCustomThumbShow = ref(false)
741
+ const mainColHovered = ref(false)
742
+ const mainThumbDragging = ref(false)
743
+ let mainThumbRo: ResizeObserver | null = null
744
+ let mainThumbDragCleanup: (() => void) | undefined
745
+
746
+ function onMainColEnter() {
747
+ mainColHovered.value = true
748
+ updateMainCustomThumb()
749
+ }
750
+
751
+ function onMainColLeave() {
752
+ if (mainThumbDragging.value) return
753
+ mainColHovered.value = false
754
+ updateMainCustomThumb()
755
+ }
756
+
757
+ function updateMainCustomThumb() {
758
+ const wrap = mainScrollWrapEl
759
+ const track = mainThumbTrackRef.value
760
+ const main = mainRef.value
761
+ if (!wrap || !track || !main) {
762
+ mainCustomThumbShow.value = false
763
+ return
764
+ }
765
+
766
+ // 軌道幾何對齊實際滾動視口(相對 main),避免超出 card
767
+ const mainRect = main.getBoundingClientRect()
768
+ const wrapRect = wrap.getBoundingClientRect()
769
+ let top = Math.max(0, Math.round(wrapRect.top - mainRect.top))
770
+ let height = Math.max(0, Math.round(wrapRect.height))
771
+
772
+ // 軌道從工具列下沿起,不蓋住 report-chapter-workspace__toolbar
773
+ const toolbar = main.querySelector(
774
+ '.report-chapter-workspace__toolbar, .report-edit-prompt-shell__toolbar'
775
+ ) as HTMLElement | null
776
+ if (toolbar) {
777
+ const toolbarH = Math.max(0, Math.round(toolbar.getBoundingClientRect().height))
778
+ top += toolbarH
779
+ height = Math.max(0, height - toolbarH)
780
+ }
781
+
782
+ track.style.top = `${top}px`
783
+ track.style.bottom = 'auto'
784
+ track.style.height = `${height}px`
785
+ if (flowStep.value === 'select') {
786
+ track.style.right = '2px'
787
+ } else {
788
+ track.style.removeProperty('right')
789
+ }
790
+
791
+ const trackH = height
792
+ const { scrollTop, scrollHeight, clientHeight } = wrap
793
+ const needsScroll = scrollHeight > clientHeight + 1 && trackH > 0
794
+ // 默認隱藏;移入 card 或拖動中且溢出才顯示
795
+ const allowShow = mainColHovered.value || mainThumbDragging.value
796
+
797
+ if (!needsScroll || !allowShow) {
798
+ mainCustomThumbShow.value = false
799
+ return
800
+ }
801
+
802
+ const thumbH = Math.min(MAIN_THUMB_H, trackH)
803
+ const maxScroll = scrollHeight - clientHeight
804
+ const maxOffset = Math.max(0, trackH - thumbH)
805
+ const y =
806
+ maxScroll > 0
807
+ ? Math.min(maxOffset, Math.max(0, Math.round((scrollTop / maxScroll) * maxOffset)))
808
+ : 0
809
+
810
+ mainThumbH.value = thumbH
811
+ mainThumbY.value = y
812
+ mainCustomThumbShow.value = true
813
+ }
814
+
815
+ function onMainCustomThumbDown(event: MouseEvent) {
816
+ const wrap = mainScrollWrapEl
817
+ if (!wrap) return
818
+ event.preventDefault()
819
+ mainThumbDragging.value = true
820
+ updateMainCustomThumb()
821
+ const startY = event.clientY
822
+ const startScrollTop = wrap.scrollTop
823
+ const trackH = mainThumbTrackRef.value?.clientHeight ?? 0
824
+ const thumbH = mainThumbH.value
825
+ const maxScroll = wrap.scrollHeight - wrap.clientHeight
826
+ const maxOffset = Math.max(0, trackH - thumbH)
827
+
828
+ const onMove = (ev: MouseEvent) => {
829
+ if (maxOffset <= 0 || maxScroll <= 0) return
830
+ wrap.scrollTop = startScrollTop + ((ev.clientY - startY) / maxOffset) * maxScroll
831
+ }
832
+ const onUp = () => {
833
+ document.removeEventListener('mousemove', onMove)
834
+ document.removeEventListener('mouseup', onUp)
835
+ mainThumbDragCleanup = undefined
836
+ mainThumbDragging.value = false
837
+ if (!mainColHovered.value) updateMainCustomThumb()
838
+ }
839
+ document.addEventListener('mousemove', onMove)
840
+ document.addEventListener('mouseup', onUp)
841
+ mainThumbDragCleanup = onUp
842
+ }
843
+
844
+ watch(mainColScrollbarAlways, () => {
845
+ updateMainCustomThumb()
846
+ })
847
+
848
+ /** 首屏工具列章節標題(與實頁下拉一致,優先模板首章) */
849
+ const promptShellChapterLabel = computed(() => {
850
+ const first = selectedTemplate.value?.chapters?.[0]
851
+ if (typeof first === 'string' && first.trim()) return first.trim()
852
+ return '1. 摘要與本年總'
853
+ })
854
+
855
+ const ReportChapterWorkspace = defineAsyncComponent(() => import('./ReportChapterWorkspace.vue'))
856
+ const ReportPromptPanel = defineAsyncComponent(() => import('./ReportPromptPanel.vue'))
857
+ const ReportGenerateSettingsPanel = defineAsyncComponent(
858
+ () => import('./ReportGenerateSettingsPanel.vue')
859
+ )
860
+
861
+ /** 首屏先出卡片骨架,雙 rAF 後再掛載重型 async 面板 */
862
+ const promptHeavyReady = ref(false)
863
+ let promptMountToken = 0
864
+
865
+ function schedulePromptHeavyMount() {
866
+ // 已掛載過則勿先置 false,避免路由重複同步時整欄閃白像「一直刷新」
867
+ if (promptHeavyReady.value) return
868
+ const token = ++promptMountToken
869
+ void nextTick(() => {
870
+ requestAnimationFrame(() => {
871
+ requestAnimationFrame(() => {
872
+ if (token !== promptMountToken) return
873
+ promptHeavyReady.value = true
874
+ })
875
+ })
876
+ })
877
+ }
878
+
879
+ watch(
880
+ flowStep,
881
+ (step) => {
882
+ if (step === 'prompt') {
883
+ schedulePromptHeavyMount()
884
+ return
885
+ }
886
+ promptMountToken += 1
887
+ promptHeavyReady.value = false
888
+ },
889
+ { immediate: true }
890
+ )
891
+
892
+ watch(
893
+ [flowStep, currentRightPanel, promptHeavyReady, sidebarCollapsed, promptCollapsed],
894
+ async () => {
895
+ await nextTick()
896
+ bindMainScrollbarAutoHide()
897
+ bindSideColOverflowWatch()
898
+ },
899
+ { immediate: true }
900
+ )
901
+
902
+ function syncFromRoute(target = route) {
903
+ syncWorkflowFromReportEditRoute(target, routeSyncActions)
904
+ }
905
+
906
+ watch(
907
+ () => route.fullPath,
908
+ () => {
909
+ if (workflow.isReportEditNavLocked()) return
910
+ syncFromRoute()
911
+ const step = currentStep.value
912
+ const panel = parsePromptRightPanel(route)
913
+ applyFlowView(step, step === 'prompt' ? panel : 'prompt')
914
+ },
915
+ { immediate: true, flush: 'sync' }
916
+ )
917
+
918
+ function handleSelectTemplate(template: ReportTemplateCard) {
919
+ setSelectedTemplate(template)
920
+ void forceNavigateAndRefresh('detail', undefined, template.id)
921
+ }
922
+
923
+ function goBackToSelect() {
924
+ void forceNavigateAndRefresh('select')
925
+ }
926
+
927
+ /** 一鍵生成 → generating */
928
+ function enterChapterEdit() {
929
+ // if (!sourceFiles.value.length) {
930
+ // ElMessage.warning('請至少添加一個資訊源檔案')
931
+ // return
932
+ // }
933
+ void forceNavigateAndRefresh('generating')
934
+ }
935
+
936
+ /** 返回章節編輯 → prompt + Prompt/章節歷史 */
937
+ function backToChapterEdit() {
938
+ void forceNavigateAndRefresh('prompt', 'prompt')
939
+ }
940
+
941
+ /** 生成報告 → prompt + 生成報告設置/報告歷史 */
942
+ function handleGenerateReportNavigate() {
943
+ stopChapterContentTypewriter()
944
+ void forceNavigateAndRefresh('prompt', 'settings')
945
+ }
946
+
947
+ function handleSettingsGenerated() {
948
+ if (!workflow.isReportEditNavLocked()) syncFromRoute()
949
+ }
950
+
951
+ /** 進入編輯 → prompt + Prompt/章節歷史 */
952
+ function handleEnterEditing() {
953
+ stopChapterContentTypewriter()
954
+ loadTemplateFromSession()
955
+ if (!selectedTemplate.value) {
956
+ ElMessage.warning('缺少報告模板,無法進入編輯')
957
+ return
958
+ }
959
+ void forceNavigateAndRefresh('prompt', 'prompt', selectedTemplate.value?.id)
960
+ }
961
+
962
+ function ensurePromptTemplate() {
963
+ if (workflow.isReportEditNavLocked()) return
964
+ if (flowStep.value !== 'prompt' && modelStep.value !== 'prompt') return
965
+
966
+ if (!selectedTemplate.value) {
967
+ loadTemplateFromSession()
968
+ }
969
+ if (!selectedTemplate.value) {
970
+ const tid = typeof route.query.templateId === 'string' ? route.query.templateId : ''
971
+ if (tid) {
972
+ const found = resolveReportTemplateById(tid)
973
+ if (found) setSelectedTemplate(found)
974
+ }
975
+ }
976
+ // 無模板時不回落本地首張卡片
977
+ }
978
+
979
+ /**
980
+ * 將中間 main card 的 left/top/width/height 寫入 CSS 變量,
981
+ * 供本頁 append-to-body 的 dialog / popover 對齊且不超出卡片。
982
+ */
983
+ function syncMainDialogAnchor() {
984
+ const main = mainRef.value
985
+ const root = document.documentElement
986
+ if (!main || flowStep.value === 'generating') {
987
+ clearMainDialogAnchor()
988
+ return
989
+ }
990
+
991
+ const rect = main.getBoundingClientRect()
992
+ root.classList.add('report-edit-dialog-anchored')
993
+ root.style.setProperty('--report-edit-main-left', `${Math.round(rect.left)}px`)
994
+ root.style.setProperty('--report-edit-main-top', `${Math.round(rect.top)}px`)
995
+ root.style.setProperty('--report-edit-main-width', `${Math.round(rect.width)}px`)
996
+ root.style.setProperty('--report-edit-main-height', `${Math.round(rect.height)}px`)
997
+ root.style.setProperty('--report-edit-main-right', `${Math.round(rect.right)}px`)
998
+ root.style.setProperty('--report-edit-main-bottom', `${Math.round(rect.bottom)}px`)
999
+ }
1000
+
1001
+ function clearMainDialogAnchor() {
1002
+ const root = document.documentElement
1003
+ root.classList.remove('report-edit-dialog-anchored')
1004
+ root.style.removeProperty('--report-edit-main-left')
1005
+ root.style.removeProperty('--report-edit-main-top')
1006
+ root.style.removeProperty('--report-edit-main-width')
1007
+ root.style.removeProperty('--report-edit-main-height')
1008
+ root.style.removeProperty('--report-edit-main-right')
1009
+ root.style.removeProperty('--report-edit-main-bottom')
1010
+ }
1011
+
1012
+ const mainResizeObserver =
1013
+ typeof ResizeObserver !== 'undefined'
1014
+ ? new ResizeObserver(() => {
1015
+ syncMainDialogAnchor()
1016
+ })
1017
+ : null
1018
+
1019
+ let cleanupDocumentScroll: (() => void) | undefined
1020
+
1021
+ let cleanupHiddenLayoutScroll: (() => void) | undefined
1022
+ watch(
1023
+ flowShowPromptWorkspace,
1024
+ (on) => {
1025
+ if (on) {
1026
+ if (!cleanupHiddenLayoutScroll) cleanupHiddenLayoutScroll = hiddenLayoutScroll()
1027
+ return
1028
+ }
1029
+ cleanupHiddenLayoutScroll?.()
1030
+ cleanupHiddenLayoutScroll = undefined
1031
+ },
1032
+ { immediate: true }
1033
+ )
1034
+
1035
+ onMounted(() => {
1036
+ loadDraftFromSession()
1037
+ loadTemplateFromSession()
1038
+ syncFromRoute()
1039
+ ensurePromptTemplate()
1040
+ /* 獨立全屏頁:鎖 document 滾動,僅三欄內部滾動 */
1041
+ cleanupDocumentScroll = lockDocumentScroll()
1042
+
1043
+ syncStackedLayout()
1044
+ window.addEventListener('resize', syncStackedLayout)
1045
+
1046
+ if (flowStep.value === 'detail' && !selectedTemplate.value) {
1047
+ void forceNavigateAndRefresh('select')
1048
+ }
1049
+
1050
+ void nextTick(() => {
1051
+ syncMainDialogAnchor()
1052
+ if (mainRef.value) mainResizeObserver?.observe(mainRef.value)
1053
+ })
1054
+
1055
+ window.addEventListener('resize', syncMainDialogAnchor)
1056
+ pageRef.value?.addEventListener('scroll', syncMainDialogAnchor, { passive: true })
1057
+ })
1058
+
1059
+ onBeforeUnmount(() => {
1060
+ window.removeEventListener('resize', syncMainDialogAnchor)
1061
+ window.removeEventListener('resize', syncStackedLayout)
1062
+ pageRef.value?.removeEventListener('scroll', syncMainDialogAnchor)
1063
+ mainResizeObserver?.disconnect()
1064
+ clearMainDialogAnchor()
1065
+ cleanupDocumentScroll?.()
1066
+ cleanupDocumentScroll = undefined
1067
+ cleanupHiddenLayoutScroll?.()
1068
+ cleanupHiddenLayoutScroll = undefined
1069
+ mainThumbDragCleanup?.()
1070
+ unbindMainScrollbarAutoHide()
1071
+ unbindSideColOverflowWatch()
1072
+ })
1073
+
1074
+ watch(flowStep, () => {
1075
+ if (flowStep.value !== 'prompt') {
1076
+ promptCollapsed.value = false
1077
+ }
1078
+ ensurePromptTemplate()
1079
+ void nextTick(() => syncMainDialogAnchor())
1080
+ })
1081
+
1082
+ watch(mainRef, (el, prev) => {
1083
+ if (prev && mainResizeObserver) mainResizeObserver.unobserve(prev)
1084
+ if (el && mainResizeObserver) mainResizeObserver.observe(el)
1085
+ syncMainDialogAnchor()
1086
+ })
1087
+ </script>
1088
+
1089
+ <style scoped>
1090
+ .report-edit-page {
1091
+ --report-edit-col-scroll-thumb: #999;
1092
+ /* select / detail:左 2fr + 間距 20px + 右 8fr(右欄對齊 prompt 中+右總寬) */
1093
+ --report-edit-split-gap: 20px;
1094
+ --report-edit-main-border-width: 0px;
1095
+ display: grid;
1096
+ grid-template-columns: minmax(0, 2fr) minmax(0, 8fr);
1097
+ grid-template-rows: minmax(0, 1fr);
1098
+ row-gap: 15px;
1099
+ column-gap: var(--report-edit-split-gap);
1100
+ box-sizing: border-box;
1101
+ align-items: stretch;
1102
+ /* 獨立全屏:視口高度固定 100dvh;padding 含在內,三欄同高,超出僅欄內滾動 */
1103
+ width: 100%;
1104
+ height: 100dvh;
1105
+ max-height: 100dvh;
1106
+ min-height: 0;
1107
+ padding: 27px 15px 15px;
1108
+ overflow: hidden;
1109
+ background: #fff;
1110
+ position: relative;
1111
+ transition: grid-template-columns 0.25s ease;
1112
+ }
1113
+
1114
+ /* select / detail:左欄與主內容間距固定 20px */
1115
+ .report-edit-page:not(.is-prompt):not(.is-generating) {
1116
+ --report-edit-split-gap: 20px;
1117
+ grid-template-columns: minmax(0, 2fr) minmax(0, 8fr);
1118
+ column-gap: var(--report-edit-split-gap);
1119
+ }
1120
+
1121
+ /* 內容層不佔 grid 欄,子節點仍作為 .report-edit-page 的 grid item */
1122
+ .report-edit-page__surface {
1123
+ display: contents;
1124
+ }
1125
+
1126
+ .report-edit-page.is-content-closed {
1127
+ /* 關閉內容時保留殼高度,避免閃縮 */
1128
+ background: #fff;
1129
+ }
1130
+
1131
+ /* 側欄從右向左收起:不佔 grid 欄寬,主內容擴展 */
1132
+ .report-edit-page.is-sidebar-collapsed:not(.is-prompt) {
1133
+ grid-template-columns: minmax(0, 1fr);
1134
+ }
1135
+
1136
+ .report-edit-page.is-sidebar-collapsed:not(.is-prompt) .report-edit-page__sidebar-slot {
1137
+ grid-column: 1;
1138
+ grid-row: 1;
1139
+ }
1140
+
1141
+ .report-edit-page.is-sidebar-collapsed:not(.is-prompt) .report-edit-page__main {
1142
+ grid-column: 1;
1143
+ grid-row: 1;
1144
+ }
1145
+
1146
+ .report-edit-page.is-generating {
1147
+ display: block;
1148
+ grid-template-columns: none;
1149
+ gap: 0;
1150
+ padding: 0;
1151
+ height: 100dvh;
1152
+ max-height: 100dvh;
1153
+ min-height: 0;
1154
+ overflow: hidden;
1155
+ }
1156
+
1157
+ .report-edit-page.is-generating .report-edit-page__generating {
1158
+ height: 100%;
1159
+ min-height: 0;
1160
+ max-height: 100%;
1161
+ overflow: hidden;
1162
+ }
1163
+
1164
+ .report-edit-page.is-prompt {
1165
+ --report-edit-border: #d8dce3;
1166
+ --report-edit-main-border-width: 1px;
1167
+ --report-edit-split-gap: 20px;
1168
+ grid-template-columns: minmax(0, 2fr) minmax(0, 6fr) minmax(0, 2fr);
1169
+ grid-template-rows: minmax(0, 1fr);
1170
+ align-items: stretch;
1171
+ row-gap: 15px;
1172
+ column-gap: var(--report-edit-split-gap);
1173
+ /* 左右 padding ≥12px,露出欄外側 right:-12px 短膠囊 */
1174
+ padding: 15px;
1175
+ height: 100dvh;
1176
+ max-height: 100dvh;
1177
+ overflow: hidden;
1178
+ background: #fff;
1179
+ }
1180
+
1181
+ .report-edit-page.is-prompt.is-sidebar-collapsed:not(.is-prompt-collapsed) {
1182
+ grid-template-columns: minmax(0, 6fr) minmax(0, 2fr);
1183
+ }
1184
+
1185
+ .report-edit-page.is-prompt.is-prompt-collapsed:not(.is-sidebar-collapsed) {
1186
+ grid-template-columns: minmax(0, 2fr) minmax(0, 8fr);
1187
+ }
1188
+
1189
+ .report-edit-page.is-prompt.is-sidebar-collapsed.is-prompt-collapsed {
1190
+ grid-template-columns: minmax(0, 1fr);
1191
+ }
1192
+
1193
+ .report-edit-page.is-prompt.is-sidebar-collapsed:not(.is-prompt-collapsed)
1194
+ > .report-edit-page__sidebar-slot {
1195
+ grid-column: 1;
1196
+ grid-row: 1;
1197
+ }
1198
+
1199
+ .report-edit-page.is-prompt.is-sidebar-collapsed:not(.is-prompt-collapsed)
1200
+ > .report-edit-page__main {
1201
+ grid-column: 1;
1202
+ }
1203
+
1204
+ .report-edit-page.is-prompt.is-sidebar-collapsed:not(.is-prompt-collapsed)
1205
+ > .report-edit-page__prompt-slot {
1206
+ grid-column: 2;
1207
+ }
1208
+
1209
+ .report-edit-page.is-prompt.is-prompt-collapsed:not(.is-sidebar-collapsed)
1210
+ > .report-edit-page__sidebar-slot {
1211
+ grid-column: 1;
1212
+ }
1213
+
1214
+ .report-edit-page.is-prompt.is-prompt-collapsed:not(.is-sidebar-collapsed)
1215
+ > .report-edit-page__main {
1216
+ grid-column: 2;
1217
+ }
1218
+
1219
+ .report-edit-page.is-prompt.is-prompt-collapsed:not(.is-sidebar-collapsed)
1220
+ > .report-edit-page__prompt-slot {
1221
+ grid-column: 2;
1222
+ grid-row: 1;
1223
+ position: absolute;
1224
+ width: 0;
1225
+ height: 0;
1226
+ overflow: visible;
1227
+ pointer-events: none;
1228
+ }
1229
+
1230
+ .report-edit-page.is-prompt.is-sidebar-collapsed.is-prompt-collapsed
1231
+ > .report-edit-page__sidebar-slot,
1232
+ .report-edit-page.is-prompt.is-sidebar-collapsed.is-prompt-collapsed
1233
+ > .report-edit-page__prompt-slot {
1234
+ grid-column: 1;
1235
+ grid-row: 1;
1236
+ }
1237
+
1238
+ .report-edit-page.is-prompt.is-sidebar-collapsed.is-prompt-collapsed > .report-edit-page__main {
1239
+ grid-column: 1;
1240
+ grid-row: 1;
1241
+ }
1242
+
1243
+ .report-edit-page.is-prompt .report-edit-page__main {
1244
+ display: flex;
1245
+ flex-direction: column;
1246
+ min-height: 0;
1247
+ height: 100%;
1248
+ max-height: 100%;
1249
+ padding: 16px 20px;
1250
+ border: 1px solid var(--report-edit-border);
1251
+ border-radius: 8px;
1252
+ background: #fff;
1253
+ box-shadow:
1254
+ 0 1px 2px rgba(15, 23, 42, 0.05),
1255
+ 0 3px 10px rgba(15, 23, 42, 0.07);
1256
+ /* visible:兩側收起按鈕落在 card 外側間隙,不可裁切 */
1257
+ overflow: visible;
1258
+ transition:
1259
+ box-shadow var(--el-transition-duration, 0.3s),
1260
+ border-color 0.22s ease;
1261
+ }
1262
+
1263
+ .report-edit-page.is-prompt .report-edit-page__main:hover {
1264
+ border-color: #c5cad3;
1265
+ box-shadow:
1266
+ inset 0 0 0 1px rgba(15, 23, 42, 0.05),
1267
+ 0 2px 6px rgba(15, 23, 42, 0.07),
1268
+ 0 10px 22px rgba(15, 23, 42, 0.11);
1269
+ }
1270
+
1271
+ .report-edit-page.is-prompt .report-edit-page__main > .report-edit-page__col-scroll {
1272
+ flex: 1 1 auto;
1273
+ min-height: 0;
1274
+ /* 允許滾動條伸入 card 右側 padding(距內邊 4px) */
1275
+ overflow: visible;
1276
+ }
1277
+
1278
+ .report-edit-page.is-prompt
1279
+ .report-edit-page__main
1280
+ > .report-edit-page__col-scroll
1281
+ :deep(.el-scrollbar) {
1282
+ overflow: visible;
1283
+ }
1284
+
1285
+ .report-edit-page.is-prompt
1286
+ .report-edit-page__main
1287
+ > .report-edit-page__col-scroll
1288
+ :deep(.el-scrollbar__wrap) {
1289
+ border-radius: 4px;
1290
+ overflow-x: hidden !important;
1291
+ overflow-y: scroll !important;
1292
+ scrollbar-gutter: stable !important;
1293
+ scrollbar-width: none !important;
1294
+ -ms-overflow-style: none !important;
1295
+ }
1296
+
1297
+ .report-edit-page.is-prompt
1298
+ .report-edit-page__main
1299
+ > .report-edit-page__col-scroll
1300
+ :deep(.el-scrollbar__wrap::-webkit-scrollbar),
1301
+ .report-edit-page.is-prompt
1302
+ .report-edit-page__main
1303
+ > .report-edit-page__col-scroll
1304
+ :deep(.el-scrollbar__wrap::-webkit-scrollbar-thumb),
1305
+ .report-edit-page.is-prompt
1306
+ .report-edit-page__main
1307
+ > .report-edit-page__col-scroll
1308
+ :deep(.el-scrollbar__wrap::-webkit-scrollbar-track) {
1309
+ width: 0 !important;
1310
+ height: 0 !important;
1311
+ display: none !important;
1312
+ background: transparent !important;
1313
+ }
1314
+
1315
+ .report-edit-page.is-prompt
1316
+ .report-edit-page__main
1317
+ > .report-edit-page__col-scroll
1318
+ :deep(.el-scrollbar__view) {
1319
+ width: 100%;
1320
+ max-width: 100%;
1321
+ box-sizing: border-box;
1322
+ }
1323
+
1324
+ .report-edit-page.is-prompt
1325
+ .report-edit-page__main
1326
+ .report-edit-page__col-scroll
1327
+ :deep(.report-chapter-workspace) {
1328
+ flex: 1 0 auto;
1329
+ min-height: 0;
1330
+ height: auto;
1331
+ }
1332
+
1333
+ .report-edit-page.is-prompt .report-edit-page__prompt {
1334
+ min-height: 0;
1335
+ height: auto;
1336
+ overflow: visible;
1337
+ }
1338
+
1339
+ .report-edit-page.is-prompt .report-edit-page__prompt:has(.report-prompt-panel.is-compact),
1340
+ .report-edit-page.is-prompt
1341
+ .report-edit-page__prompt:has(.chatbot-report-panel--settings.is-compact) {
1342
+ min-height: 0;
1343
+ height: auto;
1344
+ align-self: flex-start;
1345
+ }
1346
+
1347
+ .report-edit-page.is-prompt .report-edit-page__sidebar-slot,
1348
+ .report-edit-page.is-prompt .report-edit-page__prompt-slot {
1349
+ min-height: 0;
1350
+ height: 100%;
1351
+ max-height: 100%;
1352
+ }
1353
+
1354
+ .report-edit-page__sidebar-slot {
1355
+ position: relative;
1356
+ display: flex;
1357
+ flex-direction: column;
1358
+ align-self: stretch;
1359
+ min-width: 0;
1360
+ min-height: 0;
1361
+ height: 100%;
1362
+ max-height: 100%;
1363
+ /* 允許滾動條落在欄外側 8px(欄間隙),不裁切 */
1364
+ overflow: visible;
1365
+ }
1366
+
1367
+ .report-edit-page__prompt-slot {
1368
+ position: relative;
1369
+ display: flex;
1370
+ flex-direction: column;
1371
+ align-self: stretch;
1372
+ min-width: 0;
1373
+ min-height: 0;
1374
+ height: 100%;
1375
+ max-height: 100%;
1376
+ overflow: visible;
1377
+ }
1378
+
1379
+ .report-edit-page__sidebar-slot.is-collapsed {
1380
+ position: absolute;
1381
+ width: 0;
1382
+ height: 0;
1383
+ min-width: 0;
1384
+ min-height: 0;
1385
+ margin: 0;
1386
+ padding: 0;
1387
+ overflow: hidden;
1388
+ pointer-events: none;
1389
+ }
1390
+
1391
+ .report-edit-page__prompt-slot.is-collapsed {
1392
+ width: 0;
1393
+ min-width: 0;
1394
+ height: 0;
1395
+ max-height: none;
1396
+ overflow: visible;
1397
+ pointer-events: none;
1398
+ }
1399
+
1400
+ .report-edit-page__generating {
1401
+ display: flex;
1402
+ flex-direction: column;
1403
+ min-height: 0;
1404
+ height: 100%;
1405
+ }
1406
+
1407
+ .report-edit-page__sidebar {
1408
+ flex: 1 1 auto;
1409
+ align-self: stretch;
1410
+ min-width: 0;
1411
+ min-height: 0;
1412
+ overflow: visible;
1413
+ }
1414
+
1415
+ .report-edit-page__main {
1416
+ position: relative;
1417
+ display: flex;
1418
+ flex-direction: column;
1419
+ min-width: 0;
1420
+ min-height: 0;
1421
+ height: 100%;
1422
+ max-height: 100%;
1423
+ border-radius: 8px;
1424
+ background: #fff;
1425
+ box-sizing: border-box;
1426
+ overflow: hidden;
1427
+ }
1428
+
1429
+ .report-edit-page__main--anchored {
1430
+ position: relative;
1431
+ }
1432
+
1433
+ .report-edit-page__main > .report-edit-page__col-scroll :deep(.el-scrollbar__bar.is-vertical),
1434
+ .report-edit-page.is-prompt
1435
+ .report-edit-page__main.is-typewriting
1436
+ > .report-edit-page__col-scroll
1437
+ :deep(.el-scrollbar__bar.is-vertical),
1438
+ .report-edit-page.is-prompt
1439
+ .report-edit-page__main.is-main-scrollbar-visible
1440
+ > .report-edit-page__col-scroll
1441
+ :deep(.el-scrollbar__bar.is-vertical),
1442
+ .report-edit-page.is-detail
1443
+ .report-edit-page__main
1444
+ > .report-edit-page__col-scroll
1445
+ :deep(.el-scrollbar__bar.is-vertical) {
1446
+ display: none !important;
1447
+ opacity: 0 !important;
1448
+ visibility: hidden !important;
1449
+ pointer-events: none !important;
1450
+ width: 0 !important;
1451
+ height: 0 !important;
1452
+ overflow: hidden !important;
1453
+ }
1454
+
1455
+ .report-edit-page__main-thumb-track {
1456
+ position: absolute !important;
1457
+ right: 4px !important;
1458
+ width: 8px !important;
1459
+ height: 0;
1460
+ z-index: 20 !important;
1461
+ overflow: hidden !important;
1462
+ pointer-events: none !important;
1463
+ box-sizing: border-box !important;
1464
+ opacity: 0 !important;
1465
+ transition: opacity 0.18s ease;
1466
+ }
1467
+
1468
+ .report-edit-page__main-thumb-track.is-visible {
1469
+ opacity: 1 !important;
1470
+ }
1471
+
1472
+ /*
1473
+ * 與 detail 同思路:內容右側留 gutter,滑塊貼主欄右緣。
1474
+ * 勿用 right:-N(會被 .report-edit-page / PageCard 的 overflow:hidden 裁掉)。
1475
+ */
1476
+ .report-edit-page.is-select {
1477
+ padding-right: 5px;
1478
+ }
1479
+
1480
+ .report-edit-page.is-select .report-edit-page__main {
1481
+ padding-right: 16px;
1482
+ box-sizing: border-box;
1483
+ overflow: hidden;
1484
+ }
1485
+
1486
+ .report-edit-page.is-select .report-edit-page__main > .report-edit-page__col-scroll {
1487
+ overflow: hidden;
1488
+ }
1489
+
1490
+ .report-edit-page.is-select .report-edit-page__main-thumb-track {
1491
+ right: 2px !important;
1492
+ }
1493
+
1494
+ .report-edit-page.is-detail .report-edit-page__main-thumb-track {
1495
+ right: 6px !important;
1496
+ }
1497
+
1498
+ .report-edit-page__main-thumb {
1499
+ width: 8px !important;
1500
+ min-height: 50px !important;
1501
+ max-height: 100% !important;
1502
+ border-radius: 9999px !important;
1503
+ background-color: #999 !important;
1504
+ pointer-events: none;
1505
+ cursor: pointer;
1506
+ will-change: transform;
1507
+ box-sizing: border-box !important;
1508
+ }
1509
+
1510
+ .report-edit-page__main-thumb-track.is-visible .report-edit-page__main-thumb {
1511
+ pointer-events: auto !important;
1512
+ }
1513
+
1514
+ .report-edit-page__main-thumb:hover {
1515
+ background-color: #777 !important;
1516
+ }
1517
+
1518
+ /* 與章節下拉同款:el-scrollbar;中欄豎滑塊已自繪,側欄/右欄亦自繪 */
1519
+ .report-edit-page__col-scroll {
1520
+ flex: 1 1 auto;
1521
+ min-height: 0;
1522
+ height: 100%;
1523
+ max-height: 100%;
1524
+ width: 100%;
1525
+ overflow: visible;
1526
+ }
1527
+
1528
+ .report-edit-page__col-scroll :deep(.el-scrollbar) {
1529
+ height: 100%;
1530
+ max-height: 100%;
1531
+ overflow: visible;
1532
+ }
1533
+
1534
+ .report-edit-page__col-scroll :deep(.el-scrollbar__wrap) {
1535
+ overflow-x: hidden !important;
1536
+ overflow-y: auto !important;
1537
+ max-height: 100% !important;
1538
+ box-sizing: border-box !important;
1539
+ scrollbar-width: none !important;
1540
+ -ms-overflow-style: none !important;
1541
+ }
1542
+
1543
+ .report-edit-page__col-scroll :deep(.el-scrollbar__view) {
1544
+ box-sizing: border-box;
1545
+ }
1546
+
1547
+ /* 側欄 / 右欄:恢復原內容寬(不加陰影預留 padding);靠 overflow 露出 iOS card 陰影 */
1548
+ .report-edit-page__sidebar-slot > .report-edit-page__col-scroll,
1549
+ .report-edit-page__prompt-slot > .report-edit-page__col-scroll {
1550
+ overflow: visible;
1551
+ }
1552
+
1553
+ .report-edit-page__sidebar-slot > .report-edit-page__col-scroll :deep(.el-scrollbar),
1554
+ .report-edit-page__prompt-slot > .report-edit-page__col-scroll :deep(.el-scrollbar) {
1555
+ overflow: visible;
1556
+ }
1557
+
1558
+ .report-edit-page__col-scroll :deep(.el-scrollbar__wrap::-webkit-scrollbar) {
1559
+ width: 0 !important;
1560
+ height: 0 !important;
1561
+ display: none !important;
1562
+ }
1563
+
1564
+ .report-edit-page__col-scroll :deep(.el-scrollbar__bar.is-horizontal) {
1565
+ display: none !important;
1566
+ }
1567
+
1568
+ .report-edit-page__col-scroll :deep(.el-scrollbar__bar.is-vertical) {
1569
+ display: none !important;
1570
+ opacity: 0 !important;
1571
+ visibility: hidden !important;
1572
+ pointer-events: none !important;
1573
+ width: 0 !important;
1574
+ height: 0 !important;
1575
+ }
1576
+
1577
+ .report-edit-page__col-scroll :deep(.el-scrollbar__bar.is-vertical .el-scrollbar__thumb) {
1578
+ display: none !important;
1579
+ }
1580
+
1581
+ .report-edit-page__side-thumb-track {
1582
+ position: absolute !important;
1583
+ top: 0 !important;
1584
+ bottom: 0 !important;
1585
+ width: 8px !important;
1586
+ z-index: 20 !important;
1587
+ overflow: hidden !important;
1588
+ pointer-events: none !important;
1589
+ box-sizing: border-box !important;
1590
+ opacity: 0 !important;
1591
+ transition: opacity 0.18s ease;
1592
+ }
1593
+
1594
+ .report-edit-page__sidebar-slot > .report-edit-page__side-thumb-track {
1595
+ right: calc(-1 * (var(--report-edit-split-gap, 20px) + 8px) / 2) !important;
1596
+ left: auto !important;
1597
+ }
1598
+
1599
+ .report-edit-page__prompt-slot > .report-edit-page__side-thumb-track {
1600
+ right: -12px !important;
1601
+ left: auto !important;
1602
+ }
1603
+
1604
+ .report-edit-page__side-thumb-track.is-visible {
1605
+ opacity: 1 !important;
1606
+ }
1607
+
1608
+ .report-edit-page__side-thumb {
1609
+ width: 8px !important;
1610
+ min-height: 50px !important;
1611
+ max-height: 100% !important;
1612
+ border-radius: 9999px !important;
1613
+ background-color: #999 !important;
1614
+ pointer-events: none;
1615
+ cursor: pointer;
1616
+ will-change: transform;
1617
+ box-sizing: border-box !important;
1618
+ }
1619
+
1620
+ .report-edit-page__side-thumb-track.is-visible .report-edit-page__side-thumb {
1621
+ pointer-events: auto !important;
1622
+ }
1623
+
1624
+ .report-edit-page__side-thumb:hover {
1625
+ background-color: #777 !important;
1626
+ }
1627
+
1628
+ /*
1629
+ * detail:右側主欄
1630
+ * - 內邊距避免圓角 overflow 裁切「返回」等按鈕邊框
1631
+ * - 膠囊滑塊 8px 寬、最短 50px(EP min-size 按比例,滾到底滑塊也到底)
1632
+ * - 頁面右內邊距 5px,滾動條貼齊主欄右緣 → 距螢幕最右側 5px(僅 detail)
1633
+ */
1634
+ .report-edit-page.is-detail {
1635
+ padding-right: 5px;
1636
+ }
1637
+
1638
+ .report-edit-page.is-detail .report-edit-page__main {
1639
+ padding: 0px 20px 16px 0;
1640
+ box-sizing: border-box;
1641
+ }
1642
+
1643
+ .report-edit-page.is-detail .report-edit-page__main > .report-edit-page__col-scroll {
1644
+ overflow: visible;
1645
+ }
1646
+
1647
+ .report-edit-page.is-detail
1648
+ .report-edit-page__main
1649
+ > .report-edit-page__col-scroll
1650
+ :deep(.el-scrollbar) {
1651
+ overflow: visible;
1652
+ height: 100%;
1653
+ max-height: 100%;
1654
+ }
1655
+
1656
+ .report-edit-page.is-detail
1657
+ .report-edit-page__main
1658
+ > .report-edit-page__col-scroll
1659
+ :deep(.el-scrollbar__wrap) {
1660
+ overflow-x: hidden !important;
1661
+ overflow-y: auto !important;
1662
+ max-height: 100% !important;
1663
+ scrollbar-width: none !important;
1664
+ -ms-overflow-style: none !important;
1665
+ }
1666
+
1667
+ .report-edit-page.is-detail
1668
+ .report-edit-page__main
1669
+ > .report-edit-page__col-scroll
1670
+ :deep(.el-scrollbar__wrap::-webkit-scrollbar),
1671
+ .report-edit-page.is-detail
1672
+ .report-edit-page__main
1673
+ > .report-edit-page__col-scroll
1674
+ :deep(.el-scrollbar__wrap::-webkit-scrollbar-thumb),
1675
+ .report-edit-page.is-detail
1676
+ .report-edit-page__main
1677
+ > .report-edit-page__col-scroll
1678
+ :deep(.el-scrollbar__wrap::-webkit-scrollbar-track) {
1679
+ width: 0 !important;
1680
+ height: 0 !important;
1681
+ display: none !important;
1682
+ background: transparent !important;
1683
+ }
1684
+
1685
+ .report-edit-page.is-detail
1686
+ .report-edit-page__main
1687
+ > .report-edit-page__col-scroll
1688
+ :deep(.el-scrollbar__bar.is-vertical) {
1689
+ display: none !important;
1690
+ opacity: 0 !important;
1691
+ visibility: hidden !important;
1692
+ pointer-events: none !important;
1693
+ width: 0 !important;
1694
+ height: 0 !important;
1695
+ }
1696
+
1697
+ .report-edit-page.is-detail
1698
+ .report-edit-page__main
1699
+ > .report-edit-page__col-scroll
1700
+ :deep(.el-scrollbar__bar.is-vertical .el-scrollbar__thumb) {
1701
+ display: none !important;
1702
+ opacity: 0 !important;
1703
+ pointer-events: none !important;
1704
+ }
1705
+
1706
+ .report-edit-page.is-detail
1707
+ .report-edit-page__main
1708
+ > .report-edit-page__col-scroll
1709
+ :deep(.el-scrollbar__bar.is-vertical .el-scrollbar__thumb:hover) {
1710
+ background-color: transparent !important;
1711
+ }
1712
+
1713
+ /* 豎條在欄外側(right:-12px),勿再加內 padding */
1714
+ .report-edit-page.is-detail .report-edit-page__sidebar-slot {
1715
+ padding-right: 0;
1716
+ box-sizing: border-box;
1717
+ overflow: visible;
1718
+ }
1719
+
1720
+ .report-edit-page.is-detail .report-edit-page__sidebar-slot > .report-edit-page__col-scroll {
1721
+ overflow: visible;
1722
+ }
1723
+
1724
+ .report-edit-page.is-detail
1725
+ .report-edit-page__sidebar-slot
1726
+ > .report-edit-page__col-scroll
1727
+ :deep(.el-scrollbar) {
1728
+ overflow: visible;
1729
+ height: 100%;
1730
+ max-height: 100%;
1731
+ }
1732
+
1733
+ .report-edit-page.is-detail
1734
+ .report-edit-page__sidebar-slot
1735
+ > .report-edit-page__col-scroll
1736
+ :deep(.el-scrollbar__wrap) {
1737
+ overflow-x: hidden !important;
1738
+ overflow-y: auto !important;
1739
+ max-height: 100% !important;
1740
+ scrollbar-width: none !important;
1741
+ -ms-overflow-style: none !important;
1742
+ }
1743
+
1744
+ .report-edit-page.is-detail
1745
+ .report-edit-page__sidebar-slot
1746
+ > .report-edit-page__col-scroll
1747
+ :deep(.el-scrollbar__wrap::-webkit-scrollbar),
1748
+ .report-edit-page.is-detail
1749
+ .report-edit-page__sidebar-slot
1750
+ > .report-edit-page__col-scroll
1751
+ :deep(.el-scrollbar__wrap::-webkit-scrollbar-thumb),
1752
+ .report-edit-page.is-detail
1753
+ .report-edit-page__sidebar-slot
1754
+ > .report-edit-page__col-scroll
1755
+ :deep(.el-scrollbar__wrap::-webkit-scrollbar-track) {
1756
+ width: 0 !important;
1757
+ height: 0 !important;
1758
+ display: none !important;
1759
+ background: transparent !important;
1760
+ }
1761
+
1762
+ .report-edit-page.is-detail
1763
+ .report-edit-page__sidebar-slot
1764
+ > .report-edit-page__col-scroll
1765
+ :deep(.el-scrollbar__bar.is-vertical) {
1766
+ display: none !important;
1767
+ opacity: 0 !important;
1768
+ pointer-events: none !important;
1769
+ width: 0 !important;
1770
+ height: 0 !important;
1771
+ }
1772
+
1773
+ .report-edit-page.is-detail
1774
+ .report-edit-page__sidebar-slot
1775
+ > .report-edit-page__col-scroll
1776
+ :deep(.el-scrollbar__bar.is-vertical .el-scrollbar__thumb) {
1777
+ display: none !important;
1778
+ }
1779
+
1780
+ .report-edit-page.is-prompt
1781
+ .report-edit-page__main
1782
+ > .report-edit-page__col-scroll
1783
+ :deep(.el-scrollbar__bar.is-vertical) {
1784
+ display: none !important;
1785
+ opacity: 0 !important;
1786
+ pointer-events: none !important;
1787
+ }
1788
+
1789
+ /* 列印中禁用 overflow-anchor,避免瀏覽器錨點把視口拽到中間造成跳動 */
1790
+ .report-edit-page.is-prompt
1791
+ .report-edit-page__main.is-typewriting
1792
+ > .report-edit-page__col-scroll
1793
+ :deep(.el-scrollbar__wrap),
1794
+ .report-edit-page.is-prompt
1795
+ .report-edit-page__main
1796
+ > .report-edit-page__col-scroll
1797
+ :deep(.el-scrollbar__wrap.is-typewriter-follow) {
1798
+ overflow-anchor: none;
1799
+ }
1800
+
1801
+ .report-edit-page.is-prompt
1802
+ .report-edit-page__main.is-typewriting
1803
+ .report-edit-page__main-thumb-track,
1804
+ .report-edit-page.is-prompt
1805
+ .report-edit-page__main.is-main-scrollbar-visible
1806
+ .report-edit-page__main-thumb-track {
1807
+ /* 實際顯示仍以 script is-visible 為準;此處僅提高優先級佔位 */
1808
+ z-index: 30 !important;
1809
+ }
1810
+
1811
+ /* 欄間折疊開關:熱區在欄間隙內、不壓中欄 border;默認僅圖標,hover 淺紅底(無品牌色邊框) */
1812
+ .report-edit-page__col-divider {
1813
+ z-index: 30;
1814
+ display: inline-flex;
1815
+ align-items: center;
1816
+ justify-content: center;
1817
+ box-sizing: border-box;
1818
+ width: 14px;
1819
+ height: 90px;
1820
+ margin: 0;
1821
+ padding: 0;
1822
+ border: none;
1823
+ border-radius: 4px;
1824
+ background: transparent;
1825
+ box-shadow: none;
1826
+ cursor: pointer;
1827
+ line-height: 0;
1828
+ pointer-events: auto;
1829
+ flex-shrink: 0;
1830
+ appearance: none;
1831
+ -webkit-appearance: none;
1832
+ color: #606266;
1833
+ transition:
1834
+ color 0.15s ease,
1835
+ background 0.15s ease;
1836
+ }
1837
+
1838
+ .report-edit-page__col-divider :deep(.el-icon) {
1839
+ color: inherit;
1840
+ }
1841
+
1842
+ .report-edit-page__col-divider:hover {
1843
+ background: #fdf0f2;
1844
+ color: #c53355;
1845
+ }
1846
+
1847
+ /* 收起態:常顯完整 button(淺紅底 + 系統紅圖標),展開/收起同一位置 */
1848
+ .report-edit-page.is-sidebar-collapsed .report-edit-page__col-divider--left,
1849
+ .report-edit-page.is-prompt-collapsed .report-edit-page__col-divider--right {
1850
+ background: #fdf0f2;
1851
+ color: #c53355;
1852
+ }
1853
+
1854
+ .report-edit-page__col-divider:focus-visible {
1855
+ outline: 2px solid rgba(197, 51, 85, 0.35);
1856
+ outline-offset: 1px;
1857
+ }
1858
+
1859
+ /* 相對中欄:落在欄間隙正中(計入中欄 border,左右等距) */
1860
+ .report-edit-page__col-divider--left {
1861
+ position: absolute;
1862
+ top: 50%;
1863
+ left: 0;
1864
+ right: auto;
1865
+ bottom: auto;
1866
+ margin: 0;
1867
+ margin-left: calc(
1868
+ -1 * (var(--report-edit-main-border-width, 0px) + var(--report-edit-split-gap, 20px) / 2)
1869
+ );
1870
+ transform: translate(-50%, -50%);
1871
+ }
1872
+
1873
+ .report-edit-page__col-divider--right {
1874
+ position: absolute;
1875
+ top: 50%;
1876
+ left: 100%;
1877
+ right: auto;
1878
+ bottom: auto;
1879
+ margin: 0;
1880
+ margin-left: calc(
1881
+ var(--report-edit-main-border-width, 0px) + var(--report-edit-split-gap, 20px) / 2
1882
+ );
1883
+ transform: translate(-50%, -50%);
1884
+ }
1885
+
1886
+ .report-edit-page__toolbar {
1887
+ margin-bottom: 12px;
1888
+ }
1889
+
1890
+ .report-edit-page__prompt {
1891
+ align-self: stretch;
1892
+ min-width: 0;
1893
+ min-height: 0;
1894
+ }
1895
+
1896
+ /* prompt 首屏靜態殼:先佔位,避免 async chunk / 重型面板掛載前中右欄空白 */
1897
+ .report-edit-prompt-shell--main {
1898
+ display: flex;
1899
+ flex: 1 0 auto;
1900
+ flex-direction: column;
1901
+ gap: 16px;
1902
+ min-height: 0;
1903
+ height: auto;
1904
+ }
1905
+
1906
+ .report-edit-prompt-shell__toolbar {
1907
+ display: flex;
1908
+ flex-wrap: wrap;
1909
+ align-items: flex-start;
1910
+ justify-content: space-between;
1911
+ gap: 12px;
1912
+ }
1913
+
1914
+ .report-edit-prompt-shell__select {
1915
+ display: inline-flex;
1916
+ align-items: center;
1917
+ justify-content: space-between;
1918
+ gap: 8px;
1919
+ box-sizing: border-box;
1920
+ width: 220px;
1921
+ min-width: 180px;
1922
+ min-height: 39px;
1923
+ padding: 0 12px;
1924
+ border-radius: 4px;
1925
+ box-shadow: 0 0 0 1px #dcdfe6 inset;
1926
+ background: #fff;
1927
+ cursor: default;
1928
+ }
1929
+
1930
+ .report-edit-prompt-shell__select-text {
1931
+ flex: 1;
1932
+ min-width: 0;
1933
+ overflow: hidden;
1934
+ text-overflow: ellipsis;
1935
+ white-space: nowrap;
1936
+ font-size: 15px;
1937
+ font-weight: 400;
1938
+ font-family: var(--gen-ai-font-family, 'Noto Sans', 'Noto Sans TC', sans-serif);
1939
+ color: #303133;
1940
+ line-height: 1.4;
1941
+ }
1942
+
1943
+ .report-edit-prompt-shell__select-caret {
1944
+ flex-shrink: 0;
1945
+ width: 0;
1946
+ height: 0;
1947
+ border-left: 5px solid transparent;
1948
+ border-right: 5px solid transparent;
1949
+ border-top: 6px solid #dcdfe6;
1950
+ }
1951
+
1952
+ .report-edit-prompt-shell__actions {
1953
+ display: flex;
1954
+ flex-wrap: wrap;
1955
+ gap: 12px;
1956
+ justify-content: flex-end;
1957
+ }
1958
+
1959
+ .report-edit-prompt-shell__action-btn {
1960
+ display: inline-flex;
1961
+ align-items: center;
1962
+ justify-content: center;
1963
+ box-sizing: border-box;
1964
+ height: 32px;
1965
+ width: 100px;
1966
+ min-width: 100px;
1967
+ max-width: 100px;
1968
+ padding: 0 8px;
1969
+ border: 1px solid #c53355;
1970
+ border-radius: 4px;
1971
+ background: #c53355;
1972
+ color: #fff;
1973
+ font-size: 16px;
1974
+ font-weight: 500;
1975
+ font-family: var(--gen-ai-font-family, 'Noto Sans', 'Noto Sans TC', sans-serif);
1976
+ line-height: 1;
1977
+ white-space: nowrap;
1978
+ cursor: default;
1979
+ opacity: 1;
1980
+ }
1981
+
1982
+ .report-edit-prompt-shell__action-btn:disabled {
1983
+ opacity: 1;
1984
+ cursor: default;
1985
+ }
1986
+
1987
+ .report-edit-prompt-shell__editor {
1988
+ display: flex;
1989
+ flex: 1 0 auto;
1990
+ flex-direction: column;
1991
+ gap: 14px;
1992
+ min-height: 320px;
1993
+ padding-top: 8px;
1994
+ }
1995
+
1996
+ .report-edit-prompt-shell__title {
1997
+ width: min(420px, 70%);
1998
+ height: 28px;
1999
+ border-radius: 4px;
2000
+ background: linear-gradient(90deg, #f2f3f5 25%, #e9ebef 37%, #f2f3f5 63%);
2001
+ background-size: 400% 100%;
2002
+ animation: report-edit-shell-shimmer 1.2s ease-in-out infinite;
2003
+ }
2004
+
2005
+ .report-edit-prompt-shell__line {
2006
+ width: 100%;
2007
+ height: 14px;
2008
+ border-radius: 4px;
2009
+ background: linear-gradient(90deg, #f5f6f8 25%, #eceef2 37%, #f5f6f8 63%);
2010
+ background-size: 400% 100%;
2011
+ animation: report-edit-shell-shimmer 1.2s ease-in-out infinite;
2012
+ }
2013
+
2014
+ .report-edit-prompt-shell__line--short {
2015
+ width: 55%;
2016
+ }
2017
+
2018
+ .report-edit-prompt-shell__line--mid {
2019
+ width: 78%;
2020
+ }
2021
+
2022
+ .report-edit-prompt-shell--right {
2023
+ display: flex;
2024
+ flex-direction: column;
2025
+ gap: 14px;
2026
+ min-width: 0;
2027
+ box-sizing: border-box;
2028
+ }
2029
+
2030
+ .report-edit-prompt-shell__pulse {
2031
+ min-height: 96px;
2032
+ border-radius: 6px;
2033
+ background: linear-gradient(90deg, #f5f6f8 25%, #eceef2 37%, #f5f6f8 63%);
2034
+ background-size: 400% 100%;
2035
+ animation: report-edit-shell-shimmer 1.2s ease-in-out infinite;
2036
+ }
2037
+
2038
+ .report-edit-prompt-shell__pulse--tall {
2039
+ min-height: 180px;
2040
+ }
2041
+
2042
+ @keyframes report-edit-shell-shimmer {
2043
+ 0% {
2044
+ background-position: 100% 0;
2045
+ }
2046
+
2047
+ 100% {
2048
+ background-position: 0 0;
2049
+ }
2050
+ }
2051
+
2052
+ .report-edit-page.is-prompt .report-edit-page__main > .report-edit-prompt-shell--main {
2053
+ flex: 1 0 auto;
2054
+ min-height: 0;
2055
+ height: auto;
2056
+ }
2057
+
2058
+ @media (max-width: 1024px) {
2059
+ /*
2060
+ * ≤1024:左 → 中 → 右 自上而下 flex 堆疊(比 grid 更不易被寬屏定位規則打斷)
2061
+ */
2062
+ .report-edit-page,
2063
+ .report-edit-page.is-prompt,
2064
+ .report-edit-page.is-stacked,
2065
+ .report-edit-page.is-prompt.is-stacked,
2066
+ .report-edit-page.is-prompt.is-sidebar-collapsed:not(.is-prompt-collapsed),
2067
+ .report-edit-page.is-prompt.is-prompt-collapsed:not(.is-sidebar-collapsed),
2068
+ .report-edit-page.is-prompt.is-sidebar-collapsed.is-prompt-collapsed,
2069
+ .report-edit-page.is-sidebar-collapsed:not(.is-prompt) {
2070
+ display: flex !important;
2071
+ flex-direction: column !important;
2072
+ flex-wrap: nowrap !important;
2073
+ align-items: stretch !important;
2074
+ justify-content: flex-start !important;
2075
+ gap: 12px !important;
2076
+ height: 100dvh !important;
2077
+ max-height: 100dvh !important;
2078
+ min-height: 0 !important;
2079
+ overflow-x: hidden !important;
2080
+ overflow-y: auto !important;
2081
+ -webkit-overflow-scrolling: touch;
2082
+ scrollbar-gutter: stable;
2083
+ }
2084
+
2085
+ .report-edit-page.is-prompt,
2086
+ .report-edit-page.is-prompt.is-stacked,
2087
+ .report-edit-page.is-prompt.is-sidebar-collapsed:not(.is-prompt-collapsed),
2088
+ .report-edit-page.is-prompt.is-prompt-collapsed:not(.is-sidebar-collapsed),
2089
+ .report-edit-page.is-prompt.is-sidebar-collapsed.is-prompt-collapsed {
2090
+ height: 100dvh !important;
2091
+ max-height: 100dvh !important;
2092
+ }
2093
+
2094
+ /* 左 → 中 → 右 */
2095
+ .report-edit-page > .report-edit-page__sidebar-slot,
2096
+ .report-edit-page.is-prompt > .report-edit-page__sidebar-slot {
2097
+ order: 1 !important;
2098
+ flex: 0 0 auto !important;
2099
+ }
2100
+
2101
+ .report-edit-page > .report-edit-page__main,
2102
+ .report-edit-page.is-prompt > .report-edit-page__main {
2103
+ order: 2 !important;
2104
+ flex: 0 0 auto !important;
2105
+ }
2106
+
2107
+ .report-edit-page.is-prompt > .report-edit-page__prompt-slot {
2108
+ order: 3 !important;
2109
+ flex: 0 0 auto !important;
2110
+ }
2111
+
2112
+ .report-edit-page__sidebar-slot,
2113
+ .report-edit-page__main,
2114
+ .report-edit-page__prompt-slot,
2115
+ .report-edit-page.is-prompt .report-edit-page__sidebar-slot,
2116
+ .report-edit-page.is-prompt .report-edit-page__main,
2117
+ .report-edit-page.is-prompt .report-edit-page__prompt-slot,
2118
+ .report-edit-page__sidebar-slot.is-collapsed,
2119
+ .report-edit-page__prompt-slot.is-collapsed {
2120
+ position: relative !important;
2121
+ left: auto !important;
2122
+ right: auto !important;
2123
+ top: auto !important;
2124
+ bottom: auto !important;
2125
+ grid-column: auto !important;
2126
+ grid-row: auto !important;
2127
+ width: 100% !important;
2128
+ min-width: 0 !important;
2129
+ max-width: 100% !important;
2130
+ height: auto !important;
2131
+ max-height: none !important;
2132
+ min-height: 0 !important;
2133
+ margin: 0 !important;
2134
+ overflow: visible !important;
2135
+ pointer-events: auto !important;
2136
+ }
2137
+
2138
+ .report-edit-page.is-prompt .report-edit-page__main {
2139
+ display: flex !important;
2140
+ flex-direction: column !important;
2141
+ min-height: 280px;
2142
+ overflow: visible !important;
2143
+ }
2144
+
2145
+ /* 強制顯示欄內容(覆蓋收起態 v-show: display:none) */
2146
+ .report-edit-page__sidebar-slot .report-edit-page__col-scroll,
2147
+ .report-edit-page__prompt-slot .report-edit-page__col-scroll {
2148
+ display: block !important;
2149
+ }
2150
+
2151
+ /* 隱藏左右收起箭頭 */
2152
+ .report-edit-page__col-divider,
2153
+ .report-edit-page__col-divider--left,
2154
+ .report-edit-page__col-divider--right {
2155
+ display: none !important;
2156
+ }
2157
+
2158
+ /* 欄內隨內容撐開,整頁滾動 */
2159
+ .report-edit-page__col-scroll {
2160
+ height: auto !important;
2161
+ max-height: none !important;
2162
+ min-height: 0;
2163
+ width: 100%;
2164
+ }
2165
+
2166
+ .report-edit-page__col-scroll :deep(.el-scrollbar) {
2167
+ height: auto !important;
2168
+ max-height: none !important;
2169
+ display: block !important;
2170
+ }
2171
+
2172
+ .report-edit-page__col-scroll :deep(.el-scrollbar__wrap) {
2173
+ height: auto !important;
2174
+ max-height: none !important;
2175
+ overflow: visible !important;
2176
+ }
2177
+
2178
+ .report-edit-page__col-scroll :deep(.el-scrollbar__view) {
2179
+ height: auto !important;
2180
+ display: block !important;
2181
+ }
2182
+
2183
+ .report-edit-page__col-scroll :deep(.el-scrollbar__bar.is-vertical) {
2184
+ display: none !important;
2185
+ }
2186
+
2187
+ .report-edit-page__sidebar,
2188
+ .report-edit-page__prompt {
2189
+ width: 100% !important;
2190
+ max-width: 100% !important;
2191
+ height: auto !important;
2192
+ min-height: 0;
2193
+ }
2194
+
2195
+ .report-edit-page,
2196
+ .report-edit-page.is-prompt {
2197
+ scrollbar-width: thin;
2198
+ scrollbar-color: #999 transparent;
2199
+ }
2200
+
2201
+ .report-edit-page::-webkit-scrollbar,
2202
+ .report-edit-page.is-prompt::-webkit-scrollbar {
2203
+ width: 8px;
2204
+ }
2205
+
2206
+ .report-edit-page::-webkit-scrollbar-thumb,
2207
+ .report-edit-page.is-prompt::-webkit-scrollbar-thumb {
2208
+ border-radius: 4px;
2209
+ background-color: #999;
2210
+ }
2211
+
2212
+ .report-edit-page::-webkit-scrollbar-track,
2213
+ .report-edit-page.is-prompt::-webkit-scrollbar-track {
2214
+ background: transparent;
2215
+ }
2216
+ }
2217
+ </style>
2218
+
2219
+ <!--
2220
+ 本頁 dialog / popover(append-to-body)對齊中間 report-edit-page__main--anchored:
2221
+ 寬度 / 頂部對齊卡片;高度不超出卡片(max = 卡片高度)
2222
+ -->
2223
+ <style>
2224
+ html.report-edit-dialog-anchored .report-workflow-dialog.el-dialog,
2225
+ html.report-edit-dialog-anchored .report-chapter-dialog.report-workflow-dialog.el-dialog,
2226
+ html.report-edit-dialog-anchored .ai-prompt-generate-dialog.el-dialog,
2227
+ html.report-edit-dialog-anchored .report-chapter-source-picker.el-dialog,
2228
+ html.report-edit-dialog-anchored .template-center-chapter-dialog.el-dialog {
2229
+ width: var(--report-edit-main-width) !important;
2230
+ min-width: var(--report-edit-main-width) !important;
2231
+ max-width: var(--report-edit-main-width) !important;
2232
+ min-height: min(60vh, var(--report-edit-main-height)) !important;
2233
+ height: auto !important;
2234
+ max-height: var(--report-edit-main-height) !important;
2235
+ margin-top: var(--report-edit-main-top) !important;
2236
+ margin-left: var(--report-edit-main-left) !important;
2237
+ margin-right: auto !important;
2238
+ margin-bottom: 0 !important;
2239
+ box-sizing: border-box;
2240
+ overflow: hidden !important;
2241
+ }
2242
+
2243
+ /* 申請創建模板:必須給確定高度,否則 body 內 el-scrollbar 無法計算滾動 */
2244
+ html.report-edit-dialog-anchored .apply-template-dialog.el-dialog {
2245
+ width: var(--report-edit-main-width) !important;
2246
+ min-width: var(--report-edit-main-width) !important;
2247
+ max-width: var(--report-edit-main-width) !important;
2248
+ height: var(--report-edit-main-height) !important;
2249
+ min-height: var(--report-edit-main-height) !important;
2250
+ max-height: var(--report-edit-main-height) !important;
2251
+ margin-top: var(--report-edit-main-top) !important;
2252
+ margin-left: var(--report-edit-main-left) !important;
2253
+ margin-right: auto !important;
2254
+ margin-bottom: 0 !important;
2255
+ box-sizing: border-box;
2256
+ overflow: hidden !important;
2257
+ }
2258
+
2259
+ /* // new prompt sections — 章節下拉錨定 main 卡片(>1024 寬度見 ReportChapterWorkspace 底部同標記) */
2260
+ html.report-edit-dialog-anchored .report-chapter-workspace__chapter-select-popper.el-popper {
2261
+ max-width: min(450px, calc(var(--report-edit-main-width) - 16px)) !important;
2262
+ width: min(450px, calc(var(--report-edit-main-width) - 16px)) !important;
2263
+ min-width: 0 !important;
2264
+ max-height: calc(var(--report-edit-main-height) - 16px) !important;
2265
+ }
2266
+
2267
+ html.report-edit-dialog-anchored
2268
+ .report-chapter-workspace__chapter-select-popper
2269
+ .el-select-dropdown {
2270
+ width: 100% !important;
2271
+ min-width: 0 !important;
2272
+ max-width: 100% !important;
2273
+ }
2274
+ /* // new prompt sections end */
2275
+
2276
+ html.report-edit-dialog-anchored .report-tiptap-table-picker-popper.el-popper,
2277
+ html.report-edit-dialog-anchored .report-tiptap-link-popper.el-popper,
2278
+ html.report-edit-dialog-anchored .report-tiptap-image-popper.el-popper,
2279
+ html.report-edit-dialog-anchored .report-tiptap-style-popper.el-popper {
2280
+ max-width: calc(var(--report-edit-main-width) - 16px) !important;
2281
+ max-height: calc(var(--report-edit-main-height) - 16px) !important;
2282
+ }
2283
+ </style>