"use client";
import Link from "next/link";
import { Activity, AlertTriangle, BarChart3, Check, FileText, LogOut, ShieldAlert, Users } from "lucide-react";
import { useEffect, useState } from "react";
import { apiFetch } from "@/lib/api";
import { clearToken, getRoleLabel } from "@/lib/auth";
import type { UserPayload } from "@/types/api";
interface DashboardData { overview?: { total_customers?: number; signed_customers?: number; total_aum?: string }; todos?: { pending?: number } }
interface RiskAlert { id: number; customer_id: number; alert_type: string; alert_level: string; status: string }
interface WorkOrder { id: number; work_order_no: string; order_type: string; status: string; priority: string }
interface Customer { customer_id?: number; id?: number; real_name?: string; name?: string; risk_level?: string; total_aum?: string | number }
interface Todo { id: number; todo_type: string; status: string; priority: string }
interface Visit { id: number; customer_id: number; visit_type?: string; content?: string }
function Frame({ title, subtitle, role, children }: { title: string; subtitle: string; role: string; children: React.ReactNode }) {
return ;
}
async function getMe() { return (await apiFetch<{ user: UserPayload }>("/auth/me")).user; }
function Notice({ children }: { children: React.ReactNode }) { return
{children}
; }
export function AdvisorWorkspace() {
const [user, setUser] = useState(null); const [dashboard, setDashboard] = useState(null); const [customers, setCustomers] = useState([]); const [todos, setTodos] = useState([]); const [visits, setVisits] = useState([]); const [report, setReport] = useState | null>(null); const [error, setError] = useState("");
async function load() { try { const [current, overview, customerData, todoData, visitData, personalReport] = await Promise.all([getMe(), apiFetch("/advisor/dashboard"), apiFetch<{ items?: Customer[] }>("/advisor/customers?page=1&page_size=50"), apiFetch<{ items?: Todo[] }>("/advisor/todos?page=1&page_size=20"), apiFetch<{ items?: Visit[] }>("/advisor/visits?page=1&page_size=20"), apiFetch>("/advisor/report/personal")]); setUser(current); setDashboard(overview); setCustomers(customerData.items ?? []); setTodos(todoData.items ?? []); setVisits(visitData.items ?? []); setReport(personalReport); } catch { setError("部分投顾数据加载失败,请确认投顾权限或后端服务状态。"); } }
useEffect(() => { void load(); }, []);
async function finishTodo(id: number) { await apiFetch(`/advisor/todos/${id}/handle`, { method: "POST", body: JSON.stringify({ action: "done" }) }); await load(); }
const overview = dashboard?.overview;
return {error && {error}}名下客户
{overview?.total_customers ?? "--"}
签约客户
{overview?.signed_customers ?? "--"}
管理资产
{overview?.total_aum ? `¥${overview.total_aum}` : "--"}
待办事项
{dashboard?.todos?.pending ?? "--"}
客户管理
{customers.slice(0, 8).map((item) =>
{item.real_name ?? item.name ?? `客户 #${item.customer_id ?? item.id}`}{item.risk_level ?? "未评估"} · {item.total_aum ?? "--"}
)}{!customers.length &&
暂无客户数据
}
待办处理
{todos.slice(0, 6).map((todo) =>
{todo.todo_type} · {todo.priority}
)}{!todos.length &&
暂无待办
}
回访记录
{visits.slice(0, 5).map((visit) =>
客户 #{visit.customer_id} · {visit.visit_type ?? "回访"}
{visit.content ?? "暂无内容"}
)}{!visits.length &&
暂无回访记录
}
个人绩效
{report ? JSON.stringify(report, null, 2) : "暂无绩效数据"} ;
}
export function RiskWorkspace() {
const [user, setUser] = useState(null); const [alerts, setAlerts] = useState([]); const [orders, setOrders] = useState([]); const [error, setError] = useState("");
async function load() { try { const [current, alertData, orderData] = await Promise.all([getMe(), apiFetch<{ items?: RiskAlert[] }>("/risk/alert/list?page=1&page_size=10"), apiFetch<{ items?: WorkOrder[] }>("/work-order/list?page=1&page_size=10")]); setUser(current); setAlerts(alertData.items ?? []); setOrders(orderData.items ?? []); } catch { setError("风控数据加载失败,请确认风控权限或后端服务状态。"); } }
useEffect(() => { void load(); }, []);
async function alertAction(id: number, action: "release" | "block" | "freeze") { await apiFetch(`/risk/alert/${id}/${action}`, { method: "POST" }); await load(); }
async function orderAction(id: number, action: "claim" | "submit-review" | "review") { const body = action === "review" ? { work_order_id: id, approve: window.confirm("确认通过该工单?"), comment: "前端工作区复核" } : { work_order_id: id }; await apiFetch(`/work-order/${action}`, { method: "POST", body: JSON.stringify(body) }); await load(); }
return {error && {error}}高风险事项
{alerts.filter((item) => item.alert_level === "高").length}
风险预警处置
{alerts.map((alert) =>
{alert.alert_type} · 客户 #{alert.customer_id}{alert.status} )}{!alerts.length &&
暂无风险预警
}
业务工单
{orders.map((item) =>
{item.work_order_no} · {item.order_type} · {item.status} )}{!orders.length &&
暂无工单
}
;
}
export function CommonWorkspace() {
const [user, setUser] = useState(null); useEffect(() => { void getMe().then(setUser).catch(() => undefined); }, []);
const isAdmin = user?.user_type === "ADMIN";
return 基金数据
查看真实基金产品和历史净值
{isAdmin ?
NL2SQL 配置
管理员专用:运行配置和查询权限管理
:
数据查询
员工自然语言查询与历史记录
}{isAdmin &&
知识库管理
管理员专用:文档上传、预览和删除
}
;
}