smart-admin-web 10.10.0 → 10.11.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/README.md +1 -0
- package/cli/icon-subset.mjs +132 -0
- package/cli/smart-admin-icons.mjs +57 -0
- package/dist/api/index.d.ts +52 -1
- package/dist/api/index.js +151 -84
- package/dist/api/index.js.map +1 -1
- package/dist/api/schema.d.ts +936 -15
- package/dist/assets/icons/ph-subset.json.js +7 -7
- package/dist/createSmartAdmin.d.ts +3 -0
- package/dist/createSmartAdmin.js +36 -36
- package/dist/createSmartAdmin.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +268 -252
- package/dist/index.js.map +1 -1
- package/dist/lib/icons.d.ts +5 -2
- package/dist/lib/icons.js +15 -13
- package/dist/lib/icons.js.map +1 -1
- package/dist/lib/runtime.js +1 -1
- package/dist/locales/en-US.d.ts +143 -0
- package/dist/locales/en-US.js +145 -0
- package/dist/locales/en-US.js.map +1 -1
- package/dist/locales/zh-CN.d.ts +143 -0
- package/dist/locales/zh-CN.js +145 -0
- package/dist/locales/zh-CN.js.map +1 -1
- package/dist/router/viewRegistry.js +1 -1
- package/dist/router/viewRegistry.js.map +1 -1
- package/dist/style.css +1 -1
- package/dist/types/api.d.ts +166 -0
- package/dist/types/api.js +12 -9
- package/dist/types/api.js.map +1 -1
- package/dist/views/system/ai-model/components/ProviderCard.vue.d.ts +13 -0
- package/dist/views/system/ai-model/components/ProviderCard.vue.js +8 -0
- package/dist/views/system/ai-model/components/ProviderCard.vue.js.map +1 -0
- package/dist/views/system/ai-model/components/ProviderCard2.vue.js +230 -0
- package/dist/views/system/ai-model/components/ProviderCard2.vue.js.map +1 -0
- package/dist/views/system/ai-model/components/ProviderForm.vue.d.ts +18 -0
- package/dist/views/system/ai-model/components/ProviderForm.vue.js +8 -0
- package/dist/views/system/ai-model/components/ProviderForm.vue.js.map +1 -0
- package/dist/views/system/ai-model/components/ProviderForm2.vue.js +507 -0
- package/dist/views/system/ai-model/components/ProviderForm2.vue.js.map +1 -0
- package/dist/views/system/ai-model/index.vue.d.ts +3 -0
- package/dist/views/system/ai-model/index.vue.js +8 -0
- package/dist/views/system/ai-model/index.vue.js.map +1 -0
- package/dist/views/system/ai-model/index2.vue.js +134 -0
- package/dist/views/system/ai-model/index2.vue.js.map +1 -0
- package/dist/views/system/ai-model/presets.d.ts +14 -0
- package/dist/views/system/ai-model/presets.js +22 -0
- package/dist/views/system/ai-model/presets.js.map +1 -0
- package/dist/views/system/ai-usage/index.vue.d.ts +3 -0
- package/dist/views/system/ai-usage/index.vue.js +8 -0
- package/dist/views/system/ai-usage/index.vue.js.map +1 -0
- package/dist/views/system/ai-usage/index2.vue.js +423 -0
- package/dist/views/system/ai-usage/index2.vue.js.map +1 -0
- package/package.json +6 -2
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { defineComponent as E, ref as d, onMounted as D, resolveDirective as P, openBlock as l, createElementBlock as g, createElementVNode as h, createVNode as o, unref as e, withCtx as r, withKeys as S, withDirectives as b, createBlock as p, createTextVNode as C, toDisplayString as z, Fragment as B, renderList as M } from "vue";
|
|
2
|
+
import { useMessage as V, NButton as w, NInput as A, NSpin as F, NEmpty as G, NGrid as I, NGi as K } from "naive-ui";
|
|
3
|
+
import { watchDebounced as T } from "@vueuse/core";
|
|
4
|
+
import { useI18n as U } from "vue-i18n";
|
|
5
|
+
import y from "../../../components/AppIcon.vue.js";
|
|
6
|
+
import { aiProviderApi as $ } from "../../../api/index.js";
|
|
7
|
+
import { translateError as q } from "../../../utils/error.js";
|
|
8
|
+
import L from "./components/ProviderCard.vue.js";
|
|
9
|
+
import O from "./components/ProviderForm.vue.js";
|
|
10
|
+
const j = { class: "view" }, H = { class: "toolbar" }, ie = /* @__PURE__ */ E({
|
|
11
|
+
__name: "index",
|
|
12
|
+
setup(J) {
|
|
13
|
+
const { t: v } = U(), _ = V(), s = d(!1), u = d(""), m = d([]);
|
|
14
|
+
async function i() {
|
|
15
|
+
s.value = !0;
|
|
16
|
+
try {
|
|
17
|
+
const { items: a } = await $.page({
|
|
18
|
+
page: 1,
|
|
19
|
+
pageSize: 100,
|
|
20
|
+
keyword: u.value.trim() || void 0
|
|
21
|
+
});
|
|
22
|
+
m.value = a;
|
|
23
|
+
} catch (a) {
|
|
24
|
+
_.error(q(a));
|
|
25
|
+
} finally {
|
|
26
|
+
s.value = !1;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
D(i), T(u, i, { debounce: 400 });
|
|
30
|
+
const c = d(!1), f = d(null);
|
|
31
|
+
function k() {
|
|
32
|
+
f.value = null, c.value = !0;
|
|
33
|
+
}
|
|
34
|
+
function N(a) {
|
|
35
|
+
f.value = a, c.value = !0;
|
|
36
|
+
}
|
|
37
|
+
return (a, n) => {
|
|
38
|
+
const x = P("auth");
|
|
39
|
+
return l(), g("div", j, [
|
|
40
|
+
h("div", H, [
|
|
41
|
+
o(e(w), {
|
|
42
|
+
quaternary: "",
|
|
43
|
+
loading: s.value,
|
|
44
|
+
onClick: i
|
|
45
|
+
}, {
|
|
46
|
+
icon: r(() => [
|
|
47
|
+
o(y, {
|
|
48
|
+
icon: "ph:arrow-clockwise",
|
|
49
|
+
size: 16
|
|
50
|
+
})
|
|
51
|
+
]),
|
|
52
|
+
_: 1
|
|
53
|
+
}, 8, ["loading"]),
|
|
54
|
+
o(e(A), {
|
|
55
|
+
value: u.value,
|
|
56
|
+
"onUpdate:value": n[0] || (n[0] = (t) => u.value = t),
|
|
57
|
+
clearable: "",
|
|
58
|
+
style: { width: "240px" },
|
|
59
|
+
placeholder: e(v)("aiModel.searchPlaceholder"),
|
|
60
|
+
onKeyup: S(i, ["enter"])
|
|
61
|
+
}, {
|
|
62
|
+
prefix: r(() => [
|
|
63
|
+
o(y, {
|
|
64
|
+
icon: "ph:magnifying-glass",
|
|
65
|
+
size: 14
|
|
66
|
+
})
|
|
67
|
+
]),
|
|
68
|
+
_: 1
|
|
69
|
+
}, 8, ["value", "placeholder"]),
|
|
70
|
+
n[2] || (n[2] = h("div", { class: "toolbar-spacer" }, null, -1)),
|
|
71
|
+
b((l(), p(e(w), {
|
|
72
|
+
type: "primary",
|
|
73
|
+
onClick: k
|
|
74
|
+
}, {
|
|
75
|
+
icon: r(() => [
|
|
76
|
+
o(y, {
|
|
77
|
+
icon: "ph:plus",
|
|
78
|
+
size: 16
|
|
79
|
+
})
|
|
80
|
+
]),
|
|
81
|
+
default: r(() => [
|
|
82
|
+
C(" " + z(e(v)("aiModel.addProvider")), 1)
|
|
83
|
+
]),
|
|
84
|
+
_: 1
|
|
85
|
+
})), [
|
|
86
|
+
[x, "POST:/api/v1/sys/ai/provider/add"]
|
|
87
|
+
])
|
|
88
|
+
]),
|
|
89
|
+
o(e(F), { show: s.value }, {
|
|
90
|
+
default: r(() => [
|
|
91
|
+
!s.value && m.value.length === 0 ? (l(), p(e(G), {
|
|
92
|
+
key: 0,
|
|
93
|
+
description: e(v)("common.noData"),
|
|
94
|
+
class: "empty"
|
|
95
|
+
}, null, 8, ["description"])) : (l(), p(e(I), {
|
|
96
|
+
key: 1,
|
|
97
|
+
cols: "1 s:2 l:3",
|
|
98
|
+
responsive: "screen",
|
|
99
|
+
"x-gap": 16,
|
|
100
|
+
"y-gap": 16
|
|
101
|
+
}, {
|
|
102
|
+
default: r(() => [
|
|
103
|
+
(l(!0), g(B, null, M(m.value, (t) => (l(), p(e(K), {
|
|
104
|
+
key: t.id
|
|
105
|
+
}, {
|
|
106
|
+
default: r(() => [
|
|
107
|
+
o(L, {
|
|
108
|
+
provider: t,
|
|
109
|
+
onEdit: (Q) => N(t),
|
|
110
|
+
onDeleted: i
|
|
111
|
+
}, null, 8, ["provider", "onEdit"])
|
|
112
|
+
]),
|
|
113
|
+
_: 2
|
|
114
|
+
}, 1024))), 128))
|
|
115
|
+
]),
|
|
116
|
+
_: 1
|
|
117
|
+
}))
|
|
118
|
+
]),
|
|
119
|
+
_: 1
|
|
120
|
+
}, 8, ["show"]),
|
|
121
|
+
o(O, {
|
|
122
|
+
show: c.value,
|
|
123
|
+
"onUpdate:show": n[1] || (n[1] = (t) => c.value = t),
|
|
124
|
+
editing: f.value,
|
|
125
|
+
onSaved: i
|
|
126
|
+
}, null, 8, ["show", "editing"])
|
|
127
|
+
]);
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
export {
|
|
132
|
+
ie as default
|
|
133
|
+
};
|
|
134
|
+
//# sourceMappingURL=index2.vue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index2.vue.js","sources":["../../../../src/views/system/ai-model/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// AI 模型管理:厂商是卡片网格,不是 SmartTable —— 厂商数量级很小(十几个封顶),卡片能把\n// 徽标/协议/Base URL/模型数/启停/测试连接一次性摆开,比表格行更直观。\n// 列表本身一次拉大页(pageSize 100)铺成网格,不做真分页;关键字过滤(厂商 code/name)交给\n// 后端 keyword 参数,输入防抖 400ms 后自动重拉,回车立即拉一次。\n// 交互都收进 ProviderCard(启停/编辑入口/删除/测试连接)与 ProviderForm(新增/编辑抽屉),\n// 本页只管拉列表、开表单、增删改后 reload。\nimport { onMounted, ref } from 'vue'\nimport { NButton, NEmpty, NGi, NGrid, NInput, NSpin, useMessage } from 'naive-ui'\nimport { watchDebounced } from '@vueuse/core'\nimport { useI18n } from 'vue-i18n'\nimport AppIcon from '#/components/AppIcon.vue'\nimport { aiProviderApi } from '#/api'\nimport { translateError } from '#/utils/error'\nimport type { AiProviderView } from '#/types/api'\nimport ProviderCard from './components/ProviderCard.vue'\nimport ProviderForm from './components/ProviderForm.vue'\n\nconst { t } = useI18n()\nconst message = useMessage()\n\nconst loading = ref(false)\nconst keyword = ref('')\nconst providers = ref<AiProviderView[]>([])\n\nasync function load() {\n loading.value = true\n try {\n const { items } = await aiProviderApi.page({\n page: 1,\n pageSize: 100,\n keyword: keyword.value.trim() || undefined,\n })\n providers.value = items\n } catch (e) {\n message.error(translateError(e))\n } finally {\n loading.value = false\n }\n}\nonMounted(load)\n// 关键字防抖重拉;回车走 @keyup.enter 立即触发,两者共用同一个 load()。\nwatchDebounced(keyword, load, { debounce: 400 })\n\n// 新增/编辑抽屉:show/editing 走 v-model + prop,与 config 页 ConfigFormModal 同一协议\n// (defineModel('show') + `editing: AiProviderView | null`,null = 新增)。\nconst formShow = ref(false)\nconst editing = ref<AiProviderView | null>(null)\nfunction openAdd() {\n editing.value = null\n formShow.value = true\n}\nfunction openEdit(p: AiProviderView) {\n editing.value = p\n formShow.value = true\n}\n</script>\n\n<template>\n <div class=\"view\">\n <div class=\"toolbar\">\n <n-button quaternary :loading=\"loading\" @click=\"load\">\n <template #icon><AppIcon icon=\"ph:arrow-clockwise\" :size=\"16\" /></template>\n </n-button>\n <n-input\n v-model:value=\"keyword\"\n clearable\n style=\"width: 240px\"\n :placeholder=\"t('aiModel.searchPlaceholder')\"\n @keyup.enter=\"load\"\n >\n <template #prefix><AppIcon icon=\"ph:magnifying-glass\" :size=\"14\" /></template>\n </n-input>\n <div class=\"toolbar-spacer\" />\n <n-button v-auth=\"'POST:/api/v1/sys/ai/provider/add'\" type=\"primary\" @click=\"openAdd\">\n <template #icon><AppIcon icon=\"ph:plus\" :size=\"16\" /></template>\n {{ t('aiModel.addProvider') }}\n </n-button>\n </div>\n\n <n-spin :show=\"loading\">\n <n-empty\n v-if=\"!loading && providers.length === 0\"\n :description=\"t('common.noData')\"\n class=\"empty\"\n />\n <n-grid v-else :cols=\"'1 s:2 l:3'\" responsive=\"screen\" :x-gap=\"16\" :y-gap=\"16\">\n <n-gi v-for=\"p in providers\" :key=\"p.id\">\n <ProviderCard :provider=\"p\" @edit=\"openEdit(p)\" @deleted=\"load\" />\n </n-gi>\n </n-grid>\n </n-spin>\n\n <ProviderForm v-model:show=\"formShow\" :editing=\"editing\" @saved=\"load\" />\n </div>\n</template>\n\n<style scoped>\n.view {\n display: flex;\n flex-direction: column;\n gap: var(--gap-card, 16px);\n}\n.toolbar {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-wrap: wrap;\n}\n.toolbar-spacer {\n flex: 1;\n}\n.empty {\n padding: 64px 0;\n}\n</style>\n"],"names":["t","useI18n","message","useMessage","loading","ref","keyword","providers","load","items","aiProviderApi","e","translateError","onMounted","watchDebounced","formShow","editing","openAdd","openEdit","p","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_createVNode","_unref","NButton","AppIcon","NInput","$event","_createBlock","_createTextVNode","NSpin","NEmpty","NGrid","_Fragment","_renderList","NGi","ProviderCard","ProviderForm"],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface AiProviderPresetMeta {
|
|
2
|
+
/** 卡片角标用的极短缩写(拉丁字母,2 个字符左右,深色徽标上的文字) */
|
|
3
|
+
abbr: string;
|
|
4
|
+
/** Iconify 图标名(ph:*,已随内核种子图标一并登记进 ph-subset.json) */
|
|
5
|
+
icon: string;
|
|
6
|
+
/** 强调色(卡片描边 / 图标底色),16 进制 */
|
|
7
|
+
color: string;
|
|
8
|
+
}
|
|
9
|
+
/** 厂商预设 code → 展示元数据。key 必须与后端 AiProviderPresets.cs 的 code 一致。 */
|
|
10
|
+
export declare const AI_PROVIDER_PRESET_META: Readonly<Record<string, AiProviderPresetMeta>>;
|
|
11
|
+
/** 未登记 code 的兜底视觉(等同 custom)。 */
|
|
12
|
+
export declare const FALLBACK_PRESET_META: AiProviderPresetMeta;
|
|
13
|
+
/** 按 code 取展示元数据;查无此 code(新预设未同步维护)时兜底成 custom,不抛错。 */
|
|
14
|
+
export declare function resolvePresetMeta(code: string | null | undefined): AiProviderPresetMeta;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const e = {
|
|
2
|
+
openai: { abbr: "AI", icon: "ph:asterisk-duotone", color: "#10A37F" },
|
|
3
|
+
"azure-openai": { abbr: "Az", icon: "ph:cloud-duotone", color: "#0078D4" },
|
|
4
|
+
anthropic: { abbr: "An", icon: "ph:mountains-duotone", color: "#CC785C" },
|
|
5
|
+
deepseek: { abbr: "DS", icon: "ph:compass-duotone", color: "#4D6BFE" },
|
|
6
|
+
qwen: { abbr: "Qw", icon: "ph:wind-duotone", color: "#615CED" },
|
|
7
|
+
zhipu: { abbr: "Zh", icon: "ph:diamond-duotone", color: "#3A5CE6" },
|
|
8
|
+
moonshot: { abbr: "Ms", icon: "ph:moon-stars-duotone", color: "#16171A" },
|
|
9
|
+
doubao: { abbr: "Db", icon: "ph:planet-duotone", color: "#F2A93B" },
|
|
10
|
+
gemini: { abbr: "Ge", icon: "ph:globe-duotone", color: "#4285F4" },
|
|
11
|
+
ollama: { abbr: "Ol", icon: "ph:terminal-window-duotone", color: "#4B5563" },
|
|
12
|
+
custom: { abbr: "Cu", icon: "ph:puzzle-piece-duotone", color: "#8A8F98" }
|
|
13
|
+
}, n = e.custom;
|
|
14
|
+
function r(o) {
|
|
15
|
+
return o ? e[o] ?? n : n;
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
e as AI_PROVIDER_PRESET_META,
|
|
19
|
+
n as FALLBACK_PRESET_META,
|
|
20
|
+
r as resolvePresetMeta
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=presets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presets.js","sources":["../../../../src/views/system/ai-model/presets.ts"],"sourcesContent":["// AI 厂商预设的展示元数据:纯静态表,不发请求、不依赖后端。\n// 后端 AiProviderPresets.cs 落定了 11 个预置 code(见 GET /api/v1/sys/ai/provider/presets 的 AiProviderPreset.code);\n// 这里只补一份「按 code 取卡片缩写/图标/强调色」的视觉层,厂商预设下拉与厂商卡片(ProviderCard.vue/ProviderForm.vue)据此渲染,\n// 厂商的展示名/协议/Base URL 等业务字段仍以后端返回的 AiProviderPreset 为准,不在这里重复。\n// 新增预设 code 时后端与这里要同步维护;未登记的 code 统一兜底成 custom 的视觉,不会渲染不出来。\n\nexport interface AiProviderPresetMeta {\n /** 卡片角标用的极短缩写(拉丁字母,2 个字符左右,深色徽标上的文字) */\n abbr: string\n /** Iconify 图标名(ph:*,已随内核种子图标一并登记进 ph-subset.json) */\n icon: string\n /** 强调色(卡片描边 / 图标底色),16 进制 */\n color: string\n}\n\n/** 厂商预设 code → 展示元数据。key 必须与后端 AiProviderPresets.cs 的 code 一致。 */\nexport const AI_PROVIDER_PRESET_META: Readonly<Record<string, AiProviderPresetMeta>> = {\n openai: { abbr: 'AI', icon: 'ph:asterisk-duotone', color: '#10A37F' },\n 'azure-openai': { abbr: 'Az', icon: 'ph:cloud-duotone', color: '#0078D4' },\n anthropic: { abbr: 'An', icon: 'ph:mountains-duotone', color: '#CC785C' },\n deepseek: { abbr: 'DS', icon: 'ph:compass-duotone', color: '#4D6BFE' },\n qwen: { abbr: 'Qw', icon: 'ph:wind-duotone', color: '#615CED' },\n zhipu: { abbr: 'Zh', icon: 'ph:diamond-duotone', color: '#3A5CE6' },\n moonshot: { abbr: 'Ms', icon: 'ph:moon-stars-duotone', color: '#16171A' },\n doubao: { abbr: 'Db', icon: 'ph:planet-duotone', color: '#F2A93B' },\n gemini: { abbr: 'Ge', icon: 'ph:globe-duotone', color: '#4285F4' },\n ollama: { abbr: 'Ol', icon: 'ph:terminal-window-duotone', color: '#4B5563' },\n custom: { abbr: 'Cu', icon: 'ph:puzzle-piece-duotone', color: '#8A8F98' },\n}\n\n/** 未登记 code 的兜底视觉(等同 custom)。 */\nexport const FALLBACK_PRESET_META: AiProviderPresetMeta = AI_PROVIDER_PRESET_META.custom!\n\n/** 按 code 取展示元数据;查无此 code(新预设未同步维护)时兜底成 custom,不抛错。 */\nexport function resolvePresetMeta(code: string | null | undefined): AiProviderPresetMeta {\n if (!code) return FALLBACK_PRESET_META\n return AI_PROVIDER_PRESET_META[code] ?? FALLBACK_PRESET_META\n}\n"],"names":["AI_PROVIDER_PRESET_META","FALLBACK_PRESET_META","resolvePresetMeta","code"],"mappings":"AAgBO,MAAMA,IAA0E;AAAA,EACrF,QAAQ,EAAE,MAAM,MAAM,MAAM,uBAAuB,OAAO,UAAA;AAAA,EAC1D,gBAAgB,EAAE,MAAM,MAAM,MAAM,oBAAoB,OAAO,UAAA;AAAA,EAC/D,WAAW,EAAE,MAAM,MAAM,MAAM,wBAAwB,OAAO,UAAA;AAAA,EAC9D,UAAU,EAAE,MAAM,MAAM,MAAM,sBAAsB,OAAO,UAAA;AAAA,EAC3D,MAAM,EAAE,MAAM,MAAM,MAAM,mBAAmB,OAAO,UAAA;AAAA,EACpD,OAAO,EAAE,MAAM,MAAM,MAAM,sBAAsB,OAAO,UAAA;AAAA,EACxD,UAAU,EAAE,MAAM,MAAM,MAAM,yBAAyB,OAAO,UAAA;AAAA,EAC9D,QAAQ,EAAE,MAAM,MAAM,MAAM,qBAAqB,OAAO,UAAA;AAAA,EACxD,QAAQ,EAAE,MAAM,MAAM,MAAM,oBAAoB,OAAO,UAAA;AAAA,EACvD,QAAQ,EAAE,MAAM,MAAM,MAAM,8BAA8B,OAAO,UAAA;AAAA,EACjE,QAAQ,EAAE,MAAM,MAAM,MAAM,2BAA2B,OAAO,UAAA;AAChE,GAGaC,IAA6CD,EAAwB;AAG3E,SAASE,EAAkBC,GAAuD;AACvF,SAAKA,IACEH,EAAwBG,CAAI,KAAKF,IADtBA;AAEpB;"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.vue.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
|
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
import { defineComponent as oe, ref as n, onMounted as ne, computed as d, watch as Q, h as p, openBlock as i, createElementBlock as m, createVNode as r, unref as l, withCtx as u, createElementVNode as o, toDisplayString as c, createTextVNode as N, Fragment as M, renderList as Y, createBlock as L, createCommentVNode as ie } from "vue";
|
|
2
|
+
import { useMessage as ue, NProgress as de, NCard as $, NDatePicker as ce, NButton as z, NSelect as j, NInput as ve, NGrid as pe, NGi as me, NSkeleton as H, NNumberAnimation as ye, NTabs as ge, NTabPane as fe, NDataTable as ke, NTag as J } from "naive-ui";
|
|
3
|
+
import { useI18n as he } from "vue-i18n";
|
|
4
|
+
import { SmartTable as be } from "smart-naive-table";
|
|
5
|
+
import Ue from "../../../components/Chart/LineChart.vue.js";
|
|
6
|
+
import { aiProviderApi as _e, aiUsageApi as B } from "../../../api/index.js";
|
|
7
|
+
import { AI_USAGE_GROUP_BY as b, AI_USAGE_SOURCE as Te } from "../../../types/api.js";
|
|
8
|
+
import { translateError as E } from "../../../utils/error.js";
|
|
9
|
+
import { fmtDateTime as we } from "../../../utils/format.js";
|
|
10
|
+
const Se = { class: "view" }, Ce = { class: "filter-bar" }, xe = { class: "filter-item" }, Ne = { class: "filter-label" }, Me = { class: "date-filter-row" }, Le = { class: "quick-range" }, $e = { class: "filter-item" }, De = { class: "filter-label" }, Pe = { class: "filter-item" }, Re = { class: "filter-label" }, Ae = { class: "filter-item" }, Ie = { class: "filter-label" }, qe = { class: "metric-body" }, ze = {
|
|
11
|
+
key: 1,
|
|
12
|
+
class: "metric-val tabular"
|
|
13
|
+
}, Be = {
|
|
14
|
+
key: 0,
|
|
15
|
+
class: "metric-suffix"
|
|
16
|
+
}, Ee = { class: "metric-label" }, We = /* @__PURE__ */ oe({
|
|
17
|
+
__name: "index",
|
|
18
|
+
setup(Ge) {
|
|
19
|
+
const { t } = he(), D = ue();
|
|
20
|
+
function G(e) {
|
|
21
|
+
const a = e.getFullYear(), s = String(e.getMonth() + 1).padStart(2, "0"), v = String(e.getDate()).padStart(2, "0");
|
|
22
|
+
return `${a}-${s}-${v}`;
|
|
23
|
+
}
|
|
24
|
+
function K(e) {
|
|
25
|
+
const a = /* @__PURE__ */ new Date();
|
|
26
|
+
return a.setDate(a.getDate() - e), a;
|
|
27
|
+
}
|
|
28
|
+
function V(e) {
|
|
29
|
+
return [G(K(e - 1)), G(K(0))];
|
|
30
|
+
}
|
|
31
|
+
const g = n(V(7)), f = n(7);
|
|
32
|
+
function P(e) {
|
|
33
|
+
g.value = V(e), f.value = e;
|
|
34
|
+
}
|
|
35
|
+
function W(e) {
|
|
36
|
+
e && (g.value = e, f.value = null);
|
|
37
|
+
}
|
|
38
|
+
const U = n(null), _ = n(null), T = n(null), F = n([]);
|
|
39
|
+
ne(async () => {
|
|
40
|
+
try {
|
|
41
|
+
const { items: e } = await _e.page({ page: 1, pageSize: 100 });
|
|
42
|
+
F.value = e.map((a) => ({ label: a.name, value: a.code }));
|
|
43
|
+
} catch {
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
const k = d(() => {
|
|
47
|
+
const e = {
|
|
48
|
+
from: `${g.value[0]}T00:00:00`,
|
|
49
|
+
to: `${g.value[1]}T23:59:59`
|
|
50
|
+
};
|
|
51
|
+
return U.value && (e.providerCode = U.value), _.value && (e.model = _.value), T.value && (e.scene = T.value), e;
|
|
52
|
+
}), O = [
|
|
53
|
+
{ value: b.Provider, labelKey: "provider" },
|
|
54
|
+
{ value: b.Model, labelKey: "model" },
|
|
55
|
+
{ value: b.Scene, labelKey: "scene" },
|
|
56
|
+
{ value: b.User, labelKey: "user" }
|
|
57
|
+
], h = n(b.Provider), R = n(null), w = n(!0);
|
|
58
|
+
let S = 0;
|
|
59
|
+
async function X() {
|
|
60
|
+
const e = ++S;
|
|
61
|
+
w.value = !0;
|
|
62
|
+
try {
|
|
63
|
+
const a = await B.summary({ ...k.value, groupBy: h.value });
|
|
64
|
+
if (e !== S) return;
|
|
65
|
+
R.value = a;
|
|
66
|
+
} catch (a) {
|
|
67
|
+
if (e !== S) return;
|
|
68
|
+
D.error(E(a));
|
|
69
|
+
} finally {
|
|
70
|
+
e === S && (w.value = !1);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
Q([k, h], X, { immediate: !0 });
|
|
74
|
+
const y = d(() => {
|
|
75
|
+
var e;
|
|
76
|
+
return ((e = R.value) == null ? void 0 : e.totals) ?? null;
|
|
77
|
+
}), A = d(() => {
|
|
78
|
+
var e;
|
|
79
|
+
return ((e = R.value) == null ? void 0 : e.groups) ?? [];
|
|
80
|
+
}), I = d(() => {
|
|
81
|
+
const e = A.value.reduce((s, v) => s + v.callCount, 0);
|
|
82
|
+
return e ? A.value.reduce((s, v) => s + v.avgLatencyMs * v.callCount, 0) / e : null;
|
|
83
|
+
}), Z = d(() => {
|
|
84
|
+
var e, a, s;
|
|
85
|
+
return [
|
|
86
|
+
{ key: "totalTokens", value: ((e = y.value) == null ? void 0 : e.totalTokens) ?? 0, empty: !y.value },
|
|
87
|
+
{ key: "totalCalls", value: ((a = y.value) == null ? void 0 : a.callCount) ?? 0, empty: !y.value },
|
|
88
|
+
{ key: "failureCount", value: ((s = y.value) == null ? void 0 : s.failureCount) ?? 0, empty: !y.value },
|
|
89
|
+
{
|
|
90
|
+
key: "avgLatency",
|
|
91
|
+
value: I.value != null ? Math.round(I.value) : 0,
|
|
92
|
+
suffix: "ms",
|
|
93
|
+
empty: I.value == null
|
|
94
|
+
}
|
|
95
|
+
];
|
|
96
|
+
}), ee = d(() => {
|
|
97
|
+
const e = O.find((a) => a.value === h.value);
|
|
98
|
+
return t(`aiUsage.groupBy.${(e == null ? void 0 : e.labelKey) ?? "provider"}`);
|
|
99
|
+
}), te = d(() => [
|
|
100
|
+
{ title: () => ee.value, key: "label", render: (e) => e.label ?? e.key },
|
|
101
|
+
{
|
|
102
|
+
title: () => t("aiUsage.trend.inputTokens"),
|
|
103
|
+
key: "inputTokens",
|
|
104
|
+
render: (e) => e.inputTokens.toLocaleString()
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
title: () => t("aiUsage.trend.outputTokens"),
|
|
108
|
+
key: "outputTokens",
|
|
109
|
+
render: (e) => e.outputTokens.toLocaleString()
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
title: () => t("aiUsage.metric.totalCalls"),
|
|
113
|
+
key: "callCount",
|
|
114
|
+
render: (e) => e.callCount.toLocaleString()
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
title: () => t("aiUsage.table.latency"),
|
|
118
|
+
key: "avgLatencyMs",
|
|
119
|
+
render: (e) => `${Math.round(e.avgLatencyMs)} ms`
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
title: () => t("aiUsage.share"),
|
|
123
|
+
key: "sharePercent",
|
|
124
|
+
render: (e) => p("div", { class: "share-cell" }, [
|
|
125
|
+
p("div", { class: "share-bar" }, [
|
|
126
|
+
p(de, {
|
|
127
|
+
type: "line",
|
|
128
|
+
percentage: Math.round(e.sharePercent),
|
|
129
|
+
showIndicator: !1,
|
|
130
|
+
height: 6
|
|
131
|
+
})
|
|
132
|
+
]),
|
|
133
|
+
p("span", { class: "share-text" }, `${e.sharePercent.toFixed(1)}%`)
|
|
134
|
+
])
|
|
135
|
+
}
|
|
136
|
+
]), C = n([]), q = n(!0);
|
|
137
|
+
let x = 0;
|
|
138
|
+
async function ae() {
|
|
139
|
+
const e = ++x;
|
|
140
|
+
q.value = !0;
|
|
141
|
+
try {
|
|
142
|
+
const a = await B.trend(k.value);
|
|
143
|
+
if (e !== x) return;
|
|
144
|
+
C.value = a;
|
|
145
|
+
} catch (a) {
|
|
146
|
+
if (e !== x) return;
|
|
147
|
+
D.error(E(a));
|
|
148
|
+
} finally {
|
|
149
|
+
e === x && (q.value = !1);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
Q(k, ae, { immediate: !0 });
|
|
153
|
+
const le = d(() => C.value.map((e) => e.date)), se = d(() => [
|
|
154
|
+
{ name: t("aiUsage.trend.inputTokens"), data: C.value.map((e) => e.inputTokens) },
|
|
155
|
+
{ name: t("aiUsage.trend.outputTokens"), data: C.value.map((e) => e.outputTokens) }
|
|
156
|
+
]), re = [
|
|
157
|
+
{
|
|
158
|
+
key: "createTime",
|
|
159
|
+
title: () => t("aiUsage.table.createTime"),
|
|
160
|
+
width: 170,
|
|
161
|
+
render: (e) => we(e.createTime)
|
|
162
|
+
},
|
|
163
|
+
{ key: "providerCode", title: () => t("aiUsage.table.provider"), width: 120 },
|
|
164
|
+
{ key: "model", title: () => t("aiUsage.table.model"), width: 140, ellipsis: { tooltip: !0 } },
|
|
165
|
+
{ key: "scene", title: () => t("aiUsage.table.scene"), width: 120, render: (e) => e.scene || "—" },
|
|
166
|
+
{
|
|
167
|
+
key: "userId",
|
|
168
|
+
title: () => t("aiUsage.table.user"),
|
|
169
|
+
width: 90,
|
|
170
|
+
render: (e) => e.userId != null ? String(e.userId) : "—"
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
key: "inputTokens",
|
|
174
|
+
title: () => t("aiUsage.table.inputTokens"),
|
|
175
|
+
width: 110,
|
|
176
|
+
render: (e) => e.inputTokens.toLocaleString()
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
key: "outputTokens",
|
|
180
|
+
title: () => t("aiUsage.table.outputTokens"),
|
|
181
|
+
width: 110,
|
|
182
|
+
render: (e) => e.outputTokens.toLocaleString()
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
key: "totalTokens",
|
|
186
|
+
title: () => t("aiUsage.table.totalTokens"),
|
|
187
|
+
width: 110,
|
|
188
|
+
render: (e) => e.totalTokens.toLocaleString()
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
key: "latencyMs",
|
|
192
|
+
title: () => t("aiUsage.table.latency"),
|
|
193
|
+
width: 90,
|
|
194
|
+
render: (e) => `${e.latencyMs} ms`
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
key: "success",
|
|
198
|
+
title: () => t("aiUsage.table.status"),
|
|
199
|
+
width: 90,
|
|
200
|
+
// 失败行用原生 title 兜底展示 errorMessage,不必为一个只读明细表再引入 NTooltip
|
|
201
|
+
render: (e) => p("span", { title: !e.success && e.errorMessage ? e.errorMessage : void 0 }, [
|
|
202
|
+
p(
|
|
203
|
+
J,
|
|
204
|
+
{ size: "small", bordered: !1, type: e.success ? "success" : "error" },
|
|
205
|
+
() => e.success ? t("aiUsage.table.success") : t("aiUsage.table.failed")
|
|
206
|
+
)
|
|
207
|
+
])
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
key: "streamed",
|
|
211
|
+
title: () => t("aiUsage.table.streamed"),
|
|
212
|
+
width: 80,
|
|
213
|
+
render: (e) => p(
|
|
214
|
+
J,
|
|
215
|
+
{ size: "small", bordered: !1 },
|
|
216
|
+
() => e.streamed ? t("common.yes") : t("common.no")
|
|
217
|
+
)
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
key: "usageSource",
|
|
221
|
+
title: () => t("aiUsage.table.usageSource"),
|
|
222
|
+
width: 110,
|
|
223
|
+
render: (e) => e.usageSource === Te.Reported ? t("aiUsage.table.usageSourceReported") : t("aiUsage.table.usageSourceMissing")
|
|
224
|
+
}
|
|
225
|
+
];
|
|
226
|
+
return (e, a) => (i(), m("div", Se, [
|
|
227
|
+
r(l($), { bordered: !0 }, {
|
|
228
|
+
default: u(() => [
|
|
229
|
+
o("div", Ce, [
|
|
230
|
+
o("div", xe, [
|
|
231
|
+
o("span", Ne, c(l(t)("aiUsage.filter.dateRange")), 1),
|
|
232
|
+
o("div", Me, [
|
|
233
|
+
r(l(ce), {
|
|
234
|
+
"formatted-value": g.value,
|
|
235
|
+
type: "daterange",
|
|
236
|
+
"value-format": "yyyy-MM-dd",
|
|
237
|
+
style: { width: "240px" },
|
|
238
|
+
"onUpdate:formattedValue": W
|
|
239
|
+
}, null, 8, ["formatted-value"]),
|
|
240
|
+
o("div", Le, [
|
|
241
|
+
r(l(z), {
|
|
242
|
+
size: "small",
|
|
243
|
+
quaternary: "",
|
|
244
|
+
type: f.value === 1 ? "primary" : "default",
|
|
245
|
+
onClick: a[0] || (a[0] = (s) => P(1))
|
|
246
|
+
}, {
|
|
247
|
+
default: u(() => [
|
|
248
|
+
N(c(l(t)("aiUsage.filter.today")), 1)
|
|
249
|
+
]),
|
|
250
|
+
_: 1
|
|
251
|
+
}, 8, ["type"]),
|
|
252
|
+
r(l(z), {
|
|
253
|
+
size: "small",
|
|
254
|
+
quaternary: "",
|
|
255
|
+
type: f.value === 7 ? "primary" : "default",
|
|
256
|
+
onClick: a[1] || (a[1] = (s) => P(7))
|
|
257
|
+
}, {
|
|
258
|
+
default: u(() => [
|
|
259
|
+
N(c(l(t)("aiUsage.filter.last7Days")), 1)
|
|
260
|
+
]),
|
|
261
|
+
_: 1
|
|
262
|
+
}, 8, ["type"]),
|
|
263
|
+
r(l(z), {
|
|
264
|
+
size: "small",
|
|
265
|
+
quaternary: "",
|
|
266
|
+
type: f.value === 30 ? "primary" : "default",
|
|
267
|
+
onClick: a[2] || (a[2] = (s) => P(30))
|
|
268
|
+
}, {
|
|
269
|
+
default: u(() => [
|
|
270
|
+
N(c(l(t)("aiUsage.filter.last30Days")), 1)
|
|
271
|
+
]),
|
|
272
|
+
_: 1
|
|
273
|
+
}, 8, ["type"])
|
|
274
|
+
])
|
|
275
|
+
])
|
|
276
|
+
]),
|
|
277
|
+
o("div", $e, [
|
|
278
|
+
o("span", De, c(l(t)("aiUsage.filter.provider")), 1),
|
|
279
|
+
r(l(j), {
|
|
280
|
+
value: U.value,
|
|
281
|
+
"onUpdate:value": a[3] || (a[3] = (s) => U.value = s),
|
|
282
|
+
options: F.value,
|
|
283
|
+
clearable: "",
|
|
284
|
+
filterable: "",
|
|
285
|
+
style: { width: "180px" },
|
|
286
|
+
placeholder: l(t)("aiUsage.filter.providerAll")
|
|
287
|
+
}, null, 8, ["value", "options", "placeholder"])
|
|
288
|
+
]),
|
|
289
|
+
o("div", Pe, [
|
|
290
|
+
o("span", Re, c(l(t)("aiUsage.filter.model")), 1),
|
|
291
|
+
r(l(j), {
|
|
292
|
+
value: _.value,
|
|
293
|
+
"onUpdate:value": a[4] || (a[4] = (s) => _.value = s),
|
|
294
|
+
options: [],
|
|
295
|
+
filterable: "",
|
|
296
|
+
tag: "",
|
|
297
|
+
clearable: "",
|
|
298
|
+
style: { width: "180px" },
|
|
299
|
+
placeholder: l(t)("aiUsage.filter.modelAll")
|
|
300
|
+
}, null, 8, ["value", "placeholder"])
|
|
301
|
+
]),
|
|
302
|
+
o("div", Ae, [
|
|
303
|
+
o("span", Ie, c(l(t)("aiUsage.filter.scene")), 1),
|
|
304
|
+
r(l(ve), {
|
|
305
|
+
value: T.value,
|
|
306
|
+
"onUpdate:value": a[5] || (a[5] = (s) => T.value = s),
|
|
307
|
+
clearable: "",
|
|
308
|
+
style: { width: "180px" },
|
|
309
|
+
placeholder: l(t)("aiUsage.filter.scenePlaceholder")
|
|
310
|
+
}, null, 8, ["value", "placeholder"])
|
|
311
|
+
])
|
|
312
|
+
])
|
|
313
|
+
]),
|
|
314
|
+
_: 1
|
|
315
|
+
}),
|
|
316
|
+
r(l(pe), {
|
|
317
|
+
cols: "1 s:2 l:4",
|
|
318
|
+
responsive: "screen",
|
|
319
|
+
"x-gap": 16,
|
|
320
|
+
"y-gap": 16
|
|
321
|
+
}, {
|
|
322
|
+
default: u(() => [
|
|
323
|
+
(i(!0), m(M, null, Y(Z.value, (s) => (i(), L(l(me), {
|
|
324
|
+
key: s.key
|
|
325
|
+
}, {
|
|
326
|
+
default: u(() => [
|
|
327
|
+
r(l($), { bordered: !0 }, {
|
|
328
|
+
default: u(() => [
|
|
329
|
+
o("div", qe, [
|
|
330
|
+
w.value ? (i(), L(l(H), {
|
|
331
|
+
key: 0,
|
|
332
|
+
text: "",
|
|
333
|
+
width: "72px",
|
|
334
|
+
height: "34px"
|
|
335
|
+
})) : (i(), m("div", ze, [
|
|
336
|
+
s.empty ? (i(), m(M, { key: 0 }, [
|
|
337
|
+
N("—")
|
|
338
|
+
], 64)) : (i(), m(M, { key: 1 }, [
|
|
339
|
+
r(l(ye), {
|
|
340
|
+
from: 0,
|
|
341
|
+
to: s.value,
|
|
342
|
+
"show-separator": ""
|
|
343
|
+
}, null, 8, ["to"]),
|
|
344
|
+
s.suffix ? (i(), m("span", Be, c(" " + s.suffix), 1)) : ie("", !0)
|
|
345
|
+
], 64))
|
|
346
|
+
])),
|
|
347
|
+
o("div", Ee, c(l(t)(`aiUsage.metric.${s.key}`)), 1)
|
|
348
|
+
])
|
|
349
|
+
]),
|
|
350
|
+
_: 2
|
|
351
|
+
}, 1024)
|
|
352
|
+
]),
|
|
353
|
+
_: 2
|
|
354
|
+
}, 1024))), 128))
|
|
355
|
+
]),
|
|
356
|
+
_: 1
|
|
357
|
+
}),
|
|
358
|
+
r(l($), { bordered: !0 }, {
|
|
359
|
+
default: u(() => [
|
|
360
|
+
r(l(ge), {
|
|
361
|
+
value: h.value,
|
|
362
|
+
"onUpdate:value": a[6] || (a[6] = (s) => h.value = s),
|
|
363
|
+
type: "line",
|
|
364
|
+
animated: ""
|
|
365
|
+
}, {
|
|
366
|
+
default: u(() => [
|
|
367
|
+
(i(), m(M, null, Y(O, (s) => r(l(fe), {
|
|
368
|
+
key: s.value,
|
|
369
|
+
name: s.value,
|
|
370
|
+
tab: l(t)(`aiUsage.groupBy.${s.labelKey}`),
|
|
371
|
+
"display-directive": "show:lazy"
|
|
372
|
+
}, {
|
|
373
|
+
default: u(() => [
|
|
374
|
+
r(l(ke), {
|
|
375
|
+
columns: te.value,
|
|
376
|
+
data: A.value,
|
|
377
|
+
loading: w.value,
|
|
378
|
+
"row-key": (v) => v.key,
|
|
379
|
+
bordered: !1,
|
|
380
|
+
size: "small"
|
|
381
|
+
}, null, 8, ["columns", "data", "loading", "row-key"])
|
|
382
|
+
]),
|
|
383
|
+
_: 1
|
|
384
|
+
}, 8, ["name", "tab"])), 64))
|
|
385
|
+
]),
|
|
386
|
+
_: 1
|
|
387
|
+
}, 8, ["value"])
|
|
388
|
+
]),
|
|
389
|
+
_: 1
|
|
390
|
+
}),
|
|
391
|
+
r(l($), {
|
|
392
|
+
title: l(t)("aiUsage.trend.title"),
|
|
393
|
+
bordered: !0
|
|
394
|
+
}, {
|
|
395
|
+
default: u(() => [
|
|
396
|
+
q.value ? (i(), L(l(H), {
|
|
397
|
+
key: 0,
|
|
398
|
+
height: "320px",
|
|
399
|
+
sharp: !1
|
|
400
|
+
})) : (i(), L(Ue, {
|
|
401
|
+
key: 1,
|
|
402
|
+
categories: le.value,
|
|
403
|
+
series: se.value
|
|
404
|
+
}, null, 8, ["categories", "series"]))
|
|
405
|
+
]),
|
|
406
|
+
_: 1
|
|
407
|
+
}, 8, ["title"]),
|
|
408
|
+
r(l(be), {
|
|
409
|
+
columns: re,
|
|
410
|
+
fetcher: l(B).page,
|
|
411
|
+
params: k.value,
|
|
412
|
+
search: !1,
|
|
413
|
+
"default-page-size": 20,
|
|
414
|
+
"storage-key": "sys-ai-usage",
|
|
415
|
+
onError: a[7] || (a[7] = (s) => l(D).error(l(E)(s)))
|
|
416
|
+
}, null, 8, ["fetcher", "params"])
|
|
417
|
+
]));
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
export {
|
|
421
|
+
We as default
|
|
422
|
+
};
|
|
423
|
+
//# sourceMappingURL=index2.vue.js.map
|