@@ -209,21 +152,37 @@ export function ProjectDetail() {
)}
-
-
-
-
-
-
{project.name}-招标文件.docx
-
AI 生成 · 共 42 页 · 支持在线编辑
-
-
+ <>
+
+ {[
+ { t: "标段划分建议", d: "建议划分为 2 个标段:①控制系统硬件 ②系统集成与服务,便于专业化竞争。" },
+ { t: "推荐评标办法", d: "综合评估法:技术 60 分 / 商务 20 分 / 价格 20 分,技术权重较高。" },
+ { t: "推荐供应商短名单", d: "基于合格供方库与历史业绩,推荐浙江中控、和利时、西门子等 3 家。" },
+ ].map((c) => (
+
+ ))}
-
+
+
+
+
+
+
+
{project.name}-招标文件.docx
+
AI 生成 · 共 42 页 · 支持在线编辑
+
+
+
+
+ >
) : (
- 点击「AI 生成文件」,系统将根据招标方案自动生成招标文件初稿,支持在线预览、编辑与一键发布公告。
+ 点击「AI 生成招标文件」,小滨将基于委托单自动生成标段划分、评标办法、推荐短名单与完整招标文件初稿,支持在线预览、编辑与一键发布公告。
)}
diff --git a/front-end/src/app/pages/ProjectList.tsx b/front-end/src/app/pages/ProjectList.tsx
index a184e6a..f6c4dd8 100644
--- a/front-end/src/app/pages/ProjectList.tsx
+++ b/front-end/src/app/pages/ProjectList.tsx
@@ -1,6 +1,7 @@
-import { useState } from "react";
+import { useMemo, useState } from "react";
import { useNavigate } from "react-router";
-import { Plus, Search, Filter, ChevronRight } from "lucide-react";
+import { Search, Filter, ChevronRight, ArrowUp, ArrowDown, ChevronsUpDown, SlidersHorizontal, Columns3, Send } from "lucide-react";
+import { toast } from "sonner";
import { Button } from "../components/ui/button";
import { Card } from "../components/ui/card";
import {
@@ -10,66 +11,184 @@ import {
SelectTrigger,
SelectValue,
} from "../components/ui/select";
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuCheckboxItem,
+ DropdownMenuLabel,
+ DropdownMenuSeparator,
+ DropdownMenuTrigger,
+} from "../components/ui/dropdown-menu";
import { PageHeader, StatusBadge } from "../components/shared/common";
import { projects } from "../data/mock";
+type ColKey = "type" | "budget" | "owner" | "dept" | "status" | "progress";
+type SortKey = "name" | "budget" | "progress";
+
+const COLUMNS: { key: ColKey; label: string; sortable?: SortKey }[] = [
+ { key: "type", label: "招标方式" },
+ { key: "budget", label: "预算(万元)", sortable: "budget" },
+ { key: "owner", label: "委托人" },
+ { key: "dept", label: "委托单位" },
+ { key: "status", label: "当前阶段" },
+ { key: "progress", label: "进度", sortable: "progress" },
+];
+
export function ProjectList() {
const navigate = useNavigate();
const [q, setQ] = useState("");
const [type, setType] = useState("all");
+ const [advanced, setAdvanced] = useState(false);
+ const [owner, setOwner] = useState("");
+ const [dept, setDept] = useState("");
+ const [minBudget, setMinBudget] = useState("");
+ const [sort, setSort] = useState<{ key: SortKey; dir: "asc" | "desc" } | null>(null);
+ const [cols, setCols] = useState
>({
+ type: true,
+ budget: true,
+ owner: true,
+ dept: true,
+ status: true,
+ progress: true,
+ });
- const list = projects.filter(
- (p) =>
- (type === "all" || p.type === type) &&
- (p.name.includes(q) || p.code.includes(q)),
- );
+ const list = useMemo(() => {
+ let r = projects.filter(
+ (p) =>
+ (type === "all" || p.type === type) &&
+ (p.name.includes(q) || p.code.includes(q)) &&
+ (!owner || p.owner.includes(owner)) &&
+ (!dept || p.dept.includes(dept)) &&
+ (!minBudget || p.budget >= Number(minBudget)),
+ );
+ if (sort) {
+ r = [...r].sort((a, b) => {
+ let cmp = 0;
+ if (sort.key === "name") cmp = a.name.localeCompare(b.name, "zh");
+ else cmp = (a[sort.key] as number) - (b[sort.key] as number);
+ return sort.dir === "asc" ? cmp : -cmp;
+ });
+ }
+ return r;
+ }, [q, type, owner, dept, minBudget, sort]);
+
+ function toggleSort(key: SortKey) {
+ setSort((s) =>
+ s?.key === key ? { key, dir: s.dir === "asc" ? "desc" : "asc" } : { key, dir: "asc" },
+ );
+ }
+
+ function SortIcon({ k }: { k: SortKey }) {
+ if (sort?.key !== k) return ;
+ return sort.dir === "asc" ? : ;
+ }
return (
navigate("/app/delegation")}>
- 发起委托
+
}
/>
-
-
-
-
setQ(e.target.value)}
- placeholder="搜索项目名称或编号"
- className="h-9 w-full rounded-lg border bg-input-background pl-9 pr-3 text-sm outline-none focus:border-primary"
- />
+
+
+
+
+ setQ(e.target.value)}
+ placeholder="搜索项目名称或编号"
+ className="h-9 w-full rounded-lg border bg-input-background pl-9 pr-3 text-sm outline-none focus:border-primary"
+ />
+
+
+
+
+
+
+
+
+ 显示的列
+
+ {COLUMNS.map((c) => (
+ setCols((s) => ({ ...s, [c.key]: !!v }))}
+ onSelect={(e) => e.preventDefault()}
+ >
+ {c.label}
+
+ ))}
+
+
-
+
+ {advanced && (
+
+
+
+ setOwner(e.target.value)} placeholder="按委托人筛选" className="h-9 w-full rounded-lg border bg-input-background px-3 text-sm outline-none focus:border-primary" />
+
+
+
+ setDept(e.target.value)} placeholder="按委托单位筛选" className="h-9 w-full rounded-lg border bg-input-background px-3 text-sm outline-none focus:border-primary" />
+
+
+
+ setMinBudget(e.target.value.replace(/\D/g, ""))} placeholder="如 500" className="h-9 w-full rounded-lg border bg-input-background px-3 text-sm outline-none focus:border-primary" />
+
+
+
+
+
+ )}
- | 项目名称 / 编号 |
- 招标方式 |
- 预算(万元) |
- 负责人 |
- 当前阶段 |
- 进度 |
+
+
+ |
+ {COLUMNS.map((c) =>
+ cols[c.key] ? (
+
+ {c.sortable ? (
+
+ ) : (
+ c.label
+ )}
+ |
+ ) : null,
+ )}
|
@@ -84,20 +203,25 @@ export function ProjectList() {
{p.name}
{p.code}
- {p.type} |
- {p.budget.toLocaleString()} |
- {p.owner} |
-
-
- |
-
-
-
-
+ {cols.type && {p.type} | }
+ {cols.budget && {p.budget.toLocaleString()} | }
+ {cols.owner && {p.owner} | }
+ {cols.dept && {p.dept} | }
+ {cols.status && (
+
+
+ |
+ )}
+ {cols.progress && (
+
+
- {p.progress}%
-
- |
+ |
+ )}
|
diff --git a/front-end/src/app/pages/SmartSourcing.tsx b/front-end/src/app/pages/SmartSourcing.tsx
index c7192f4..5d41ad9 100644
--- a/front-end/src/app/pages/SmartSourcing.tsx
+++ b/front-end/src/app/pages/SmartSourcing.tsx
@@ -1,15 +1,41 @@
-import { useNavigate } from "react-router";
-import { ArrowLeft, Sparkles, Send, Eye, Check, Globe } from "lucide-react";
+import { useState } from "react";
+import { useNavigate, useParams } from "react-router";
+import { ArrowLeft, Sparkles, Send, Eye, Check, Globe, Database, Boxes } from "lucide-react";
import { toast } from "sonner";
import { Button } from "../components/ui/button";
import { Card } from "../components/ui/card";
import { AiBadge } from "../components/shared/common";
-import { sourcingRecords } from "../data/mock";
+import { sourcingRecords, projects } from "../data/mock";
+
+type SourceKey = "all" | "internet" | "srm" | "pool";
+
+const SOURCES: { key: SourceKey; label: string; icon: any; desc: string }[] = [
+ { key: "all", label: "全部来源", icon: Sparkles, desc: "AI 综合多渠道寻源" },
+ { key: "internet", label: "互联网寻源", icon: Globe, desc: "公共资源交易平台等" },
+ { key: "srm", label: "SRM 库寻源", icon: Database, desc: "集团合格供方库" },
+ { key: "pool", label: "临时供应商池", icon: Boxes, desc: "STP 平台临时池" },
+];
+
+// 依据记录派生来源(示例):按序分配到三类来源
+function sourceOf(index: number): Exclude {
+ return (["internet", "srm", "pool"] as const)[index % 3];
+}
+const SOURCE_LABEL: Record, string> = {
+ internet: "互联网",
+ srm: "SRM 库",
+ pool: "临时池",
+};
export function SmartSourcing() {
const navigate = useNavigate();
- const viewed = sourcingRecords.filter((r) => r.viewed).length;
- const registered = sourcingRecords.filter((r) => r.registered).length;
+ const { id } = useParams();
+ const project = projects.find((p) => p.id === id) ?? projects[0];
+ const [tab, setTab] = useState("all");
+
+ const records = sourcingRecords.map((r, i) => ({ ...r, source: sourceOf(i) }));
+ const filtered = tab === "all" ? records : records.filter((r) => r.source === tab);
+ const viewed = filtered.filter((r) => r.viewed).length;
+ const registered = filtered.filter((r) => r.registered).length;
return (
@@ -17,15 +43,50 @@ export function SmartSourcing() {
-
-
AI 智慧寻源结果
-
+
+
+ {/* 关联项目 */}
+
+ 关联项目:{project.name} · {project.code}
+
+ {/* 三类寻源来源 */}
+
+ {SOURCES.map((s) => {
+ const Icon = s.icon;
+ const active = tab === s.key;
+ const count = s.key === "all" ? records.length : records.filter((r) => r.source === s.key).length;
+ return (
+
+ );
+ })}
+
+
{[
- { l: "AI 外发邀请", v: sourcingRecords.length, c: "#2563eb" },
+ { l: "AI 外发邀请", v: filtered.length, c: "var(--primary)" },
{ l: "已查看回执", v: viewed, c: "#f59e0b" },
{ l: "已报名", v: registered, c: "#14b8a6" },
].map((s) => (
@@ -38,13 +99,17 @@ export function SmartSourcing() {
-
-
互联网平台主动外发邀请记录
+
+ 主动外发邀请记录
+
+ {SOURCES.find((s) => s.key === tab)?.label}
+
| 目标供应商 |
+ 寻源来源 |
外发渠道 |
外发时间 |
查看回执 |
@@ -53,9 +118,12 @@ export function SmartSourcing() {
- {sourcingRecords.map((r) => (
+ {filtered.map((r) => (
| {r.supplier} |
+
+ {SOURCE_LABEL[r.source]}
+ |
{r.channel} |
{r.sentAt} |
@@ -79,9 +147,9 @@ export function SmartSourcing() {
|
-
-
- 小滨已根据采购品类与历史成交,自动从全国公共资源交易平台等渠道匹配并外发邀请,未查看回执的供应商已为您高亮提醒。
+
+
+ 小滨已结合本项目采购品类与历史成交,从互联网平台、集团 SRM 合格供方库与 STP 临时供应商池三类来源综合寻源并外发邀请,未查看回执的供应商已为您高亮提醒。
);
diff --git a/front-end/src/app/pages/SupplierInbound.tsx b/front-end/src/app/pages/SupplierInbound.tsx
deleted file mode 100644
index 6425808..0000000
--- a/front-end/src/app/pages/SupplierInbound.tsx
+++ /dev/null
@@ -1,89 +0,0 @@
-import { useState } from "react";
-import { PackagePlus, Sparkles, ArrowRight, Check } from "lucide-react";
-import { toast } from "sonner";
-import { Button } from "../components/ui/button";
-import { Card } from "../components/ui/card";
-import { PageHeader, RiskBadge } from "../components/shared/common";
-import { suppliers } from "../data/mock";
-
-type Status = "待发起" | "审批中" | "已入库";
-
-export function SupplierInbound() {
- const [rows, setRows] = useState(
- suppliers.slice(0, 5).map((s, i) => ({
- ...s,
- inbound: (i === 0 ? "已入库" : i === 1 ? "审批中" : "待发起") as Status,
- })),
- );
-
- function advance(id: string) {
- setRows((r) =>
- r.map((x) =>
- x.id === id ? { ...x, inbound: x.inbound === "待发起" ? "审批中" : "已入库" } : x,
- ),
- );
- toast.success("已发起供应商入库流程,自动推送至 SRM 系统");
- }
-
- const statusColor: Record
= {
- 待发起: "bg-slate-100 text-slate-600",
- 审批中: "bg-amber-100 text-amber-700",
- 已入库: "bg-emerald-100 text-emerald-700",
- };
-
- return (
-
-
-
-
-
- 以下供应商来自定标后自动触发的入库清单,发起入库后系统将自动同步工商风险信息并推送至 SRM 系统。
-
-
-
-
-
-
- | 供应商名称 |
- 经营类别 |
- 风险等级 |
- 入库状态 |
- 操作 |
-
-
-
- {rows.map((s) => (
-
- | {s.name} |
- {s.category} |
-
-
- |
-
- {s.inbound}
- |
-
- {s.inbound === "待发起" && (
-
- )}
- {s.inbound === "审批中" && (
-
- )}
- {s.inbound === "已入库" && (
-
- 已同步 SRM
-
- )}
- |
-
- ))}
-
-
-
-
- );
-}
diff --git a/front-end/src/app/pages/SupplierManagement.tsx b/front-end/src/app/pages/SupplierManagement.tsx
index a9ea8e3..33efa1f 100644
--- a/front-end/src/app/pages/SupplierManagement.tsx
+++ b/front-end/src/app/pages/SupplierManagement.tsx
@@ -1,17 +1,13 @@
import { useState } from "react";
import {
- Plus,
Search,
Filter,
- PackagePlus,
Building2,
Phone,
Star,
Sparkles,
TrendingUp,
} from "lucide-react";
-import { toast } from "sonner";
-import { Button } from "../components/ui/button";
import { Card } from "../components/ui/card";
import {
Sheet,
@@ -42,17 +38,7 @@ export function SupplierManagement() {
-
-
-
- }
+ description="管理已注册供应商,资质审核通过后系统自动入库,工商风险信息由 AI 自动同步"
/>
diff --git a/front-end/src/app/pages/SupplierShortlist.tsx b/front-end/src/app/pages/SupplierShortlist.tsx
index 4119353..b936a11 100644
--- a/front-end/src/app/pages/SupplierShortlist.tsx
+++ b/front-end/src/app/pages/SupplierShortlist.tsx
@@ -1,36 +1,23 @@
import { useState } from "react";
import { useNavigate } from "react-router";
-import {
- ArrowLeft,
- Check,
- X,
- Trash2,
- PackagePlus,
- ChevronDown,
- Sparkles,
- FileCheck2,
- Loader2,
- Megaphone,
- Send,
-} from "lucide-react";
+import { ArrowLeft, Check, X, Trash2, PackagePlus } from "lucide-react";
import { toast } from "sonner";
import { Button } from "../components/ui/button";
import { Card } from "../components/ui/card";
-import { Tabs, TabsList, TabsTrigger, TabsContent } from "../components/ui/tabs";
-import {
- PageHeader,
- AiResultTag,
- RiskBadge,
- ApprovalTracker,
-} from "../components/shared/common";
+import { PageHeader } from "../components/shared/common";
import { suppliers } from "../data/mock";
+// 招标方式已在需求委托阶段确定,故本页不再区分"邀请/公开"分支,直接进行长短名单管理。
export function SupplierShortlist() {
const navigate = useNavigate();
+ const [longList, setLongList] = useState(
+ suppliers.map((s) => ({ ...s, decision: "" as "" | "pass" | "reject" })),
+ );
+ const shortList = longList.filter((s) => s.decision === "pass");
return (
-
+
@@ -40,154 +27,54 @@ export function SupplierShortlist() {
/>
-
-
- 邀请招标分支
- 公开招标分支
-
-
-
-
-
-
-
-
-
-
- );
-}
-
-/* ---------------- 邀请招标:长名单 / 短名单 ---------------- */
-function InviteBranch() {
- const [longList, setLongList] = useState(
- suppliers.map((s) => ({ ...s, decision: "" as "" | "pass" | "reject" })),
- );
- const shortList = longList.filter((s) => s.decision === "pass");
-
- return (
-
- {/* 长名单 */}
-
-
-
-
供应商长名单
-
- 共 {longList.length} 家
-
+
+ {/* 长名单 */}
+
+
+
+
供应商长名单
+
+ 共 {longList.length} 家
+
+
+
对供应商进行初步评审,确定是否进入短名单
- 对供应商进行初步评审,确定是否进入短名单
-
-
-
-
- | 供应商名称 |
- 联系人 |
- 推荐部门 |
- 初步评审意见 |
- 操作 |
-
-
-
- {longList.map((s, i) => (
-
- | {s.name} |
- {s.contact} |
- {s.dept} |
- {s.opinion} |
-
-
-
-
-
- |
-
- ))}
-
-
-
-
- {/* 短名单 */}
-
-
-
-
供应商短名单
-
- 已遴选 {shortList.length} 家
-
-
-
-
- {shortList.length === 0 ? (
-
-
- 请在上方长名单中点击「通过」,将供应商加入短名单
-
- ) : (
| 供应商名称 |
- 是否在合格供方库 |
- 最终评审结论 |
+ 联系人 |
+ 初步评审意见 |
操作 |
- {shortList.map((s) => (
+ {longList.map((s, i) => (
| {s.name} |
-
- {s.inLibrary ? (
-
- 库内
-
- ) : (
- 库外
- )}
- |
- {s.conclusion} |
+ {s.contact} |
+ {s.opinion} |
- {!s.inLibrary && (
-
- )}
+
|
@@ -195,175 +82,69 @@ function InviteBranch() {
))}
- )}
-
-
- );
-}
+
-/* ---------------- 公开招标:寻源公告 + 报名审核 ---------------- */
-function PublicBranch() {
- return (
-
-
-
-
- 公告审批状态
-
+ {/* 短名单 */}
+
+
+
+
供应商短名单
+
+ 已遴选 {shortList.length} 家
+
+
+
+
+ {shortList.length === 0 ? (
+
+
+ 请在上方长名单中点击「通过」,将供应商加入短名单
+
+ ) : (
+
+
+
+ | 供应商名称 |
+ 是否在合格供方库 |
+ 最终评审结论 |
+ 操作 |
+
+
+
+ {shortList.map((s) => (
+
+ | {s.name} |
+
+ {s.inLibrary ? (
+
+ 库内
+
+ ) : (
+ 库外(审核通过后自动入库)
+ )}
+ |
+ {s.conclusion} |
+
+
+ |
+
+ ))}
+
+
+ )}
);
}
-
-function AnnouncementEditor() {
- return (
-
-
-
寻源公告编辑
-
-
- {/* 富文本工具栏 */}
-
- {["B", "I", "U", "H1", "H2", "•", "1.", "🔗"].map((b) => (
-
- ))}
-
-
-
滨化集团厂区污水处理提标改造工程公开招标公告
-
- 滨化集团股份有限公司就「厂区污水处理提标改造工程」进行公开招标,欢迎符合条件的供应商参与报名。
-
-
一、项目概况
-
- 本工程对现有污水处理系统进行提标改造,出水水质须达到《城镇污水处理厂污染物排放标准》一级 A 标准,工期 180 日历天。
-
-
二、供应商资格要求
-
- 具有独立法人资格;具备环保工程专业承包二级及以上资质;近三年承担过同类污水处理工程业绩不少于 2 项。
-
-
三、报名时间
-
2026 年 6 月 25 日 至 2026 年 7 月 5 日(每日 9:00-17:00)。
-
-
-
-
-
-
- );
-}
-
-function RegistrationReview() {
- const applicants = suppliers.slice(0, 4);
- const [expanded, setExpanded] = useState
(applicants[0].id);
- const [approved, setApproved] = useState([]);
-
- return (
-
-
-
-
-
报名审核
-
- {applicants.length} 家报名
-
-
-
- 审核通过后自动进入「报名通过单位名单」(已通过 {approved.length} 家)
-
-
-
- {applicants.map((s) => {
- const open = expanded === s.id;
- const isApproved = approved.includes(s.id);
- return (
-
-
- {open && (
-
-
提交的资质文件
-
- {["营业执照.pdf", "环保工程资质证书.pdf", "近三年业绩证明.pdf"].map((f) => (
-
-
- {f}
-
- ))}
-
- {/* AI 审核结果 */}
-
-
- AI 辅助审核结果
-
-
- {s.aiResult === "资质有效"
- ? "资质文件齐全有效,工商信息正常,未发现关联投标及失信风险,建议通过。"
- : "检测到该供应商与其他报名单位存在股权关联,建议人工进一步核实后决定。"}
-
-
-
-
-
-
-
-
- )}
-
- );
- })}
-
-
- );
-}
diff --git a/front-end/src/app/pages/Workbench.tsx b/front-end/src/app/pages/Workbench.tsx
index a1a3bb4..70f5ed7 100644
--- a/front-end/src/app/pages/Workbench.tsx
+++ b/front-end/src/app/pages/Workbench.tsx
@@ -2,21 +2,20 @@ import { useNavigate } from "react-router";
import {
ChevronRight,
Sparkles,
- GitMerge,
+ Bot,
Activity,
ShieldAlert,
Network,
- TrendingUp,
Gavel,
- CheckCircle2,
- FileText,
+ FilePlus2,
} from "lucide-react";
import { Button } from "../components/ui/button";
import { Card } from "../components/ui/card";
import { AiBadge } from "../components/shared/common";
+import { AgentTaskMonitor } from "../components/AgentTaskMonitor";
import { useRole } from "../role-context";
import { WORKBENCH } from "../data/workbench";
-import { mergeCandidates, riskWarnings, bidProjects, approvals } from "../data/mock";
+import { riskWarnings, bidProjects } from "../data/mock";
const priorityStyle: Record = {
高: "bg-red-50 text-red-600",
@@ -69,7 +68,7 @@ export function Workbench() {
-
「事找人」待办中心
+ 待办中心
{totalTodo} 项
@@ -113,6 +112,13 @@ export function Workbench() {
{/* 角色专属附加区 */}
{wb.extra && }
+
+ {/* 后台智能体任务监控(招标专员 / 系统管理员) */}
+ {wb.agentMonitor && (
+
+ )}
);
}
@@ -124,24 +130,47 @@ function RoleExtra({ extra }: { extra: string }) {
return (
- 检测到 {mergeCandidates.length} 个同类型可合并委托,预计可节省采购周期 ~15 天。
+ 当前有 2 个后台智能体任务正在执行,详见下方「后台智能体任务」看板。
-
- {mergeCandidates.map((m) => (
-
-
{m.name}
-
重叠 {m.overlap}%
+
+ {[
+ { l: "🔍 AI 智慧寻源", v: "70%" },
+ { l: "🔬 AI 雷同检测", v: "30%" },
+ ].map((x) => (
+
+ {x.l}
+ {x.v}
))}
-
+
+ );
+ }
+
+ if (extra === "requester") {
+ return (
+
+
+
+ 用自然语言描述需求,AI 自动生成《招标委托书》,也可导入采购计划或选择模板。
+
+
+
+
+
);
}
@@ -176,29 +205,6 @@ function RoleExtra({ extra }: { extra: string }) {
);
}
- if (extra === "approver") {
- return (
-
- 最近待审批
-
- {approvals.slice(0, 3).map((a) => (
-
- ))}
-
-
- );
- }
-
if (extra === "admin") {
return (
diff --git a/front-end/src/app/pages/admin/ProcessConfig.tsx b/front-end/src/app/pages/admin/ProcessConfig.tsx
deleted file mode 100644
index f515814..0000000
--- a/front-end/src/app/pages/admin/ProcessConfig.tsx
+++ /dev/null
@@ -1,104 +0,0 @@
-import { Workflow, Plus, Settings, ArrowRight, History, RotateCcw } from "lucide-react";
-import { toast } from "sonner";
-import { Button } from "../../components/ui/button";
-import { Card } from "../../components/ui/card";
-import { PageHeader } from "../../components/shared/common";
-
-const nodes = [
- { name: "经办人提交", rule: "招标专员发起" },
- { name: "部门负责人", rule: "本部门负责人" },
- { name: "分管领导", rule: "金额 ≥ 500 万" },
- { name: "总经理审批", rule: "金额 ≥ 2000 万" },
-];
-
-const versions = [
- { v: "v3.2", date: "2026-06-01", status: "当前版本", by: "运维管理员" },
- { v: "v3.1", date: "2026-04-15", status: "历史", by: "运维管理员" },
- { v: "v3.0", date: "2026-01-10", status: "历史", by: "运维管理员" },
-];
-
-export function ProcessConfig() {
- return (
-
-
toast.success("已发布新流程版本")}>发布流程
- }
- />
-
-
-
-
-
-
-
定标审批流程(可视化编辑)
-
-
-
-
-
- {nodes.map((n, i) => (
-
-
-
- {n.name}
-
-
-
{n.rule}
-
- {i < nodes.length - 1 &&
}
-
- ))}
-
-
-
-
审批人规则(按金额自动匹配)
-
- {[
- ["金额 < 500 万", "部门负责人审批"],
- ["500 万 ≤ 金额 < 2000 万", "部门负责人 + 分管领导"],
- ["金额 ≥ 2000 万", "部门负责人 + 分管领导 + 总经理"],
- ].map(([cond, route]) => (
-
- {cond}
- {route}
-
- ))}
-
-
-
-
-
-
-
-
流程版本管理
-
-
- {versions.map((v) => (
-
-
-
- {v.v}
- {v.status === "当前版本" && (
- {v.status}
- )}
-
-
{v.date} · {v.by}
-
- {v.status !== "当前版本" && (
-
- )}
-
- ))}
-
-
-
-
- );
-}
diff --git a/front-end/src/app/roles.ts b/front-end/src/app/roles.ts
index 09a656b..a6ed1a4 100644
--- a/front-end/src/app/roles.ts
+++ b/front-end/src/app/roles.ts
@@ -1,12 +1,16 @@
-// 滨化集团智慧招标平台 (STP) - 多角色配置 V1.3
+// 滨化集团智慧招标平台 (STP) - 多角色配置 V1.4
+// 说明:依据内部评审意见调整——
+// 1)统一科技蓝主题(呼应滨化 LOGO);
+// 2)合并"需求部门人员/采购专员"为"采购需求人员";
+// 3)移除"审批人"(审批在 OA 中体现);
+// 4)发起招标委托归属"采购需求人员",招标专员不含该功能;
+// 5)移除合并招标、供应商入库、合同管理、审批中心、流程配置等入口。
export type RoleId =
| "requester"
| "specialist"
- | "purchaser"
| "expert"
| "committee"
- | "approver"
| "supplier"
| "admin"
| "auditor";
@@ -23,24 +27,31 @@ export interface RoleConfig {
name: string; // 角色名
user: string; // 示例用户/企业名
dept: string;
- color: string; // 辅助色
+ color: string; // 辅助色(统一科技蓝)
bannerFrom: string;
bannerTo: string;
nav: NavItem[];
}
+// 全平台统一科技蓝
+const BRAND_FROM = "#0d47a1";
+const BRAND_TO = "#1e88e5";
+const BRAND_DOT = "#1565c0";
+
export const ROLES: Record = {
requester: {
id: "requester",
- name: "需求部门人员",
+ name: "采购需求人员",
user: "刘晓敏",
- dept: "氯碱生产部",
- color: "#0ea5e9",
- bannerFrom: "#0c4a6e",
- bannerTo: "#0ea5e9",
+ dept: "氯碱生产部 / 采购供应部",
+ color: BRAND_DOT,
+ bannerFrom: BRAND_FROM,
+ bannerTo: BRAND_TO,
nav: [
{ to: "/app", label: "工作台", icon: "LayoutDashboard", end: true },
+ { to: "/app/delegation", label: "发起委托", icon: "FilePlus2" },
{ to: "/app/projects", label: "我的项目", icon: "FolderKanban" },
+ { to: "/app/deposits", label: "保证金管理", icon: "Wallet" },
],
},
specialist: {
@@ -48,43 +59,26 @@ export const ROLES: Record = {
name: "招标专员",
user: "张伟",
dept: "招标采购中心",
- color: "#00695c",
- bannerFrom: "#00695c",
- bannerTo: "#00897b",
+ color: BRAND_DOT,
+ bannerFrom: BRAND_FROM,
+ bannerTo: BRAND_TO,
nav: [
{ to: "/app", label: "工作台", icon: "LayoutDashboard", end: true },
{ to: "/app/projects", label: "项目管理", icon: "FolderKanban" },
- { to: "/app/merge", label: "合并招标", icon: "GitMerge" },
{ to: "/app/suppliers", label: "供应商管理", icon: "Building2" },
{ to: "/app/experts", label: "专家管理", icon: "UserCog" },
{ to: "/app/deposits", label: "保证金管理", icon: "Wallet" },
{ to: "/app/reports", label: "报表中心", icon: "BarChart3" },
],
},
- purchaser: {
- id: "purchaser",
- name: "采购专员",
- user: "陈晨",
- dept: "采购供应部",
- color: "#6366f1",
- bannerFrom: "#312e81",
- bannerTo: "#6366f1",
- nav: [
- { to: "/app", label: "工作台", icon: "LayoutDashboard", end: true },
- { to: "/app/projects", label: "我的项目", icon: "FolderKanban" },
- { to: "/app/contracts", label: "合同管理", icon: "FileSignature" },
- { to: "/app/inbound", label: "供应商入库", icon: "PackagePlus" },
- { to: "/app/deposits", label: "保证金管理", icon: "Wallet" },
- ],
- },
expert: {
id: "expert",
name: "评标专家",
user: "郑国华",
dept: "外部专家 · 化工工艺",
- color: "#1565c0",
- bannerFrom: "#0d47a1",
- bannerTo: "#1976d2",
+ color: BRAND_DOT,
+ bannerFrom: BRAND_FROM,
+ bannerTo: BRAND_TO,
nav: [
{ to: "/app", label: "工作台", icon: "LayoutDashboard", end: true },
{ to: "/app/expert-tasks", label: "评标任务", icon: "Gavel" },
@@ -95,35 +89,22 @@ export const ROLES: Record = {
name: "评标委员会工作领导小组",
user: "孙建华",
dept: "评标委员会",
- color: "#dc2626",
- bannerFrom: "#7f1d1d",
- bannerTo: "#dc2626",
+ color: BRAND_DOT,
+ bannerFrom: BRAND_FROM,
+ bannerTo: BRAND_TO,
nav: [
{ to: "/app", label: "工作台", icon: "LayoutDashboard", end: true },
{ to: "/app/exceptions", label: "异常决策", icon: "ShieldAlert" },
],
},
- approver: {
- id: "approver",
- name: "审批人",
- user: "王立强",
- dept: "分管副总",
- color: "#10b981",
- bannerFrom: "#064e3b",
- bannerTo: "#10b981",
- nav: [
- { to: "/app", label: "工作台", icon: "LayoutDashboard", end: true },
- { to: "/app/approvals", label: "待审批", icon: "ClipboardCheck" },
- ],
- },
supplier: {
id: "supplier",
name: "供应商",
user: "浙江中控技术股份有限公司",
dept: "投标用户",
- color: "#c2185b",
- bannerFrom: "#c2185b",
- bannerTo: "#e91e63",
+ color: BRAND_DOT,
+ bannerFrom: BRAND_FROM,
+ bannerTo: BRAND_TO,
nav: [
{ to: "/app", label: "工作台", icon: "LayoutDashboard", end: true },
{ to: "/app/bidding", label: "投标中心", icon: "PackageOpen" },
@@ -134,13 +115,12 @@ export const ROLES: Record = {
name: "系统管理员",
user: "运维管理员",
dept: "信息中心",
- color: "#475569",
- bannerFrom: "#1e293b",
- bannerTo: "#475569",
+ color: BRAND_DOT,
+ bannerFrom: BRAND_FROM,
+ bannerTo: BRAND_TO,
nav: [
{ to: "/app", label: "工作台", icon: "LayoutDashboard", end: true },
{ to: "/app/admin/users", label: "用户与权限", icon: "Users" },
- { to: "/app/admin/process", label: "流程配置", icon: "Workflow" },
{ to: "/app/admin/keys", label: "密钥管理", icon: "KeyRound" },
{ to: "/app/suppliers", label: "供应商管理", icon: "Building2" },
{ to: "/app/experts", label: "专家管理", icon: "UserCog" },
@@ -153,9 +133,9 @@ export const ROLES: Record = {
name: "合规 / 审计",
user: "李审计",
dept: "审计监察部",
- color: "#0d9488",
- bannerFrom: "#134e4a",
- bannerTo: "#0d9488",
+ color: BRAND_DOT,
+ bannerFrom: BRAND_FROM,
+ bannerTo: BRAND_TO,
nav: [
{ to: "/app", label: "工作台", icon: "LayoutDashboard", end: true },
{ to: "/app/audit-logs", label: "审计日志", icon: "ScrollText" },
@@ -169,10 +149,8 @@ export const ROLES: Record = {
export const ROLE_ORDER: RoleId[] = [
"specialist",
"requester",
- "purchaser",
"expert",
"committee",
- "approver",
"supplier",
"admin",
"auditor",
diff --git a/front-end/src/styles/theme.css b/front-end/src/styles/theme.css
index 49d0401..2b33a38 100644
--- a/front-end/src/styles/theme.css
+++ b/front-end/src/styles/theme.css
@@ -8,14 +8,14 @@
--card-foreground: #1a2332;
--popover: #ffffff;
--popover-foreground: #1a2332;
- --primary: #c2185b;
+ --primary: #1565c0;
--primary-foreground: #ffffff;
- --secondary: #fce4ec;
- --secondary-foreground: #ad1457;
+ --secondary: #e3f2fd;
+ --secondary-foreground: #0d47a1;
--muted: #f1f5f9;
--muted-foreground: #64748b;
- --accent: #fce4ec;
- --accent-foreground: #ad1457;
+ --accent: #e3f2fd;
+ --accent-foreground: #0d47a1;
--destructive: #dc2626;
--destructive-foreground: #ffffff;
--border: #e2e8f0;
@@ -24,24 +24,24 @@
--switch-background: #cbd5e1;
--font-weight-medium: 500;
--font-weight-normal: 400;
- --ring: #c2185b;
- --chart-1: #c2185b;
- --chart-2: #1565c0;
- --chart-3: #00897b;
- --chart-4: #f59e0b;
- --chart-5: #9c27b0;
+ --ring: #1565c0;
+ --chart-1: #1565c0;
+ --chart-2: #00897b;
+ --chart-3: #f59e0b;
+ --chart-4: #7e57c2;
+ --chart-5: #ef5350;
--radius: 0.75rem;
- /* 品牌渐变(全平台统一): #c2185b → #e91e63 */
- --brand-from: #c2185b;
- --brand-to: #e91e63;
- --sidebar: #2d0a19;
- --sidebar-foreground: #f4d9e4;
- --sidebar-primary: #e91e63;
+ /* 品牌渐变(全平台统一科技蓝,呼应滨化 LOGO): #0d47a1 → #1e88e5 */
+ --brand-from: #0d47a1;
+ --brand-to: #1e88e5;
+ --sidebar: #0d2137;
+ --sidebar-foreground: #d6e4f5;
+ --sidebar-primary: #1e88e5;
--sidebar-primary-foreground: #ffffff;
- --sidebar-accent: #6d1338;
+ --sidebar-accent: #16375a;
--sidebar-accent-foreground: #ffffff;
- --sidebar-border: #4a0e26;
- --sidebar-ring: #e91e63;
+ --sidebar-border: #16375a;
+ --sidebar-ring: #1e88e5;
}
.dark {