- 新增 model_deploy 与 model_operations 双库查询,支持模型列表、模型详情、单月监控结果和运维工作台真实接口。 - 关闭运维模块生产 Mock 数据,补充缺表/空数据降级、工作台空状态和首条纵向链路测试。 - 按业务团队、模型团队、管理员权限矩阵接入菜单、页面、操作按钮和后端接口权限校验,支持 business_team 角色。 - 更新工作台布局、深色欢迎卡片、全宽页面适配、顶部回退,以及权限分组展示。 - 新增架构实现基线、周目标完成情况和角色权限矩阵初始化 SQL 文档。
64 lines
6.7 KiB
TypeScript
64 lines
6.7 KiB
TypeScript
import { Fragment, useState } from "react";
|
|
import { CheckCircle2, Edit3, Save, Sparkles } from "lucide-react";
|
|
import { toast } from "sonner";
|
|
|
|
import { Button } from "~/components/ui/button";
|
|
import { Card, CardAction, CardContent, CardDescription, CardHeader, CardTitle } from "~/components/ui/card";
|
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "~/components/ui/table";
|
|
import { Textarea } from "~/components/ui/textarea";
|
|
import { FilterSelect, OperationsPageHeader } from "./OperationsUi";
|
|
import { PROMPTS, PROMPT_REGRESSION, PROMPT_VERSIONS, type PromptKey } from "./governanceData";
|
|
import { useCanOperationsAction } from "./operationsRole";
|
|
|
|
function PromptPreview({ text }: { text: string }) {
|
|
const parts = text.split(/(\{\{[^}]+\}\})/g);
|
|
return <pre className="whitespace-pre-wrap rounded-xl bg-bg-log p-5 font-mono text-xs leading-6 text-white/80">{parts.map((part, index) => part.startsWith("{{") ? <mark className="rounded bg-warning/20 px-1 text-warning" key={`${part}-${index}`}>{part}</mark> : <Fragment key={`${part}-${index}`}>{part}</Fragment>)}</pre>;
|
|
}
|
|
|
|
export default function PromptManagementPage() {
|
|
const canEdit = useCanOperationsAction("prompts:manage");
|
|
const canRegression = useCanOperationsAction("prompts:regression");
|
|
const [promptKey, setPromptKey] = useState<PromptKey>("BC");
|
|
const [texts, setTexts] = useState<Record<PromptKey, string>>({ A: "", BC: "" });
|
|
const [editing, setEditing] = useState(false);
|
|
const [versions] = useState(PROMPT_VERSIONS);
|
|
const prompt = PROMPTS[promptKey];
|
|
const passed = PROMPT_REGRESSION.filter((item) => item.result === "通过").length;
|
|
|
|
const savePrompt = () => {
|
|
toast.info("Prompt保存接口尚未接入");
|
|
};
|
|
|
|
return (
|
|
<section className="h-full overflow-auto bg-bg p-6">
|
|
<div className="flex w-full flex-col gap-6 pb-8">
|
|
<OperationsPageHeader title="报告 Prompt 管理" description="查看和调整提示词全文,保留版本记录,并通过历史样本回归后生效。" actions={canRegression ? <Button onClick={savePrompt}><Save />保存并提交回归</Button> : undefined} />
|
|
<div className="rounded-xl bg-brand-soft p-4 text-sm leading-6 text-primary">提示词查看与调整属于需求沟通补充项,建议在下一版需求文档中同步固化。平台注入变量由程序取数,不交由大模型计算。</div>
|
|
|
|
<div className="grid grid-cols-[minmax(0,1.5fr)_minmax(20rem,0.7fr)] gap-6">
|
|
<Card>
|
|
<CardHeader className="border-b border-border"><CardTitle className="flex items-center gap-2"><Sparkles className="size-5 text-primary" />提示词全文</CardTitle><CardDescription>变量占位符必须保持双花括号格式</CardDescription><CardAction className="flex items-end gap-2"><FilterSelect className="w-72" label="报告模板" value={promptKey} allLabel="暂无模板" options={Object.entries(PROMPTS).map(([value, item]) => ({ label: item.name, value }))} onChange={(value) => { setPromptKey(value as PromptKey); setEditing(false); }} /><Button variant="outline" size="sm" disabled={!prompt || !canEdit} onClick={() => setEditing((value) => !value)}><Edit3 />{editing ? "退出编辑" : "编辑"}</Button></CardAction></CardHeader>
|
|
<CardContent className="space-y-4">
|
|
{prompt ? (editing ? <Textarea className="min-h-[36rem] font-mono text-xs leading-6" value={texts[promptKey]} onChange={(event) => setTexts((current) => ({ ...current, [promptKey]: event.target.value }))} /> : <PromptPreview text={texts[promptKey]} />) : <div className="grid min-h-[36rem] place-items-center rounded-xl border border-dashed border-border text-sm text-muted-foreground">暂无 Prompt 数据</div>}
|
|
<p className="rounded-xl bg-muted/50 p-4 text-xs leading-5 text-muted-foreground">高亮内容为程序注入变量。等级字段仅用于选择模板,不进入报告正文;Prompt 禁止自行计算指标或臆测业务原因。</p>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<div className="space-y-6">
|
|
<Card>
|
|
<CardHeader><CardTitle>版本留痕</CardTitle><CardDescription>当前生效与历史版本</CardDescription></CardHeader>
|
|
<CardContent className="space-y-3">{versions.length ? versions.map((version) => <div className="flex items-center gap-3 rounded-xl border border-border p-4" key={version.version}><b className="text-sm text-foreground">{version.version}</b><span className="min-w-0 flex-1"><small className="block truncate text-xs text-muted-foreground">{version.note}</small><small className="text-3xs text-muted-foreground">{version.author} · {version.createdAt}</small></span>{version.current ? <span className="rounded-full bg-success-soft px-2.5 py-1 text-xs text-success-strong">生效中</span> : <span className="rounded-full bg-muted px-2.5 py-1 text-xs text-muted-foreground">历史</span>}</div>) : <div className="py-10 text-center text-sm text-muted-foreground">暂无 Prompt 版本数据</div>}</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader><CardTitle>回归评审</CardTitle><CardDescription>上线前使用历史样本回归</CardDescription></CardHeader>
|
|
<CardContent className="grid grid-cols-3 gap-3"><div className="rounded-xl bg-muted/50 p-3"><span className="text-xs text-muted-foreground">回归样本</span><strong className="mt-1 block text-xl tabular-nums">{PROMPT_REGRESSION.length}</strong></div><div className="rounded-xl bg-success-soft p-3"><span className="text-xs text-success-strong">通过</span><strong className="mt-1 block text-xl tabular-nums text-success-strong">{passed}</strong></div><div className="rounded-xl bg-warning-soft p-3"><span className="text-xs text-warning">待复核</span><strong className="mt-1 block text-xl tabular-nums text-warning">{PROMPT_REGRESSION.length - passed}</strong></div></CardContent>
|
|
<CardContent className="px-0 pt-0"><Table><TableHeader><TableRow><TableHead>历史样本</TableHead><TableHead>结果</TableHead><TableHead>说明</TableHead></TableRow></TableHeader><TableBody>{PROMPT_REGRESSION.map((item) => <TableRow key={item.sample}><TableCell className="min-w-48 whitespace-normal">{item.sample}</TableCell><TableCell>{item.result === "通过" ? <span className="inline-flex items-center gap-1 rounded-full bg-success-soft px-2.5 py-1 text-xs text-success-strong"><CheckCircle2 className="size-3" />通过</span> : <span className="rounded-full bg-warning-soft px-2.5 py-1 text-xs text-warning">待复核</span>}</TableCell><TableCell className="whitespace-normal text-muted-foreground">{item.detail}</TableCell></TableRow>)}</TableBody></Table></CardContent>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|