feat(front-end): 依据内部评审意见对前端 UI 进行二次升级优化
- 主题色统一改回科技蓝(呼应滨化 LOGO) - 合并"采购需求人员"、移除审批人角色(审批在 OA) - 发起委托归属采购需求人员,招标专员不含该功能 - 删除合并招标/定标审批/合同生成/合同管理/供应商入库/审批中心/流程配置页面 - 小滨助手默认展开可收起、各角色主动提醒、问答直接给出按钮/链接 - 待办中心去掉"事找人"前缀 - 新增后台智能体任务监控组件(招标专员/管理员) - 发起委托增加导入采购计划/直接填写/选择模板(含自动) - 项目列表:排序/高级搜索/委托人列/提交审批/列显隐 - 项目详情:修正流程步骤、委托人信息、方案与文件合一、提交审批 - 长短名单去分支与推荐部门列、寻源关联项目并支持三来源 - 开标去自动开标、专家管理去抽取与回避、供应商管理去新增与入库
This commit is contained in:
@@ -1,12 +1,5 @@
|
||||
import { useState } from "react";
|
||||
import { Search, Filter, Dices, Loader2, Check, ShieldAlert, UserCog } from "lucide-react";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogFooter,
|
||||
} from "../components/ui/dialog";
|
||||
import { Search, Filter } from "lucide-react";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
@@ -14,42 +7,25 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "../components/ui/select";
|
||||
import { Button } from "../components/ui/button";
|
||||
import { Card } from "../components/ui/card";
|
||||
import { PageHeader } from "../components/shared/common";
|
||||
import { experts } from "../data/mock";
|
||||
|
||||
// 说明(评审意见):专家的随机抽取与回避校验属于"具体项目评标流程",
|
||||
// 不在专家总体管理页体现;本页仅做专家库信息维护与查询。
|
||||
export function ExpertManagement() {
|
||||
const [q, setQ] = useState("");
|
||||
const [cat, setCat] = useState("all");
|
||||
const [open, setOpen] = useState(false);
|
||||
const [drawing, setDrawing] = useState(false);
|
||||
const [result, setResult] = useState<typeof experts | null>(null);
|
||||
|
||||
const list = experts.filter(
|
||||
(e) => (cat === "all" || e.category === cat) && e.name.includes(q),
|
||||
);
|
||||
|
||||
function draw() {
|
||||
setDrawing(true);
|
||||
setResult(null);
|
||||
setTimeout(() => {
|
||||
setDrawing(false);
|
||||
// 抽取未需回避的专家
|
||||
setResult(experts.filter((e) => !e.avoid).slice(0, 3));
|
||||
}, 1800);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PageHeader
|
||||
title="专家管理"
|
||||
description="管理内外部评标专家,支持随机抽取与回避校验"
|
||||
actions={
|
||||
<Button onClick={() => { setOpen(true); setResult(null); }}>
|
||||
<Dices className="size-4" /> 抽取专家
|
||||
</Button>
|
||||
}
|
||||
description="维护内外部评标专家库信息(随机抽取与回避校验在具体项目评标流程中进行)"
|
||||
/>
|
||||
|
||||
<Card className="mb-4 flex-row items-center gap-3 p-4">
|
||||
@@ -88,7 +64,6 @@ export function ExpertManagement() {
|
||||
<th className="px-4 py-3 font-medium">地区</th>
|
||||
<th className="px-4 py-3 font-medium">评审次数</th>
|
||||
<th className="px-4 py-3 font-medium">类型</th>
|
||||
<th className="px-4 py-3 font-medium">回避状态</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y">
|
||||
@@ -102,109 +77,17 @@ export function ExpertManagement() {
|
||||
<td className="px-4 py-4">
|
||||
<span
|
||||
className={`rounded px-2 py-0.5 text-xs ${
|
||||
e.type === "内部" ? "bg-blue-50 text-blue-600" : "bg-violet-50 text-violet-600"
|
||||
e.type === "内部" ? "bg-blue-50 text-blue-600" : "bg-sky-50 text-sky-600"
|
||||
}`}
|
||||
>
|
||||
{e.type}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-4 py-4">
|
||||
{e.avoid ? (
|
||||
<span className="inline-flex items-center gap-1 text-red-600">
|
||||
<ShieldAlert className="size-4" /> 需回避
|
||||
</span>
|
||||
) : (
|
||||
<span className="text-emerald-600">可参与</span>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</Card>
|
||||
|
||||
{/* 抽取弹窗 */}
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center gap-2">
|
||||
<Dices className="size-5 text-primary" /> 随机抽取评标专家
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
{!result && !drawing && (
|
||||
<div className="space-y-4 py-2">
|
||||
<div className="grid grid-cols-2 gap-3 text-sm">
|
||||
<div>
|
||||
<label className="mb-1.5 block">抽取专业</label>
|
||||
<Select defaultValue="自动化控制">
|
||||
<SelectTrigger><SelectValue /></SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="自动化控制">自动化控制</SelectItem>
|
||||
<SelectItem value="化工工艺">化工工艺</SelectItem>
|
||||
<SelectItem value="环保工程">环保工程</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="mb-1.5 block">抽取人数</label>
|
||||
<Select defaultValue="3">
|
||||
<SelectTrigger><SelectValue /></SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="3">3 人</SelectItem>
|
||||
<SelectItem value="5">5 人</SelectItem>
|
||||
<SelectItem value="7">7 人</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-start gap-2 rounded-lg bg-muted/40 p-3 text-xs text-muted-foreground">
|
||||
<ShieldAlert className="mt-0.5 size-4 shrink-0 text-amber-500" />
|
||||
系统将自动执行回避校验,排除与投标人存在关联或利益冲突的专家。
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{drawing && (
|
||||
<div className="flex flex-col items-center justify-center gap-3 py-10">
|
||||
<Loader2 className="size-10 animate-spin text-primary" />
|
||||
<p className="text-sm text-muted-foreground">正在随机抽取并执行回避校验…</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{result && (
|
||||
<div className="space-y-3 py-2">
|
||||
<div className="flex items-center gap-2 rounded-lg bg-emerald-50 px-3 py-2 text-sm text-emerald-700">
|
||||
<Check className="size-4" /> 抽取完成,回避校验通过,已排除 1 名需回避专家
|
||||
</div>
|
||||
{result.map((e) => (
|
||||
<div key={e.id} className="flex items-center gap-3 rounded-lg border bg-card p-3">
|
||||
<div className="flex size-9 items-center justify-center rounded-full bg-primary/10 text-primary">
|
||||
<UserCog className="size-4" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="font-medium text-foreground">{e.name}</div>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
{e.title} · {e.category} · {e.region}
|
||||
</div>
|
||||
</div>
|
||||
<span className="text-xs text-emerald-600">无需回避</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<DialogFooter>
|
||||
{!result ? (
|
||||
<Button onClick={draw} disabled={drawing}>
|
||||
<Dices className="size-4" /> {drawing ? "抽取中…" : "开始抽取"}
|
||||
</Button>
|
||||
) : (
|
||||
<Button onClick={() => setOpen(false)}>确认专家组</Button>
|
||||
)}
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user