diff --git a/docs/architecture.md b/docs/architecture.md
index 48247ed32..ddb1db30e 100644
--- a/docs/architecture.md
+++ b/docs/architecture.md
@@ -313,7 +313,7 @@ Client Key 费用账本独立累计各次 attempt 的实际费用,不能因请
### 3.4 前端模块职责
-`frontend/src` 持有应用状态和业务交互,基础组件与主题算法由 `@codex-proxy/ui` 提供:
+`frontend/src` 持有应用状态和业务交互,基础组件与主题算法由 `@codex-proxy/ui` 提供,组件目录与合同见 [UI 组件架构](../modules/ui/playground/guide/architecture.md):
| 入口 | 职责 |
| --- | --- |
diff --git a/docs/development.md b/docs/development.md
index 3e33d3420..1a86920e4 100644
--- a/docs/development.md
+++ b/docs/development.md
@@ -63,6 +63,8 @@ pnpm --dir frontend dev
后端职责和依赖方向见 [Workspace 边界](architecture.md#3-workspace-边界),页面与共享逻辑见 [前端模块职责](architecture.md#34-前端模块职责)。
先按所属模块定位,再跟踪请求、状态与展示的调用关系
+共享 UI 的命名与目录见[组件架构](../modules/ui/playground/guide/architecture.md)
+
## 源码联调
宿主、组件库和官方插件保留独立仓库,通过 Git 子模块在同一目录开发:
diff --git a/frontend/package.json b/frontend/package.json
index c90605f8a..6ad7c1f02 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -17,7 +17,7 @@
},
"dependencies": {
"@boxicons/vue": "1.0.1",
- "@codex-proxy/ui": "github:zyycn/codex-proxy-ui#v0.3.2",
+ "@codex-proxy/ui": "github:zyycn/codex-proxy-ui#v0.4.0",
"@fontsource-variable/inter": "^5.3.0",
"@fontsource-variable/jetbrains-mono": "^5.3.0",
"@lucide/vue": "^1.47.0",
diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml
index 4f0a18e2d..19c5d66bc 100644
--- a/frontend/pnpm-lock.yaml
+++ b/frontend/pnpm-lock.yaml
@@ -170,8 +170,8 @@ importers:
specifier: 1.0.1
version: 1.0.1(vue@3.5.43(typescript@6.0.3))
'@codex-proxy/ui':
- specifier: github:zyycn/codex-proxy-ui#v0.3.2
- version: https://codeload.github.com/zyycn/codex-proxy-ui/tar.gz/83c92024dec82b5a644d6adca96a140c541684b0(axios@1.20.0(debug@4.4.3))(change-case@5.4.4)(vite@8.3.0(@types/node@26.6.2)(jiti@2.7.0)(yaml@2.9.0))(vue@3.5.43(typescript@6.0.3))
+ specifier: github:zyycn/codex-proxy-ui#v0.4.0
+ version: https://codeload.github.com/zyycn/codex-proxy-ui/tar.gz/db615f3d72975e0d09847a07d03ed5fe7ba8c8b0(axios@1.20.0(debug@4.4.3))(change-case@5.4.4)(vite@8.3.0(@types/node@26.6.2)(jiti@2.7.0)(yaml@2.9.0))(vue@3.5.43(typescript@6.0.3))
'@fontsource-variable/inter':
specifier: ^5.3.0
version: 5.3.0
@@ -381,9 +381,9 @@ packages:
resolution: {integrity: sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A==}
engines: {node: '>= 20.12.0'}
- '@codex-proxy/ui@https://codeload.github.com/zyycn/codex-proxy-ui/tar.gz/83c92024dec82b5a644d6adca96a140c541684b0':
- resolution: {gitHosted: true, integrity: sha512-9s6sXP8QrUZATh80wQnIMi68lORp+HuixhoXM2WANsgULqF0Rq270VHllSCNISUCj6aP8t5ugNDPkIrkAFpu3A==, tarball: https://codeload.github.com/zyycn/codex-proxy-ui/tar.gz/83c92024dec82b5a644d6adca96a140c541684b0}
- version: 0.3.2
+ '@codex-proxy/ui@https://codeload.github.com/zyycn/codex-proxy-ui/tar.gz/db615f3d72975e0d09847a07d03ed5fe7ba8c8b0':
+ resolution: {gitHosted: true, integrity: sha512-AhG9idgKHs9AWY1Fyo75wlVcBx3KXD3NEY1dF+sOg84PGAz/7mKq6Fb4xqkYqCT6UrduTjT3WbAw/2VhJJdblQ==, tarball: https://codeload.github.com/zyycn/codex-proxy-ui/tar.gz/db615f3d72975e0d09847a07d03ed5fe7ba8c8b0}
+ version: 0.4.0
engines: {node: '>=24'}
peerDependencies:
vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0
@@ -537,6 +537,11 @@ packages:
peerDependencies:
vue: '>=3.0.1'
+ '@lucide/vue@1.54.0':
+ resolution: {integrity: sha512-fq5S0Fk3a3c2VPs+QRiiHZylZV+1pxyTyOYxoH507b/OdiqciUiEm83N7d7xijS8lDlsGFf12ad9AkLGVHRevg==}
+ peerDependencies:
+ vue: '>=3.0.1'
+
'@ota-meshi/ast-token-store@0.3.0':
resolution: {integrity: sha512-XRO0zi2NIUKq2lUk3T1ecFSld1fMWRKE6naRFGkgkdeosx7IslyUKNv5Dcb5PJTja9tHJoFu0v/7yEpAkrkrTg==}
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
@@ -1319,8 +1324,8 @@ packages:
resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- dompurify@3.4.15:
- resolution: {integrity: sha512-EUBjM+B+lkDE41iE82DDSCfkoPGfXx8IxFxPMjNzm/Uk4xDet77rTN9wqlxlVg71kK7XGuUMv6wUxJUwwv+Xyw==}
+ dompurify@3.4.16:
+ resolution: {integrity: sha512-sqo+pNp3qRhCIpbgRi1y8Tgk27Bo2Ry7w0dC1NBeNTdZChWjz9Xb/KOoZbRP/R6pQZ80Qw8YhXw13hWWBbMRnQ==}
dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
@@ -2003,8 +2008,8 @@ packages:
markdown-table@3.0.4:
resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
- marked@18.0.14:
- resolution: {integrity: sha512-mBHK6FBHuBAlhgRe88w9F0O1AbwwXJUcQibUbC/QcdTbVGAD7aWza+xt3N6oT/jCZx3/OMeS+8rnuiHZcQ9s7A==}
+ marked@18.1.0:
+ resolution: {integrity: sha512-PamYXWWWg2nboG3oX5Ffzpy3EFZROqZJK9hSlMmUnekp7TxPs5DcT95vwd46m73/exfKCRVMtgXoPMI4FEJL6w==}
engines: {node: '>= 20'}
hasBin: true
@@ -2777,17 +2782,17 @@ snapshots:
fast-wrap-ansi: 0.2.2
sisteransi: 1.0.5
- '@codex-proxy/ui@https://codeload.github.com/zyycn/codex-proxy-ui/tar.gz/83c92024dec82b5a644d6adca96a140c541684b0(axios@1.20.0(debug@4.4.3))(change-case@5.4.4)(vite@8.3.0(@types/node@26.6.2)(jiti@2.7.0)(yaml@2.9.0))(vue@3.5.43(typescript@6.0.3))':
+ '@codex-proxy/ui@https://codeload.github.com/zyycn/codex-proxy-ui/tar.gz/db615f3d72975e0d09847a07d03ed5fe7ba8c8b0(axios@1.20.0(debug@4.4.3))(change-case@5.4.4)(vite@8.3.0(@types/node@26.6.2)(jiti@2.7.0)(yaml@2.9.0))(vue@3.5.43(typescript@6.0.3))':
dependencies:
'@ant-design/colors': 8.0.1
'@ant-design/fast-color': 3.0.1
- '@lucide/vue': 1.47.0(vue@3.5.43(typescript@6.0.3))
+ '@lucide/vue': 1.54.0(vue@3.5.43(typescript@6.0.3))
'@vueuse/core': 15.0.0(vue@3.5.43(typescript@6.0.3))
'@vueuse/integrations': 15.0.0(axios@1.20.0(debug@4.4.3))(change-case@5.4.4)(sortablejs@1.15.7)(vue@3.5.43(typescript@6.0.3))
- dompurify: 3.4.15
+ dompurify: 3.4.16
es-toolkit: 1.52.0
gsap: 3.15.0
- marked: 18.0.14
+ marked: 18.1.0
sortablejs: 1.15.7
vue: 3.5.43(typescript@6.0.3)
optionalDependencies:
@@ -2955,6 +2960,10 @@ snapshots:
dependencies:
vue: 3.5.43(typescript@6.0.3)
+ '@lucide/vue@1.54.0(vue@3.5.43(typescript@6.0.3))':
+ dependencies:
+ vue: 3.5.43(typescript@6.0.3)
+
'@ota-meshi/ast-token-store@0.3.0': {}
'@oxc-project/types@0.149.0': {}
@@ -3581,7 +3590,7 @@ snapshots:
diff-sequences@29.6.3: {}
- dompurify@3.4.15:
+ dompurify@3.4.16:
optionalDependencies:
'@types/trusted-types': 2.0.7
@@ -4270,7 +4279,7 @@ snapshots:
markdown-table@3.0.4: {}
- marked@18.0.14: {}
+ marked@18.1.0: {}
math-intrinsics@1.1.0: {}
diff --git a/frontend/src/App.vue b/frontend/src/App.vue
index 8d0c05d35..a78fb6fd3 100644
--- a/frontend/src/App.vue
+++ b/frontend/src/App.vue
@@ -1,10 +1,7 @@
-
diff --git a/frontend/src/api/request/plugins/feedback.ts b/frontend/src/api/request/plugins/feedback.ts
index 108254bcc..2e96e3ccf 100644
--- a/frontend/src/api/request/plugins/feedback.ts
+++ b/frontend/src/api/request/plugins/feedback.ts
@@ -1,5 +1,5 @@
import type { RequestContext, RequestNext } from './index'
-import { toast } from '@codex-proxy/ui'
+import { ZNotification } from '@codex-proxy/ui'
import { ApiError, isSessionRequired } from './error'
// 共享刷新 Promise 的同一个失败只提示一次,弱引用不保留已结束请求
@@ -13,7 +13,7 @@ export async function feedbackPlugin(context: RequestContext, next: RequestNext)
if (error instanceof ApiError && error.kind !== 'cancelled' && !isSessionRequired(error)
&& !context.config.silent && context.isCurrent() && !reported.has(error)) {
reported.add(error)
- toast.error(error.message)
+ ZNotification.error({ message: error.message })
}
throw error
}
diff --git a/frontend/src/api/request/plugins/session.ts b/frontend/src/api/request/plugins/session.ts
index 4a534787f..3100c071a 100644
--- a/frontend/src/api/request/plugins/session.ts
+++ b/frontend/src/api/request/plugins/session.ts
@@ -1,6 +1,6 @@
import type { RequestConfig } from '../index'
import type { RequestContext, RequestNext } from './index'
-import { toast } from '@codex-proxy/ui'
+import { ZNotification } from '@codex-proxy/ui'
import { ApiError, isSessionRequired } from './error'
// 会话失效是后端业务事实,登录凭据错误和 403 不清除已有会话
@@ -54,7 +54,7 @@ function expireSession(error: ApiError, config: RequestConfig, generation: numbe
const alreadyHandled = unauthorizedHandled
handleUnauthorizedOnce()
if (!config.silent && !alreadyHandled)
- toast.error(error.message)
+ ZNotification.error({ message: error.message })
}
throw error
}
diff --git a/frontend/src/components/AccountGroupCheckboxGrid.vue b/frontend/src/components/AccountGroupCheckboxGrid.vue
index 92912fdd2..72d0e5a0c 100644
--- a/frontend/src/components/AccountGroupCheckboxGrid.vue
+++ b/frontend/src/components/AccountGroupCheckboxGrid.vue
@@ -1,7 +1,7 @@
-
-
-
+
{{ configPath }}
-
-
+
-
+
-
+
-
+
导入 CCSwitch
-
-
+
+
关闭
-
+
-
+
diff --git a/frontend/src/components/AppAboutModal.vue b/frontend/src/components/AppAboutModal.vue
index 2786203d1..cc7743e2c 100644
--- a/frontend/src/components/AppAboutModal.vue
+++ b/frontend/src/components/AppAboutModal.vue
@@ -1,6 +1,6 @@
-
+
-
+
diff --git a/frontend/src/components/AppBrandMark.vue b/frontend/src/components/AppBrandMark.vue
index f82e17a6b..baa40fcc6 100644
--- a/frontend/src/components/AppBrandMark.vue
+++ b/frontend/src/components/AppBrandMark.vue
@@ -31,7 +31,7 @@ const mistGradientId = `${id}-brand-mist`
-
+
diff --git a/frontend/src/components/ProviderFilter.vue b/frontend/src/components/ProviderFilter.vue
index cb8fe11f8..1aba937a5 100644
--- a/frontend/src/components/ProviderFilter.vue
+++ b/frontend/src/components/ProviderFilter.vue
@@ -1,5 +1,5 @@
-
+
{
-
-
+
-
+
diff --git a/frontend/src/components/usage/UsageDetailPopover.vue b/frontend/src/components/usage/UsageDetailPopover.vue
index 579ad5294..b12b586a1 100644
--- a/frontend/src/components/usage/UsageDetailPopover.vue
+++ b/frontend/src/components/usage/UsageDetailPopover.vue
@@ -1,5 +1,5 @@
-
-
+
-
+
diff --git a/frontend/src/components/usage/UsageRecordsTable.vue b/frontend/src/components/usage/UsageRecordsTable.vue
index 9e5423bdf..8ae0d9beb 100644
--- a/frontend/src/components/usage/UsageRecordsTable.vue
+++ b/frontend/src/components/usage/UsageRecordsTable.vue
@@ -1,8 +1,8 @@
-
@@ -142,5 +142,5 @@ withDefaults(
-
+
diff --git a/frontend/src/components/usage/shared/columns.ts b/frontend/src/components/usage/shared/columns.ts
index 6f33ff5df..9d9a09a16 100644
--- a/frontend/src/components/usage/shared/columns.ts
+++ b/frontend/src/components/usage/shared/columns.ts
@@ -18,7 +18,7 @@ export const usageRecordColumns = defineTableColumns
([
kind: 'status',
size: 'md',
fixedWidth: true,
- format: (value: unknown) => formatProviderLabel(typeof value === 'string' ? value : null),
+ formatter: (value: unknown) => formatProviderLabel(typeof value === 'string' ? value : null),
},
{ key: 'model', label: '模型', kind: 'custom', size: 'xl' },
{ key: 'reasoningEffort', label: '推理强度', kind: 'status', size: 'md', align: 'left' },
diff --git a/frontend/src/composables/useAsyncAction.ts b/frontend/src/composables/useAsyncAction.ts
index baf126aba..6dfbe8fb7 100644
--- a/frontend/src/composables/useAsyncAction.ts
+++ b/frontend/src/composables/useAsyncAction.ts
@@ -1,4 +1,4 @@
-import { toast } from '@codex-proxy/ui'
+import { ZNotification } from '@codex-proxy/ui'
import { shallowRef } from 'vue'
import { ApiError } from '@/api/request'
@@ -42,7 +42,7 @@ export function useAsyncAction(defaults: AsyncActionRunOptions = {}) {
const message = resolveErrorText(error, options.errorText)
if (message) {
- toast.error(message)
+ ZNotification.error({ message })
}
if (options.rethrow) {
diff --git a/frontend/src/composables/useCopyText.ts b/frontend/src/composables/useCopyText.ts
index ac0e3814a..006deb650 100644
--- a/frontend/src/composables/useCopyText.ts
+++ b/frontend/src/composables/useCopyText.ts
@@ -1,4 +1,4 @@
-import { toast } from '@codex-proxy/ui'
+import { ZNotification } from '@codex-proxy/ui'
import { useClipboard } from '@vueuse/core'
import { errorMessage } from '@/utils/operation'
@@ -11,7 +11,7 @@ interface CopyTextOptions {
errorFromException?: boolean
}
-// 剪贴板复制 + toast 反馈;空值与错误文案语义由调用方按站点配置。
+// 剪贴板复制 + notification 反馈;空值与错误文案语义由调用方按站点配置。
export function useCopyText() {
// 普通 HTTP 页面没有 Clipboard API,启用 VueUse 内置的兼容复制路径。
const { copy } = useClipboard({ legacy: true })
@@ -19,15 +19,15 @@ export function useCopyText() {
return async function copyText(value: string, options: CopyTextOptions) {
if (!value) {
if (options.emptyErrorText)
- toast.error(options.emptyErrorText)
+ ZNotification.error({ message: options.emptyErrorText })
return
}
try {
await copy(value)
- toast.success(options.successText)
+ ZNotification.success({ message: options.successText })
}
catch (error: unknown) {
- toast.error(options.errorFromException ? errorMessage(error, '复制失败') : '复制失败')
+ ZNotification.error({ message: options.errorFromException ? errorMessage(error, '复制失败') : '复制失败' })
}
}
}
diff --git a/frontend/src/directives/loading.ts b/frontend/src/directives/loading.ts
deleted file mode 100644
index ade203238..000000000
--- a/frontend/src/directives/loading.ts
+++ /dev/null
@@ -1,156 +0,0 @@
-import type { Directive, DirectiveBinding } from 'vue'
-
-type LoadingBindingValue
- = | boolean
- | {
- loading?: boolean
- text?: string
- preserveContent?: boolean
- }
-
-interface LoadingState {
- overlay: HTMLDivElement
- previousPosition: string
- managedPosition: boolean
- preserveContent: boolean
-}
-
-type LoadingElement = HTMLElement & {
- __cpLoading?: LoadingState
-}
-
-const OVERLAY_BASE_CLASS = [
- 'absolute',
- 'inset-0',
- 'z-50',
- 'grid',
- 'min-h-18',
- 'place-items-center',
- 'rounded-[inherit]',
-].join(' ')
-const OVERLAY_MASK_CLASS = 'bg-cp-bg-container/82 backdrop-blur-[4px]'
-const PANEL_CLASS = [
- 'inline-flex',
- 'min-h-10',
- 'items-center',
- 'gap-2.5',
- 'rounded-xl',
- 'py-2.25',
- 'pr-3.5',
- 'pl-3',
- 'text-xs',
- 'leading-[1.15]',
- 'font-heavy',
- 'text-cp-text-secondary',
-].join(' ')
-const MARK_CLASS = [
- 'inline-block',
- 'size-4',
- 'rounded-full',
- 'animate-spin',
- 'bg-[radial-gradient(circle_at_center,var(--cp-color-bg-container)_0_44%,transparent_46%),conic-gradient(from_0deg,var(--cp-color-primary)_0deg_105deg,var(--cp-color-primary-hover)_105deg_200deg,var(--cp-color-fill-tertiary)_200deg_360deg)]',
-].join(' ')
-const LABEL_CLASS = 'whitespace-nowrap'
-
-function normalizeBinding(value: LoadingBindingValue | undefined) {
- if (typeof value === 'object' && value !== null) {
- return {
- loading: Boolean(value.loading),
- text: value.text || '加载中',
- preserveContent: Boolean(value.preserveContent),
- }
- }
-
- return {
- loading: Boolean(value),
- text: '加载中',
- preserveContent: false,
- }
-}
-
-function overlayClass(preserveContent: boolean) {
- return preserveContent ? OVERLAY_BASE_CLASS : `${OVERLAY_BASE_CLASS} ${OVERLAY_MASK_CLASS}`
-}
-
-function createOverlay(text: string, preserveContent: boolean) {
- const overlay = document.createElement('div')
- overlay.className = overlayClass(preserveContent)
- overlay.setAttribute('role', 'status')
- overlay.setAttribute('aria-live', 'polite')
-
- const panel = document.createElement('div')
- panel.className = PANEL_CLASS
-
- const mark = document.createElement('span')
- mark.className = MARK_CLASS
-
- const label = document.createElement('span')
- label.className = LABEL_CLASS
- label.dataset.loadingLabel = ''
- label.textContent = text
-
- panel.append(mark, label)
- overlay.append(panel)
-
- return overlay
-}
-
-function showLoading(element: LoadingElement, text: string, preserveContent: boolean) {
- if (element.__cpLoading) {
- const label = element.__cpLoading.overlay.querySelector('[data-loading-label]')
- if (label)
- label.textContent = text
- if (element.__cpLoading.preserveContent !== preserveContent) {
- element.__cpLoading.overlay.className = overlayClass(preserveContent)
- element.__cpLoading.preserveContent = preserveContent
- }
- return
- }
-
- const previousPosition = element.style.position
- const managedPosition = window.getComputedStyle(element).position === 'static'
- if (managedPosition) {
- element.style.position = 'relative'
- }
-
- const overlay = createOverlay(text, preserveContent)
- element.append(overlay)
- element.setAttribute('aria-busy', 'true')
- element.classList.add('overflow-hidden')
- element.__cpLoading = {
- overlay,
- previousPosition,
- managedPosition,
- preserveContent,
- }
-}
-
-function hideLoading(element: LoadingElement) {
- const state = element.__cpLoading
- if (!state)
- return
-
- state.overlay.remove()
- element.removeAttribute('aria-busy')
- element.classList.remove('overflow-hidden')
- if (state.managedPosition) {
- element.style.position = state.previousPosition
- }
- element.__cpLoading = undefined
-}
-
-function syncLoading(element: LoadingElement, binding: DirectiveBinding) {
- const { loading, text, preserveContent } = normalizeBinding(binding.value)
- if (loading) {
- showLoading(element, text, preserveContent)
- }
- else {
- hideLoading(element)
- }
-}
-
-export const loading: Directive = {
- mounted: syncLoading,
- updated: syncLoading,
- beforeUnmount: hideLoading,
-}
diff --git a/frontend/src/layout/components/AppSidebar.vue b/frontend/src/layout/components/AppSidebar.vue
index 85a9dc984..079cde98e 100644
--- a/frontend/src/layout/components/AppSidebar.vue
+++ b/frontend/src/layout/components/AppSidebar.vue
@@ -1,7 +1,7 @@
-
@@ -305,7 +305,7 @@ watch(
class="mt-2 mb-0 h-[1em] truncate font-mono text-cp leading-none font-bold text-cp-text"
:title="item.title || item.value"
>
-
{{ updateError || updateInfo?.warning }}
-
-
-
+
+
+
上次操作失败
-
+
@@ -344,7 +344,7 @@ watch(
{{ lastFailedOperation.error || lastFailedOperation.message || '操作失败' }}
-
+
-
+
{{ presentation.releaseVersion }}
-
+
-
+
-
@@ -423,27 +423,27 @@ watch(
-
+
-
-
+
-
-
-
+
+
+
-
+
@@ -454,10 +454,9 @@ watch(
选择仅用于本次检查,重新打开时按运行版本选择通道,不会自动安装或降级
-
+
-
检查更新
-
-
+
{{ presentation.restartButtonLabel }}
-
-
+
{{ updating ? '更新中' : '下载并更新' }}
-
+
-
+
-
-
+
-
-
+
diff --git a/frontend/src/layout/index.vue b/frontend/src/layout/index.vue
index 3a4f521ea..eb44184df 100644
--- a/frontend/src/layout/index.vue
+++ b/frontend/src/layout/index.vue
@@ -1,5 +1,5 @@
-
('selectedGroupIds', { required: t
-
+
取消
-
-
+
保存更改
-
+
-
+
diff --git a/frontend/src/views/accounts/components/AccountConnectionTestModal.vue b/frontend/src/views/accounts/components/AccountConnectionTestModal.vue
index ac2516aef..e97ab9fa6 100644
--- a/frontend/src/views/accounts/components/AccountConnectionTestModal.vue
+++ b/frontend/src/views/accounts/components/AccountConnectionTestModal.vue
@@ -1,7 +1,7 @@
-
-
-
+
关闭
-
-
+
{{ logs.length > 0 || error ? '重新测试' : '开始测试' }}
-
+
-
+
diff --git a/frontend/src/views/accounts/components/AccountEditModal.vue b/frontend/src/views/accounts/components/AccountEditModal.vue
index 2f4746af9..2a11e1c7c 100644
--- a/frontend/src/views/accounts/components/AccountEditModal.vue
+++ b/frontend/src/views/accounts/components/AccountEditModal.vue
@@ -3,7 +3,7 @@ import type { ApiKeyAccountForm } from '../utils/upstreamApiKey'
import type { Account, AccountGroupRef, AccountModelAccess } from '@/api'
-import { BaseButton, BaseFormItem, BaseModal, BaseSegmented, BaseTextarea } from '@codex-proxy/ui'
+import { ZButton, ZDialog, ZFormItem, ZSegmented, ZTextarea } from '@codex-proxy/ui'
import AccountPlanBadge from '@/components/account/AccountPlanBadge.vue'
import ProviderIconGroup from '@/components/ProviderIconGroup.vue'
import { isOpenAiApiKeyAccount, isOpenAiOAuthAccount } from '../utils/upstreamApiKey'
@@ -42,11 +42,11 @@ const selectedGroupIds = defineModel('selectedGroupIds', { required: t
-
('selectedGroupIds', { required: t
-
+
正在读取上游设置…
传输方式读取失败,其他设置仍可保存
-
-
+
+
@@ -105,29 +105,29 @@ const selectedGroupIds = defineModel('selectedGroupIds', { required: t
:account-id="account.id"
/>
-
-
+
-
+
-
+
取消
-
-
+
保存更改
-
+
-
+
diff --git a/frontend/src/views/accounts/components/AccountFilters.vue b/frontend/src/views/accounts/components/AccountFilters.vue
index 680817154..22659a29c 100644
--- a/frontend/src/views/accounts/components/AccountFilters.vue
+++ b/frontend/src/views/accounts/components/AccountFilters.vue
@@ -1,6 +1,6 @@
- props.notes, recheckOpen, { flush: 'post' })
:hover-delay="240"
@update:model-value="updateOpen"
>
-
+
-
+
diff --git a/frontend/src/views/accounts/components/AccountOverviewCards.vue b/frontend/src/views/accounts/components/AccountOverviewCards.vue
index 168525aae..864ad7c20 100644
--- a/frontend/src/views/accounts/components/AccountOverviewCards.vue
+++ b/frontend/src/views/accounts/components/AccountOverviewCards.vue
@@ -1,6 +1,6 @@
-
-
-
+
+
+
diff --git a/frontend/src/views/accounts/components/AccountSettingsFields.vue b/frontend/src/views/accounts/components/AccountSettingsFields.vue
index f3eb64829..369924069 100644
--- a/frontend/src/views/accounts/components/AccountSettingsFields.vue
+++ b/frontend/src/views/accounts/components/AccountSettingsFields.vue
@@ -1,6 +1,6 @@
-
+
-
+
上传文件
-
+
-
-
+
diff --git a/frontend/src/views/accounts/components/account-create-modal/AccountOAuthFields.vue b/frontend/src/views/accounts/components/account-create-modal/AccountOAuthFields.vue
index 8cd423408..6658562db 100644
--- a/frontend/src/views/accounts/components/account-create-modal/AccountOAuthFields.vue
+++ b/frontend/src/views/accounts/components/account-create-modal/AccountOAuthFields.vue
@@ -1,6 +1,6 @@
-
diff --git a/frontend/src/views/accounts/components/account-create-modal/AccountSetupFields.vue b/frontend/src/views/accounts/components/account-create-modal/AccountSetupFields.vue
index 6c5cc1ac8..2d7c8cc66 100644
--- a/frontend/src/views/accounts/components/account-create-modal/AccountSetupFields.vue
+++ b/frontend/src/views/accounts/components/account-create-modal/AccountSetupFields.vue
@@ -1,7 +1,7 @@
-
@@ -111,15 +111,15 @@ function continueToImport() {
:provider="account.provider"
:authentication-kind="account.authenticationKind"
/>
-
-
+
@@ -135,10 +135,10 @@ function continueToImport() {
{{ scheduling.message }}
-
-
+
取消
-
-
+
+
上一步
-
-
+
+
继续导入
-
-
+
+
{{ view.submitLabel }}
-
+
-
+
diff --git a/frontend/src/views/accounts/components/account-create-modal/presenter.ts b/frontend/src/views/accounts/components/account-create-modal/presenter.ts
index 128b43d4d..d417cf075 100644
--- a/frontend/src/views/accounts/components/account-create-modal/presenter.ts
+++ b/frontend/src/views/accounts/components/account-create-modal/presenter.ts
@@ -49,8 +49,8 @@ export function resolveAccountCreatePresentation(input: {
modal: {
title: configuring ? '账号设置' : input.reauthorizing ? '重新授权账号' : '导入账号',
description: configuring ? '设置将应用于本次导入的账号' : input.reauthorizing ? '完成授权后更新账号凭据' : description,
- tone: configuring ? 'neutral' as const : 'info' as const,
- size: configuring ? 'md-wide' as const : 'md' as const,
+ type: configuring ? 'default' as const : 'info' as const,
+ width: configuring ? '42rem' : '36rem',
},
oauth: {
callbackLabel: id === 'xai' ? '回调地址或授权码' : '回调地址',
diff --git a/frontend/src/views/accounts/components/account-import-tasks/TaskDetail.vue b/frontend/src/views/accounts/components/account-import-tasks/TaskDetail.vue
index 8dc946f77..ee88ee250 100644
--- a/frontend/src/views/accounts/components/account-import-tasks/TaskDetail.vue
+++ b/frontend/src/views/accounts/components/account-import-tasks/TaskDetail.vue
@@ -1,6 +1,6 @@
-
+
进度暂未更新:{{ error.replace(/[。.]\s*$/u, '') }},恢复连接后将自动刷新
-
+
重试
-
+
-
+
-
-
-
+
+
-
+
@@ -83,11 +83,11 @@ function handleRetentionKeydown(event: KeyboardEvent) {
服务重启后任务记录消失,已入库账号保留
-
-
+
+
关闭
-
+
-
+
diff --git a/frontend/src/views/accounts/components/account-profile-modal/Metrics.vue b/frontend/src/views/accounts/components/account-profile-modal/Metrics.vue
index 7250bee11..8c2d8f948 100644
--- a/frontend/src/views/accounts/components/account-profile-modal/Metrics.vue
+++ b/frontend/src/views/accounts/components/account-profile-modal/Metrics.vue
@@ -1,6 +1,6 @@
@@ -8,20 +8,20 @@ import { BaseSkeleton } from '@codex-proxy/ui'
diff --git a/frontend/src/views/accounts/components/account-profile-modal/Subscription.vue b/frontend/src/views/accounts/components/account-profile-modal/Subscription.vue
index 2f8aa435a..94e2cccea 100644
--- a/frontend/src/views/accounts/components/account-profile-modal/Subscription.vue
+++ b/frontend/src/views/accounts/components/account-profile-modal/Subscription.vue
@@ -51,7 +51,7 @@ const dates = computed(() => [
计费
-
+
{{ billing }}
diff --git a/frontend/src/views/accounts/components/account-profile-modal/TokenActivity.vue b/frontend/src/views/accounts/components/account-profile-modal/TokenActivity.vue
index 91d3c8c84..fd2726ea5 100644
--- a/frontend/src/views/accounts/components/account-profile-modal/TokenActivity.vue
+++ b/frontend/src/views/accounts/components/account-profile-modal/TokenActivity.vue
@@ -1,7 +1,7 @@
-
+
@@ -42,10 +42,10 @@ const { profile, subscription, loading, error, load } = useAccountPersonalInfo({
正在加载订阅信息
-
+
-
-
-
-
+
关闭
-
-
+
+
刷新信息
-
+
-
+
diff --git a/frontend/src/views/accounts/components/account-quota-forecast-modal/Skeleton.vue b/frontend/src/views/accounts/components/account-quota-forecast-modal/Skeleton.vue
index c3e7d1a02..672399d1e 100644
--- a/frontend/src/views/accounts/components/account-quota-forecast-modal/Skeleton.vue
+++ b/frontend/src/views/accounts/components/account-quota-forecast-modal/Skeleton.vue
@@ -1,5 +1,5 @@
@@ -9,27 +9,27 @@ import { BaseSkeleton } from '@codex-proxy/ui'
diff --git a/frontend/src/views/accounts/components/account-quota-forecast-modal/index.vue b/frontend/src/views/accounts/components/account-quota-forecast-modal/index.vue
index 8b24023e9..33addd0a0 100644
--- a/frontend/src/views/accounts/components/account-quota-forecast-modal/index.vue
+++ b/frontend/src/views/accounts/components/account-quota-forecast-modal/index.vue
@@ -1,7 +1,7 @@
-
@@ -80,23 +80,23 @@ function handleExplanationKeydown(event: KeyboardEvent) {
-
+
-
+
-
+
重新加载
-
+
-
+
-
+
@@ -108,18 +108,17 @@ function handleExplanationKeydown(event: KeyboardEvent) {
更新于 {{ forecast.source.observedAtDisplay }}
-
-
-
+
+
-
+
@@ -141,12 +140,12 @@ function handleExplanationKeydown(event: KeyboardEvent) {
预测以数据更新时间为准,等价费用不是实际账单或账户余额
-
+
-
+
关闭
-
-
+
+
@@ -154,7 +153,7 @@ function handleExplanationKeydown(event: KeyboardEvent) {
刷新额度
-
+
-
+
diff --git a/frontend/src/views/accounts/components/account-quota-panel/ResetCredits.vue b/frontend/src/views/accounts/components/account-quota-panel/ResetCredits.vue
index 2ba63eec3..8afb7290e 100644
--- a/frontend/src/views/accounts/components/account-quota-panel/ResetCredits.vue
+++ b/frontend/src/views/accounts/components/account-quota-panel/ResetCredits.vue
@@ -1,6 +1,6 @@
-
-
+
+
-
+
diff --git a/frontend/src/views/accounts/components/account-status-badge/index.vue b/frontend/src/views/accounts/components/account-status-badge/index.vue
index e0e074b1b..2a9197ef7 100644
--- a/frontend/src/views/accounts/components/account-status-badge/index.vue
+++ b/frontend/src/views/accounts/components/account-status-badge/index.vue
@@ -1,6 +1,6 @@
-
-
+
+
上游原始反馈
仅供排查
-
+
{{ presentation.errorText }}
-
+
-
+
diff --git a/frontend/src/views/accounts/composables/useAccountBatchEditor.ts b/frontend/src/views/accounts/composables/useAccountBatchEditor.ts
index 54bf8c793..ee86ac861 100644
--- a/frontend/src/views/accounts/composables/useAccountBatchEditor.ts
+++ b/frontend/src/views/accounts/composables/useAccountBatchEditor.ts
@@ -1,7 +1,7 @@
import type { Ref } from 'vue'
import type { Account, AccountModelAccess } from '@/api'
-import { toast } from '@codex-proxy/ui'
+import { ZNotification } from '@codex-proxy/ui'
import { computed, ref, shallowRef, watch } from 'vue'
import { batchUpdateAccounts } from '@/api'
import { useAsyncAction } from '@/composables/useAsyncAction'
@@ -64,20 +64,20 @@ export function useAccountBatchEditor(options: {
return
const modelError = accountModelAccessError(modelAccess.value)
if (modelError) {
- toast.warning(modelError)
+ ZNotification.warning({ message: modelError })
return
}
if (!hasChanges.value) {
- toast.warning('请选择需要更新的设置')
+ ZNotification.warning({ message: '请选择需要更新的设置' })
return
}
const scheduling = parseAccountSchedulingForm(editedFields.value.has('concurrencyLimit') ? concurrencyLimit.value : '', editedFields.value.has('weight') ? weight.value : '1')
if (proxyMode.value === 'proxy' && !proxyId.value.trim()) {
- toast.warning('请选择已通过测试的代理')
+ ZNotification.warning({ message: '请选择已通过测试的代理' })
return
}
if (!scheduling.valid) {
- toast.warning(scheduling.message)
+ ZNotification.warning({ message: scheduling.message })
return
}
@@ -94,7 +94,7 @@ export function useAccountBatchEditor(options: {
})
showBatchEditModal.value = false
options.selectedIds.value = new Set()
- toast.success(`已更新 ${accountIds.length} 个账号`)
+ ZNotification.success({ message: `已更新 ${accountIds.length} 个账号` })
void Promise.allSettled([options.reloadAccounts(), options.reloadGroups()])
}, { onError: () => void options.reloadAccounts() })
}
diff --git a/frontend/src/views/accounts/composables/useAccountConnectionTest.ts b/frontend/src/views/accounts/composables/useAccountConnectionTest.ts
index fa12226bf..a192b59e7 100644
--- a/frontend/src/views/accounts/composables/useAccountConnectionTest.ts
+++ b/frontend/src/views/accounts/composables/useAccountConnectionTest.ts
@@ -1,5 +1,5 @@
import type { Account, AccountModelsResponse } from '@/api'
-import { toast } from '@codex-proxy/ui'
+import { ZNotification } from '@codex-proxy/ui'
import { CheckCircle2, Clock3, Wifi, XCircle } from '@lucide/vue'
import { useEventSource } from '@vueuse/core'
@@ -424,7 +424,7 @@ export function useAccountConnectionTest(options: { reload: () => Promise {
void loadAccounts().catch(() => undefined)
- toast.error(
- deletedCount > 0
- ? `已删除 ${deletedCount} 个账号,其余未删除:${errorMessage(error, '操作失败')}`
- : errorMessage(error, '批量删除失败'),
- )
+ ZNotification.error({ message: deletedCount > 0
+ ? `已删除 ${deletedCount} 个账号,其余未删除:${errorMessage(error, '操作失败')}`
+ : errorMessage(error, '批量删除失败') })
},
},
)
@@ -149,11 +147,11 @@ export function useAccountMutations(options: {
return
const selected = [...options.selectedIds.value]
if (selected.length === 0) {
- toast.warning('请选择要导出的账号')
+ ZNotification.warning({ message: '请选择要导出的账号' })
return
}
if (exportDisabledReason.value) {
- toast.warning(exportDisabledReason.value)
+ ZNotification.warning({ message: exportDisabledReason.value })
return
}
@@ -165,7 +163,7 @@ export function useAccountMutations(options: {
})
const fileName = payload.fileName
await downloadJson(payload, fileName)
- toast.success(`已导出 ${selected.length} 个账号`)
+ ZNotification.success({ message: `已导出 ${selected.length} 个账号` })
},
{ errorText: '导出失败' },
)
@@ -178,7 +176,7 @@ export function useAccountMutations(options: {
const plan = account.planTypeDisplay.trim().replace(/[^\p{L}\p{N}_-]/gu, '_') || 'unknown-plan'
const name = account.name.trim().replace(/[^\p{L}\p{N}_-]/gu, '_') || 'account'
await downloadJson(result.catalog, `cpr-model-catalog-${plan}-${name}.json`)
- toast.success(`已下载模型目录,共 ${result.modelCount} 个模型`)
+ ZNotification.success({ message: `已下载模型目录,共 ${result.modelCount} 个模型` })
}
catch {}
})
@@ -194,14 +192,14 @@ export function useAccountMutations(options: {
)
await loadAccounts()
if (result.result === 'skipped') {
- toast.warning(result.error || 'Token 正在刷新中')
+ ZNotification.warning({ message: result.error || 'Token 正在刷新中' })
return
}
if (result.result === 'failed') {
- toast.error(result.error || '刷新失败')
+ ZNotification.error({ message: result.error || '刷新失败' })
return
}
- toast.success('Token 已刷新')
+ ZNotification.success({ message: 'Token 已刷新' })
}
catch {}
})
@@ -212,7 +210,7 @@ export function useAccountMutations(options: {
try {
await batchUpdateAccounts({ accountIds: [account.id], enabled: !account.enabled })
await loadAccounts()
- toast.success(account.enabled ? '调度已停用' : '调度已启用')
+ ZNotification.success({ message: account.enabled ? '调度已停用' : '调度已启用' })
}
catch {}
})
@@ -228,7 +226,7 @@ export function useAccountMutations(options: {
selectedIds.delete(accountId)
options.selectedIds.value = selectedIds
}
- toast.success('额度已刷新')
+ ZNotification.success({ message: '额度已刷新' })
}
catch {}
})
@@ -242,10 +240,7 @@ export function useAccountMutations(options: {
await options.replaceAccount(result.account)
}
catch (error: unknown) {
- toast.warning(
- `额度已重置,但最新额度加载失败:${errorMessage(error, '请手动刷新额度')}`,
- { duration: 5000 },
- )
+ ZNotification.warning({ message: `额度已重置,但最新额度加载失败:${errorMessage(error, '请手动刷新额度')}`, ...({ duration: 5000 }) })
}
}
@@ -259,7 +254,7 @@ export function useAccountMutations(options: {
selectedIds.delete(accountId)
options.selectedIds.value = selectedIds
}
- toast.success('账号状态已恢复')
+ ZNotification.success({ message: '账号状态已恢复' })
}
catch {}
})
diff --git a/frontend/src/views/accounts/composables/useAccountOnboarding.ts b/frontend/src/views/accounts/composables/useAccountOnboarding.ts
index 427c61e37..4593b85ec 100644
--- a/frontend/src/views/accounts/composables/useAccountOnboarding.ts
+++ b/frontend/src/views/accounts/composables/useAccountOnboarding.ts
@@ -1,5 +1,5 @@
import type { Account, AccountImportTask } from '@/api'
-import { toast } from '@codex-proxy/ui'
+import { ZNotification } from '@codex-proxy/ui'
import { computed, ref, shallowRef, watch } from 'vue'
import { createAccountImportTask, importAccounts } from '@/api'
import { useAsyncAction } from '@/composables/useAsyncAction'
@@ -92,7 +92,7 @@ export function useAccountOnboarding(options: {
})
showCreateModal.value = false
options.onImportTaskCreated(task)
- toast.success('导入任务已创建')
+ ZNotification.success({ message: '导入任务已创建' })
})
}
@@ -119,7 +119,7 @@ export function useAccountOnboarding(options: {
})
}
catch (cause) {
- toast.error(errorMessage(cause, '启动授权失败'))
+ ZNotification.error({ message: errorMessage(cause, '启动授权失败') })
}
}
@@ -142,7 +142,7 @@ export function useAccountOnboarding(options: {
async function finishCreate(message: string) {
showCreateModal.value = false
- toast.success(message)
+ ZNotification.success({ message })
await options.reload()
}
diff --git a/frontend/src/views/accounts/composables/useAccountQuotaForecast.ts b/frontend/src/views/accounts/composables/useAccountQuotaForecast.ts
index 2e8cee18d..0494e1885 100644
--- a/frontend/src/views/accounts/composables/useAccountQuotaForecast.ts
+++ b/frontend/src/views/accounts/composables/useAccountQuotaForecast.ts
@@ -1,6 +1,6 @@
import type { Ref } from 'vue'
import type { Account, AccountQuotaForecastResponse } from '@/api'
-import { toast } from '@codex-proxy/ui'
+import { ZNotification } from '@codex-proxy/ui'
import { onScopeDispose, shallowRef, watch } from 'vue'
import { getAccountQuotaForecast, refreshAccountQuota } from '@/api'
@@ -66,7 +66,7 @@ export function useAccountQuotaForecast(
return
onAccountUpdated(result.account)
if (accountId.value === targetAccountId && await load())
- toast.success('额度已刷新')
+ ZNotification.success({ message: '额度已刷新' })
}
catch {
if (!disposed && accountId.value === targetAccountId) {
diff --git a/frontend/src/views/accounts/composables/useAccountResetCredits.ts b/frontend/src/views/accounts/composables/useAccountResetCredits.ts
index 193416f6c..eccc53aaf 100644
--- a/frontend/src/views/accounts/composables/useAccountResetCredits.ts
+++ b/frontend/src/views/accounts/composables/useAccountResetCredits.ts
@@ -1,5 +1,5 @@
import type { AccountResetCredit } from '@/api'
-import { toast } from '@codex-proxy/ui'
+import { ZNotification } from '@codex-proxy/ui'
import { computed, shallowReactive, shallowRef, watch } from 'vue'
import {
@@ -189,7 +189,7 @@ export function useAccountResetCredits(options: {
|| (result.code === 'already_redeemed' && operation.hasTransportFailure)
target.pendingOperation = null
if (!confirmed) {
- toast.error(resetResultMessage(result.code))
+ ZNotification.error({ message: resetResultMessage(result.code) })
await loadSessionCredits(target, true)
return false
}
@@ -201,7 +201,7 @@ export function useAccountResetCredits(options: {
if (session.value === target)
showConfirm.value = false
options.onConsumed(operation.accountId)
- toast.success(successMessage)
+ ZNotification.success({ message: successMessage })
applyConfirmedConsumption(target, operation)
await loadSessionCredits(target, true)
return true
@@ -212,11 +212,11 @@ export function useAccountResetCredits(options: {
...operation,
hasTransportFailure: true,
}
- toast.warning('消费结果暂不确定,重试会复用同一个请求标识', { duration: 5000 })
+ ZNotification.warning({ message: '消费结果暂不确定,重试会复用同一个请求标识', ...({ duration: 5000 }) })
}
else {
target.pendingOperation = null
- toast.error(errorMessage(error, '额度重置失败'))
+ ZNotification.error({ message: errorMessage(error, '额度重置失败') })
await loadSessionCredits(target, true)
}
return false
diff --git a/frontend/src/views/accounts/composables/useAccountsQuery.ts b/frontend/src/views/accounts/composables/useAccountsQuery.ts
index 907155332..52b486158 100644
--- a/frontend/src/views/accounts/composables/useAccountsQuery.ts
+++ b/frontend/src/views/accounts/composables/useAccountsQuery.ts
@@ -1,4 +1,4 @@
-import type { BaseTableSort } from '@codex-proxy/ui'
+import type { TableSort } from '@codex-proxy/ui'
import type { Account } from '@/api'
import { computed, onMounted, shallowRef, watch } from 'vue'
@@ -10,7 +10,7 @@ export function useAccountsQuery() {
const providerQuery = shallowRef('')
const statusQuery = shallowRef('')
const groupQuery = shallowRef('')
- const sort = shallowRef()
+ const sort = shallowRef()
const accountSummary = shallowRef({
total: 0,
normal: 0,
@@ -55,7 +55,7 @@ export function useAccountsQuery() {
void query.execute()
}
- function handleSortChange(nextSort: BaseTableSort | undefined) {
+ function handleSortChange(nextSort: TableSort | undefined) {
sort.value = nextSort
query.page.value = 1
void query.execute()
diff --git a/frontend/src/views/accounts/constants.ts b/frontend/src/views/accounts/constants.ts
index f58554f47..a5bc7c3b5 100644
--- a/frontend/src/views/accounts/constants.ts
+++ b/frontend/src/views/accounts/constants.ts
@@ -31,7 +31,7 @@ export const accountColumns = defineTableColumns([
kind: 'meta',
size: 'md',
align: 'center',
- format: value => formatProviderLabel(typeof value === 'string' ? value : null),
+ formatter: value => formatProviderLabel(typeof value === 'string' ? value : null),
},
{ key: 'status', label: '状态', kind: 'status', align: 'left', sortable: true },
{ key: 'planType', label: '订阅', kind: 'status', sortable: true },
@@ -49,7 +49,7 @@ export const accountColumns = defineTableColumns([
label: '令牌过期',
kind: 'datetime',
sortable: 'expiresAt',
- format: value => optionalAccountCell(value),
+ formatter: value => optionalAccountCell(value),
emptyText: '',
},
{ key: 'actions', label: '操作', kind: 'actions', size: 'lg', hideable: false },
diff --git a/frontend/src/views/accounts/index.vue b/frontend/src/views/accounts/index.vue
index 206802147..85b133c0f 100644
--- a/frontend/src/views/accounts/index.vue
+++ b/frontend/src/views/accounts/index.vue
@@ -1,5 +1,5 @@
-
+
@@ -225,7 +225,7 @@ const statusBars = computed(() => {
- {
-
+
diff --git a/frontend/src/views/dashboard/components/DashboardContent.vue b/frontend/src/views/dashboard/components/DashboardContent.vue
index c28289197..6b8c6c181 100644
--- a/frontend/src/views/dashboard/components/DashboardContent.vue
+++ b/frontend/src/views/dashboard/components/DashboardContent.vue
@@ -1,7 +1,7 @@
-
+
-
-
+
{{ metric.title }}
@@ -128,5 +128,5 @@ const sparklineOption = computed(() => {
-
+
diff --git a/frontend/src/views/dashboard/components/RequestTrendCard.vue b/frontend/src/views/dashboard/components/RequestTrendCard.vue
index 7de97786a..9214e1113 100644
--- a/frontend/src/views/dashboard/components/RequestTrendCard.vue
+++ b/frontend/src/views/dashboard/components/RequestTrendCard.vue
@@ -1,7 +1,7 @@
-
+
-
-
-
+
diff --git a/frontend/src/views/dashboard/components/UsageRecordCard.vue b/frontend/src/views/dashboard/components/UsageRecordCard.vue
index f61e6cba6..0d523c25d 100644
--- a/frontend/src/views/dashboard/components/UsageRecordCard.vue
+++ b/frontend/src/views/dashboard/components/UsageRecordCard.vue
@@ -1,7 +1,7 @@
-
-
+
diff --git a/frontend/src/views/dashboard/components/WireProfileCard.vue b/frontend/src/views/dashboard/components/WireProfileCard.vue
index d8e560227..2902ffa30 100644
--- a/frontend/src/views/dashboard/components/WireProfileCard.vue
+++ b/frontend/src/views/dashboard/components/WireProfileCard.vue
@@ -1,5 +1,5 @@
-
+
通用上游身份
-
-
+
-
+
diff --git a/frontend/src/views/groups/components/AccountGroupActions.vue b/frontend/src/views/groups/components/AccountGroupActions.vue
index 74444911d..5e26f994b 100644
--- a/frontend/src/views/groups/components/AccountGroupActions.vue
+++ b/frontend/src/views/groups/components/AccountGroupActions.vue
@@ -1,6 +1,6 @@
-
-
-
-
+
+
-
-
-
+
+
-
-
-
+
+
-
-
-
+
+
-
-
+
+
-
+
取消
-
-
+
保存分组
-
+
-
+
diff --git a/frontend/src/views/groups/composables/useAccountGroups.ts b/frontend/src/views/groups/composables/useAccountGroups.ts
index 19d101701..8155b1197 100644
--- a/frontend/src/views/groups/composables/useAccountGroups.ts
+++ b/frontend/src/views/groups/composables/useAccountGroups.ts
@@ -1,5 +1,5 @@
import type { AccountGroup, ApiKey, FastMode } from '@/api'
-import { normalizeRgbaHexColor, toast } from '@codex-proxy/ui'
+import { normalizeRgbaHexColor, ZNotification } from '@codex-proxy/ui'
import { computed, onMounted, ref, shallowRef, watch } from 'vue'
import {
@@ -131,12 +131,12 @@ export function useAccountGroups() {
return
const name = form.value.name.trim()
if (!name) {
- toast.warning('请输入分组名称')
+ ZNotification.warning({ message: '请输入分组名称' })
return
}
const color = normalizeRgbaHexColor(form.value.color)
if (!color) {
- toast.warning('请选择有效的分组颜色')
+ ZNotification.warning({ message: '请选择有效的分组颜色' })
return
}
@@ -157,7 +157,7 @@ export function useAccountGroups() {
}
showFormModal.value = false
await Promise.all([query.execute(), loadReferenceKeys()])
- toast.success(updating ? '分组已更新' : '分组已创建')
+ ZNotification.success({ message: updating ? '分组已更新' : '分组已创建' })
})
}
@@ -178,7 +178,7 @@ export function useAccountGroups() {
await disableAccountGroup({ id: group.id })
showDisableModal.value = false
await query.execute()
- toast.success('分组已禁用')
+ ZNotification.success({ message: '分组已禁用' })
})
}
@@ -188,7 +188,7 @@ export function useAccountGroups() {
const mutation = group.enabled ? disableAccountGroup : enableAccountGroup
await mutation({ id: group.id })
await query.execute()
- toast.success(group.enabled ? '分组已禁用' : '分组已启用')
+ ZNotification.success({ message: group.enabled ? '分组已禁用' : '分组已启用' })
}
catch {}
})
@@ -210,7 +210,7 @@ export function useAccountGroups() {
selectedIds.value = remaining
showDeleteModal.value = false
await query.execute()
- toast.success('分组已删除')
+ ZNotification.success({ message: '分组已删除' })
}, { onError: () => void query.execute() })
}
@@ -239,16 +239,14 @@ export function useAccountGroups() {
await query.execute()
showBatchDeleteModal.value = false
- toast.success(`已删除 ${deletedCount} 个分组`)
+ ZNotification.success({ message: `已删除 ${deletedCount} 个分组` })
}, {
errorText: false,
onError: (error) => {
void query.execute().catch(() => undefined)
- toast.error(
- deletedCount > 0
- ? `已删除 ${deletedCount} 个分组,其余未删除:${errorMessage(error, '操作失败')}`
- : errorMessage(error, '批量删除失败'),
- )
+ ZNotification.error({ message: deletedCount > 0
+ ? `已删除 ${deletedCount} 个分组,其余未删除:${errorMessage(error, '操作失败')}`
+ : errorMessage(error, '批量删除失败') })
},
})
}
diff --git a/frontend/src/views/groups/index.vue b/frontend/src/views/groups/index.vue
index d2e7f9824..9d7bec144 100644
--- a/frontend/src/views/groups/index.vue
+++ b/frontend/src/views/groups/index.vue
@@ -1,5 +1,5 @@
-
+
@@ -32,7 +32,7 @@ const windows = computed(() => [
-
+
@@ -54,5 +54,5 @@ const windows = computed(() => [
-
+
diff --git a/frontend/src/views/key-usage/components/KeyUsageHeader.vue b/frontend/src/views/key-usage/components/KeyUsageHeader.vue
index c9d54341b..5af474b0c 100644
--- a/frontend/src/views/key-usage/components/KeyUsageHeader.vue
+++ b/frontend/src/views/key-usage/components/KeyUsageHeader.vue
@@ -1,5 +1,5 @@
-
+
@@ -42,31 +42,31 @@ async function logout() {
-
+
-
-
+
+
密钥配置
-
-
-
-
+
+
+
+
-
-
+
+
-
-
+
+
-
+
-
+