feat(front-end): 初始化STP前端工程并提交页面框架
引入前端项目基础结构、页面骨架和UI组件,建立可运行的开发与构建配置,方便后续按模块迭代。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
import { useNavigate } from "react-router";
|
||||
import { ArrowLeft, Sparkles, Trophy, ThumbsUp, RotateCcw, FileText } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { Button } from "../components/ui/button";
|
||||
import { Card } from "../components/ui/card";
|
||||
import { AiBadge, ApprovalTracker } from "../components/shared/common";
|
||||
|
||||
const ranking = [
|
||||
{ rank: 1, name: "供应商 A(浙江中控技术)", tech: 56, biz: 18, price: 28, total: 102, reason: "技术方案最优,冗余架构与本地化服务承诺突出,综合得分第一。" },
|
||||
{ rank: 2, name: "供应商 B(和利时科技)", tech: 52, biz: 17, price: 30, total: 99, reason: "报价最具竞争力,技术方案满足要求,略逊于第一名。" },
|
||||
{ rank: 3, name: "供应商 C(西门子中国)", tech: 54, biz: 16, price: 24, total: 94, reason: "品牌与性能优秀,但报价偏高,价格分较低。" },
|
||||
];
|
||||
|
||||
export function AwardApproval() {
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<div>
|
||||
<div className="mb-1 flex items-center gap-3">
|
||||
<Button variant="ghost" size="icon" onClick={() => navigate(-1)}>
|
||||
<ArrowLeft className="size-5" />
|
||||
</Button>
|
||||
<div>
|
||||
<h1 className="text-foreground">定标审批</h1>
|
||||
<p className="text-sm text-muted-foreground">环氧丙烷装置大修工程 · 评标报告审批</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-5 grid grid-cols-3 gap-6">
|
||||
<div className="col-span-2 space-y-6">
|
||||
{/* 评标报告 */}
|
||||
<Card className="gap-0 p-6">
|
||||
<div className="mb-4 flex items-center gap-2">
|
||||
<FileText className="size-5 text-primary" />
|
||||
<h3 className="text-foreground">评标报告</h3>
|
||||
<AiBadge label="AI 汇总" />
|
||||
</div>
|
||||
|
||||
{/* AI 评标汇总表 */}
|
||||
<div className="overflow-hidden rounded-lg border">
|
||||
<table className="w-full text-sm">
|
||||
<thead>
|
||||
<tr className="bg-muted/40 text-left text-muted-foreground">
|
||||
<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>
|
||||
<th className="px-4 py-3 font-medium">价格分</th>
|
||||
<th className="px-4 py-3 font-medium">总分</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y">
|
||||
{ranking.map((r) => (
|
||||
<tr key={r.rank} className={r.rank === 1 ? "bg-amber-50/50" : ""}>
|
||||
<td className="px-4 py-3">
|
||||
{r.rank === 1 ? (
|
||||
<span className="inline-flex items-center gap-1 font-medium text-amber-600">
|
||||
<Trophy className="size-4" /> 第 1 名
|
||||
</span>
|
||||
) : (
|
||||
<span className="text-muted-foreground">第 {r.rank} 名</span>
|
||||
)}
|
||||
</td>
|
||||
<td className="px-4 py-3 font-medium text-foreground">{r.name}</td>
|
||||
<td className="px-4 py-3 text-muted-foreground">{r.tech}</td>
|
||||
<td className="px-4 py-3 text-muted-foreground">{r.biz}</td>
|
||||
<td className="px-4 py-3 text-muted-foreground">{r.price}</td>
|
||||
<td className="px-4 py-3 font-semibold text-foreground">{r.total}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{/* 中标候选人排名及理由 */}
|
||||
<div className="mt-5">
|
||||
<h4 className="mb-3 text-foreground">中标候选人排名及理由</h4>
|
||||
<div className="space-y-3">
|
||||
{ranking.map((r) => (
|
||||
<div key={r.rank} className="flex gap-3 rounded-lg border bg-card p-4">
|
||||
<div
|
||||
className={`flex size-8 shrink-0 items-center justify-center rounded-full text-sm font-semibold ${
|
||||
r.rank === 1 ? "bg-amber-100 text-amber-700" : "bg-muted text-muted-foreground"
|
||||
}`}
|
||||
>
|
||||
{r.rank}
|
||||
</div>
|
||||
<div>
|
||||
<div className="font-medium text-foreground">{r.name}</div>
|
||||
<p className="mt-1 text-sm text-muted-foreground">
|
||||
<Sparkles className="mr-1 inline size-3.5 text-violet-500" />
|
||||
{r.reason}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* 审批决策 */}
|
||||
<Card className="gap-0 p-6">
|
||||
<h3 className="text-foreground">审批决策</h3>
|
||||
<div className="mt-3 rounded-lg bg-primary/5 p-4 text-sm">
|
||||
评标委员会推荐 <span className="font-semibold text-primary">供应商 A(浙江中控技术)</span> 为第一中标候选人,建议授予中标。
|
||||
</div>
|
||||
<label className="mb-1.5 mt-4 block text-sm">审批意见</label>
|
||||
<textarea
|
||||
rows={3}
|
||||
placeholder="请填写您的审批意见…"
|
||||
className="w-full resize-none rounded-lg border bg-input-background p-3 text-sm outline-none focus:border-primary"
|
||||
/>
|
||||
<div className="mt-4 flex gap-3">
|
||||
<Button
|
||||
className="flex-1"
|
||||
onClick={() => {
|
||||
toast.success("已同意推荐中标人,进入合同生成阶段");
|
||||
setTimeout(() => navigate("/app/projects/P2026003/contract"), 800);
|
||||
}}
|
||||
>
|
||||
<ThumbsUp className="size-4" /> 同意推荐中标人
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="flex-1 text-destructive"
|
||||
onClick={() => toast.error("已驳回,项目将重新评标")}
|
||||
>
|
||||
<RotateCcw className="size-4" /> 驳回重评
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<Card className="gap-0 p-6">
|
||||
<h4 className="mb-4 text-foreground">审批流程跟踪</h4>
|
||||
<ApprovalTracker
|
||||
nodes={[
|
||||
{ role: "评标委员会", name: "完成评标并出具报告", status: "completed", time: "06-20 16:00" },
|
||||
{ role: "招标专员复核", name: "王强 · 已复核", status: "completed", time: "06-21 09:30" },
|
||||
{ role: "分管领导审批", name: "分管副总 · 审批中", status: "current" },
|
||||
{ role: "定标完成", name: "发出中标通知书", status: "pending" },
|
||||
]}
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user