- 删除模型大类概览和细分银行概览中原型未包含的过渡跳转按钮,保留卡片点击、筛选、指标趋势和详情入口。 - 移除运维系统配置页中的模型平台新增页面依赖、登录角色来源等内部说明,仅保留实际配置内容。 - 将开发工作台访问控制统一收敛到 dashboard:view,业务团队仅保留运维工作台权限;直接访问开发工作台时自动回到运维工作台。 - 补充架构实现基线、外部写入协议、运维 API 清单、三角色权限验收说明和首条纵向链路联调手册。 - 按当前实现更新架构变更记录和本周目标完成情况。
74 lines
7.7 KiB
TypeScript
74 lines
7.7 KiB
TypeScript
import { useState } from "react";
|
|
import { Database, Download, History, RefreshCw, Save } 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 { Input } from "~/components/ui/input";
|
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "~/components/ui/table";
|
|
import { exportRowsToExcel } from "~/lib/exportExcel";
|
|
import { FilterSelect, OperationsPageHeader } from "./OperationsUi";
|
|
import { BANK_REPORT_CONFIG, TEMPLATE_VERSIONS } from "./governanceData";
|
|
|
|
function nextGeneration(frequency: string, day: number): string {
|
|
const formattedDay = String(day).padStart(2, "0");
|
|
if (frequency === "月度") return `2026-09-${formattedDay}`;
|
|
if (frequency === "季度") return `2026-10-${formattedDay}`;
|
|
return `2027-01-${formattedDay}`;
|
|
}
|
|
|
|
export default function SystemConfigPage() {
|
|
const [readDay, setReadDay] = useState("");
|
|
const [readPeriod, setReadPeriod] = useState("");
|
|
const [templates] = useState(TEMPLATE_VERSIONS);
|
|
const [selectedBank, setSelectedBank] = useState("");
|
|
const [bankConfigs] = useState(BANK_REPORT_CONFIG);
|
|
const currentBankConfig = selectedBank ? bankConfigs[selectedBank] : undefined;
|
|
const notificationRows: string[][] = [];
|
|
|
|
const publishTemplate = () => {
|
|
toast.info("报告模板接口尚未接入");
|
|
};
|
|
|
|
const updateBankConfig = (updates: Partial<{ frequency: string; day: number }>) => {
|
|
void updates;
|
|
toast.info("报告周期配置接口尚未接入");
|
|
};
|
|
|
|
return (
|
|
<section className="h-full overflow-auto bg-bg p-6">
|
|
<div className="flex w-full flex-col gap-6 pb-8">
|
|
<OperationsPageHeader title="运维系统配置" description="维护指标读取、报告模板、通知催办和银行报告周期。" actions={<Button onClick={() => toast.info("系统配置接口尚未接入")}><Save />保存配置</Button>} />
|
|
|
|
<div className="grid grid-cols-2 gap-6">
|
|
<Card>
|
|
<CardHeader><CardTitle className="flex items-center gap-2"><Database className="size-5 text-primary" />指标读取配置</CardTitle><CardDescription>从共享数据库读取模型平台计算结果</CardDescription></CardHeader>
|
|
<CardContent className="space-y-4">
|
|
<div className="grid grid-cols-2 gap-3"><FilterSelect label="读取日(每月)" value={readDay} allLabel="请选择" options={["1 日", "15 日", "20 日"]} onChange={setReadDay} /><FilterSelect label="读取周期" value={readPeriod} allLabel="请选择" options={["上一周期(月)", "上一周期(季)"]} onChange={setReadPeriod} /></div>
|
|
<Button className="w-full" variant="outline" onClick={() => toast.info("指标同步接口尚未接入")}><RefreshCw />立即重新读取上一周期指标</Button>
|
|
<p className="rounded-xl bg-muted/50 p-4 text-xs leading-5 text-muted-foreground">读取排序性、KS、PSI、IV、CSI。本平台不重算指标,只读取模型平台计算结果;共享表名和字段映射待接口设计阶段确定。</p>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader><CardTitle className="flex items-center gap-2"><History className="size-5 text-primary" />报告模板版本管理</CardTitle><CardDescription>监控报告与诊断报告共用版本体系</CardDescription><CardAction><Button size="sm" onClick={publishTemplate}>发布新版本</Button></CardAction></CardHeader>
|
|
<CardContent className="space-y-3">{templates.length ? templates.map((template) => <div className="flex items-center gap-3 rounded-xl border border-border p-4" key={template.version}><b className="text-sm text-foreground">{template.version}</b><span className="min-w-0 flex-1"><small className="block truncate text-xs text-muted-foreground">{template.note}</small><small className="text-3xs text-muted-foreground">{template.author} · {template.createdAt}</small></span>{template.current ? <span className="rounded-full bg-success-soft px-2.5 py-1 text-xs text-success-strong">当前生效</span> : <Button variant="outline" size="xs" onClick={() => toast.info("报告模板接口尚未接入")}>一键回滚</Button>}</div>) : <div className="py-10 text-center text-sm text-muted-foreground">暂无报告模板版本数据</div>}</CardContent>
|
|
</Card>
|
|
</div>
|
|
|
|
<Card>
|
|
<CardHeader className="border-b border-border"><CardTitle>通知与催办</CardTitle><CardDescription>邮件通道已取消</CardDescription><CardAction><Button variant="outline" size="xs" onClick={() => void exportRowsToExcel({ fileName: "通知与催办配置", sheetName: "通知配置", headers: ["配置项", "配置值"], rows: notificationRows })}><Download />导出 Excel</Button></CardAction></CardHeader>
|
|
<CardContent className="px-0"><Table><TableBody>{notificationRows.map(([item, value]) => <TableRow key={item}><TableCell className="w-52 font-medium text-foreground">{item}</TableCell><TableCell>{value}</TableCell></TableRow>)}</TableBody></Table></CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader className="border-b border-border"><CardTitle>报告时间维度与输出日期</CardTitle><CardDescription>按银行单独配置,不强制统一为每月 15 日</CardDescription><CardAction className="flex items-end gap-2"><FilterSelect className="w-44" label="选择银行" value={selectedBank} allLabel="暂无银行数据" options={Object.keys(bankConfigs)} onChange={setSelectedBank} /><Button variant="outline" size="xs" onClick={() => void exportRowsToExcel({ fileName: "报告周期配置", sheetName: "报告周期", headers: ["银行", "报告时间维度", "输出日期", "下次生成"], rows: Object.entries(bankConfigs).map(([bank, config]) => [bank, config.frequency, `每月 ${config.day} 日`, nextGeneration(config.frequency, config.day)]) })}><Download />导出 Excel</Button></CardAction></CardHeader>
|
|
<CardContent className="grid grid-cols-3 gap-3"><FilterSelect label="报告时间维度" value={currentBankConfig?.frequency ?? ""} allLabel="暂无配置" options={["月度", "季度", "半年度", "年度"]} disabled={!currentBankConfig} onChange={(frequency) => updateBankConfig({ frequency })} /><label className="flex flex-col gap-1.5"><span className="text-xs font-medium text-ink-caption">报告输出日期(每月第几日)</span><Input disabled={!currentBankConfig} type="number" min="1" max="28" value={currentBankConfig?.day ?? ""} onChange={(event) => updateBankConfig({ day: Number(event.target.value) })} /></label><label className="flex flex-col gap-1.5"><span className="text-xs font-medium text-ink-caption">下次生成</span><Input disabled value={currentBankConfig ? nextGeneration(currentBankConfig.frequency, currentBankConfig.day) : "—"} /></label></CardContent>
|
|
<CardContent className="px-0 pt-0"><Table><TableHeader><TableRow><TableHead>银行</TableHead><TableHead>报告时间维度</TableHead><TableHead>输出日期</TableHead><TableHead>下次生成</TableHead></TableRow></TableHeader><TableBody>{Object.entries(bankConfigs).length ? Object.entries(bankConfigs).map(([bank, config]) => <TableRow data-state={bank === selectedBank ? "selected" : undefined} key={bank}><TableCell className="font-medium text-foreground">{bank}</TableCell><TableCell>{config.frequency}</TableCell><TableCell>每月 {config.day} 日</TableCell><TableCell>{nextGeneration(config.frequency, config.day)}</TableCell></TableRow>) : <TableRow><TableCell colSpan={4} className="h-28 text-center text-muted-foreground">暂无银行报告周期数据</TableCell></TableRow>}</TableBody></Table></CardContent>
|
|
</Card>
|
|
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|