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,46 @@
1
+ import ExcelJS from 'exceljs'
2
+
3
+ export type WorksheetData = Array<Array<string | number | null | undefined>>
4
+
5
+ /**
6
+ * 行業數據 Excel 匯出(與其它系統 `@/utils/function` 呼叫方式一致)
7
+ * @param worksheetData 二維陣列:首行為表頭,其餘為資料列
8
+ * @param sheetName 工作表名稱
9
+ * @param excelName 匯出檔名(不含 .xlsx)
10
+ */
11
+ export async function industryExportToExcel(
12
+ worksheetData: WorksheetData,
13
+ sheetName: string,
14
+ excelName: string,
15
+ ): Promise<void> {
16
+ const workbook = new ExcelJS.Workbook()
17
+ const worksheet = workbook.addWorksheet(sheetName)
18
+ worksheet.addRows(worksheetData)
19
+
20
+ const headerRow = worksheet.getRow(1)
21
+ headerRow.eachCell((cell) => {
22
+ cell.font = { name: 'Calibri', size: 11, bold: true, color: { argb: 'FF000000' } }
23
+ cell.alignment = { vertical: 'middle', horizontal: 'left', wrapText: true }
24
+ })
25
+
26
+ worksheet.eachRow((row, rowIndex) => {
27
+ if (rowIndex === 1) return
28
+ row.eachCell((cell) => {
29
+ cell.font = { name: 'Calibri', size: 11, color: { argb: 'FF000000' } }
30
+ cell.alignment = { vertical: 'middle', horizontal: 'left', wrapText: true }
31
+ })
32
+ })
33
+
34
+ const buffer = await workbook.xlsx.writeBuffer()
35
+ const blob = new Blob([buffer], {
36
+ type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
37
+ })
38
+ const url = URL.createObjectURL(blob)
39
+ const anchor = document.createElement('a')
40
+ anchor.href = url
41
+ anchor.download = `${excelName}.xlsx`
42
+ document.body.appendChild(anchor)
43
+ anchor.click()
44
+ document.body.removeChild(anchor)
45
+ URL.revokeObjectURL(url)
46
+ }
@@ -0,0 +1 @@
1
+ export * from '@/views/gen-ai/common/utils/navigation'
@@ -0,0 +1 @@
1
+ export * from '@/views/gen-ai/common/utils/scroll'
@@ -0,0 +1,33 @@
1
+ const EXPORT_WORD_API = '/opendataloader/export/word'
2
+
3
+ export interface OpenDataLoaderWordExportOptions {
4
+ fileName?: string
5
+ }
6
+
7
+ export async function exportPdfViaOpenDataLoader(
8
+ pdfBlob: Blob,
9
+ options: OpenDataLoaderWordExportOptions = {},
10
+ ): Promise<Blob> {
11
+ const fileName = options.fileName ?? 'report.pdf'
12
+ const response = await fetch(EXPORT_WORD_API, {
13
+ method: 'POST',
14
+ headers: {
15
+ 'Content-Type': 'application/pdf',
16
+ 'X-File-Name': encodeURIComponent(fileName),
17
+ },
18
+ body: pdfBlob,
19
+ })
20
+
21
+ if (!response.ok) {
22
+ let message = `Word export failed (${response.status})`
23
+ try {
24
+ const payload = (await response.json()) as { message?: string }
25
+ if (payload.message) message = payload.message
26
+ } catch {
27
+ // ignore json parse errors
28
+ }
29
+ throw new Error(message)
30
+ }
31
+
32
+ return response.blob()
33
+ }
@@ -0,0 +1,115 @@
1
+ import { lockDocumentScroll } from './gen-ai-scroll'
2
+
3
+ export { lockDocumentScroll }
4
+
5
+ export interface PageScrollbarStyleOptions {
6
+ /** 滚动条宽高,默认 20px */
7
+ size?: number
8
+ /** 挂载到滚动容器的 class,默认 app-page-scrollbar */
9
+ className?: string
10
+ trackColor?: string
11
+ thumbColor?: string
12
+ thumbHoverColor?: string
13
+ }
14
+
15
+ export interface SetupPageScrollOptions extends PageScrollbarStyleOptions {
16
+ /** 需要滚动的容器(元素或选择器) */
17
+ containers: (HTMLElement | string)[]
18
+ /** 进入页面时锁定 html/body 满屏滚动,默认 true */
19
+ lockDocumentScroll?: boolean
20
+ }
21
+
22
+ const DEFAULT_CLASS = 'app-page-scrollbar'
23
+ const STYLE_ID_PREFIX = 'app-page-scrollbar-style'
24
+
25
+ function resolveElements(targets: (HTMLElement | string)[]): HTMLElement[] {
26
+ const result: HTMLElement[] = []
27
+ for (const target of targets) {
28
+ if (typeof target === 'string') {
29
+ result.push(...Array.from(document.querySelectorAll<HTMLElement>(target)))
30
+ } else {
31
+ result.push(target)
32
+ }
33
+ }
34
+ return result
35
+ }
36
+
37
+ /** 注入 20px(可配置)滚动条样式,返回 cleanup */
38
+ export function injectPageScrollbarStyle(options?: PageScrollbarStyleOptions): () => void {
39
+ const size = options?.size ?? 20
40
+ const className = options?.className ?? DEFAULT_CLASS
41
+ const track = options?.trackColor ?? '#f4f5f7'
42
+ const thumb = options?.thumbColor ?? '#cbd5e1'
43
+ const thumbHover = options?.thumbHoverColor ?? '#94a3b8'
44
+ const styleId = `${STYLE_ID_PREFIX}-${size}`
45
+
46
+ const css = `
47
+ .${className}::-webkit-scrollbar {
48
+ width: ${size}px !important;
49
+ height: ${size}px !important;
50
+ }
51
+ .${className}::-webkit-scrollbar-track {
52
+ background: ${track} !important;
53
+ border-radius: 9999px !important;
54
+ }
55
+ .${className}::-webkit-scrollbar-thumb {
56
+ background-color: ${thumb} !important;
57
+ border-radius: 9999px !important;
58
+ border: 3px solid transparent !important;
59
+ background-clip: padding-box !important;
60
+ min-height: 40px;
61
+ }
62
+ .${className}::-webkit-scrollbar-thumb:hover {
63
+ background-color: ${thumbHover} !important;
64
+ }
65
+ .${className} {
66
+ scrollbar-color: ${thumb} ${track};
67
+ scrollbar-width: auto;
68
+ }
69
+ `
70
+
71
+ let style = document.getElementById(styleId) as HTMLStyleElement | null
72
+ if (!style) {
73
+ style = document.createElement('style')
74
+ style.id = styleId
75
+ document.head.appendChild(style)
76
+ }
77
+ style.textContent = css
78
+
79
+ return () => {
80
+ style?.remove()
81
+ }
82
+ }
83
+
84
+
85
+ /** 为容器标记滚动条 class,返回 cleanup */
86
+ export function markScrollContainers(
87
+ containers: (HTMLElement | string)[],
88
+ className = DEFAULT_CLASS,
89
+ ): () => void {
90
+ const elements = resolveElements(containers)
91
+ elements.forEach((el) => el.classList.add(className))
92
+
93
+ return () => {
94
+ elements.forEach((el) => el.classList.remove(className))
95
+ }
96
+ }
97
+
98
+ /**
99
+ * 进入页面:禁用满屏滚动 + 为指定容器应用定制滚动条(默认 20px)
100
+ * 离开页面时调用返回的 cleanup 恢复
101
+ */
102
+ export function setupPageScroll(options: SetupPageScrollOptions): () => void {
103
+ const className = options.className ?? DEFAULT_CLASS
104
+ const lockDocument = options.lockDocumentScroll ?? true
105
+
106
+ const cleanStyle = injectPageScrollbarStyle(options)
107
+ const cleanLock = lockDocument ? lockDocumentScroll() : () => {}
108
+ const cleanMark = markScrollContainers(options.containers, className)
109
+
110
+ return () => {
111
+ cleanMark()
112
+ cleanLock()
113
+ cleanStyle()
114
+ }
115
+ }
@@ -0,0 +1,87 @@
1
+ export type TranscodeMethod =
2
+ | 'plain'
3
+ | 'base64'
4
+ | 'url'
5
+ | 'unicode'
6
+ | 'hex'
7
+ | 'htmlEntity'
8
+ | 'binary'
9
+
10
+ export const transcodeMethodLabels: Record<TranscodeMethod, string> = {
11
+ plain: '原文',
12
+ base64: 'Base64',
13
+ url: 'URL 编码',
14
+ unicode: 'Unicode 转义',
15
+ hex: 'Hex 编码',
16
+ htmlEntity: 'HTML 实体',
17
+ binary: '二进制',
18
+ }
19
+
20
+ const utf8Encoder = new TextEncoder()
21
+
22
+ function toBytes(text: string): Uint8Array {
23
+ return utf8Encoder.encode(text)
24
+ }
25
+
26
+ function bytesToBinary(bytes: Uint8Array): string {
27
+ return Array.from(bytes, (b) => b.toString(2).padStart(8, '0')).join(' ')
28
+ }
29
+
30
+ function bytesToHex(bytes: Uint8Array): string {
31
+ return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join(' ')
32
+ }
33
+
34
+ function toBase64(text: string): string {
35
+ const bytes = toBytes(text)
36
+ let binary = ''
37
+ bytes.forEach((b) => {
38
+ binary += String.fromCharCode(b)
39
+ })
40
+ return btoa(binary)
41
+ }
42
+
43
+ function toUnicodeEscape(text: string): string {
44
+ return Array.from(text)
45
+ .map((ch) => {
46
+ const code = ch.codePointAt(0) ?? 0
47
+ return code > 0xffff
48
+ ? `\\u{${code.toString(16)}}`
49
+ : `\\u${code.toString(16).padStart(4, '0')}`
50
+ })
51
+ .join('')
52
+ }
53
+
54
+ function toHtmlEntity(text: string): string {
55
+ return Array.from(text)
56
+ .map((ch) => `&#${(ch.codePointAt(0) ?? 0)};`)
57
+ .join('')
58
+ }
59
+
60
+ const transcoders: Record<Exclude<TranscodeMethod, 'plain'>, (text: string) => string> = {
61
+ base64: toBase64,
62
+ url: (text) => encodeURIComponent(text),
63
+ unicode: toUnicodeEscape,
64
+ hex: (text) => bytesToHex(toBytes(text)),
65
+ htmlEntity: toHtmlEntity,
66
+ binary: (text) => bytesToBinary(toBytes(text)),
67
+ }
68
+
69
+ export function pickRandomTranscodeMethod(): TranscodeMethod {
70
+ const methods = Object.keys(transcoders) as Exclude<TranscodeMethod, 'plain'>[]
71
+ return methods[Math.floor(Math.random() * methods.length)] ?? 'hex'
72
+ }
73
+
74
+ export function transcodeText(text: string, method: TranscodeMethod = pickRandomTranscodeMethod()): {
75
+ method: TranscodeMethod
76
+ label: string
77
+ result: string
78
+ } {
79
+ if (method === 'plain') {
80
+ return { method, label: transcodeMethodLabels.plain, result: text }
81
+ }
82
+ return {
83
+ method,
84
+ label: transcodeMethodLabels[method],
85
+ result: transcoders[method](text),
86
+ }
87
+ }
@@ -0,0 +1,44 @@
1
+ import html2canvas from 'html2canvas'
2
+ import { jsPDF } from 'jspdf'
3
+
4
+ export interface ReportPdfExportOptions {
5
+ scale?: number
6
+ backgroundColor?: string
7
+ }
8
+
9
+ export async function renderReportPdfBlob(
10
+ element: HTMLElement,
11
+ options: ReportPdfExportOptions = {},
12
+ ): Promise<Blob> {
13
+ const scale = options.scale ?? 2.5
14
+ const backgroundColor = options.backgroundColor ?? '#ffffff'
15
+
16
+ const canvas = await html2canvas(element, {
17
+ scale,
18
+ backgroundColor,
19
+ useCORS: true,
20
+ logging: false,
21
+ windowWidth: element.scrollWidth,
22
+ })
23
+
24
+ const imgData = canvas.toDataURL('image/png')
25
+ const pdf = new jsPDF('p', 'mm', 'a4')
26
+ const imgWidth = 210
27
+ const pageHeight = 297
28
+ const imgHeight = (canvas.height * imgWidth) / canvas.width
29
+
30
+ let heightLeft = imgHeight
31
+ let position = 0
32
+
33
+ pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight)
34
+ heightLeft -= pageHeight
35
+
36
+ while (heightLeft > 0) {
37
+ position = heightLeft - imgHeight
38
+ pdf.addPage()
39
+ pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight)
40
+ heightLeft -= pageHeight
41
+ }
42
+
43
+ return pdf.output('blob')
44
+ }
@@ -0,0 +1,68 @@
1
+ <template>
2
+ <div class="page-blank">
3
+ <p class="page-blank__title">{{ welcomeText }}</p>
4
+
5
+ <div class="page-blank__tools">
6
+ <button
7
+ v-for="tool in tools"
8
+ :key="tool.id"
9
+ type="button"
10
+ class="app-btn app-btn--wide"
11
+ @click="handleToolClick(tool)"
12
+ >
13
+ {{ tool.label }}
14
+ </button>
15
+ </div>
16
+ </div>
17
+ </template>
18
+
19
+
20
+ <script setup lang="ts">
21
+ import { useRouter } from 'vue-router'
22
+
23
+ const router = useRouter()
24
+
25
+ const welcomeText = '歡迎使用XX SMART,請選擇你想使用的工具'
26
+
27
+ const tools = [
28
+ { id: 'industry', label: 'aa分析', routeName: 'gen-entry' as const },
29
+ { id: 'global', label: 'bb市場分析', routeName: 'model-manager' as const },
30
+ { id: 'peer', label: 'cc分析', routeName: null },
31
+ ] as const
32
+
33
+ function handleToolClick(tool: (typeof tools)[number]) {
34
+ if (tool.routeName) {
35
+ const { href } = router.resolve({ name: tool.routeName })
36
+ window.open(href, '_blank')
37
+ }
38
+ }
39
+ </script>
40
+
41
+ <style scoped>
42
+ .page-blank {
43
+ display: flex;
44
+ flex-direction: column;
45
+ align-items: center;
46
+ justify-content: center;
47
+ min-height: 420px;
48
+ padding: 24px 0 8px;
49
+ text-align: center;
50
+ }
51
+
52
+ .page-blank__title {
53
+ margin: 0 0 36px;
54
+ font-size: 18px;
55
+ line-height: 1.6;
56
+ color: #4a4a4a;
57
+ font-weight: 500;
58
+ max-width: 720px;
59
+ }
60
+
61
+ .page-blank__tools {
62
+ display: flex;
63
+ flex-wrap: wrap;
64
+ align-items: center;
65
+ justify-content: center;
66
+ gap: 20px;
67
+ }
68
+ </style>
@@ -0,0 +1,29 @@
1
+ <template>
2
+ <div class="page-home">
3
+ <h1>欢迎</h1>
4
+ <p>GenAI Demo 演示平台</p>
5
+ </div>
6
+ </template>
7
+
8
+ <style scoped>
9
+ .page-home {
10
+ display: flex;
11
+ flex-direction: column;
12
+ align-items: center;
13
+ justify-content: center;
14
+ min-height: 320px;
15
+ color: #333;
16
+ }
17
+
18
+ .page-home h1 {
19
+ margin: 0 0 12px;
20
+ font-size: 32px;
21
+ font-weight: 600;
22
+ }
23
+
24
+ .page-home p {
25
+ margin: 0;
26
+ font-size: 16px;
27
+ color: #666;
28
+ }
29
+ </style>
@@ -0,0 +1,83 @@
1
+ /** Offline / fallback answers for HederaRoot assistant. */
2
+ export const HEDERA_SYSTEM_PROMPT = `你是 HederaRoot 平台的 Hedera 链上运营助手。
3
+ 你熟悉 HTS(代币)、HCS(共识存证)、HSCS(智能合约)、Governance(KYC/密钥矩阵)、RWA 上链与 Mirror Node 监控。
4
+ 回答应简洁、可执行,优先给出页面路径(如 /hts/tokens、/governance/kyc)与 .env 配置提示。
5
+ 若涉及私钥,提醒用户仅在 .env 本地配置,不要提交到 Git。`;
6
+
7
+ export const HEDERA_PROMPT_SUGGESTIONS = [
8
+ '如何创建带 KYC Key 的 HTS 代币?',
9
+ 'TokenServe 暂停代币失败怎么排查?',
10
+ 'RWA 上链 metadata 超过 100 字节怎么办?',
11
+ '如何在 HSCS 调试页调用合约 read 方法?',
12
+ 'KYC 授权链上交易需要什么 Key?',
13
+ 'Mirror Node 与 Hashio RPC 有什么区别?',
14
+ ];
15
+
16
+ type KnowledgeEntry = {
17
+ keywords: string[];
18
+ answer: string;
19
+ };
20
+
21
+ const KNOWLEDGE_BASE: KnowledgeEntry[] = [
22
+ {
23
+ keywords: ['创建', '代币', 'hts', 'create'],
24
+ answer:
25
+ '创建 FT/NFT:打开 **/hts/create-token**,在 .env 配置 ACCOUNT_ID 与 PRIVATE_KEY。勾选需要的管理 Key(KYC、Pause、Supply 等),Treasury 默认为操作员账户。创建成功后可在 **/hts/tokens** 查看并在 **/hts/TokenServe** 管理。',
26
+ },
27
+ {
28
+ keywords: ['kyc', '白名单', '准入'],
29
+ answer:
30
+ 'KYC 流程:1) 创建代币时设置 **KYC Key**;2) **/governance/keys** 确认 KYC Key 已激活;3) **/governance/kyc** 新增申请并链上授权。操作员私钥须与 KYC Key 匹配,否则 `INVALID_SIGNATURE`。',
31
+ },
32
+ {
33
+ keywords: ['暂停', 'pause', '熔断'],
34
+ answer:
35
+ '代币暂停需 Token 设置 **Pause Key** 且操作员持有该 Key。在 **/hts/TokenServe** 连接账户后执行暂停/恢复。若报 `TOKEN_HAS_NO_PAUSE_KEY`,说明创建时未配置 Pause Key。',
36
+ },
37
+ {
38
+ keywords: ['rwa', 'metadata', '100'],
39
+ answer:
40
+ 'Hedera Token metadata 上限 **100 字节**。RWA 完整信息会先写入 **HCS Topic**,链上 metadata 使用 `hcs:0.0.xxx/seq` 指针或紧凑 JSON。见 **/hts/rwa** 执行上链流程。',
41
+ },
42
+ {
43
+ keywords: ['合约', 'hscs', 'deploy', '部署'],
44
+ answer:
45
+ '智能合约:**/hscs/contracts** 部署(MyToken 模板 / 上传 artifact / 粘贴 bytecode),使用 ContractCreateFlow。部署后在 **/hscs/debug** 选择 Contract ID,加载 ABI,读操作用 Query,写操作用 Transaction。',
46
+ },
47
+ {
48
+ keywords: ['mirror', 'tps', '网络'],
49
+ answer:
50
+ '网络监控:**/settings/network** 与 **/dashboard/monitor** 从 Mirror Node 拉取 TPS、节点、Gas。链上读写可用 Hashio RPC(.env 的 HEDERA_RPC_URL)。Operator 配置在 **/settings/operator**。',
51
+ },
52
+ {
53
+ keywords: ['hcs', '存证', 'topic'],
54
+ answer:
55
+ 'HCS 共识存证:**/hcs** 查看 Topic 消息流。RWA 审计默认 Topic `0.0.529001`。消息可通过 Mirror 查询,**AI 审计** 页会采样分析。',
56
+ },
57
+ {
58
+ keywords: ['env', 'account', '私钥', '配置'],
59
+ answer:
60
+ '在项目根目录 `.env` 配置 ACCOUNT_ID、PRIVATE_KEY、HEDERA_RPC_URL。修改后需重启 npm start。切勿将 .env 提交到 Git。',
61
+ },
62
+ ];
63
+
64
+ export function matchLocalKnowledge(question: string): string | null {
65
+ const lower = question.toLowerCase();
66
+ let best: KnowledgeEntry | null = null;
67
+ let bestScore = 0;
68
+
69
+ for (const entry of KNOWLEDGE_BASE) {
70
+ let score = 0;
71
+ for (const kw of entry.keywords) {
72
+ if (lower.includes(kw.toLowerCase())) score += 1;
73
+ }
74
+ if (score > bestScore) {
75
+ bestScore = score;
76
+ best = entry;
77
+ }
78
+ }
79
+
80
+ return bestScore > 0 ? best!.answer : null;
81
+ }
82
+
83
+ export const DEFAULT_WELCOME = '🤖 Hedera 链上助手 · 可问我 HTS / HCS / HSCS / 合规相关问题';
@@ -0,0 +1,10 @@
1
+ export interface ConversationItem {
2
+ key: string;
3
+ label: string;
4
+ group?: string;
5
+ isDraft?: boolean;
6
+ }
7
+
8
+ export type ParsedMessage =
9
+ | { role: 'user'; content: string }
10
+ | { role: 'assistant'; content: string; thinkContent?: string };