feat(admin): 后台列表分页 + 积分显示格式化
9 张 admin 列表表格接服务端分页(共享 Pager 组件,10条/页,alwaysShow 单页也显示分页条); 积分数值统一 pts() 格式化(去除 DecimalField 序列化的多余小数位,整数不再显示 .0000)。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,11 +1,15 @@
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { Server, X } from "lucide-react";
|
||||
import { adminApi } from "../../api";
|
||||
import { Pager } from "../../components/pager";
|
||||
import { IconKitSvg } from "../../components/IconKitSvg";
|
||||
import type { AdminModel, AdminProvider } from "../../types";
|
||||
import { pts } from "../stage-config";
|
||||
|
||||
type Notify = (type: "success" | "error" | "info", text: string) => void;
|
||||
|
||||
const PAGE_SIZE = 10;
|
||||
|
||||
const CAPABILITIES = ["text", "image", "video", "vision", "audio", "export"];
|
||||
|
||||
function statusPill(active: boolean) {
|
||||
@@ -20,6 +24,7 @@ const EMPTY_MODEL = { id: "", provider: "", name: "", display_name: "", capabili
|
||||
export function AdminModelsPage({ notify }: { notify: Notify }) {
|
||||
const [providers, setProviders] = useState<AdminProvider[]>([]);
|
||||
const [models, setModels] = useState<AdminModel[]>([]);
|
||||
const [modelPage, setModelPage] = useState(1);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [provModal, setProvModal] = useState<typeof EMPTY_PROVIDER | null>(null);
|
||||
const [modelModal, setModelModal] = useState<typeof EMPTY_MODEL | null>(null);
|
||||
@@ -152,14 +157,14 @@ export function AdminModelsPage({ notify }: { notify: Notify }) {
|
||||
<div className="admin-detail-subhead" style={{ marginTop: 28 }}>模型</div>
|
||||
<div className="admin-table-wrap">
|
||||
<table className="t admin-table">
|
||||
<thead><tr><th>供应商</th><th>模型</th><th>能力</th><th>单价</th><th>状态</th><th>默认</th><th className="col-actions">操作</th></tr></thead>
|
||||
<thead><tr><th>供应商</th><th>模型</th><th>能力</th><th>单价(积分/次)</th><th>状态</th><th>默认</th><th className="col-actions">操作</th></tr></thead>
|
||||
<tbody>
|
||||
{models.map((m) => (
|
||||
{models.slice((modelPage - 1) * PAGE_SIZE, modelPage * PAGE_SIZE).map((m) => (
|
||||
<tr key={m.id}>
|
||||
<td className="mono">{m.provider_name}</td>
|
||||
<td>{m.display_name || m.name}</td>
|
||||
<td><span className="pill neutral"><span className="dot" />{m.capability}</span></td>
|
||||
<td className="num mono">¥{m.unit_price}</td>
|
||||
<td className="num mono">{pts(m.unit_price)} 积分</td>
|
||||
<td>{statusPill(m.status === "active")}</td>
|
||||
<td>{m.is_default ? <span className="pill info"><span className="dot" />默认</span> : <span className="muted">—</span>}</td>
|
||||
<td className="col-actions">
|
||||
@@ -172,6 +177,7 @@ export function AdminModelsPage({ notify }: { notify: Notify }) {
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
<Pager page={modelPage} total={models.length} pageSize={PAGE_SIZE} onChange={setModelPage} alwaysShow />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
@@ -246,7 +252,7 @@ export function AdminModelsPage({ notify }: { notify: Notify }) {
|
||||
</div>
|
||||
<div className="field-row">
|
||||
<div className="field">
|
||||
<label className="field-label">单价</label>
|
||||
<label className="field-label">单价(积分/次)</label>
|
||||
<input className="input" type="text" placeholder="0" value={modelModal.unit_price} onChange={(e) => setModelModal((m) => m && ({ ...m, unit_price: e.target.value }))} />
|
||||
</div>
|
||||
<div className="field">
|
||||
|
||||
Reference in New Issue
Block a user