feat(frontend): 对齐万华门户风格并更新全量截图文档
- 新增门户导航子页面(交易信息、政策法规、操作指南、常见问题、采购平台)并统一门户壳层样式 - 按万华站点风格重构首页与登录页(导航、轮播、公告、登录区) - 优化小滨助手:首页/登录页接入、可拖拽吸边、圆形图标、圆形外框与切换动画优化 - 重新生成全量页面截图并更新《滨化智慧招标平台-前端界面截图汇总.docx》 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,224 +1,221 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { Link, useNavigate } from "react-router";
|
||||
import { Hexagon, ArrowRight, Sparkles, Bot } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { useNavigate } from "react-router";
|
||||
import { UserRound, Building2, Briefcase, Users } from "lucide-react";
|
||||
import { cn } from "../components/ui/utils";
|
||||
import { PortalShell } from "./portal/PortalShell";
|
||||
import { XiaobinAssistant } from "../components/XiaobinAssistant";
|
||||
|
||||
const NAV = ["首页", "招标公告", "定标公告", "企业新闻"];
|
||||
type Notice = { title: string; date: string };
|
||||
|
||||
const ROLES = [
|
||||
{ key: "purchaser", label: "采购人", en: "Purchaser", icon: Building2 },
|
||||
{ key: "supplier", label: "供应商", en: "Supplier", icon: Briefcase },
|
||||
{ key: "expert", label: "专家", en: "Expert", icon: UserRound },
|
||||
{ key: "other", label: "其他", en: "Other", icon: Users },
|
||||
];
|
||||
const NOTICE_TABS = ["招标公告", "资格预审公告", "中标候选人公示", "结果公告", "终止公告"];
|
||||
const BANNERS = [
|
||||
{
|
||||
title: "AI 赋能的智慧招标",
|
||||
subtitle: "全流程线上闭环,主动智能寻源,自动风险评估",
|
||||
tags: ["智能招标委托", "供应商 AI 寻源", "自动化评标辅助"],
|
||||
title: "廉洁过节",
|
||||
subtitle: "阳光招采 · 公开透明 · 全流程可追溯",
|
||||
style: "from-[#1f4d8f] via-[#2e6dc2] to-[#5c8fe0]",
|
||||
},
|
||||
{
|
||||
title: "一次注册,双平台通用",
|
||||
subtitle: "自动同步 SRM,建立统一供应商身份,秒级 AI 审核即时生效",
|
||||
tags: ["营业执照 OCR", "工商实时验真", "SRM 无感登录"],
|
||||
title: "上线试运行",
|
||||
subtitle: "智慧招标平台已上线,欢迎采购人、供应商、专家使用",
|
||||
style: "from-[#0d5f89] via-[#0f7da8] to-[#4ba6c9]",
|
||||
},
|
||||
{
|
||||
title: "阳光招采,全程存证",
|
||||
subtitle: "投标文件加密上链,评审操作哈希存证,围串标智能预警",
|
||||
tags: ["链上存证", "盲评脱敏", "AI 雷同检测"],
|
||||
title: "轮播图片2",
|
||||
subtitle: "统一门户、统一身份、统一公告发布",
|
||||
style: "from-[#2f5f3f] via-[#3b8460] to-[#66a37f]",
|
||||
},
|
||||
];
|
||||
|
||||
const TENDERS = [
|
||||
{ title: "年产5万吨聚丙烯项目设备采购", meta: "2026-07-01 | 货物", status: "报名中", color: "#2e7d32", dot: "#4caf50" },
|
||||
{ title: "数字化交付平台开发服务", meta: "2026-06-29 | 服务", status: "即将截止", color: "#e65100", dot: "#ff9800" },
|
||||
{ title: "2026年度防腐保温工程框架", meta: "2026-06-28 | 工程", status: "已截止", color: "#9e9e9e", dot: "#bdbdbd" },
|
||||
];
|
||||
const NOTICE_DATA: Record<string, Notice[]> = {
|
||||
招标公告: [
|
||||
{ title: "[公开招标] 2026年地脚螺栓、不锈钢及五金紧固件框架招标", date: "2026-07-13" },
|
||||
{ title: "[公开招标] 万华莱州100MW分散式风电项目EPC工程总承包[变更公告]", date: "2026-07-13" },
|
||||
{ title: "[公开招标] 2026年橡胶密封件框架招标O型圈", date: "2026-07-13" },
|
||||
{ title: "[公开招标] 万华旋塞阀框架包一 金属旋塞阀、包二 衬氟旋塞阀", date: "2026-07-10" },
|
||||
{ title: "[公开招标] 改性TPU熟化料仓", date: "2026-07-09" },
|
||||
],
|
||||
资格预审公告: [
|
||||
{ title: "滨州园区危化品运输服务资格预审公告", date: "2026-07-11" },
|
||||
{ title: "公辅系统维保服务资格预审公告", date: "2026-07-10" },
|
||||
{ title: "智慧园区网络安全服务资格预审公告", date: "2026-07-08" },
|
||||
],
|
||||
中标候选人公示: [
|
||||
{ title: "[公开招标] 牵引车租赁服务框架中标候选人公示", date: "2026-07-07" },
|
||||
{ title: "[公开招标] 电池材料项目地质勘察工程中标候选人公示", date: "2026-07-06" },
|
||||
{ title: "[公开招标] 四轮防爆巡检机器人系统中标候选人公示", date: "2026-06-26" },
|
||||
],
|
||||
结果公告: [
|
||||
{ title: "[公开招标] HDPE管道管件框架招标中标结果公告", date: "2026-07-07" },
|
||||
{ title: "[公开招标] 万华起重框架招标包一 单梁起重机中标结果公告", date: "2026-07-02" },
|
||||
{ title: "[公开招标] 万华海阳绿电直连光伏组件项目中标结果公告", date: "2026-06-30" },
|
||||
],
|
||||
终止公告: [
|
||||
{ title: "国标切断双偏心蝶阀框架招标废标公告", date: "2026-07-06" },
|
||||
{ title: "TPU四期熟化料仓招标废标公告", date: "2026-07-01" },
|
||||
{ title: "万华滨州碳酸锂项目冷却窑废标公告", date: "2026-06-24" },
|
||||
],
|
||||
};
|
||||
|
||||
const AWARDS = [
|
||||
{ title: "催化剂采购项目(包1)", meta: "2026-07-01 | 中标方:滨化催化剂有限公司" },
|
||||
{ title: "厂区安防监控升级项目", meta: "2026-06-30 | 中标方:海康威视" },
|
||||
{ title: "办公楼装修工程", meta: "2026-06-28 | 中标方:滨州建工集团" },
|
||||
];
|
||||
|
||||
const NEWS = [
|
||||
{ title: "滨化集团获评“省级智能工厂”", meta: "2026-07-01 | 集团动态" },
|
||||
{ title: "2026 年供应商大会圆满举办", meta: "2026-06-25 | 合作伙伴" },
|
||||
{ title: "智慧招标平台正式上线运营", meta: "2026-06-01 | 平台公告" },
|
||||
];
|
||||
|
||||
function AnnouncementCard({
|
||||
title,
|
||||
tag,
|
||||
headerColor,
|
||||
items,
|
||||
moreBg,
|
||||
moreText,
|
||||
}: {
|
||||
title: string;
|
||||
tag: string;
|
||||
headerColor: string;
|
||||
items: { title: string; meta: string; status?: string; color?: string; dot?: string }[];
|
||||
moreBg: string;
|
||||
moreText: string;
|
||||
}) {
|
||||
function NoticeList({ items }: { items: Notice[] }) {
|
||||
return (
|
||||
<div className="flex flex-col overflow-hidden rounded-2xl bg-white shadow-[0_4px_16px_rgba(0,0,0,0.06)]">
|
||||
<div className="px-5 py-3 text-white" style={{ backgroundColor: headerColor }}>
|
||||
<div className="text-base font-bold">{title}</div>
|
||||
<div className="text-[11px] text-white/80">{tag}</div>
|
||||
</div>
|
||||
<div className="flex-1 space-y-2 p-4">
|
||||
{items.map((it) => (
|
||||
<div key={it.title} className="cursor-pointer rounded-lg bg-[#fafafa] px-3 py-2.5 transition-colors hover:bg-[#f0f2f7]">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<span className="truncate text-sm text-[#1a2332]">{it.title}</span>
|
||||
{it.status && (
|
||||
<span className="flex shrink-0 items-center gap-1 text-xs" style={{ color: it.color }}>
|
||||
<span className="size-1.5 rounded-full" style={{ backgroundColor: it.dot }} />
|
||||
{it.status}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-1 text-xs text-[#8895aa]">{it.meta}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="px-4 pb-4">
|
||||
<button
|
||||
className="w-full rounded-full py-1.5 text-xs font-bold transition-opacity hover:opacity-80"
|
||||
style={{ backgroundColor: moreBg, color: moreText }}
|
||||
<ul className="space-y-1.5">
|
||||
{items.map((item) => (
|
||||
<li
|
||||
key={item.title}
|
||||
className="flex items-center gap-3 border-b border-dashed border-[#e5e7eb] py-1.5 text-sm"
|
||||
>
|
||||
查看全部 →
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<span className="line-clamp-1 flex-1 text-[#1f2937] hover:text-primary">{item.title}</span>
|
||||
<span className="shrink-0 text-xs text-[#6b7280]">{item.date}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
export function PortalHome() {
|
||||
const navigate = useNavigate();
|
||||
const [banner, setBanner] = useState(0);
|
||||
const [activeNav, setActiveNav] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const t = setInterval(() => setBanner((b) => (b + 1) % BANNERS.length), 5000);
|
||||
return () => clearInterval(t);
|
||||
}, []);
|
||||
|
||||
const b = BANNERS[banner];
|
||||
const [activeTab, setActiveTab] = useState(NOTICE_TABS[0]);
|
||||
const [activeBanner, setActiveBanner] = useState(0);
|
||||
const banner = BANNERS[activeBanner];
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-[#f5f7fa]">
|
||||
{/* 顶部导航 */}
|
||||
<header className="sticky top-0 z-30 bg-brand-gradient shadow-sm">
|
||||
<div className="mx-auto flex h-[68px] max-w-[1200px] items-center px-8">
|
||||
<Link to="/portal" className="flex items-baseline gap-2 text-white">
|
||||
<Hexagon className="size-6 self-center" />
|
||||
<span className="text-xl font-bold">智慧招标平台</span>
|
||||
<span className="hidden text-xs text-white/70 sm:inline">Smart Tendering Platform</span>
|
||||
</Link>
|
||||
<nav className="ml-12 hidden gap-1 md:flex">
|
||||
{NAV.map((n, i) => (
|
||||
<button
|
||||
key={n}
|
||||
onClick={() => setActiveNav(i)}
|
||||
className={cn(
|
||||
"group relative px-4 py-2 text-sm text-white/80 transition-colors hover:text-white",
|
||||
activeNav === i && "font-bold text-white",
|
||||
)}
|
||||
>
|
||||
{n}
|
||||
<span
|
||||
className={cn(
|
||||
"absolute inset-x-4 -bottom-0.5 h-0.5 rounded-full bg-white transition-all",
|
||||
activeNav === i ? "opacity-100" : "opacity-0 group-hover:opacity-60",
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
))}
|
||||
</nav>
|
||||
<div className="ml-auto flex items-center gap-3">
|
||||
<button
|
||||
onClick={() => navigate("/")}
|
||||
className="rounded-lg border border-white/60 px-4 py-1.5 text-sm text-white transition-colors hover:bg-white/15"
|
||||
>
|
||||
登录
|
||||
</button>
|
||||
<button
|
||||
onClick={() => navigate("/register")}
|
||||
className="rounded-lg bg-white px-4 py-1.5 text-sm font-bold text-primary transition-transform hover:-translate-y-0.5"
|
||||
>
|
||||
注册
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main className="mx-auto max-w-[1200px] px-8 pb-16">
|
||||
{/* Banner 轮播 */}
|
||||
<section className="relative mt-6 overflow-hidden rounded-2xl bg-gradient-to-br from-[#fce4ec] to-[#f3e5f5] shadow-[0_6px_24px_rgba(0,0,0,0.08)]">
|
||||
<div className="flex min-h-[280px] flex-col justify-center px-12 py-10">
|
||||
<div className="mb-3 inline-flex w-fit items-center gap-1.5 rounded-full bg-white/70 px-3 py-1 text-xs text-primary">
|
||||
<Sparkles className="size-3.5" /> AI 原生 · 全流程线上闭环
|
||||
<PortalShell active="home">
|
||||
<section className="grid grid-cols-12 gap-4">
|
||||
<div className="col-span-12 border bg-white lg:col-span-3">
|
||||
<div className="border-b bg-[#f8fafc] px-4 py-3">
|
||||
<h2 className="text-base font-semibold">用户登录</h2>
|
||||
<p className="mt-1 text-xs text-[#6b7280]">
|
||||
还没有账号,<button onClick={() => navigate("/register")} className="text-primary hover:underline">去注册</button>
|
||||
</p>
|
||||
</div>
|
||||
<h1 key={banner} className="animate-slide-up text-primary" style={{ fontSize: 34, fontWeight: 700 }}>
|
||||
{b.title}
|
||||
</h1>
|
||||
<p className="mt-3 text-lg text-[#4a5568]">{b.subtitle}</p>
|
||||
<div className="mt-3 flex flex-wrap gap-x-5 gap-y-1 text-sm text-[#8895aa]">
|
||||
{b.tags.map((t) => (
|
||||
<span key={t}>• {t}</span>
|
||||
<div className="grid grid-cols-2 gap-2 p-4">
|
||||
{ROLES.map((r) => {
|
||||
const Icon = r.icon;
|
||||
return (
|
||||
<button
|
||||
key={r.key}
|
||||
onClick={() => navigate("/")}
|
||||
className="flex flex-col items-center justify-center border border-[#d9dee7] px-3 py-3.5 text-center hover:border-primary hover:bg-[#f8fbff]"
|
||||
>
|
||||
<Icon className="size-5 text-primary" />
|
||||
<span className="mt-2 text-sm">{r.label}</span>
|
||||
<span className="text-[11px] text-[#6b7280]">{r.en}</span>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className="space-y-3 px-4 pb-4">
|
||||
<input
|
||||
placeholder="账号 / 手机号"
|
||||
className="h-9 w-full border border-[#d9dee7] bg-white px-3 text-sm outline-none focus:border-primary"
|
||||
/>
|
||||
<input
|
||||
type="password"
|
||||
placeholder="密码"
|
||||
className="h-9 w-full border border-[#d9dee7] bg-white px-3 text-sm outline-none focus:border-primary"
|
||||
/>
|
||||
<button
|
||||
onClick={() => navigate("/")}
|
||||
className="h-9 w-full bg-primary text-sm font-medium text-white hover:bg-[#0f4ea6]"
|
||||
>
|
||||
登录
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-span-12 border bg-white lg:col-span-9">
|
||||
<div className="relative h-[310px] overflow-hidden">
|
||||
<div className={cn("absolute inset-0 bg-gradient-to-br", banner.style)} />
|
||||
<div className="absolute inset-0 bg-black/20" />
|
||||
<div className="relative flex h-full flex-col justify-end p-7 text-white">
|
||||
<div className="text-3xl font-bold tracking-wide">{banner.title}</div>
|
||||
<div className="mt-2 text-sm text-white/90">{banner.subtitle}</div>
|
||||
</div>
|
||||
<div className="absolute left-5 top-5 rounded bg-black/35 px-2 py-1 text-xs text-white/90">
|
||||
首页轮播
|
||||
</div>
|
||||
<div className="absolute bottom-4 right-5 flex gap-2">
|
||||
{BANNERS.map((b, idx) => (
|
||||
<button
|
||||
key={b.title}
|
||||
onClick={() => setActiveBanner(idx)}
|
||||
className={cn(
|
||||
"rounded px-2.5 py-1 text-xs",
|
||||
idx === activeBanner ? "bg-white text-[#1f2937]" : "bg-black/35 text-white",
|
||||
)}
|
||||
>
|
||||
{b.title}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="border bg-white">
|
||||
<div className="border-b bg-[#f8fafc] px-4 py-3">
|
||||
<h2 className="text-base font-semibold">交易信息</h2>
|
||||
</div>
|
||||
<div className="border-b px-3">
|
||||
<div className="flex flex-wrap items-center">
|
||||
{NOTICE_TABS.map((tab) => (
|
||||
<button
|
||||
key={tab}
|
||||
onClick={() => setActiveTab(tab)}
|
||||
className={cn(
|
||||
"relative px-4 py-3 text-sm",
|
||||
activeTab === tab ? "font-semibold text-primary" : "text-[#4b5563] hover:text-primary",
|
||||
)}
|
||||
>
|
||||
{tab}
|
||||
{activeTab === tab && <span className="absolute inset-x-2 bottom-0 h-0.5 bg-primary" />}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<button
|
||||
onClick={() => navigate("/register")}
|
||||
className="mt-6 inline-flex w-fit items-center gap-1.5 rounded-lg bg-brand-gradient px-6 py-2.5 text-sm font-bold text-white shadow-md transition-transform hover:scale-105"
|
||||
>
|
||||
了解更多 <ArrowRight className="size-4" />
|
||||
</button>
|
||||
</div>
|
||||
{/* 指示器 */}
|
||||
<div className="absolute bottom-6 right-12 flex gap-2">
|
||||
{BANNERS.map((_, i) => (
|
||||
<button
|
||||
key={i}
|
||||
aria-label={`切换到第 ${i + 1} 张`}
|
||||
onClick={() => setBanner(i)}
|
||||
className={cn("h-2 rounded-full transition-all", i === banner ? "w-6 bg-primary" : "w-2 bg-[#d1d5db]")}
|
||||
<div className="p-4">
|
||||
<NoticeList items={NOTICE_DATA[activeTab]} />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="grid grid-cols-12 gap-4">
|
||||
<div className="col-span-12 border bg-white lg:col-span-6">
|
||||
<div className="border-b bg-[#f8fafc] px-4 py-3 text-sm font-semibold">通知公告</div>
|
||||
<div className="p-4">
|
||||
<NoticeList
|
||||
items={[
|
||||
{ title: "万华蓬莱园区高温管道耐火衬里类物资供应商招募", date: "2026-07-10" },
|
||||
{ title: "万华化学桨叶冷却机类供应商招募", date: "2026-07-10" },
|
||||
{ title: "万华化学洗车平台服务类供应商招募", date: "2026-06-25" },
|
||||
]}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-span-12 border bg-white lg:col-span-6">
|
||||
<div className="border-b bg-[#f8fafc] px-4 py-3 text-sm font-semibold">常见问题 / 操作指南</div>
|
||||
<div className="grid grid-cols-2 gap-2 p-4 text-sm">
|
||||
{[
|
||||
"系统使用常见问题处理",
|
||||
"常见问题帮助",
|
||||
"供应商注册操作指南",
|
||||
"投标文件制作软件操作手册",
|
||||
"标证通申请-投标单位操作指南",
|
||||
"浏览器切换IE模式",
|
||||
].map((x) => (
|
||||
<button key={x} className="border px-3 py-2 text-left hover:border-primary hover:bg-[#f8fbff]">
|
||||
{x}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* 公告区 */}
|
||||
<section className="mt-8">
|
||||
<h2 className="mb-4 flex items-center gap-2 text-[#1a2332]" style={{ fontSize: 20, fontWeight: 700 }}>
|
||||
📢 最新公告
|
||||
</h2>
|
||||
<div className="grid gap-5 md:grid-cols-3">
|
||||
<AnnouncementCard title="招标公告" tag="最新发布" headerColor="#c2185b" items={TENDERS} moreBg="#fce4ec" moreText="#c2185b" />
|
||||
<AnnouncementCard title="定标公告" tag="最新定标" headerColor="#1565c0" items={AWARDS} moreBg="#e3f2fd" moreText="#1565c0" />
|
||||
<AnnouncementCard title="企业新闻" tag="集团动态" headerColor="#e65100" items={NEWS} moreBg="#fff3e0" moreText="#e65100" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* 免责声明 */}
|
||||
<section className="mt-8 rounded-2xl bg-white p-6 text-center shadow-[0_4px_16px_rgba(0,0,0,0.06)]">
|
||||
<div className="text-sm font-semibold text-[#4a5568]">免责声明</div>
|
||||
<p className="mx-auto mt-2 max-w-3xl text-xs leading-relaxed text-[#8895aa]">
|
||||
本平台所有招标信息均由滨化集团或其下属公司发布,信息真实有效。供应商应对投标行为负责,本平台保留对违规行为的处理权。
|
||||
</p>
|
||||
<p className="mt-2 text-xs text-[#8895aa]">隐私政策 | 服务协议 | 法律声明 | © 2026 滨化集团 | 鲁ICP备XXXXXXXX号</p>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
{/* AI 助手浮标 */}
|
||||
<button
|
||||
onClick={() => navigate("/")}
|
||||
className="group fixed bottom-8 right-8 z-50 flex size-[68px] items-center justify-center rounded-full bg-brand-gradient text-white shadow-xl transition-transform hover:scale-105"
|
||||
aria-label="小滨 AI 助手"
|
||||
>
|
||||
<span className="pointer-events-none absolute inset-0 rounded-full bg-brand-gradient animate-breathe" />
|
||||
<span className="relative flex flex-col items-center leading-none">
|
||||
<Bot className="size-5" />
|
||||
<span className="mt-0.5 text-[9px] text-white/90">小滨</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<XiaobinAssistant pageType="portal" />
|
||||
</PortalShell>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user