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,314 @@
1
+ <template>
2
+ <label class="gen-ai-prompt-field" :class="{ 'gen-ai-prompt-field--row': layout === 'row' }" :style="fieldStyle">
3
+ <span class="gen-ai-prompt-field__label">
4
+ {{ label }}<span v-if="required" class="gen-ai-prompt-field__required">*</span>
5
+ </span>
6
+ <div class="gen-ai-prompt-field__control" :style="controlStyle">
7
+ <div class="gen-ai-prompt-field__box" :class="{ 'gen-ai-prompt-field__box--constrained': isConstrained }"
8
+ :style="boxStyle">
9
+ <div class="gen-ai-prompt-field__body" :class="{ 'gen-ai-prompt-field__body--scroll': isConstrained }">
10
+ <el-input :model-value="modelValue" type="textarea" :autosize="textareaAutosize"
11
+ :rows="isConstrained ? rows : undefined" :maxlength="maxlength" :placeholder="placeholder"
12
+ :disabled="disabled" resize="none" :class="[
13
+ 'gen-ai-prompt-field__textarea',
14
+ { 'gen-ai-prompt-field__textarea--fill': isConstrained },
15
+ ]" @update:model-value="emit('update:modelValue', $event)" />
16
+ </div>
17
+ <div class="gen-ai-prompt-field__toolbar">
18
+ <button type="button" class="gen-ai-prompt-field__ai" :disabled="disabled" @click="openAiDialog">
19
+ AI+
20
+ </button>
21
+ </div>
22
+ </div>
23
+ <p class="gen-ai-prompt-field__count">{{ wordCountText }}</p>
24
+ </div>
25
+ </label>
26
+
27
+ <AiPromptGenerateDialog v-model="aiDialogVisible" :initial-title="chapterTitle"
28
+ :initial-description="chapterDescription" @confirm="handleAiConfirm" />
29
+ </template>
30
+
31
+ <script setup lang="ts">
32
+ import { computed, ref, type StyleValue } from 'vue';
33
+ import AiPromptGenerateDialog from './AiPromptGenerateDialog.vue'
34
+
35
+ const props = withDefaults(
36
+ defineProps<{
37
+ modelValue: string
38
+ label?: string
39
+ required?: boolean
40
+ maxlength?: number
41
+ rows?: number
42
+ maxRows?: number
43
+ chapterTitle?: string
44
+ chapterDescription?: string
45
+ /** 外层可指定宽度,默认随父级撑满 */
46
+ width?: string
47
+ /** 外层可指定整体高度(含底栏),内部文字区域滚动 */
48
+ height?: string
49
+ minHeight?: string
50
+ /** 外层可指定最大高度,超出后内部滚动 */
51
+ maxHeight?: string
52
+ placeholder?: string
53
+ disabled?: boolean
54
+ layout?: 'row' | 'stack'
55
+ labelWidth?: string
56
+ fieldGap?: string
57
+ rootStyle?: StyleValue
58
+ }>(),
59
+ {
60
+ label: 'Prompt',
61
+ required: true,
62
+ maxlength: 1300,
63
+ rows: 8,
64
+ maxRows: 16,
65
+ placeholder: '',
66
+ disabled: false,
67
+ layout: 'row',
68
+ chapterTitle: '',
69
+ chapterDescription: '',
70
+ },
71
+ )
72
+
73
+ const emit = defineEmits<{
74
+ 'update:modelValue': [value: string]
75
+ 'ai-assist': [prompt: string]
76
+ }>()
77
+
78
+ const aiDialogVisible = ref(false)
79
+
80
+ function openAiDialog() {
81
+ if (props.disabled) return
82
+ aiDialogVisible.value = true
83
+ }
84
+
85
+ function handleAiConfirm(prompt: string) {
86
+ emit('update:modelValue', prompt)
87
+ emit('ai-assist', prompt)
88
+ }
89
+
90
+ /** 指定 height / maxHeight 时改为固定容器 + 内部滚动 */
91
+ const isConstrained = computed(() => !!(props.height || props.maxHeight))
92
+
93
+ const textareaAutosize = computed(() => {
94
+ if (isConstrained.value) return false
95
+ return {
96
+ minRows: props.rows,
97
+ maxRows: props.maxRows,
98
+ }
99
+ })
100
+
101
+ const wordCountText = computed(() => `${props.modelValue.length} / ${props.maxlength}`)
102
+
103
+ function pickSizeStyle(
104
+ width?: string,
105
+ height?: string,
106
+ minHeight?: string,
107
+ maxHeight?: string,
108
+ ): StyleValue {
109
+ const style: Record<string, string> = {}
110
+ if (width) style.width = width
111
+ if (height) style.height = height
112
+ if (minHeight) style.minHeight = minHeight
113
+ if (maxHeight) style.maxHeight = maxHeight
114
+ return style
115
+ }
116
+
117
+ const fieldStyle = computed((): StyleValue => {
118
+ const style: Record<string, string> = {}
119
+ if (props.labelWidth) style['--gen-ai-prompt-field-label-w'] = props.labelWidth
120
+ if (props.fieldGap) style['--gen-ai-prompt-field-gap'] = props.fieldGap
121
+ if (!props.rootStyle) return style
122
+ if (typeof props.rootStyle === 'string') return [style, props.rootStyle]
123
+ if (Array.isArray(props.rootStyle)) return [style, ...props.rootStyle]
124
+ return { ...style, ...props.rootStyle }
125
+ })
126
+
127
+ const controlStyle = computed(() => pickSizeStyle(props.width))
128
+ const boxStyle = computed(() =>
129
+ pickSizeStyle(props.width, props.height, props.minHeight, props.maxHeight),
130
+ )
131
+
132
+ export interface PromptFieldLayoutBind {
133
+ labelWidth?: string
134
+ fieldGap?: string
135
+ width?: string
136
+ height?: string
137
+ minHeight?: string
138
+ maxHeight?: string
139
+ rootStyle?: StyleValue
140
+ }
141
+ </script>
142
+
143
+ <style scoped>
144
+ .gen-ai-prompt-field {
145
+ margin: 0;
146
+ }
147
+
148
+ .gen-ai-prompt-field--row {
149
+ --gen-ai-prompt-field-label-w: 100px;
150
+ --gen-ai-prompt-field-gap: 16px;
151
+ display: grid;
152
+ grid-template-columns: var(--gen-ai-prompt-field-label-w) minmax(0, 1fr);
153
+ column-gap: var(--gen-ai-prompt-field-gap);
154
+ align-items: start;
155
+ }
156
+
157
+ .gen-ai-prompt-field__label {
158
+ flex-shrink: 0;
159
+ padding-top: 8px;
160
+ font-size: 14px;
161
+ font-weight: 500;
162
+ font-family: Arial, sans-serif;
163
+ color: #303133;
164
+ white-space: nowrap;
165
+ }
166
+
167
+ .gen-ai-prompt-field__required {
168
+ margin-left: 2px;
169
+ color: #f56c6c;
170
+ }
171
+
172
+ .gen-ai-prompt-field__control {
173
+ min-width: 0;
174
+ width: 100%;
175
+ }
176
+
177
+ .gen-ai-prompt-field__box {
178
+ display: flex;
179
+ flex-direction: column;
180
+ width: 100%;
181
+ border: 1px solid #dcdfe6;
182
+ border-radius: 8px;
183
+ background: #fff;
184
+ overflow: hidden;
185
+ transition: border-color 0.2s ease;
186
+ }
187
+
188
+ .gen-ai-prompt-field__box--constrained {
189
+ min-height: 0;
190
+ }
191
+
192
+ .gen-ai-prompt-field__box:focus-within {
193
+ border-color: #c0c4cc;
194
+ }
195
+
196
+ .gen-ai-prompt-field__body {
197
+ flex: 1 1 auto;
198
+ min-height: 0;
199
+ /* 右侧 1px:滚动条贴边框;左侧 12px 与 textarea 内边距共同保证文字两端留白一致 */
200
+ padding: 12px 2px 4px 12px;
201
+ }
202
+
203
+ .gen-ai-prompt-field__body--scroll {
204
+ display: flex;
205
+ flex-direction: column;
206
+ overflow: hidden;
207
+ }
208
+
209
+ .gen-ai-prompt-field__textarea {
210
+ width: 100%;
211
+ }
212
+
213
+ .gen-ai-prompt-field__textarea :deep(.el-textarea),
214
+ .gen-ai-prompt-field__textarea :deep(.el-textarea__wrapper) {
215
+ padding: 0;
216
+ margin: 0;
217
+ box-shadow: none;
218
+ background: transparent;
219
+ }
220
+
221
+ .gen-ai-prompt-field__textarea :deep(.el-textarea__inner) {
222
+ padding: 0 10px 0 0;
223
+ margin: 0;
224
+ border: none;
225
+ box-shadow: none;
226
+ background: transparent;
227
+ font-size: 14px;
228
+ line-height: 1.6;
229
+ color: #303133;
230
+ resize: none;
231
+ box-sizing: border-box;
232
+ }
233
+
234
+ .gen-ai-prompt-field__textarea :deep(.el-textarea__inner:focus) {
235
+ box-shadow: none;
236
+ }
237
+
238
+ .gen-ai-prompt-field__textarea--fill {
239
+ flex: 1 1 auto;
240
+ min-height: 0;
241
+ height: 100%;
242
+ display: flex;
243
+ flex-direction: column;
244
+ }
245
+
246
+ .gen-ai-prompt-field__textarea--fill :deep(.el-textarea) {
247
+ flex: 1 1 auto;
248
+ min-height: 0;
249
+ height: 100%;
250
+ display: flex;
251
+ flex-direction: column;
252
+ }
253
+
254
+ .gen-ai-prompt-field__textarea--fill :deep(.el-textarea__inner) {
255
+ flex: 1 1 auto;
256
+ min-height: 0 !important;
257
+ height: 100% !important;
258
+ overflow-y: auto !important;
259
+ }
260
+
261
+ .gen-ai-prompt-field__textarea :deep(.el-textarea__inner::-webkit-scrollbar) {
262
+ width: 6px;
263
+ }
264
+
265
+ .gen-ai-prompt-field__textarea :deep(.el-textarea__inner::-webkit-scrollbar-thumb) {
266
+ border-radius: 3px;
267
+ background: #c0c4cc;
268
+ }
269
+
270
+ .gen-ai-prompt-field__toolbar {
271
+ flex-shrink: 0;
272
+ display: flex;
273
+ justify-content: flex-end;
274
+ align-items: center;
275
+ padding: 0 12px 10px;
276
+ }
277
+
278
+ .gen-ai-prompt-field__ai {
279
+ flex-shrink: 0;
280
+ width: 40px;
281
+ height: 40px;
282
+ padding: 0;
283
+ border: none;
284
+ border-radius: 50%;
285
+ background: linear-gradient(135deg, #7b61ff 0%, #5b8def 100%);
286
+ color: #fff;
287
+ font-size: 12px;
288
+ font-weight: 700;
289
+ line-height: 1;
290
+ cursor: pointer;
291
+ box-shadow: 0 2px 8px rgba(91, 141, 239, 0.35);
292
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
293
+ }
294
+
295
+ .gen-ai-prompt-field__ai:hover:not(:disabled) {
296
+ transform: translateY(-1px);
297
+ box-shadow: 0 4px 12px rgba(91, 141, 239, 0.45);
298
+ }
299
+
300
+ .gen-ai-prompt-field__ai:disabled {
301
+ opacity: 0.45;
302
+ cursor: not-allowed;
303
+ transform: none;
304
+ box-shadow: 0 2px 8px rgba(91, 141, 239, 0.35);
305
+ }
306
+
307
+ .gen-ai-prompt-field__count {
308
+ margin: 4px 0 0;
309
+ text-align: right;
310
+ font-size: 12px;
311
+ color: #909399;
312
+ line-height: 1;
313
+ }
314
+ </style>
@@ -0,0 +1,104 @@
1
+ <template>
2
+ <aside class="report-workflow-sidebar">
3
+ <ReportConfigPanel />
4
+
5
+ <ReportSourceFileSummary v-if="showEditorPanel" />
6
+
7
+ <ReportCollapsibleSection ref="sourcesSectionRef" v-model:open="sourcesOpen" title="信息源"
8
+ class="report-workflow-sidebar__sources-wrap" :class="{ 'is-collapsed': !sourcesOpen }"
9
+ @before-collapse="closeSourcesOverlays">
10
+ <ReportSourcesPanel ref="sourcesPanelRef" sync-workflow embedded :section-boundary-el="sourcesSectionRoot"
11
+ :panel-open="sourcesOpen" :sources-readonly="sourcesReadonly" :use-more-overlay="useMoreOverlay"
12
+ :class="{ 'is-section-collapsed': !sourcesOpen }" @submitted="collapseSources" @show-more="emit('show-more')" />
13
+ </ReportCollapsibleSection>
14
+ </aside>
15
+ </template>
16
+
17
+ <script setup lang="ts">
18
+ import { computed, ref } from 'vue'
19
+ import ReportSourcesPanel from './ReportSourcesPanel.vue'
20
+ import ReportCollapsibleSection from './ReportCollapsibleSection.vue'
21
+ import ReportConfigPanel from './ReportConfigPanel.vue'
22
+ import ReportSourceFileSummary from './ReportSourceFileSummary.vue'
23
+ import { useReportWorkflow } from '../useReportWorkflow'
24
+
25
+ withDefaults(
26
+ defineProps<{
27
+ useMoreOverlay?: boolean
28
+ }>(),
29
+ {
30
+ useMoreOverlay: false,
31
+ },
32
+ )
33
+
34
+ const emit = defineEmits<{
35
+ 'show-more': []
36
+ }>()
37
+
38
+ const { promptRightPanel, modelStep, chapterEditMode } = useReportWorkflow()
39
+
40
+ const showEditorPanel = computed(() => promptRightPanel.value !== 'settings')
41
+ const sourcesReadonly = computed(() => modelStep.value === 'prompt' && !chapterEditMode.value)
42
+
43
+ const sourcesOpen = ref(true)
44
+ const sourcesSectionRef = ref<InstanceType<typeof ReportCollapsibleSection> | null>(null)
45
+ const sourcesPanelRef = ref<InstanceType<typeof ReportSourcesPanel> | null>(null)
46
+ const sourcesSectionRoot = computed(() => sourcesSectionRef.value?.rootRef ?? null)
47
+
48
+ function closeSourcesOverlays(done: (hadOpenOverlays: boolean) => void) {
49
+ const hadOpen = sourcesPanelRef.value?.hasOpenOverlays() ?? false
50
+ if (hadOpen) {
51
+ sourcesPanelRef.value?.closeAllOverlays(true)
52
+ }
53
+ done(hadOpen)
54
+ }
55
+
56
+ function collapseSources() {
57
+ sourcesOpen.value = false
58
+ }
59
+ </script>
60
+
61
+ <style scoped>
62
+ .report-workflow-sidebar {
63
+ display: flex;
64
+ flex-direction: column;
65
+ gap: 14px;
66
+ min-width: 0;
67
+ height: 100%;
68
+ overflow: visible;
69
+ }
70
+
71
+ .report-workflow-sidebar__sources-wrap {
72
+ display: flex;
73
+ flex-direction: column;
74
+ min-width: 0;
75
+ flex: 1 1 auto;
76
+ min-height: 0;
77
+ }
78
+
79
+ .report-workflow-sidebar__sources-wrap :deep(.report-collapsible-section) {
80
+ flex: 1;
81
+ display: flex;
82
+ flex-direction: column;
83
+ min-height: 0;
84
+ }
85
+
86
+ .report-workflow-sidebar__sources-wrap :deep(.report-collapsible-section__body) {
87
+ flex: 1;
88
+ display: flex;
89
+ flex-direction: column;
90
+ min-height: 0;
91
+ }
92
+
93
+ .report-workflow-sidebar__sources-wrap :deep(.report-collapsible-section__body) {
94
+ min-width: 0;
95
+ }
96
+
97
+ .report-workflow-sidebar__sources-wrap :deep(.report-collapsible-section__toggle) {
98
+ border-bottom: none;
99
+ }
100
+
101
+ .report-workflow-sidebar__sources-wrap :deep(.report-collapsible-section.is-collapsed .report-collapsible-section__toggle) {
102
+ padding-bottom: 14px;
103
+ }
104
+ </style>