Initial MVP for QA asset backend
This commit is contained in:
166
hy_qa_asset_backend/frontend/app/settings/page.tsx
Normal file
166
hy_qa_asset_backend/frontend/app/settings/page.tsx
Normal file
@@ -0,0 +1,166 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { Save, RefreshCw } from "lucide-react";
|
||||
import { api } from "@/lib/api";
|
||||
import type { FeishuSetupGuide, FeishuStatus, SafeSettings } from "@/lib/types";
|
||||
import StatusBadge from "@/components/StatusBadge";
|
||||
|
||||
export default function SettingsPage() {
|
||||
const [settings, setSettings] = useState<SafeSettings | null>(null);
|
||||
const [feishuStatus, setFeishuStatus] = useState<FeishuStatus | null>(null);
|
||||
const [feishuGuide, setFeishuGuide] = useState<FeishuSetupGuide | null>(null);
|
||||
const [keyName, setKeyName] = useState("");
|
||||
const [value, setValue] = useState("");
|
||||
|
||||
async function load() {
|
||||
const [settingsData, statusData, guideData] = await Promise.all([
|
||||
api.get<SafeSettings>("/settings"),
|
||||
api.get<FeishuStatus>("/feishu/status"),
|
||||
api.get<FeishuSetupGuide>("/feishu/setup-guide")
|
||||
]);
|
||||
setSettings(settingsData);
|
||||
setFeishuStatus(statusData);
|
||||
setFeishuGuide(guideData);
|
||||
}
|
||||
|
||||
async function saveSetting() {
|
||||
if (!keyName) return;
|
||||
await api.patch<SafeSettings>("/settings", { settings: { [keyName]: value } });
|
||||
setKeyName("");
|
||||
setValue("");
|
||||
await load();
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
load();
|
||||
}, []);
|
||||
|
||||
if (!settings || !feishuStatus || !feishuGuide) {
|
||||
return <div className="text-sm text-slate-500">加载中...</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex flex-wrap items-center justify-between gap-3">
|
||||
<h1 className="text-2xl font-semibold text-ink">系统设置</h1>
|
||||
<button
|
||||
onClick={load}
|
||||
className="inline-flex h-10 items-center gap-2 rounded-md border border-line bg-white px-4 text-sm font-medium text-ink hover:bg-slate-50"
|
||||
>
|
||||
<RefreshCw className="h-4 w-4" aria-hidden />
|
||||
刷新连接状态
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
|
||||
<div className="rounded-md border border-line bg-white p-4">
|
||||
<div className="text-sm text-slate-500">飞书配置</div>
|
||||
<div className="mt-3">
|
||||
<StatusBadge status={settings.feishu_configured ? "approved" : "pending"} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="rounded-md border border-line bg-white p-4">
|
||||
<div className="text-sm text-slate-500">飞书 token</div>
|
||||
<div className="mt-3">
|
||||
<StatusBadge status={feishuStatus.token_ok ? "approved" : "pending"} />
|
||||
</div>
|
||||
<p className="mt-2 text-sm text-slate-600">{feishuStatus.message}</p>
|
||||
<p className="mt-1 text-xs text-slate-500">
|
||||
{feishuStatus.app_token_configured ? "Bitable app_token 模式" : "Wiki 节点 token 模式"}
|
||||
</p>
|
||||
</div>
|
||||
<div className="rounded-md border border-line bg-white p-4">
|
||||
<div className="text-sm text-slate-500">大模型配置</div>
|
||||
<div className="mt-3">
|
||||
<StatusBadge status={settings.openai_configured ? "approved" : "pending"} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="rounded-md border border-line bg-white p-4">
|
||||
<div className="text-sm text-slate-500">当前模型</div>
|
||||
<div className="mt-2 text-lg font-semibold">{settings.model_name}</div>
|
||||
</div>
|
||||
<div className="rounded-md border border-line bg-white p-4">
|
||||
<div className="text-sm text-slate-500">定时任务</div>
|
||||
<div className="mt-2 text-lg font-semibold">{settings.schedule_cron}</div>
|
||||
<div className="mt-1 text-sm text-slate-500">{settings.schedule_timezone}</div>
|
||||
</div>
|
||||
<div className="rounded-md border border-line bg-white p-4">
|
||||
<div className="text-sm text-slate-500">mock 模式</div>
|
||||
<div className="mt-3">
|
||||
<StatusBadge status={settings.mock_mode ? "running" : "completed"} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-md border border-line bg-white p-4">
|
||||
<div className="mb-3 text-sm font-semibold text-ink">飞书字段模板</div>
|
||||
<div className="grid gap-4 xl:grid-cols-3">
|
||||
{feishuGuide.tables.map((table) => (
|
||||
<div key={table.table_key} className="rounded-md border border-line p-3">
|
||||
<div className="font-medium text-ink">{table.table_name}</div>
|
||||
<div className="mt-1 text-xs text-slate-500">{table.env_name}</div>
|
||||
<div className="mt-3 flex flex-wrap gap-1">
|
||||
{table.required_fields.map((field) => (
|
||||
<span key={field} className="rounded-md bg-panel px-2 py-1 text-xs text-slate-700">
|
||||
{field}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="mt-4 text-sm text-slate-600">
|
||||
{feishuGuide.notes.map((note) => (
|
||||
<p key={note}>{note}</p>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-md border border-line bg-white p-4">
|
||||
<div className="grid gap-3 md:grid-cols-[1fr_1fr_auto]">
|
||||
<input
|
||||
value={keyName}
|
||||
onChange={(event) => setKeyName(event.target.value)}
|
||||
placeholder="非敏感配置 key"
|
||||
className="h-10 rounded-md border border-line px-3 outline-none focus:border-jade"
|
||||
/>
|
||||
<input
|
||||
value={value}
|
||||
onChange={(event) => setValue(event.target.value)}
|
||||
placeholder="value"
|
||||
className="h-10 rounded-md border border-line px-3 outline-none focus:border-jade"
|
||||
/>
|
||||
<button
|
||||
onClick={saveSetting}
|
||||
className="inline-flex h-10 items-center justify-center gap-2 rounded-md bg-jade px-4 text-sm font-medium text-white hover:bg-teal-800"
|
||||
>
|
||||
<Save className="h-4 w-4" aria-hidden />
|
||||
保存
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="table-wrap rounded-md border border-line bg-white">
|
||||
<table className="w-full min-w-[760px] border-collapse text-left text-sm">
|
||||
<thead className="bg-panel text-xs uppercase text-slate-500">
|
||||
<tr>
|
||||
<th className="px-4 py-3">key</th>
|
||||
<th className="px-4 py-3">value</th>
|
||||
<th className="px-4 py-3">说明</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{settings.system_settings.map((row) => (
|
||||
<tr key={row.key} className="border-t border-line">
|
||||
<td className="px-4 py-3 font-medium">{row.key}</td>
|
||||
<td className="px-4 py-3">{row.value ?? "-"}</td>
|
||||
<td className="px-4 py-3">{row.description ?? "-"}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user