smart-admin-web 10.10.1 → 10.12.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.
Files changed (43) hide show
  1. package/dist/api/index.d.ts +52 -1
  2. package/dist/api/index.js +151 -84
  3. package/dist/api/index.js.map +1 -1
  4. package/dist/api/schema.d.ts +936 -15
  5. package/dist/assets/icons/ph-subset.json.js +7 -7
  6. package/dist/index.js +278 -274
  7. package/dist/lib/runtime.js +1 -1
  8. package/dist/locales/en-US.d.ts +144 -0
  9. package/dist/locales/en-US.js +146 -0
  10. package/dist/locales/en-US.js.map +1 -1
  11. package/dist/locales/zh-CN.d.ts +144 -0
  12. package/dist/locales/zh-CN.js +146 -0
  13. package/dist/locales/zh-CN.js.map +1 -1
  14. package/dist/router/viewRegistry.js +1 -1
  15. package/dist/router/viewRegistry.js.map +1 -1
  16. package/dist/style.css +1 -1
  17. package/dist/types/api.d.ts +166 -0
  18. package/dist/types/api.js +12 -9
  19. package/dist/types/api.js.map +1 -1
  20. package/dist/views/system/ai-model/components/ProviderCard.vue.d.ts +13 -0
  21. package/dist/views/system/ai-model/components/ProviderCard.vue.js +8 -0
  22. package/dist/views/system/ai-model/components/ProviderCard.vue.js.map +1 -0
  23. package/dist/views/system/ai-model/components/ProviderCard2.vue.js +230 -0
  24. package/dist/views/system/ai-model/components/ProviderCard2.vue.js.map +1 -0
  25. package/dist/views/system/ai-model/components/ProviderForm.vue.d.ts +18 -0
  26. package/dist/views/system/ai-model/components/ProviderForm.vue.js +8 -0
  27. package/dist/views/system/ai-model/components/ProviderForm.vue.js.map +1 -0
  28. package/dist/views/system/ai-model/components/ProviderForm2.vue.js +507 -0
  29. package/dist/views/system/ai-model/components/ProviderForm2.vue.js.map +1 -0
  30. package/dist/views/system/ai-model/index.vue.d.ts +3 -0
  31. package/dist/views/system/ai-model/index.vue.js +8 -0
  32. package/dist/views/system/ai-model/index.vue.js.map +1 -0
  33. package/dist/views/system/ai-model/index2.vue.js +134 -0
  34. package/dist/views/system/ai-model/index2.vue.js.map +1 -0
  35. package/dist/views/system/ai-model/presets.d.ts +14 -0
  36. package/dist/views/system/ai-model/presets.js +22 -0
  37. package/dist/views/system/ai-model/presets.js.map +1 -0
  38. package/dist/views/system/ai-usage/index.vue.d.ts +3 -0
  39. package/dist/views/system/ai-usage/index.vue.js +8 -0
  40. package/dist/views/system/ai-usage/index.vue.js.map +1 -0
  41. package/dist/views/system/ai-usage/index2.vue.js +423 -0
  42. package/dist/views/system/ai-usage/index2.vue.js.map +1 -0
  43. package/package.json +2 -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,8 @@
1
+ import o from "./index2.vue.js";
2
+ /* empty css */
3
+ import t from "../../../_virtual/_plugin-vue_export-helper.js";
4
+ const m = /* @__PURE__ */ t(o, [["__scopeId", "data-v-d81fc5a2"]]);
5
+ export {
6
+ m as default
7
+ };
8
+ //# sourceMappingURL=index.vue.js.map
@@ -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