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
package/package.json
ADDED
package/src/App.vue
ADDED
package/src/api/index.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export {
|
|
2
|
+
postRequest,
|
|
3
|
+
postStreamRequest,
|
|
4
|
+
streamPostSse,
|
|
5
|
+
getToken,
|
|
6
|
+
buildAuthHeaders,
|
|
7
|
+
type PostRequestOptions,
|
|
8
|
+
type SseBlock,
|
|
9
|
+
} from './request'
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
reportApi,
|
|
13
|
+
REPORT_STREAM_USE_MOCK,
|
|
14
|
+
MOCK_REPORT_STREAM_TEXT,
|
|
15
|
+
REPORT_STREAM_API_URL,
|
|
16
|
+
streamGenerateReport,
|
|
17
|
+
type GenerateReportParams,
|
|
18
|
+
type AiStreamParams,
|
|
19
|
+
} from './modules'
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { postRequest } from '@/api/request'
|
|
2
|
+
import type { genAiReportDataParams } from '@/types/gen-ai/gen-entry/index'
|
|
3
|
+
|
|
4
|
+
const GEN_AI_API_BASE = '/aiapi/v1'
|
|
5
|
+
|
|
6
|
+
async function callGenAiPost<T>(action: string, path: string, data?: unknown): Promise<T> {
|
|
7
|
+
try {
|
|
8
|
+
const response = await postRequest<T>({ url: `${GEN_AI_API_BASE}${path}`, data })
|
|
9
|
+
if (response == null) {
|
|
10
|
+
throw new Error('暫無數據')
|
|
11
|
+
}
|
|
12
|
+
return response
|
|
13
|
+
} catch (error) {
|
|
14
|
+
console.error(`獲取${action}失敗`, error)
|
|
15
|
+
throw error
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const genEntryApi = {
|
|
20
|
+
/** gen-entry: report list;params: usmRight,不傳表示全部 */
|
|
21
|
+
fetchGenAiReportListData(data: genAiReportDataParams) {
|
|
22
|
+
return callGenAiPost<unknown>('fetchGenAiReportListData', '/reportLatest', data)
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
fetchtest(data: unknown) {
|
|
26
|
+
return callGenAiPost<unknown>('fetchtest', '/hello', data)
|
|
27
|
+
},
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default genEntryApi
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { postRequest } from '@/api/request'
|
|
2
|
+
import type { TemplateItem, TemplateListParams } from '@/types/gen-ai/model-manager/index'
|
|
3
|
+
import modelManagerMockApi from './mockApi'
|
|
4
|
+
|
|
5
|
+
const GEN_AI_API_BASE = '/aiapi/v1'
|
|
6
|
+
|
|
7
|
+
/** VITE_GEN_AI_MODEL_MANAGER_MOCK=true 時僅走 mock;默認先請求後端,失敗回退 mock */
|
|
8
|
+
const FORCE_MOCK = import.meta.env.VITE_GEN_AI_MODEL_MANAGER_MOCK === 'true'
|
|
9
|
+
|
|
10
|
+
async function callGenAiPost<T>(action: string, path: string, data?: unknown): Promise<T> {
|
|
11
|
+
try {
|
|
12
|
+
const response = await postRequest<T>({ url: `${GEN_AI_API_BASE}${path}`, data })
|
|
13
|
+
if (response == null) {
|
|
14
|
+
throw new Error('暫無數據')
|
|
15
|
+
}
|
|
16
|
+
return response
|
|
17
|
+
} catch (error) {
|
|
18
|
+
console.error(`獲取${action}失敗`, error)
|
|
19
|
+
throw error
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const modelManagerApi = {
|
|
24
|
+
/** model-manager: 模板列表 */
|
|
25
|
+
async fetchTemplateListData(params: TemplateListParams = {}) {
|
|
26
|
+
if (FORCE_MOCK) {
|
|
27
|
+
return modelManagerMockApi.fetchTemplateListData(params)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
return await callGenAiPost<TemplateItem[]>(
|
|
32
|
+
'fetchTemplateListData',
|
|
33
|
+
'/template/list',
|
|
34
|
+
params,
|
|
35
|
+
)
|
|
36
|
+
} catch {
|
|
37
|
+
return modelManagerMockApi.fetchTemplateListData(params)
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default modelManagerApi
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { TemplateItem, TemplateListParams } from '@/types/gen-ai/model-manager/index'
|
|
2
|
+
import { MOCK_TEMPLATES } from '@/views/gen-ai/model-manager/mockData'
|
|
3
|
+
|
|
4
|
+
const MOCK_DELAY_MS = 200
|
|
5
|
+
|
|
6
|
+
function delay(ms = MOCK_DELAY_MS) {
|
|
7
|
+
return new Promise<void>((resolve) => {
|
|
8
|
+
setTimeout(resolve, ms)
|
|
9
|
+
})
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function filterTemplates(list: TemplateItem[], params: TemplateListParams) {
|
|
13
|
+
const kw = params.keyword?.trim().toLowerCase() ?? ''
|
|
14
|
+
return list.filter((item) => {
|
|
15
|
+
const unitOk = !params.unit || item.unit === params.unit
|
|
16
|
+
const keywordOk =
|
|
17
|
+
!kw ||
|
|
18
|
+
item.name.toLowerCase().includes(kw) ||
|
|
19
|
+
item.description.toLowerCase().includes(kw) ||
|
|
20
|
+
item.author.toLowerCase().includes(kw)
|
|
21
|
+
return unitOk && keywordOk
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const modelManagerMockApi = {
|
|
26
|
+
/** 模板列表(本地 mock) */
|
|
27
|
+
async fetchTemplateListData(params: TemplateListParams = {}) {
|
|
28
|
+
await delay()
|
|
29
|
+
return filterTemplates([...MOCK_TEMPLATES], params)
|
|
30
|
+
},
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default modelManagerMockApi
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { getToken, streamPostSse } from '../request'
|
|
2
|
+
|
|
3
|
+
/** 仅当 VITE_REPORT_STREAM_MOCK=true 时使用 Mock;默认走真实 SSE 接口调试 */
|
|
4
|
+
export const REPORT_STREAM_USE_MOCK =
|
|
5
|
+
import.meta.env.VITE_REPORT_STREAM_MOCK === 'true'
|
|
6
|
+
|
|
7
|
+
export const REPORT_STREAM_API_URL =
|
|
8
|
+
import.meta.env.VITE_REPORT_STREAM_URL || '/sse/aiStream'
|
|
9
|
+
|
|
10
|
+
export const MOCK_REPORT_STREAM_TEXT = `# 行业分析报告(Mock)
|
|
11
|
+
|
|
12
|
+
## 摘要與本年總結
|
|
13
|
+
|
|
14
|
+
本报告为本地 Mock 流式输出。接入后端 SSE 后由接口返回替换。
|
|
15
|
+
|
|
16
|
+
## 宏觀環境與政策背景
|
|
17
|
+
|
|
18
|
+
宏观政策延续稳健基调,行业监管框架逐步完善。`
|
|
19
|
+
|
|
20
|
+
export interface GenerateReportParams {
|
|
21
|
+
userId?: string
|
|
22
|
+
question?: string
|
|
23
|
+
chapters?: string[]
|
|
24
|
+
chapterVersions?: Record<string, string>
|
|
25
|
+
reportMode?: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface AiStreamParams {
|
|
29
|
+
userId: string
|
|
30
|
+
question: string
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function buildMockStreamText(params: GenerateReportParams): string {
|
|
34
|
+
const chapters = params.chapters?.length
|
|
35
|
+
? params.chapters
|
|
36
|
+
.map((label, i) => `## ${label}\n\n(Mock)第 ${i + 1} 章内容占位。\n`)
|
|
37
|
+
.join('\n')
|
|
38
|
+
: MOCK_REPORT_STREAM_TEXT
|
|
39
|
+
|
|
40
|
+
return `# 生成报告预览(Mock)\n\n**模式**:${params.reportMode === 'rewrite' ? '重寫整篇報告' : '拼裝並潤色'}\n\n${chapters}`
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function* streamMockReport(text: string): AsyncGenerator<string> {
|
|
44
|
+
for (const char of text) {
|
|
45
|
+
yield char
|
|
46
|
+
await new Promise((resolve) => setTimeout(resolve, 12))
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function* streamAiReportSse(
|
|
51
|
+
params: AiStreamParams,
|
|
52
|
+
signal?: AbortSignal,
|
|
53
|
+
): AsyncGenerator<string> {
|
|
54
|
+
for await (const block of streamPostSse({
|
|
55
|
+
url: REPORT_STREAM_API_URL,
|
|
56
|
+
data: params,
|
|
57
|
+
signal,
|
|
58
|
+
})) {
|
|
59
|
+
if (block.event === 'text') {
|
|
60
|
+
yield block.data
|
|
61
|
+
}
|
|
62
|
+
if (block.event === 'end') {
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** 与 basicInformationApi 同风格的 reportApi */
|
|
69
|
+
export const reportApi = {
|
|
70
|
+
getToken,
|
|
71
|
+
|
|
72
|
+
/** SSE 流式生成报告(POST + Token,event: text / end) */
|
|
73
|
+
async *streamAiReport(params: AiStreamParams, signal?: AbortSignal) {
|
|
74
|
+
yield* streamAiReportSse(params, signal)
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
async *generateReport(params: GenerateReportParams, signal?: AbortSignal) {
|
|
78
|
+
yield* streamGenerateReport(params, signal)
|
|
79
|
+
},
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export async function* streamGenerateReport(
|
|
83
|
+
params: GenerateReportParams,
|
|
84
|
+
signal?: AbortSignal,
|
|
85
|
+
): AsyncGenerator<string> {
|
|
86
|
+
if (REPORT_STREAM_USE_MOCK) {
|
|
87
|
+
yield* streamMockReport(buildMockStreamText(params))
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
yield* streamAiReportSse(
|
|
92
|
+
{
|
|
93
|
+
userId: params.userId ?? 'user001',
|
|
94
|
+
question: params.question ?? '介绍一下SSE流式传输',
|
|
95
|
+
},
|
|
96
|
+
signal,
|
|
97
|
+
)
|
|
98
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
export interface PostRequestOptions {
|
|
2
|
+
url: string
|
|
3
|
+
data?: unknown
|
|
4
|
+
signal?: AbortSignal
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function getToken(): string {
|
|
8
|
+
return localStorage.getItem('token') || ''
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function buildAuthHeaders(): HeadersInit {
|
|
12
|
+
const token = getToken()
|
|
13
|
+
return {
|
|
14
|
+
'Content-Type': 'application/json',
|
|
15
|
+
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** 普通 POST JSON 請求(已含 method / Content-Type / Authorization) */
|
|
20
|
+
export async function postRequest<T = unknown>(options: PostRequestOptions): Promise<T> {
|
|
21
|
+
const response = await fetch(options.url, {
|
|
22
|
+
method: 'POST',
|
|
23
|
+
headers: buildAuthHeaders(),
|
|
24
|
+
body: JSON.stringify(options.data ?? {}),
|
|
25
|
+
signal: options.signal,
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
if (!response.ok) {
|
|
29
|
+
throw new Error(`請求失敗 ${response.status}`)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return response.json() as Promise<T>
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** SSE POST 請求(與 postRequest 相同 headers,返回原始 Response 供流式讀取) */
|
|
36
|
+
export async function postStreamRequest(options: PostRequestOptions): Promise<Response> {
|
|
37
|
+
const response = await fetch(options.url, {
|
|
38
|
+
method: 'POST',
|
|
39
|
+
headers: buildAuthHeaders(),
|
|
40
|
+
body: JSON.stringify(options.data ?? {}),
|
|
41
|
+
signal: options.signal,
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
throw new Error(`請求失敗 ${response.status}`)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return response
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface SseBlock {
|
|
52
|
+
event: string
|
|
53
|
+
data: string
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function parseSseBlock(block: string): SseBlock | null {
|
|
57
|
+
if (!block.trim()) return null
|
|
58
|
+
|
|
59
|
+
let event = ''
|
|
60
|
+
let data = ''
|
|
61
|
+
for (const line of block.split('\n')) {
|
|
62
|
+
if (line.startsWith('event:')) {
|
|
63
|
+
event = line.replace('event:', '').trim()
|
|
64
|
+
} else if (line.startsWith('data:')) {
|
|
65
|
+
data += line.replace('data:', '')
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return { event, data }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** SSE POST 流(event: text / end),基于 postRequest 同款 headers */
|
|
73
|
+
export async function* streamPostSse(
|
|
74
|
+
options: PostRequestOptions,
|
|
75
|
+
): AsyncGenerator<SseBlock> {
|
|
76
|
+
const response = await postStreamRequest(options)
|
|
77
|
+
const reader = response.body?.getReader()
|
|
78
|
+
if (!reader) {
|
|
79
|
+
throw new Error('No reader')
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const decoder = new TextDecoder('utf-8')
|
|
83
|
+
let buffer = ''
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
while (true) {
|
|
87
|
+
const { done, value } = await reader.read()
|
|
88
|
+
if (done) break
|
|
89
|
+
|
|
90
|
+
buffer += decoder.decode(value, { stream: true })
|
|
91
|
+
const blocks = buffer.split('\n\n')
|
|
92
|
+
buffer = blocks.pop() || ''
|
|
93
|
+
|
|
94
|
+
for (const block of blocks) {
|
|
95
|
+
const parsed = parseSseBlock(block)
|
|
96
|
+
if (parsed) yield parsed
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
} finally {
|
|
100
|
+
reader.releaseLock()
|
|
101
|
+
}
|
|
102
|
+
}
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
v-if="canScroll"
|
|
4
|
+
:class="[rootClass, { [`${rootClass}--hidden`]: !shown }]"
|
|
5
|
+
:style="rootStyle"
|
|
6
|
+
aria-hidden="true"
|
|
7
|
+
>
|
|
8
|
+
<div :class="thumbClass" :style="thumbStyle" @mousedown.stop="onThumbMouseDown" />
|
|
9
|
+
</div>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script setup lang="ts">
|
|
13
|
+
import { initCapsuleScrollbarGlobal, useCapsuleScrollbar } from '@/utils/gen-ai-scroll'
|
|
14
|
+
import { onMounted, ref, toRef, toValue, watch, type MaybeRef } from 'vue'
|
|
15
|
+
|
|
16
|
+
const props = withDefaults(
|
|
17
|
+
defineProps<{
|
|
18
|
+
/** 滾動容器;模板傳 ref 時會自動解包為 HTMLElement */
|
|
19
|
+
scrollEl?: MaybeRef<HTMLElement | null>
|
|
20
|
+
anchorEl?: MaybeRef<HTMLElement | null>
|
|
21
|
+
active?: boolean
|
|
22
|
+
gutterPx?: number
|
|
23
|
+
thumbWidthPx?: number
|
|
24
|
+
minThumbPx?: number
|
|
25
|
+
visibleRatio?: number
|
|
26
|
+
alwaysVisible?: boolean
|
|
27
|
+
autoHideAfterMs?: number
|
|
28
|
+
rightOffsetPx?: number
|
|
29
|
+
classPrefix?: string
|
|
30
|
+
}>(),
|
|
31
|
+
{
|
|
32
|
+
scrollEl: null,
|
|
33
|
+
anchorEl: null,
|
|
34
|
+
active: false,
|
|
35
|
+
alwaysVisible: false,
|
|
36
|
+
autoHideAfterMs: 3000,
|
|
37
|
+
visibleRatio: 1,
|
|
38
|
+
rightOffsetPx: 1,
|
|
39
|
+
},
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
const scrollElRef = ref<HTMLElement | null>(toValue(props.scrollEl))
|
|
43
|
+
const anchorElRef = ref<HTMLElement | null>(toValue(props.anchorEl))
|
|
44
|
+
const activeRef = toRef(props, 'active')
|
|
45
|
+
|
|
46
|
+
watch(
|
|
47
|
+
() => toValue(props.scrollEl),
|
|
48
|
+
(el) => {
|
|
49
|
+
scrollElRef.value = el ?? null
|
|
50
|
+
},
|
|
51
|
+
{ immediate: true },
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
watch(
|
|
55
|
+
() => toValue(props.anchorEl),
|
|
56
|
+
(el) => {
|
|
57
|
+
anchorElRef.value = el ?? null
|
|
58
|
+
},
|
|
59
|
+
{ immediate: true },
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
onMounted(() => {
|
|
63
|
+
initCapsuleScrollbarGlobal({
|
|
64
|
+
classPrefix: props.classPrefix,
|
|
65
|
+
thumbWidthPx: props.thumbWidthPx,
|
|
66
|
+
})
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
const {
|
|
70
|
+
canScroll,
|
|
71
|
+
shown,
|
|
72
|
+
rootStyle,
|
|
73
|
+
thumbStyle,
|
|
74
|
+
rootClass,
|
|
75
|
+
thumbClass,
|
|
76
|
+
onThumbMouseDown,
|
|
77
|
+
refresh,
|
|
78
|
+
} = useCapsuleScrollbar({
|
|
79
|
+
scrollEl: scrollElRef,
|
|
80
|
+
anchorEl: anchorElRef,
|
|
81
|
+
active: activeRef,
|
|
82
|
+
gutterPx: props.gutterPx,
|
|
83
|
+
thumbWidthPx: props.thumbWidthPx,
|
|
84
|
+
minThumbPx: props.minThumbPx,
|
|
85
|
+
visibleRatio: props.visibleRatio,
|
|
86
|
+
alwaysVisible: props.alwaysVisible,
|
|
87
|
+
autoHideAfterMs: props.autoHideAfterMs,
|
|
88
|
+
rightOffsetPx: props.rightOffsetPx,
|
|
89
|
+
classPrefix: props.classPrefix,
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
defineExpose({ refresh })
|
|
93
|
+
</script>
|