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.
Files changed (86) hide show
  1. package/package.json +12 -0
  2. package/src/App.vue +3 -0
  3. package/src/api/index.ts +19 -0
  4. package/src/api/modules/gen-ai/gen-entry/index.ts +30 -0
  5. package/src/api/modules/gen-ai/model-manager/index.ts +42 -0
  6. package/src/api/modules/gen-ai/model-manager/mockApi.ts +33 -0
  7. package/src/api/modules/index.ts +98 -0
  8. package/src/api/modules/user/index.ts +4 -0
  9. package/src/api/request.ts +102 -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 +93 -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 +142 -0
  21. package/src/components/GEN-AI/index1.vue +456 -0
  22. package/src/components/GEN-AI/index10.vue +5 -0
  23. package/src/components/GEN-AI/index2.vue +568 -0
  24. package/src/components/GEN-AI/index3.vue +623 -0
  25. package/src/components/GEN-AI/index4.vue +629 -0
  26. package/src/components/GEN-AI/index5.vue +578 -0
  27. package/src/components/GEN-AI/index6.vue +656 -0
  28. package/src/components/GEN-AI/index7.vue +717 -0
  29. package/src/components/GEN-AI/index8.vue +405 -0
  30. package/src/components/GEN-AI/index9.vue +1065 -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 +7 -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/components/el-date-picker.vue +64 -0
  42. package/src/directives/btnLoading.ts +427 -0
  43. package/src/directives/debounce copy.ts +670 -0
  44. package/src/directives/debounce.ts +98 -0
  45. package/src/directives/index.ts +25 -0
  46. package/src/layouts/MainLayout.vue +101 -0
  47. package/src/main.ts +85 -0
  48. package/src/router/index.ts +76 -0
  49. package/src/router/menus.ts +28 -0
  50. package/src/style.css +79 -0
  51. package/src/styles/_variables.scss +24 -0
  52. package/src/styles/app-button.css +26 -0
  53. package/src/styles/element-overrides.css +23 -0
  54. package/src/styles/global.css +44 -0
  55. package/src/styles/index.scss +1 -0
  56. package/src/styles/page-card.css +21 -0
  57. package/src/styles/variables.css +26 -0
  58. package/src/test/mock.ts +101 -0
  59. package/src/test/test1.vue +402 -0
  60. package/src/test/test2.vue +1689 -0
  61. package/src/types/gen-ai/gen-entry/index.ts +17 -0
  62. package/src/types/gen-ai/model-manager/index.ts +19 -0
  63. package/src/utils/docxExport.ts +1610 -0
  64. package/src/utils/gen-ai-navigation.ts +37 -0
  65. package/src/utils/gen-ai-scroll.ts +455 -0
  66. package/src/utils/openDataLoaderWordExport.ts +33 -0
  67. package/src/utils/pageScrollbar.ts +115 -0
  68. package/src/utils/randomTranscode.ts +87 -0
  69. package/src/utils/reportPdfExport.ts +44 -0
  70. package/src/views/AdminCenter/index.vue +817 -0
  71. package/src/views/Blank.vue +68 -0
  72. package/src/views/Home.vue +29 -0
  73. package/src/views/ReportCenter/index.vue +1380 -0
  74. package/src/views/TemplateCenter/Knowledge.ts +83 -0
  75. package/src/views/TemplateCenter/data.d.ts +10 -0
  76. package/src/views/TemplateCenter/index.vue +1205 -0
  77. package/src/views/TemplateCenter/service.ts +69 -0
  78. package/src/views/gen-ai/components/RecentReportsTable.vue +193 -0
  79. package/src/views/gen-ai/gen-entry/index.vue +309 -0
  80. package/src/views/gen-ai/gen-entry/mockData.ts +160 -0
  81. package/src/views/gen-ai/management-center/index.vue +53 -0
  82. package/src/views/gen-ai/model-manager/ChapterTitleScroll.vue +275 -0
  83. package/src/views/gen-ai/model-manager/index.vue +1205 -0
  84. package/src/views/gen-ai/model-manager/mockData.ts +122 -0
  85. package/src/views/gen-ai/report-center/index.vue +158 -0
  86. 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
+ }