koishi-plugin-media-luna 0.0.3 → 0.0.5
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/client/api.ts +36 -86
- package/client/components/ChannelsView.vue +28 -208
- package/client/components/GenerateView.vue +46 -11
- package/client/components/HistoryGallery.vue +47 -12
- package/client/components/PresetsView.vue +26 -200
- package/client/components/SettingsView.vue +26 -0
- package/client/components/TasksView.vue +15 -68
- package/client/composables/index.ts +14 -0
- package/client/composables/useDataFetch.ts +102 -0
- package/client/composables/useDialog.ts +58 -0
- package/client/composables/useLoading.ts +84 -0
- package/client/composables/usePagination.ts +110 -0
- package/client/constants/categories.ts +36 -0
- package/client/constants/index.ts +5 -0
- package/client/constants/phases.ts +44 -0
- package/client/styles/shared.css +42 -0
- package/client/types.ts +73 -0
- package/dist/index.js +1 -1
- package/dist/style.css +1 -1
- package/lib/core/api/plugin-api.d.ts.map +1 -1
- package/lib/core/api/plugin-api.js +31 -0
- package/lib/core/api/plugin-api.js.map +1 -1
- package/lib/core/medialuna.service.d.ts.map +1 -1
- package/lib/core/medialuna.service.js +21 -17
- package/lib/core/medialuna.service.js.map +1 -1
- package/lib/core/pipeline/generation-pipeline.d.ts +4 -0
- package/lib/core/pipeline/generation-pipeline.d.ts.map +1 -1
- package/lib/core/pipeline/generation-pipeline.js +61 -20
- package/lib/core/pipeline/generation-pipeline.js.map +1 -1
- package/lib/core/plugin-loader.d.ts +42 -0
- package/lib/core/plugin-loader.d.ts.map +1 -1
- package/lib/core/plugin-loader.js +231 -2
- package/lib/core/plugin-loader.js.map +1 -1
- package/lib/core/request.service.d.ts +4 -1
- package/lib/core/request.service.d.ts.map +1 -1
- package/lib/core/request.service.js +11 -1
- package/lib/core/request.service.js.map +1 -1
- package/lib/core/types.d.ts +10 -0
- package/lib/core/types.d.ts.map +1 -1
- package/lib/plugins/README.md +716 -0
- package/lib/plugins/cache/middleware.d.ts.map +1 -1
- package/lib/plugins/cache/middleware.js +2 -0
- package/lib/plugins/cache/middleware.js.map +1 -1
- package/lib/plugins/task/middleware.d.ts.map +1 -1
- package/lib/plugins/task/middleware.js +20 -2
- package/lib/plugins/task/middleware.js.map +1 -1
- package/lib/types/index.d.ts +4 -0
- package/lib/types/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 数据获取 composable
|
|
3
|
+
* 结合 useLoading 和 usePagination,提供完整的数据获取能力
|
|
4
|
+
*/
|
|
5
|
+
import { ref, Ref, watch, onMounted } from 'vue'
|
|
6
|
+
import { useLoading, UseLoadingOptions } from './useLoading'
|
|
7
|
+
import { usePagination, UsePaginationOptions } from './usePagination'
|
|
8
|
+
|
|
9
|
+
export interface UseDataFetchOptions<T> extends UseLoadingOptions, UsePaginationOptions {
|
|
10
|
+
/** 是否在挂载时自动获取 */
|
|
11
|
+
immediate?: boolean
|
|
12
|
+
/** 是否启用分页 */
|
|
13
|
+
paginated?: boolean
|
|
14
|
+
/** 数据获取函数 */
|
|
15
|
+
fetchFn: (params: { offset: number; limit: number }) => Promise<{ items: T[]; total: number } | T[]>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface UseDataFetchReturn<T> {
|
|
19
|
+
/** 数据列表 */
|
|
20
|
+
data: Ref<T[]>
|
|
21
|
+
/** 加载状态 */
|
|
22
|
+
loading: Ref<boolean>
|
|
23
|
+
/** 错误信息 */
|
|
24
|
+
error: Ref<string | null>
|
|
25
|
+
/** 分页信息(如果启用) */
|
|
26
|
+
pagination: ReturnType<typeof usePagination> | null
|
|
27
|
+
/** 刷新数据 */
|
|
28
|
+
refresh: () => Promise<void>
|
|
29
|
+
/** 重置并刷新(回到第一页) */
|
|
30
|
+
reset: () => Promise<void>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function useDataFetch<T>(options: UseDataFetchOptions<T>): UseDataFetchReturn<T> {
|
|
34
|
+
const {
|
|
35
|
+
immediate = true,
|
|
36
|
+
paginated = false,
|
|
37
|
+
fetchFn,
|
|
38
|
+
...loadingOptions
|
|
39
|
+
} = options
|
|
40
|
+
|
|
41
|
+
const data = ref<T[]>([]) as Ref<T[]>
|
|
42
|
+
const { loading, error, withLoading } = useLoading(loadingOptions)
|
|
43
|
+
const pagination = paginated ? usePagination(options) : null
|
|
44
|
+
|
|
45
|
+
const fetchData = async () => {
|
|
46
|
+
const params = pagination
|
|
47
|
+
? { offset: pagination.offset.value, limit: pagination.pageSize.value }
|
|
48
|
+
: { offset: 0, limit: 1000 }
|
|
49
|
+
|
|
50
|
+
await withLoading(async () => {
|
|
51
|
+
const result = await fetchFn(params)
|
|
52
|
+
|
|
53
|
+
if (Array.isArray(result)) {
|
|
54
|
+
// 非分页响应
|
|
55
|
+
data.value = result
|
|
56
|
+
if (pagination) {
|
|
57
|
+
pagination.setTotal(result.length)
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
// 分页响应
|
|
61
|
+
data.value = result.items
|
|
62
|
+
if (pagination) {
|
|
63
|
+
pagination.setTotal(result.total)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const refresh = async () => {
|
|
70
|
+
await fetchData()
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const reset = async () => {
|
|
74
|
+
if (pagination) {
|
|
75
|
+
pagination.reset()
|
|
76
|
+
}
|
|
77
|
+
await fetchData()
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// 监听分页变化
|
|
81
|
+
if (pagination) {
|
|
82
|
+
watch([pagination.page, pagination.pageSize], () => {
|
|
83
|
+
fetchData()
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// 自动获取
|
|
88
|
+
if (immediate) {
|
|
89
|
+
onMounted(() => {
|
|
90
|
+
fetchData()
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
data,
|
|
96
|
+
loading,
|
|
97
|
+
error,
|
|
98
|
+
pagination,
|
|
99
|
+
refresh,
|
|
100
|
+
reset
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 对话框控制 composable
|
|
3
|
+
*/
|
|
4
|
+
import { ref, Ref } from 'vue'
|
|
5
|
+
|
|
6
|
+
export interface UseDialogReturn<T = any> {
|
|
7
|
+
/** 对话框是否可见 */
|
|
8
|
+
visible: Ref<boolean>
|
|
9
|
+
/** 当前数据(编辑模式) */
|
|
10
|
+
data: Ref<T | null>
|
|
11
|
+
/** 是否为编辑模式 */
|
|
12
|
+
isEdit: Ref<boolean>
|
|
13
|
+
/** 打开对话框(新建模式) */
|
|
14
|
+
open: () => void
|
|
15
|
+
/** 打开对话框(编辑模式) */
|
|
16
|
+
openEdit: (item: T) => void
|
|
17
|
+
/** 关闭对话框 */
|
|
18
|
+
close: () => void
|
|
19
|
+
/** 重置数据 */
|
|
20
|
+
reset: () => void
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function useDialog<T = any>(defaultData?: T): UseDialogReturn<T> {
|
|
24
|
+
const visible = ref(false)
|
|
25
|
+
const data = ref<T | null>(null) as Ref<T | null>
|
|
26
|
+
const isEdit = ref(false)
|
|
27
|
+
|
|
28
|
+
const open = () => {
|
|
29
|
+
data.value = defaultData ? { ...defaultData } : null
|
|
30
|
+
isEdit.value = false
|
|
31
|
+
visible.value = true
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const openEdit = (item: T) => {
|
|
35
|
+
data.value = { ...item }
|
|
36
|
+
isEdit.value = true
|
|
37
|
+
visible.value = true
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const close = () => {
|
|
41
|
+
visible.value = false
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const reset = () => {
|
|
45
|
+
data.value = null
|
|
46
|
+
isEdit.value = false
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
visible,
|
|
51
|
+
data,
|
|
52
|
+
isEdit,
|
|
53
|
+
open,
|
|
54
|
+
openEdit,
|
|
55
|
+
close,
|
|
56
|
+
reset
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 加载状态管理 composable
|
|
3
|
+
* 提供统一的 loading、error 状态管理
|
|
4
|
+
*/
|
|
5
|
+
import { ref, Ref } from 'vue'
|
|
6
|
+
import { message } from '@koishijs/client'
|
|
7
|
+
|
|
8
|
+
export interface UseLoadingOptions {
|
|
9
|
+
/** 初始加载状态 */
|
|
10
|
+
initialLoading?: boolean
|
|
11
|
+
/** 错误时是否显示 toast */
|
|
12
|
+
showErrorToast?: boolean
|
|
13
|
+
/** 默认错误消息 */
|
|
14
|
+
defaultErrorMessage?: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface UseLoadingReturn {
|
|
18
|
+
/** 是否正在加载 */
|
|
19
|
+
loading: Ref<boolean>
|
|
20
|
+
/** 错误信息 */
|
|
21
|
+
error: Ref<string | null>
|
|
22
|
+
/** 包装异步函数,自动处理 loading 和 error 状态 */
|
|
23
|
+
withLoading: <T>(fn: () => Promise<T>, errorMessage?: string) => Promise<T | undefined>
|
|
24
|
+
/** 手动设置加载状态 */
|
|
25
|
+
setLoading: (value: boolean) => void
|
|
26
|
+
/** 手动设置错误 */
|
|
27
|
+
setError: (message: string | null) => void
|
|
28
|
+
/** 清除错误 */
|
|
29
|
+
clearError: () => void
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function useLoading(options: UseLoadingOptions = {}): UseLoadingReturn {
|
|
33
|
+
const {
|
|
34
|
+
initialLoading = false,
|
|
35
|
+
showErrorToast = true,
|
|
36
|
+
defaultErrorMessage = '操作失败'
|
|
37
|
+
} = options
|
|
38
|
+
|
|
39
|
+
const loading = ref(initialLoading)
|
|
40
|
+
const error = ref<string | null>(null)
|
|
41
|
+
|
|
42
|
+
const setLoading = (value: boolean) => {
|
|
43
|
+
loading.value = value
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const setError = (msg: string | null) => {
|
|
47
|
+
error.value = msg
|
|
48
|
+
if (msg && showErrorToast) {
|
|
49
|
+
message.error(msg)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const clearError = () => {
|
|
54
|
+
error.value = null
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const withLoading = async <T>(
|
|
58
|
+
fn: () => Promise<T>,
|
|
59
|
+
errorMessage?: string
|
|
60
|
+
): Promise<T | undefined> => {
|
|
61
|
+
loading.value = true
|
|
62
|
+
error.value = null
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
const result = await fn()
|
|
66
|
+
return result
|
|
67
|
+
} catch (e) {
|
|
68
|
+
const msg = e instanceof Error ? e.message : (errorMessage || defaultErrorMessage)
|
|
69
|
+
setError(msg)
|
|
70
|
+
return undefined
|
|
71
|
+
} finally {
|
|
72
|
+
loading.value = false
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
loading,
|
|
78
|
+
error,
|
|
79
|
+
withLoading,
|
|
80
|
+
setLoading,
|
|
81
|
+
setError,
|
|
82
|
+
clearError
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 分页管理 composable
|
|
3
|
+
* 提供统一的分页状态和控制
|
|
4
|
+
*/
|
|
5
|
+
import { ref, computed, Ref, ComputedRef } from 'vue'
|
|
6
|
+
|
|
7
|
+
export interface UsePaginationOptions {
|
|
8
|
+
/** 初始页码(从 1 开始) */
|
|
9
|
+
initialPage?: number
|
|
10
|
+
/** 每页数量 */
|
|
11
|
+
initialPageSize?: number
|
|
12
|
+
/** 可选的每页数量选项 */
|
|
13
|
+
pageSizeOptions?: number[]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface UsePaginationReturn {
|
|
17
|
+
/** 当前页码(从 1 开始) */
|
|
18
|
+
page: Ref<number>
|
|
19
|
+
/** 每页数量 */
|
|
20
|
+
pageSize: Ref<number>
|
|
21
|
+
/** 总数量 */
|
|
22
|
+
total: Ref<number>
|
|
23
|
+
/** 总页数 */
|
|
24
|
+
totalPages: ComputedRef<number>
|
|
25
|
+
/** 是否有下一页 */
|
|
26
|
+
hasNext: ComputedRef<boolean>
|
|
27
|
+
/** 是否有上一页 */
|
|
28
|
+
hasPrev: ComputedRef<boolean>
|
|
29
|
+
/** 当前页的 offset(用于 API 调用) */
|
|
30
|
+
offset: ComputedRef<number>
|
|
31
|
+
/** 每页数量选项 */
|
|
32
|
+
pageSizeOptions: number[]
|
|
33
|
+
/** 设置总数 */
|
|
34
|
+
setTotal: (value: number) => void
|
|
35
|
+
/** 下一页 */
|
|
36
|
+
nextPage: () => void
|
|
37
|
+
/** 上一页 */
|
|
38
|
+
prevPage: () => void
|
|
39
|
+
/** 跳转到指定页 */
|
|
40
|
+
goToPage: (pageNum: number) => void
|
|
41
|
+
/** 重置到第一页 */
|
|
42
|
+
reset: () => void
|
|
43
|
+
/** 更改每页数量(会重置到第一页) */
|
|
44
|
+
changePageSize: (size: number) => void
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function usePagination(options: UsePaginationOptions = {}): UsePaginationReturn {
|
|
48
|
+
const {
|
|
49
|
+
initialPage = 1,
|
|
50
|
+
initialPageSize = 20,
|
|
51
|
+
pageSizeOptions = [10, 20, 50, 100]
|
|
52
|
+
} = options
|
|
53
|
+
|
|
54
|
+
const page = ref(initialPage)
|
|
55
|
+
const pageSize = ref(initialPageSize)
|
|
56
|
+
const total = ref(0)
|
|
57
|
+
|
|
58
|
+
const totalPages = computed(() => Math.ceil(total.value / pageSize.value) || 1)
|
|
59
|
+
const hasNext = computed(() => page.value < totalPages.value)
|
|
60
|
+
const hasPrev = computed(() => page.value > 1)
|
|
61
|
+
const offset = computed(() => (page.value - 1) * pageSize.value)
|
|
62
|
+
|
|
63
|
+
const setTotal = (value: number) => {
|
|
64
|
+
total.value = value
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const nextPage = () => {
|
|
68
|
+
if (hasNext.value) {
|
|
69
|
+
page.value++
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const prevPage = () => {
|
|
74
|
+
if (hasPrev.value) {
|
|
75
|
+
page.value--
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const goToPage = (pageNum: number) => {
|
|
80
|
+
if (pageNum >= 1 && pageNum <= totalPages.value) {
|
|
81
|
+
page.value = pageNum
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const reset = () => {
|
|
86
|
+
page.value = 1
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const changePageSize = (size: number) => {
|
|
90
|
+
pageSize.value = size
|
|
91
|
+
page.value = 1
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
page,
|
|
96
|
+
pageSize,
|
|
97
|
+
total,
|
|
98
|
+
totalPages,
|
|
99
|
+
hasNext,
|
|
100
|
+
hasPrev,
|
|
101
|
+
offset,
|
|
102
|
+
pageSizeOptions,
|
|
103
|
+
setTotal,
|
|
104
|
+
nextPage,
|
|
105
|
+
prevPage,
|
|
106
|
+
goToPage,
|
|
107
|
+
reset,
|
|
108
|
+
changePageSize
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 中间件分类定义
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface CategoryDefinition {
|
|
6
|
+
id: string
|
|
7
|
+
label: string
|
|
8
|
+
icon?: string
|
|
9
|
+
order: number
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** 中间件分类列表 */
|
|
13
|
+
export const CATEGORIES: CategoryDefinition[] = [
|
|
14
|
+
{ id: 'billing', label: '计费模块', icon: 'coins', order: 1 },
|
|
15
|
+
{ id: 'transform', label: '转换处理', icon: 'edit', order: 2 },
|
|
16
|
+
{ id: 'cache', label: '缓存模块', icon: 'folder', order: 3 },
|
|
17
|
+
{ id: 'preset', label: '预设模块', icon: 'bookmark', order: 4 },
|
|
18
|
+
{ id: 'request', label: '请求模块', icon: 'link', order: 5 },
|
|
19
|
+
{ id: 'task', label: '任务模块', icon: 'clipboard', order: 6 },
|
|
20
|
+
{ id: 'other', label: '其他', icon: 'more', order: 99 }
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
/** 分类 ID 到标签的映射 */
|
|
24
|
+
export const CATEGORY_LABELS: Record<string, string> = Object.fromEntries(
|
|
25
|
+
CATEGORIES.map(c => [c.id, c.label])
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
/** 获取分类定义 */
|
|
29
|
+
export function getCategory(id: string): CategoryDefinition | undefined {
|
|
30
|
+
return CATEGORIES.find(c => c.id === id)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** 获取分类标签 */
|
|
34
|
+
export function getCategoryLabel(id: string): string {
|
|
35
|
+
return CATEGORY_LABELS[id] || id
|
|
36
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 中间件生命周期阶段定义
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface PhaseDefinition {
|
|
6
|
+
id: string
|
|
7
|
+
label: string
|
|
8
|
+
color: string
|
|
9
|
+
order: number
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** 生命周期阶段列表 */
|
|
13
|
+
export const PHASES: PhaseDefinition[] = [
|
|
14
|
+
{ id: 'lifecycle-prepare', label: '准备', color: '#909399', order: 1 },
|
|
15
|
+
{ id: 'lifecycle-pre-request', label: '预处理', color: '#e6a23c', order: 2 },
|
|
16
|
+
{ id: 'lifecycle-request', label: '请求', color: '#409eff', order: 3 },
|
|
17
|
+
{ id: 'lifecycle-post-request', label: '后处理', color: '#67c23a', order: 4 },
|
|
18
|
+
{ id: 'lifecycle-finalize', label: '完成', color: '#909399', order: 5 }
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
/** 阶段 ID 到标签的映射 */
|
|
22
|
+
export const PHASE_LABELS: Record<string, string> = Object.fromEntries(
|
|
23
|
+
PHASES.map(p => [p.id, p.label])
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
/** 阶段 ID 到颜色的映射 */
|
|
27
|
+
export const PHASE_COLORS: Record<string, string> = Object.fromEntries(
|
|
28
|
+
PHASES.map(p => [p.id, p.color])
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
/** 获取阶段定义 */
|
|
32
|
+
export function getPhase(id: string): PhaseDefinition | undefined {
|
|
33
|
+
return PHASES.find(p => p.id === id)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** 获取阶段标签 */
|
|
37
|
+
export function getPhaseLabel(id: string): string {
|
|
38
|
+
return PHASE_LABELS[id] || id
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** 获取阶段颜色 */
|
|
42
|
+
export function getPhaseColor(id: string): string {
|
|
43
|
+
return PHASE_COLORS[id] || '#909399'
|
|
44
|
+
}
|
package/client/styles/shared.css
CHANGED
|
@@ -256,3 +256,45 @@
|
|
|
256
256
|
.ml-fade-in {
|
|
257
257
|
animation: ml-fade-in 0.3s ease;
|
|
258
258
|
}
|
|
259
|
+
|
|
260
|
+
/* ========== 隐藏式滚动条 ========== */
|
|
261
|
+
/* 通用隐藏式滚动条样式 - 默认隐藏,悬停时显示 */
|
|
262
|
+
.ml-scrollbar,
|
|
263
|
+
.ml-view-content {
|
|
264
|
+
scrollbar-width: thin;
|
|
265
|
+
scrollbar-color: transparent transparent;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.ml-scrollbar:hover,
|
|
269
|
+
.ml-view-content:hover {
|
|
270
|
+
scrollbar-color: var(--k-color-border) transparent;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/* Webkit 浏览器滚动条 */
|
|
274
|
+
.ml-scrollbar::-webkit-scrollbar,
|
|
275
|
+
.ml-view-content::-webkit-scrollbar {
|
|
276
|
+
width: 6px;
|
|
277
|
+
height: 6px;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.ml-scrollbar::-webkit-scrollbar-track,
|
|
281
|
+
.ml-view-content::-webkit-scrollbar-track {
|
|
282
|
+
background: transparent;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.ml-scrollbar::-webkit-scrollbar-thumb,
|
|
286
|
+
.ml-view-content::-webkit-scrollbar-thumb {
|
|
287
|
+
background-color: transparent;
|
|
288
|
+
border-radius: 3px;
|
|
289
|
+
transition: background-color 0.2s;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.ml-scrollbar:hover::-webkit-scrollbar-thumb,
|
|
293
|
+
.ml-view-content:hover::-webkit-scrollbar-thumb {
|
|
294
|
+
background-color: var(--k-color-border);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.ml-scrollbar::-webkit-scrollbar-thumb:hover,
|
|
298
|
+
.ml-view-content::-webkit-scrollbar-thumb:hover {
|
|
299
|
+
background-color: var(--k-color-text-description);
|
|
300
|
+
}
|
package/client/types.ts
CHANGED
|
@@ -44,6 +44,11 @@ export type {
|
|
|
44
44
|
CardFieldsResponse
|
|
45
45
|
} from '../src/types'
|
|
46
46
|
|
|
47
|
+
// 从核心模块导入插件相关类型
|
|
48
|
+
export type {
|
|
49
|
+
PluginInfo
|
|
50
|
+
} from '../src/core/types'
|
|
51
|
+
|
|
47
52
|
// 类型别名(保持向后兼容)
|
|
48
53
|
import type { ConfigField, CardFieldsResponse as _CardFieldsResponse } from '../src/types'
|
|
49
54
|
export type FieldDefinition = ConfigField
|
|
@@ -73,6 +78,74 @@ export interface RemotePresetConfig {
|
|
|
73
78
|
deleteRemoved: boolean
|
|
74
79
|
}
|
|
75
80
|
|
|
81
|
+
// ============ 画廊类型 ============
|
|
82
|
+
|
|
83
|
+
/** 画廊项目 */
|
|
84
|
+
export interface GalleryItem {
|
|
85
|
+
id: number
|
|
86
|
+
prompt: string
|
|
87
|
+
images: string[]
|
|
88
|
+
createdAt: Date
|
|
89
|
+
channelId: number
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** 画廊响应 */
|
|
93
|
+
export interface GalleryResponse {
|
|
94
|
+
items: GalleryItem[]
|
|
95
|
+
total: number
|
|
96
|
+
hasMore: boolean
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** 最近图片 */
|
|
100
|
+
export interface RecentImage {
|
|
101
|
+
taskId: number
|
|
102
|
+
url: string
|
|
103
|
+
prompt: string
|
|
104
|
+
createdAt: Date
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ============ 缓存类型 ============
|
|
108
|
+
|
|
109
|
+
/** 缓存文件信息 */
|
|
110
|
+
export interface CacheFileInfo {
|
|
111
|
+
id: string
|
|
112
|
+
url?: string
|
|
113
|
+
filename: string
|
|
114
|
+
mime: string
|
|
115
|
+
size: number
|
|
116
|
+
createdAt?: Date
|
|
117
|
+
accessedAt?: Date
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** 缓存统计 */
|
|
121
|
+
export interface CacheStats {
|
|
122
|
+
totalFiles: number
|
|
123
|
+
totalSizeMB: number
|
|
124
|
+
maxSizeMB: number
|
|
125
|
+
oldestAccess: Date | null
|
|
126
|
+
newestAccess: Date | null
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ============ 外部插件类型 ============
|
|
130
|
+
|
|
131
|
+
/** 外部插件信息 */
|
|
132
|
+
export interface ExternalPluginInfo {
|
|
133
|
+
id: string
|
|
134
|
+
moduleName: string
|
|
135
|
+
name: string
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ============ 认证类型 ============
|
|
139
|
+
|
|
140
|
+
/** 当前用户信息 */
|
|
141
|
+
export interface CurrentUser {
|
|
142
|
+
loggedIn: boolean
|
|
143
|
+
source?: string
|
|
144
|
+
uid?: number
|
|
145
|
+
name?: string
|
|
146
|
+
authority?: number
|
|
147
|
+
}
|
|
148
|
+
|
|
76
149
|
declare module '@koishijs/client' {
|
|
77
150
|
interface Events {
|
|
78
151
|
// 渠道
|