feat(admin-web): expose AI point balance and usage ledger

Surfaces the new AI point quota in the workspace shell and adds a
Personal Center → AI Point Usage page that shows balance, base-char
rule, and the paginated reservation/refund history. Updates shared
types for the QuotaSummary and ledger payloads.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-28 11:34:07 +08:00
parent e307a048d1
commit bf7594ccd8
7 changed files with 536 additions and 4 deletions
+20 -4
View File
@@ -3,12 +3,12 @@ import {
AppstoreOutlined,
BookOutlined,
GlobalOutlined,
HistoryOutlined,
RadarChartOutlined,
SearchOutlined,
PictureOutlined,
DownOutlined,
LogoutOutlined,
TranslationOutlined,
} from "@ant-design/icons-vue";
import { useQuery } from "@tanstack/vue-query";
import { computed, type Component } from "vue";
@@ -30,6 +30,7 @@ const quotaQuery = useQuery({
});
const userInitial = computed(() => authStore.user?.name?.slice(0, 1).toUpperCase() ?? "A");
const quotaSummary = computed(() => quotaQuery.data.value);
const selectedKeys = computed(() => {
if (route.meta.navKey === null) {
return [];
@@ -125,6 +126,13 @@ const navSections = computed<NavSection[]>(() => {
{ key: "/kol/marketplace", label: t("nav.kolMarketplace") },
],
},
{
key: "personalCenter",
title: t("nav.personalCenter"),
items: [
{ key: "/account/ai-points", label: t("nav.aiPointUsage"), icon: HistoryOutlined },
],
},
];
if (authStore.isActiveKol) {
@@ -279,10 +287,13 @@ async function handleLogout(): Promise<void> {
<!-- Quota Indicator -->
<div class="quota-pill">
<a-tag color="blue" :bordered="false" class="quota-pill-tag">{{ quotaQuery.data.value?.plan_name || t("shell.planFallback") }}</a-tag>
<a-tag color="blue" :bordered="false" class="quota-pill-tag">{{ quotaSummary?.plan_name || t("shell.planFallback") }}</a-tag>
<span class="quota-pill-text">
{{ t("shell.remainingQuota") }}: <strong>{{ quotaQuery.data.value?.balance ?? '--' }}</strong>
<span class="quota-pill-total">/ {{ quotaQuery.data.value?.total_quota ?? '--' }}</span>
{{ t("shell.remainingQuota") }}: <strong>{{ quotaSummary?.balance ?? '--' }}</strong>
<span class="quota-pill-total">/ {{ quotaSummary?.total_quota ?? '--' }}</span>
<span class="quota-pill-divider">·</span>
{{ t("shell.aiPoints") }}: <strong>{{ quotaSummary?.ai_points_balance ?? '--' }}</strong>
<span class="quota-pill-total">/ {{ quotaSummary?.ai_points_total ?? '--' }}</span>
</span>
</div>
@@ -485,6 +496,11 @@ async function handleLogout(): Promise<void> {
display: inline-block;
}
.quota-pill-divider {
color: #bfbfbf;
margin: 0 6px;
}
.user-dropdown-trigger {
display: flex;
align-items: center;