aegon-gen 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.
- package/package.json +12 -0
- package/src/App.vue +3 -0
- package/src/api/index.ts +19 -0
- package/src/api/modules/gen-ai/gen-entry/index.ts +30 -0
- package/src/api/modules/gen-ai/model-manager/index.ts +42 -0
- package/src/api/modules/gen-ai/model-manager/mockApi.ts +33 -0
- package/src/api/modules/index.ts +98 -0
- package/src/api/modules/user/index.ts +4 -0
- package/src/api/request.ts +102 -0
- package/src/assets/sample-access-icon.png +0 -0
- package/src/assets/sample-pie-chart.png +0 -0
- package/src/assets/vue.svg +1 -0
- package/src/components/CapsuleScrollbar.vue +93 -0
- package/src/components/Export/ExcelExport.vue +592 -0
- package/src/components/Export/ExcelExport2.vue +494 -0
- package/src/components/Export/ExcelExport3.vue +342 -0
- package/src/components/Export/ExcelExport4.vue +665 -0
- package/src/components/Export/excelExport.js +547 -0
- package/src/components/Export/excelExport.ts +551 -0
- package/src/components/GEN-AI/index.vue +142 -0
- package/src/components/GEN-AI/index1.vue +456 -0
- package/src/components/GEN-AI/index10.vue +5 -0
- package/src/components/GEN-AI/index2.vue +568 -0
- package/src/components/GEN-AI/index3.vue +623 -0
- package/src/components/GEN-AI/index4.vue +629 -0
- package/src/components/GEN-AI/index5.vue +578 -0
- package/src/components/GEN-AI/index6.vue +656 -0
- package/src/components/GEN-AI/index7.vue +717 -0
- package/src/components/GEN-AI/index8.vue +405 -0
- package/src/components/GEN-AI/index9.vue +1065 -0
- package/src/components/GEN-AI/types.ts +12 -0
- package/src/components/GEN-AI/utils.ts +42 -0
- package/src/components/HelloWorld.vue +41 -0
- package/src/components/PageCard.vue +7 -0
- package/src/components/PageHeader.vue +32 -0
- package/src/components/backup/index5 copy.vue +556 -0
- package/src/components/backup/index5.vue +620 -0
- package/src/components/backup/index9 copy.vue +1029 -0
- package/src/components/backup/index9-pro.vue +1065 -0
- package/src/components/backup/index9.vue +1057 -0
- package/src/components/el-date-picker.vue +64 -0
- package/src/directives/btnLoading.ts +427 -0
- package/src/directives/debounce copy.ts +670 -0
- package/src/directives/debounce.ts +98 -0
- package/src/directives/index.ts +25 -0
- package/src/layouts/MainLayout.vue +101 -0
- package/src/main.ts +85 -0
- package/src/router/index.ts +76 -0
- package/src/router/menus.ts +28 -0
- package/src/style.css +79 -0
- package/src/styles/_variables.scss +24 -0
- package/src/styles/app-button.css +26 -0
- package/src/styles/element-overrides.css +23 -0
- package/src/styles/global.css +44 -0
- package/src/styles/index.scss +1 -0
- package/src/styles/page-card.css +21 -0
- package/src/styles/variables.css +26 -0
- package/src/test/mock.ts +101 -0
- package/src/test/test1.vue +402 -0
- package/src/test/test2.vue +1689 -0
- package/src/types/gen-ai/gen-entry/index.ts +17 -0
- package/src/types/gen-ai/model-manager/index.ts +19 -0
- package/src/utils/docxExport.ts +1610 -0
- package/src/utils/gen-ai-navigation.ts +37 -0
- package/src/utils/gen-ai-scroll.ts +455 -0
- package/src/utils/openDataLoaderWordExport.ts +33 -0
- package/src/utils/pageScrollbar.ts +115 -0
- package/src/utils/randomTranscode.ts +87 -0
- package/src/utils/reportPdfExport.ts +44 -0
- package/src/views/AdminCenter/index.vue +817 -0
- package/src/views/Blank.vue +68 -0
- package/src/views/Home.vue +29 -0
- package/src/views/ReportCenter/index.vue +1380 -0
- package/src/views/TemplateCenter/Knowledge.ts +83 -0
- package/src/views/TemplateCenter/data.d.ts +10 -0
- package/src/views/TemplateCenter/index.vue +1205 -0
- package/src/views/TemplateCenter/service.ts +69 -0
- package/src/views/gen-ai/components/RecentReportsTable.vue +193 -0
- package/src/views/gen-ai/gen-entry/index.vue +309 -0
- package/src/views/gen-ai/gen-entry/mockData.ts +160 -0
- package/src/views/gen-ai/management-center/index.vue +53 -0
- package/src/views/gen-ai/model-manager/ChapterTitleScroll.vue +275 -0
- package/src/views/gen-ai/model-manager/index.vue +1205 -0
- package/src/views/gen-ai/model-manager/mockData.ts +122 -0
- package/src/views/gen-ai/report-center/index.vue +158 -0
- package/src/vite-env.d.ts +38 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { Directive, DirectiveBinding } from 'vue'
|
|
2
|
+
|
|
3
|
+
const DEBOUNCE_KEY = Symbol('vDebounce')
|
|
4
|
+
|
|
5
|
+
/** 默认防重间隔 2s;v-debounce:800 自定义毫秒 */
|
|
6
|
+
const DEFAULT_WAIT_MS = 2000
|
|
7
|
+
const DEFAULT_EVENT = 'click'
|
|
8
|
+
|
|
9
|
+
export type DebounceHandler = (event: Event) => unknown
|
|
10
|
+
export type DebounceBindingValue = DebounceHandler | undefined
|
|
11
|
+
export type DebounceDirective = Directive<HTMLElement, DebounceBindingValue>
|
|
12
|
+
export type DebounceDirectiveBinding = DirectiveBinding<DebounceBindingValue>
|
|
13
|
+
|
|
14
|
+
interface DebounceBindingMeta {
|
|
15
|
+
listener: (event: Event) => void
|
|
16
|
+
event: string
|
|
17
|
+
binding: DebounceDirectiveBinding
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function resolveButtonHost(el: HTMLElement): HTMLElement {
|
|
21
|
+
if (el.tagName === 'BUTTON') return el
|
|
22
|
+
const nested = el.querySelector<HTMLElement>('button.el-button')
|
|
23
|
+
return nested ?? el
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function resolveWait(arg?: string): number {
|
|
27
|
+
if (arg && /^\d+$/.test(arg)) return Number(arg)
|
|
28
|
+
return DEFAULT_WAIT_MS
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function resolveEvent(arg?: string): string {
|
|
32
|
+
if (arg && !/^\d+$/.test(arg)) return arg
|
|
33
|
+
return DEFAULT_EVENT
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* v-debounce — 纯点击防重,与 loading 解耦
|
|
38
|
+
* - v-debounce @click="fn" 默认 2s
|
|
39
|
+
* - v-debounce:800 @click="fn" 自定义间隔
|
|
40
|
+
* - v-debounce:800="fn" 绑定 handler(拦截原生 @click)
|
|
41
|
+
*/
|
|
42
|
+
export const vDebounce: DebounceDirective = {
|
|
43
|
+
mounted(el: HTMLElement, binding: DebounceDirectiveBinding) {
|
|
44
|
+
const host = resolveButtonHost(el)
|
|
45
|
+
let locked = false
|
|
46
|
+
|
|
47
|
+
const listener = (e: Event) => {
|
|
48
|
+
const meta = (host as HTMLElement & { [DEBOUNCE_KEY]?: DebounceBindingMeta })[DEBOUNCE_KEY]
|
|
49
|
+
const currentBinding = meta?.binding ?? binding
|
|
50
|
+
const wait = resolveWait(currentBinding.arg)
|
|
51
|
+
const handler =
|
|
52
|
+
typeof currentBinding.value === 'function' ? currentBinding.value : undefined
|
|
53
|
+
|
|
54
|
+
if (locked) {
|
|
55
|
+
e.preventDefault()
|
|
56
|
+
e.stopImmediatePropagation()
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
locked = true
|
|
61
|
+
|
|
62
|
+
if (handler) {
|
|
63
|
+
e.preventDefault()
|
|
64
|
+
e.stopImmediatePropagation()
|
|
65
|
+
Promise.resolve(handler(e)).finally(() => {
|
|
66
|
+
window.setTimeout(() => {
|
|
67
|
+
locked = false
|
|
68
|
+
}, wait)
|
|
69
|
+
})
|
|
70
|
+
return
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
window.setTimeout(() => {
|
|
74
|
+
locked = false
|
|
75
|
+
}, wait)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const event = resolveEvent(binding.arg)
|
|
79
|
+
host.addEventListener(event, listener, true)
|
|
80
|
+
;(host as HTMLElement & { [DEBOUNCE_KEY]?: DebounceBindingMeta })[DEBOUNCE_KEY] = {
|
|
81
|
+
listener,
|
|
82
|
+
event,
|
|
83
|
+
binding,
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
updated(el: HTMLElement, binding: DebounceDirectiveBinding) {
|
|
87
|
+
const host = resolveButtonHost(el)
|
|
88
|
+
const meta = (host as HTMLElement & { [DEBOUNCE_KEY]?: DebounceBindingMeta })[DEBOUNCE_KEY]
|
|
89
|
+
if (meta) meta.binding = binding
|
|
90
|
+
},
|
|
91
|
+
unmounted(el: HTMLElement) {
|
|
92
|
+
const host = resolveButtonHost(el)
|
|
93
|
+
const meta = (host as HTMLElement & { [DEBOUNCE_KEY]?: DebounceBindingMeta })[DEBOUNCE_KEY]
|
|
94
|
+
if (!meta) return
|
|
95
|
+
host.removeEventListener(meta.event, meta.listener, true)
|
|
96
|
+
delete (host as HTMLElement & { [DEBOUNCE_KEY]?: DebounceBindingMeta })[DEBOUNCE_KEY]
|
|
97
|
+
},
|
|
98
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { App, Directive } from 'vue'
|
|
2
|
+
import { closeBtnLoading, vBtnLoading } from './btnLoading'
|
|
3
|
+
import { vDebounce } from './debounce'
|
|
4
|
+
|
|
5
|
+
/** 全局自定义指令清单(新增指令在此单独追加一项) */
|
|
6
|
+
const directiveRegistry: ReadonlyArray<{
|
|
7
|
+
name: string
|
|
8
|
+
directive: Directive
|
|
9
|
+
}> = [
|
|
10
|
+
{ name: 'debounce', directive: vDebounce as Directive },
|
|
11
|
+
{ name: 'btnLoading', directive: vBtnLoading },
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
export function registerDirectives(app: App) {
|
|
15
|
+
directiveRegistry.forEach(({ name, directive }) => {
|
|
16
|
+
app.directive(name, directive)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
app.config.globalProperties.closeBtnLoading = closeBtnLoading
|
|
20
|
+
;(globalThis as typeof globalThis & { closeBtnLoading: typeof closeBtnLoading }).closeBtnLoading =
|
|
21
|
+
closeBtnLoading
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export { vDebounce, type DebounceBindingValue, type DebounceDirective, type DebounceHandler } from './debounce'
|
|
25
|
+
export { vBtnLoading, closeBtnLoading, hasActiveBtnLoading } from './btnLoading'
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-container class="main-layout">
|
|
3
|
+
<el-aside width="220px" class="main-layout__aside">
|
|
4
|
+
<div class="main-layout__logo">GenAI Demo</div>
|
|
5
|
+
<el-menu
|
|
6
|
+
:default-active="activeMenu"
|
|
7
|
+
router
|
|
8
|
+
class="main-layout__menu"
|
|
9
|
+
>
|
|
10
|
+
<el-menu-item index="/">
|
|
11
|
+
<span>HOME</span>
|
|
12
|
+
</el-menu-item>
|
|
13
|
+
<el-menu-item index="/blank">
|
|
14
|
+
<span>SMART</span>
|
|
15
|
+
</el-menu-item>
|
|
16
|
+
<el-menu-item index="/report-center">
|
|
17
|
+
<span>ReportCenter</span>
|
|
18
|
+
</el-menu-item>
|
|
19
|
+
<el-menu-item index="new-tab:template-center" @click.stop.prevent="openTemplateCenterPage">
|
|
20
|
+
<span>TemplateCenter</span>
|
|
21
|
+
</el-menu-item>
|
|
22
|
+
<el-menu-item index="/admin-center">
|
|
23
|
+
<span>AdminCenter</span>
|
|
24
|
+
</el-menu-item>
|
|
25
|
+
<el-sub-menu index="gen-ai">
|
|
26
|
+
<template #title>
|
|
27
|
+
<span>GEN-TYPER</span>
|
|
28
|
+
</template>
|
|
29
|
+
<el-menu-item
|
|
30
|
+
v-for="item in genAiAppMenus"
|
|
31
|
+
:key="item.path"
|
|
32
|
+
:index="item.path"
|
|
33
|
+
>
|
|
34
|
+
{{ item.title }}
|
|
35
|
+
</el-menu-item>
|
|
36
|
+
<el-menu-item
|
|
37
|
+
v-for="item in genAiMenus"
|
|
38
|
+
:key="item.path"
|
|
39
|
+
:index="item.path"
|
|
40
|
+
>
|
|
41
|
+
{{ item.title }}
|
|
42
|
+
</el-menu-item>
|
|
43
|
+
</el-sub-menu>
|
|
44
|
+
</el-menu>
|
|
45
|
+
</el-aside>
|
|
46
|
+
<el-main class="main-layout__main">
|
|
47
|
+
<PageCard>
|
|
48
|
+
<router-view />
|
|
49
|
+
</PageCard>
|
|
50
|
+
</el-main>
|
|
51
|
+
</el-container>
|
|
52
|
+
</template>
|
|
53
|
+
|
|
54
|
+
<script setup lang="ts">
|
|
55
|
+
import { computed } from 'vue'
|
|
56
|
+
import { useRoute, useRouter } from 'vue-router'
|
|
57
|
+
import PageCard from '../components/PageCard.vue'
|
|
58
|
+
import { genAiAppMenus, genAiMenus } from '../router/menus'
|
|
59
|
+
import { openTemplateCenter } from '@/utils/gen-ai-navigation'
|
|
60
|
+
|
|
61
|
+
const route = useRoute()
|
|
62
|
+
const router = useRouter()
|
|
63
|
+
|
|
64
|
+
const activeMenu = computed(() => route.path)
|
|
65
|
+
|
|
66
|
+
function openTemplateCenterPage() {
|
|
67
|
+
openTemplateCenter(router)
|
|
68
|
+
}
|
|
69
|
+
</script>
|
|
70
|
+
|
|
71
|
+
<style scoped>
|
|
72
|
+
.main-layout {
|
|
73
|
+
min-height: 100vh;
|
|
74
|
+
background: var(--page-bg);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.main-layout__aside {
|
|
78
|
+
background: #fff;
|
|
79
|
+
border-right: 1px solid var(--page-card-border);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.main-layout__logo {
|
|
83
|
+
height: 56px;
|
|
84
|
+
line-height: 56px;
|
|
85
|
+
padding: 0 20px;
|
|
86
|
+
font-size: 16px;
|
|
87
|
+
font-weight: 600;
|
|
88
|
+
color: #2d3139;
|
|
89
|
+
border-bottom: 1px solid var(--page-card-border);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.main-layout__menu {
|
|
93
|
+
border-right: none;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.main-layout__main {
|
|
97
|
+
padding: var(--page-outer-spacing);
|
|
98
|
+
overflow: auto;
|
|
99
|
+
box-sizing: border-box;
|
|
100
|
+
}
|
|
101
|
+
</style>
|
package/src/main.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { createApp, type App as VueApp } from 'vue'
|
|
2
|
+
import ElementPlus from 'element-plus'
|
|
3
|
+
import zhTw from 'element-plus/es/locale/lang/zh-tw'
|
|
4
|
+
import './styles/variables.css'
|
|
5
|
+
import './styles/index.scss'
|
|
6
|
+
import 'element-plus/dist/index.css'
|
|
7
|
+
import './styles/global.css'
|
|
8
|
+
import './styles/element-overrides.css'
|
|
9
|
+
import './styles/page-card.css'
|
|
10
|
+
import './styles/app-button.css'
|
|
11
|
+
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
|
|
12
|
+
import App from './App.vue'
|
|
13
|
+
import router from './router'
|
|
14
|
+
import { registerDirectives } from '@/directives'
|
|
15
|
+
import CapsuleScrollbar from '@/components/CapsuleScrollbar.vue'
|
|
16
|
+
import { initCapsuleScrollbarGlobal } from '@/utils/gen-ai-scroll'
|
|
17
|
+
|
|
18
|
+
let app: VueApp | null = null
|
|
19
|
+
|
|
20
|
+
function registerElementPlusIcons(instance: VueApp) {
|
|
21
|
+
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
|
22
|
+
instance.component(key, component)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function mountApp() {
|
|
27
|
+
if (app) return
|
|
28
|
+
app = createApp(App)
|
|
29
|
+
registerElementPlusIcons(app)
|
|
30
|
+
registerDirectives(app)
|
|
31
|
+
initCapsuleScrollbarGlobal()
|
|
32
|
+
app.component('CapsuleScrollbar', CapsuleScrollbar)
|
|
33
|
+
app.use(ElementPlus, { locale: zhTw })
|
|
34
|
+
app.use(router)
|
|
35
|
+
app.mount('#app')
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function unmountApp() {
|
|
39
|
+
app?.unmount()
|
|
40
|
+
app = null
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function shouldRemountOnUpdate(payload: { updates?: Array<{ type?: string }> }) {
|
|
44
|
+
return (
|
|
45
|
+
payload.updates?.some((update) => update.type === 'js-update' || update.type === 'vue') ??
|
|
46
|
+
false
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
mountApp()
|
|
51
|
+
|
|
52
|
+
if (import.meta.hot) {
|
|
53
|
+
import.meta.hot.accept(['./App.vue'], () => {
|
|
54
|
+
unmountApp()
|
|
55
|
+
mountApp()
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
import.meta.hot.accept(
|
|
59
|
+
[
|
|
60
|
+
'./components/GEN-AI/index9.vue',
|
|
61
|
+
'./components/GEN-AI/index10.vue',
|
|
62
|
+
'./utils/docxExport.ts',
|
|
63
|
+
],
|
|
64
|
+
() => {
|
|
65
|
+
unmountApp()
|
|
66
|
+
mountApp()
|
|
67
|
+
}
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
import.meta.hot.on('vite:beforeUpdate', (payload) => {
|
|
71
|
+
if (shouldRemountOnUpdate(payload)) {
|
|
72
|
+
unmountApp()
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
import.meta.hot.on('vite:afterUpdate', (payload) => {
|
|
77
|
+
if (shouldRemountOnUpdate(payload) && !app) {
|
|
78
|
+
mountApp()
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
import.meta.hot.dispose(() => {
|
|
83
|
+
unmountApp()
|
|
84
|
+
})
|
|
85
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// router/index.ts
|
|
2
|
+
import type { Component } from 'vue'
|
|
3
|
+
import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router'
|
|
4
|
+
import MainLayout from '../layouts/MainLayout.vue'
|
|
5
|
+
import { genAiMenus } from './menus'
|
|
6
|
+
|
|
7
|
+
const genAiModules = import.meta.glob('../components/GEN-AI/index*.vue')
|
|
8
|
+
|
|
9
|
+
const genAiRoutes: RouteRecordRaw[] = genAiMenus.flatMap((item) => {
|
|
10
|
+
const modulePath = `../components/GEN-AI/${item.file}.vue`
|
|
11
|
+
const componentLoader = genAiModules[modulePath]
|
|
12
|
+
if (!componentLoader) {
|
|
13
|
+
console.warn(`GEN-AI component not found: ${modulePath}`)
|
|
14
|
+
return []
|
|
15
|
+
}
|
|
16
|
+
return [{
|
|
17
|
+
path: item.path.replace(/^\//, ''),
|
|
18
|
+
name: `GenAI-${item.file}`,
|
|
19
|
+
component: componentLoader as () => Promise<Component>,
|
|
20
|
+
meta: { title: item.title, group: 'GEN-TYPER' },
|
|
21
|
+
}]
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const routes: RouteRecordRaw[] = [
|
|
25
|
+
{
|
|
26
|
+
path: '/gen-ai/gen-entry',
|
|
27
|
+
name: 'gen-entry',
|
|
28
|
+
component: () => import('../views/gen-ai/gen-entry/index.vue'),
|
|
29
|
+
meta: { title: '行業分析', standalone: true },
|
|
30
|
+
},
|
|
31
|
+
{ path: '/gen-entry', redirect: '/gen-ai/gen-entry' },
|
|
32
|
+
{
|
|
33
|
+
path: '/gen-ai/model-manager',
|
|
34
|
+
name: 'model-manager',
|
|
35
|
+
component: () => import('../views/gen-ai/model-manager/index.vue'),
|
|
36
|
+
meta: { title: '模板中心', standalone: true },
|
|
37
|
+
},
|
|
38
|
+
{ path: '/model-manager', redirect: '/gen-ai/model-manager' },
|
|
39
|
+
{
|
|
40
|
+
path: '/gen-ai/management-center',
|
|
41
|
+
name: 'management-center',
|
|
42
|
+
component: () => import('../views/gen-ai/management-center/index.vue'),
|
|
43
|
+
meta: { title: '管理中心', standalone: true },
|
|
44
|
+
},
|
|
45
|
+
{ path: '/management-center', redirect: '/gen-ai/management-center' },
|
|
46
|
+
{
|
|
47
|
+
path: '/gen-ai/report-center',
|
|
48
|
+
name: 'report-center',
|
|
49
|
+
component: () => import('../views/gen-ai/report-center/index.vue'),
|
|
50
|
+
meta: { title: '報告中心', standalone: true },
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
path: '/template-center',
|
|
54
|
+
name: 'TemplateCenter',
|
|
55
|
+
component: () => import('../test/test2.vue'),
|
|
56
|
+
meta: { title: '模板中心', standalone: true },
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
path: '/',
|
|
60
|
+
component: MainLayout,
|
|
61
|
+
children: [
|
|
62
|
+
{ path: '', name: 'Home', component: () => import('../views/Home.vue'), meta: { title: 'HOME' } },
|
|
63
|
+
{ path: 'blank', name: 'Blank', component: () => import('../views/Blank.vue'), meta: { title: 'SMART' } },
|
|
64
|
+
{ path: 'report-center', name: 'ReportCenter', component: () => import('../views/ReportCenter/index.vue'), meta: { title: '報告中心' } },
|
|
65
|
+
{ path: 'admin-center', name: 'AdminCenter', component: () => import('../views/AdminCenter/index.vue'), meta: { title: '管理後台' } },
|
|
66
|
+
...genAiRoutes,
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
const router = createRouter({
|
|
72
|
+
history: createWebHistory(import.meta.env.BASE_URL),
|
|
73
|
+
routes,
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
export default router
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface GenAiMenuItem {
|
|
2
|
+
title: string
|
|
3
|
+
path: string
|
|
4
|
+
file: string
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/** GEN-AI 業務頁面(獨立全屏) */
|
|
8
|
+
export const genAiAppMenus: GenAiMenuItem[] = [
|
|
9
|
+
{ title: '行業分析', path: '/gen-ai/gen-entry', file: 'gen-entry' },
|
|
10
|
+
{ title: '報告中心', path: '/gen-ai/report-center', file: 'report-center' },
|
|
11
|
+
{ title: '模板中心', path: '/gen-ai/model-manager', file: 'model-manager' },
|
|
12
|
+
{ title: '管理中心', path: '/gen-ai/management-center', file: 'management-center' },
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
/** GEN-AI 目录下全部 index 页面(二级菜单) */
|
|
16
|
+
export const genAiMenus: GenAiMenuItem[] = [
|
|
17
|
+
{ title: 'index', path: '/gen-ai/index', file: 'index' },
|
|
18
|
+
{ title: 'index1', path: '/gen-ai/index1', file: 'index1' },
|
|
19
|
+
{ title: 'index2', path: '/gen-ai/index2', file: 'index2' },
|
|
20
|
+
{ title: 'index3', path: '/gen-ai/index3', file: 'index3' },
|
|
21
|
+
{ title: 'index4', path: '/gen-ai/index4', file: 'index4' },
|
|
22
|
+
{ title: 'index5', path: '/gen-ai/index5', file: 'index5' },
|
|
23
|
+
{ title: 'index6', path: '/gen-ai/index6', file: 'index6' },
|
|
24
|
+
{ title: 'index7', path: '/gen-ai/index7', file: 'index7' },
|
|
25
|
+
{ title: 'index8', path: '/gen-ai/index8', file: 'index8' },
|
|
26
|
+
{ title: 'index9', path: '/gen-ai/index9', file: 'index9' },
|
|
27
|
+
{ title: 'index10', path: '/gen-ai/index10', file: 'index10' },
|
|
28
|
+
]
|
package/src/style.css
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
|
|
3
|
+
line-height: 1.5;
|
|
4
|
+
font-weight: 400;
|
|
5
|
+
|
|
6
|
+
color-scheme: light dark;
|
|
7
|
+
color: rgba(255, 255, 255, 0.87);
|
|
8
|
+
background-color: #242424;
|
|
9
|
+
|
|
10
|
+
font-synthesis: none;
|
|
11
|
+
text-rendering: optimizeLegibility;
|
|
12
|
+
-webkit-font-smoothing: antialiased;
|
|
13
|
+
-moz-osx-font-smoothing: grayscale;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
a {
|
|
17
|
+
font-weight: 500;
|
|
18
|
+
color: #646cff;
|
|
19
|
+
text-decoration: inherit;
|
|
20
|
+
}
|
|
21
|
+
a:hover {
|
|
22
|
+
color: #535bf2;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
body {
|
|
26
|
+
margin: 0;
|
|
27
|
+
display: flex;
|
|
28
|
+
place-items: center;
|
|
29
|
+
min-width: 320px;
|
|
30
|
+
min-height: 100vh;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
h1 {
|
|
34
|
+
font-size: 3.2em;
|
|
35
|
+
line-height: 1.1;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
button {
|
|
39
|
+
border-radius: 8px;
|
|
40
|
+
border: 1px solid transparent;
|
|
41
|
+
padding: 0.6em 1.2em;
|
|
42
|
+
font-size: 1em;
|
|
43
|
+
font-weight: 500;
|
|
44
|
+
font-family: inherit;
|
|
45
|
+
background-color: #1a1a1a;
|
|
46
|
+
cursor: pointer;
|
|
47
|
+
transition: border-color 0.25s;
|
|
48
|
+
}
|
|
49
|
+
button:hover {
|
|
50
|
+
border-color: #646cff;
|
|
51
|
+
}
|
|
52
|
+
button:focus,
|
|
53
|
+
button:focus-visible {
|
|
54
|
+
outline: 4px auto -webkit-focus-ring-color;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.card {
|
|
58
|
+
padding: 2em;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
#app {
|
|
62
|
+
max-width: 1280px;
|
|
63
|
+
margin: 0 auto;
|
|
64
|
+
padding: 2rem;
|
|
65
|
+
text-align: center;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@media (prefers-color-scheme: light) {
|
|
69
|
+
:root {
|
|
70
|
+
color: #213547;
|
|
71
|
+
background-color: #ffffff;
|
|
72
|
+
}
|
|
73
|
+
a:hover {
|
|
74
|
+
color: #747bff;
|
|
75
|
+
}
|
|
76
|
+
button {
|
|
77
|
+
background-color: #f9f9f9;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// 全局 SCSS 变量(可在任意 <style lang="scss"> 中直接使用)
|
|
2
|
+
|
|
3
|
+
$color-primary: #c53355;
|
|
4
|
+
$color-primary-soft: #fdf0f2;
|
|
5
|
+
$color-text: #1a1a1a;
|
|
6
|
+
$color-text-secondary: #333;
|
|
7
|
+
$color-muted: #999;
|
|
8
|
+
$color-border: #ebebeb;
|
|
9
|
+
$color-page-bg: #f3f3f3;
|
|
10
|
+
$color-card-bg: #f5f5f5;
|
|
11
|
+
$color-white: #fff;
|
|
12
|
+
|
|
13
|
+
$report-accent: $color-primary;
|
|
14
|
+
$report-accent-soft: $color-primary-soft;
|
|
15
|
+
$report-border: $color-border;
|
|
16
|
+
$report-bg: $color-page-bg;
|
|
17
|
+
$report-text: $color-text;
|
|
18
|
+
$report-muted: $color-muted;
|
|
19
|
+
$report-card-bg: $color-card-bg;
|
|
20
|
+
|
|
21
|
+
$radius-sm: 4px;
|
|
22
|
+
$radius-md: 6px;
|
|
23
|
+
$radius-lg: 12px;
|
|
24
|
+
$radius-pill: 20px;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
.app-btn {
|
|
2
|
+
min-width: var(--app-btn-min-width);
|
|
3
|
+
padding: var(--app-btn-padding-y) var(--app-btn-padding-x);
|
|
4
|
+
border: 1px solid var(--app-btn-border);
|
|
5
|
+
border-radius: var(--app-btn-radius);
|
|
6
|
+
background: var(--app-btn-bg);
|
|
7
|
+
color: var(--app-btn-color);
|
|
8
|
+
font-size: var(--app-btn-font-size);
|
|
9
|
+
font-weight: var(--app-btn-font-weight);
|
|
10
|
+
line-height: 1.4;
|
|
11
|
+
font-family: inherit;
|
|
12
|
+
cursor: pointer;
|
|
13
|
+
transition: all 0.2s ease;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.app-btn:hover,
|
|
17
|
+
.app-btn.is-active,
|
|
18
|
+
.app-btn--active {
|
|
19
|
+
background: var(--app-btn-bg-hover);
|
|
20
|
+
border-color: var(--app-btn-border-hover);
|
|
21
|
+
color: var(--app-btn-color-hover);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.app-btn--wide {
|
|
25
|
+
min-width: 148px;
|
|
26
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Element Plus 全局样式覆盖
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/* el-card 圆角 */
|
|
6
|
+
.el-card {
|
|
7
|
+
border-radius: 4px;
|
|
8
|
+
overflow: hidden;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/* el-table 行:手型 + hover 底部连通蓝线(box-shadow 不占位,避免 hover 跳动) */
|
|
12
|
+
.el-table .el-table__body tr.el-table__row {
|
|
13
|
+
cursor: pointer;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.el-table .el-table__body tr.el-table__row > td.el-table__cell {
|
|
17
|
+
transition: box-shadow 0.2s ease;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.el-table .el-table__body tr.el-table__row:hover > td.el-table__cell {
|
|
21
|
+
background-color: var(--el-table-tr-bg-color, #fff) !important;
|
|
22
|
+
box-shadow: inset 0 -1px 0 rgba(64, 158, 255, 0.5);
|
|
23
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
html,
|
|
2
|
+
body {
|
|
3
|
+
margin: 0;
|
|
4
|
+
min-height: 100%;
|
|
5
|
+
font-family: var(--app-font-family);
|
|
6
|
+
font-synthesis: none;
|
|
7
|
+
text-rendering: optimizeLegibility;
|
|
8
|
+
-webkit-font-smoothing: antialiased;
|
|
9
|
+
-moz-osx-font-smoothing: grayscale;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
body {
|
|
13
|
+
color: #2d3139;
|
|
14
|
+
background: var(--page-bg);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
body,
|
|
18
|
+
button,
|
|
19
|
+
input,
|
|
20
|
+
textarea,
|
|
21
|
+
select {
|
|
22
|
+
font-family: inherit;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
#app {
|
|
26
|
+
width: 100%;
|
|
27
|
+
max-width: none;
|
|
28
|
+
margin: 0;
|
|
29
|
+
padding: 0;
|
|
30
|
+
text-align: left;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* 膠囊滾動條:可滾動容器通用 class(配合 <CapsuleScrollbar /> 或 useCapsuleScrollbar) */
|
|
34
|
+
.is-scrollable {
|
|
35
|
+
overflow-y: auto;
|
|
36
|
+
-webkit-overflow-scrolling: touch;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* v-debounce.lock.loading */
|
|
40
|
+
.is-v-debounce-loading {
|
|
41
|
+
cursor: wait !important;
|
|
42
|
+
opacity: 0.65;
|
|
43
|
+
pointer-events: none;
|
|
44
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@forward 'variables';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
.page-card {
|
|
2
|
+
min-height: calc(100vh - var(--page-outer-spacing) * 2);
|
|
3
|
+
border-radius: var(--page-card-radius);
|
|
4
|
+
border: 1px solid var(--page-card-border);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.page-card .el-card__body {
|
|
8
|
+
padding: var(--page-inner-spacing);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.page-card__inner {
|
|
12
|
+
min-height: calc(100vh - var(--page-outer-spacing) * 2 - var(--page-inner-spacing) * 2);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* GEN-AI 等全屏页放入 Card 后取消重复视口高度与背景 */
|
|
16
|
+
.page-card__inner > .min-h-screen,
|
|
17
|
+
.page-card__inner > .h-screen {
|
|
18
|
+
min-height: auto;
|
|
19
|
+
height: auto;
|
|
20
|
+
background: transparent;
|
|
21
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--page-outer-spacing: 20px;
|
|
3
|
+
--page-inner-spacing: 20px;
|
|
4
|
+
--page-card-radius: 4px;
|
|
5
|
+
--page-card-border: #e8eaec;
|
|
6
|
+
--page-bg: #f3f4f6;
|
|
7
|
+
|
|
8
|
+
/* 繁體中文優先字體棧 */
|
|
9
|
+
--app-font-family: 'PingFang TC', 'SF Pro TC', -apple-system, BlinkMacSystemFont, 'Helvetica Neue',
|
|
10
|
+
'Microsoft JhengHei', 'Noto Sans TC', sans-serif;
|
|
11
|
+
--el-font-family: var(--app-font-family);
|
|
12
|
+
|
|
13
|
+
/* 全局圓角按鈕 */
|
|
14
|
+
--app-btn-color: #fff;
|
|
15
|
+
--app-btn-color-hover: #c53355;
|
|
16
|
+
--app-btn-bg: #c53355;
|
|
17
|
+
--app-btn-bg-hover: #fff;
|
|
18
|
+
--app-btn-border: #c53355;
|
|
19
|
+
--app-btn-border-hover: #c53355;
|
|
20
|
+
--app-btn-radius: 5px;
|
|
21
|
+
--app-btn-font-size: 15px;
|
|
22
|
+
--app-btn-font-weight: 600;
|
|
23
|
+
--app-btn-padding-y: 8px;
|
|
24
|
+
--app-btn-padding-x: 15px;
|
|
25
|
+
--app-btn-min-width: 120px;
|
|
26
|
+
}
|