diff --git a/docs/content/docs/backend/code-map.mdx b/docs/content/docs/backend/code-map.mdx
index d4e4beafb..1a4a57332 100644
--- a/docs/content/docs/backend/code-map.mdx
+++ b/docs/content/docs/backend/code-map.mdx
@@ -17,7 +17,9 @@ description: 从产品功能快速定位主要代码入口
| 创作工作台 | `web/src/pages/create/index.tsx` | `creation-workspace.tsx`、`creation-conversations.ts`、`creation-types.ts`、`creation-assets.ts`、`creation-references.ts` |
| 登录注册 | `web/src/pages/auth/` | `stores/use-user-store.ts`、`services/api/auth.ts`、后端 `internal/auth/` |
| 积分与计费 | `web/src/components/layout/workspace-wallet-modal.tsx`、`pages/admin/components/platform-finance-panel.tsx` | `services/api/wallet.ts`、`services/api/payments.ts`、后端 `internal/app/finance.go`、`internal/app/payment.go`、`payment-plugins/`、`plugin-packages/official-payment-*` |
+| 视频 Token 报价与结算 | `web/src/pages/admin/components/channel-model-price-tier-fields.tsx`、`web/src/components/model-picker.tsx` | `lib/model-pricing.ts`、`services/api/logical-models.ts`;后端 `app/video_token_billing.go` 管像素与时长估算,`app/logical_model_quote.go` 复用准入与价格规则,`app/analytics.go` 提取可信用量,`repository/finance.go` 按订单快照退补差额 |
| 任务中心 | `web/src/pages/tasks/` | `services/api/task-center.ts`、`services/api/task-text-stream.ts` |
+| 产品模型与渠道选择 | `web/src/components/model-picker.tsx`、`pages/admin/components/channel-model-editor.tsx` | `lib/model-picker-groups.ts` 只构建跨渠道展示分组;`lib/user-session.ts` 透传渠道展示名;`components/model-logo.tsx` 按需加载原色图标;后端 `app/channel_models.go` 校验写入,`app/model_catalog.go` 发布目录,schema v24 增加 `channel_label` |
| 我的素材 | `web/src/pages/assets/` | `stores/use-asset-store.ts`、`services/image-storage.ts` |
| 技能库 | `web/src/pages/skills/` | `services/api/skills.ts`、`services/skill-runtime.ts`、`components/skills/skill-runtime-picker.tsx` |
| 画布列表 | `web/src/pages/canvas/index.tsx` | `stores/canvas/use-canvas-store.ts` |
diff --git a/docs/content/docs/backend/meta.json b/docs/content/docs/backend/meta.json
index 3f3b87feb..8ad5a2da0 100644
--- a/docs/content/docs/backend/meta.json
+++ b/docs/content/docs/backend/meta.json
@@ -7,6 +7,7 @@
"http-api",
"code-map",
"backend-database",
+ "video-token-billing",
"task-runtime-stability",
"newapi-channel-2",
"system-update",
diff --git a/docs/content/docs/overview/features.mdx b/docs/content/docs/overview/features.mdx
index 6f0c20aa3..fdce94381 100644
--- a/docs/content/docs/overview/features.mdx
+++ b/docs/content/docs/overview/features.mdx
@@ -93,6 +93,8 @@ description: 当前项目已实现的核心工作台能力与使用入口
## 系统渠道排序与前台别名
+系统渠道模型选择器按产品模型分组:一级显示模型展示名和原色 Logo,二级显示各渠道的展示名及规格价格。管理员在渠道模型的“基本信息”中配置“渠道展示名”(例如“优惠渠道-993”);留空沿用渠道公开名称。同一能力下相同的产品模型标识跨渠道归为一组,调用仍保留用户选中的具体渠道。收起后显示“模型 · 渠道”,不因另一渠道更便宜而自动切换。图标优先使用图标库的原色版本,缺少彩色版本时使用单色版本;缺少配置时显示通用图标,不猜测产品品牌。
+
后台系统渠道及渠道模型列表通过“设置排序”打开完整列表,支持拖动、上移和下移,点击“保存排序”统一生效;取消不会修改线上顺序。渠道行的“更多”菜单支持复制渠道,复制会生成独立的渠道、模型和价格档,并保留原连接配置与凭证。界面不显示内部排序数字,排序不受筛选及分页影响;并发修改会提示重新加载,避免覆盖其他管理员的调整。系统渠道模式下,用户端模型选择器沿用同一渠道及模型顺序。模型排序独立保存,不改变价格、能力版本或启用状态。
系统渠道可设置可选的前台别名;为空时显示渠道名,设置后公开目录和用户会话只返回别名,后台仍保留原名。别名最长 80 字,支持后台搜索。前台模型目录模式保留其独立配置。
diff --git a/web/src/lib/user-session.ts b/web/src/lib/user-session.ts
index fa7d6cdf2..332a14ce1 100644
--- a/web/src/lib/user-session.ts
+++ b/web/src/lib/user-session.ts
@@ -178,7 +178,8 @@ export function systemChannelModelChannels(channels: PublicChannelCatalog[]): Mo
return {
model: model.modelKey,
displayName: model.displayName,
- description: "",
+ channelLabel: model.channelLabel,
+ description: model.description || "",
icon: model.icon || "",
capability: model.capability as ModelCapability,
protocol: model.protocol as any,
diff --git a/web/src/pages/admin/components/credit-operations-panel.tsx b/web/src/pages/admin/components/credit-operations-panel.tsx
index c655eeb5c..ddcc901ae 100644
--- a/web/src/pages/admin/components/credit-operations-panel.tsx
+++ b/web/src/pages/admin/components/credit-operations-panel.tsx
@@ -328,7 +328,11 @@ export default function CreditOperationsPanel({ users, activeOperation, onOperat
{order.status === "settled" ? `${formatCredits(order.actualAmountMicrocredits)} 积分` : "等待用量结算"}
- 输入 {order.inputTokens} · 输出 {order.outputTokens} · 缓存 {order.cachedTokens}
+ {order.usageSource === "video_formula"
+ ? `公式结算 · ${order.outputTokens.toLocaleString()} 视频 Token`
+ : order.capability === "video"
+ ? `上游用量 · ${order.outputTokens.toLocaleString()} 视频 Token`
+ : `输入 ${order.inputTokens} · 输出 ${order.outputTokens} · 缓存 ${order.cachedTokens}`}
) : (
diff --git a/web/src/stores/use-config-store.ts b/web/src/stores/use-config-store.ts
index 626ef91a4..69d36c832 100644
--- a/web/src/stores/use-config-store.ts
+++ b/web/src/stores/use-config-store.ts
@@ -363,6 +363,7 @@ export type ModelChannel = {
modelCosts?: Array<{
model: string;
displayName?: string;
+ channelLabel?: string;
description?: string;
icon?: string;
capability: ModelCapability;
diff --git a/web/src/styles/admin-ui.css b/web/src/styles/admin-ui.css
index 30bf7b573..f3d3081cf 100644
--- a/web/src/styles/admin-ui.css
+++ b/web/src/styles/admin-ui.css
@@ -9,11 +9,25 @@
padding: 14px 16px;
}
-/* Appearance management follows the same full-width settings document used by storage and access pages. */
+/* Appearance categories share one draft and command bar. */
.admin-appearance-settings {
padding-bottom: 24px;
}
+.admin-appearance-tabs,
+.admin-appearance-tabs .ant-tabs-content-holder,
+.admin-appearance-tabs .ant-tabs-tabpane {
+ min-width: 0;
+}
+
+.admin-appearance-tabs > .ant-tabs-nav {
+ margin-bottom: var(--space-4);
+}
+
+.admin-appearance-tabs .ant-tabs-tab {
+ padding-block: var(--space-3);
+}
+
.admin-appearance-settings .admin-settings-section {
border: 1px solid var(--admin-card-border);
}
@@ -724,7 +738,6 @@
.admin-skin-card.is-selected {
border-color: color-mix(in srgb, var(--workspace-accent) 76%, var(--admin-card-border));
background: color-mix(in srgb, var(--workspace-accent) 5%, var(--admin-layer-2));
- box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--workspace-accent) 36%, transparent);
}
.admin-skin-card-select {
@@ -9124,10 +9137,80 @@
}
.admin-model-editor-references .admin-capability-reference-grid {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
align-items: start;
gap: 10px;
}
+.admin-model-editor-modal .admin-capability-reference-card,
+.admin-model-editor-modal .admin-capability-protocol-card {
+ min-width: 0;
+ border: 1px solid color-mix(in srgb, var(--foreground) 10%, transparent);
+ border-radius: 8px;
+ background: color-mix(in srgb, var(--foreground) 2.5%, var(--admin-layer-1));
+}
+
+.admin-model-editor-modal .admin-capability-reference-card-heading,
+.admin-model-editor-modal .admin-capability-protocol-card-heading {
+ display: flex;
+ min-width: 0;
+ align-items: flex-start;
+ gap: 8px;
+ border-bottom: 1px solid color-mix(in srgb, var(--foreground) 8%, transparent);
+ padding: 12px;
+}
+
+.admin-model-editor-modal .admin-capability-reference-card-heading h3,
+.admin-model-editor-modal .admin-capability-protocol-card-heading h3 {
+ margin: 0;
+ color: var(--admin-text-primary);
+ font-size: 12px;
+ font-weight: 650;
+ line-height: 1.4;
+}
+
+.admin-model-editor-modal .admin-capability-reference-card-heading p,
+.admin-model-editor-modal .admin-capability-protocol-card-heading p {
+ margin: 2px 0 0;
+ color: var(--admin-text-muted);
+ font-size: 11px;
+ line-height: 1.45;
+}
+
+.admin-model-editor-modal .admin-capability-reference-fields,
+.admin-model-editor-modal .admin-capability-protocol-fields {
+ display: grid;
+ min-width: 0;
+ gap: 8px;
+ padding: 10px 12px 12px;
+}
+
+.admin-model-editor-modal .admin-capability-protocol-grid {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ align-items: start;
+ gap: 12px;
+}
+
+.admin-model-editor-modal .admin-capability-protocol-card-heading > span {
+ display: grid;
+ flex: none;
+ width: 24px;
+ height: 24px;
+ place-items: center;
+ border-radius: 6px;
+ background: color-mix(in srgb, var(--foreground) 8%, transparent);
+ color: var(--admin-text-muted);
+ font-size: 10px;
+ font-weight: 700;
+ letter-spacing: 0.04em;
+}
+
+.admin-model-editor-modal .admin-capability-protocol-card-heading > div {
+ min-width: 0;
+}
+
.admin-model-editor-references .admin-capability-reference-card {
padding: 10px 12px;
}
@@ -9174,6 +9257,10 @@
.admin-model-editor-references .admin-capability-reference-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
+
+ .admin-model-editor-modal .admin-capability-protocol-grid {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
}
.admin-price-tier-card {
@@ -9423,6 +9510,9 @@
.admin-model-editor-modal .admin-capability-reference-grid {
grid-template-columns: minmax(0, 1fr);
}
+ .admin-model-editor-modal .admin-capability-protocol-grid {
+ grid-template-columns: minmax(0, 1fr);
+ }
.admin-price-tier-upstream {
grid-column: 1 / -1;
}
@@ -10853,4 +10943,3 @@ html[data-magicui-theme-vt="active"] .admin-shell * {
.admin-banner-type-card[data-banner-type="warning"] .admin-banner-type-card-preview {
background: var(--notice-banner-surface-warning);
}
-