first commit
|
|
@ -0,0 +1,43 @@
|
||||||
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
/.pnp
|
||||||
|
.pnp.*
|
||||||
|
.yarn/*
|
||||||
|
!.yarn/patches
|
||||||
|
!.yarn/plugins
|
||||||
|
!.yarn/releases
|
||||||
|
!.yarn/versions
|
||||||
|
|
||||||
|
# testing
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
# next.js
|
||||||
|
/.next/
|
||||||
|
/out/
|
||||||
|
|
||||||
|
# production
|
||||||
|
/build
|
||||||
|
|
||||||
|
# misc
|
||||||
|
.DS_Store
|
||||||
|
*.pem
|
||||||
|
|
||||||
|
# debug
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
.pnpm-debug.log*
|
||||||
|
|
||||||
|
# env files (can opt-in for committing if needed)
|
||||||
|
.env*
|
||||||
|
|
||||||
|
# vercel
|
||||||
|
.vercel
|
||||||
|
|
||||||
|
# typescript
|
||||||
|
*.tsbuildinfo
|
||||||
|
next-env.d.ts
|
||||||
|
|
||||||
|
/lib/generated/prisma
|
||||||
|
|
@ -0,0 +1,489 @@
|
||||||
|
# 白马家园官网 - 产品需求文档 (PRD)
|
||||||
|
|
||||||
|
## 📋 文档信息
|
||||||
|
|
||||||
|
- **项目名称**:白马家园官网
|
||||||
|
- **版本**:v3.3
|
||||||
|
- **更新日期**:2025年1月16日
|
||||||
|
- **状态**:开发完成,准备部署
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 项目概述
|
||||||
|
|
||||||
|
### 1.1 项目背景
|
||||||
|
|
||||||
|
白马家园是一家专注于数字经济和新质生产力产业集群的科技公司,致力于通过军工技术和人工智能赋能小微企业和实体商业。公司需要建设一个现代化、响应式的官方网站,用于:
|
||||||
|
|
||||||
|
- 品牌形象展示(中英文双语)
|
||||||
|
- 产品矩阵介绍
|
||||||
|
- 客户商机获取
|
||||||
|
- 行业资讯传播
|
||||||
|
- 合作加盟引流
|
||||||
|
|
||||||
|
### 1.2 项目目标
|
||||||
|
|
||||||
|
1. **品牌升级**:打造数字化、科技感的品牌形象(中英文双语)
|
||||||
|
2. **产品展示**:清晰展示四大核心产品线
|
||||||
|
3. **商机转化**:通过客服企业微信二维码引导潜在客户直接联系
|
||||||
|
4. **内容营销**:自动抓取行业资讯,保持网站活跃度
|
||||||
|
5. **用户体验**:支持手机、平板、桌面全设备响应式访问
|
||||||
|
6. **国际化**:支持中英文切换,服务全球用户
|
||||||
|
|
||||||
|
### 1.3 目标用户
|
||||||
|
|
||||||
|
- **潜在合作伙伴**:实体商家、创业者、投资人
|
||||||
|
- **C端消费者**:小微企业主、门店经营者
|
||||||
|
- **媒体和行业人士**:记者、分析师、行业专家
|
||||||
|
- **国际用户**:海外华人和全球商业伙伴
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🏗️ 系统架构
|
||||||
|
|
||||||
|
### 2.1 技术栈
|
||||||
|
|
||||||
|
```
|
||||||
|
前端:Next.js 16 + React 19 + TypeScript
|
||||||
|
UI框架:Tailwind CSS 4 + Radix UI
|
||||||
|
动画:Framer Motion
|
||||||
|
状态管理:React Hooks
|
||||||
|
后端:Next.js API Routes
|
||||||
|
部署:Vercel
|
||||||
|
国际化:Next.js i18n
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
baima-home/
|
||||||
|
├── app/
|
||||||
|
│ ├── page.tsx # 首页(中文)
|
||||||
|
│ ├── layout.tsx # 全局布局
|
||||||
|
│ ├── globals.css # 全局样式
|
||||||
|
│ ├── en/
|
||||||
|
│ │ └── page.tsx # 首页(英文)
|
||||||
|
│ ├── about/ # 关于我们
|
||||||
|
│ ├── products/ # 产品矩阵
|
||||||
|
│ ├── news/ # 新闻动态
|
||||||
|
│ ├── contact/ # 联系加盟
|
||||||
|
│ ├── admin/ # 后台管理
|
||||||
|
│ └── api/ # API接口
|
||||||
|
│ ├── news/ # 新闻API(静态数据)
|
||||||
|
│ └── auto-fetch/ # 自动抓取API(静态数据)
|
||||||
|
├── components/
|
||||||
|
│ ├── home/ # 首页组件
|
||||||
|
│ │ ├── Hero.tsx # 首屏区域
|
||||||
|
│ │ ├── ProductPreview.tsx # 产品矩阵
|
||||||
|
│ │ ├── MissionVision.tsx # 使命愿景价值观
|
||||||
|
│ │ ├── HonorSection.tsx # 资质荣誉
|
||||||
|
│ │ └── Infrastructure.tsx # 生态基础设施
|
||||||
|
│ ├── layout/ # 布局组件
|
||||||
|
│ │ ├── Navbar.tsx # 导航栏
|
||||||
|
│ │ └── Footer.tsx # 页脚
|
||||||
|
│ └── ui/ # 基础UI组件
|
||||||
|
├── lib/
|
||||||
|
│ └── utils.ts # 工具函数
|
||||||
|
└── public/ # 静态资源
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📱 页面规划
|
||||||
|
|
||||||
|
### 3.1 前台页面
|
||||||
|
|
||||||
|
#### 首页 (/ 和 /en)
|
||||||
|
**设计风格**:单页全景布局,沉浸式体验
|
||||||
|
|
||||||
|
**功能模块**:
|
||||||
|
1. **Hero首屏**
|
||||||
|
- 品牌Logo(大尺寸展示)
|
||||||
|
- 核心标签:军工技术、AI赋能、小微企业
|
||||||
|
- 价值主张:AI数智增长引擎
|
||||||
|
- 三大核心价值:支付即锁粉、让利即引流、跨界即分润
|
||||||
|
- CTA按钮:立即加入白马联盟 / Join Baima Alliance
|
||||||
|
- 背景:深蓝色科技感渐变 + 网格效果
|
||||||
|
|
||||||
|
2. **产品矩阵**
|
||||||
|
- 四大核心板块卡片布局
|
||||||
|
- 金融科技支撑(白马智付)
|
||||||
|
- 私域运营工具(AI拓客宝)【原名"爆客宝AI"】
|
||||||
|
- 异业联盟系统(商家联盟)
|
||||||
|
- 生态基础设施(智能硬件)
|
||||||
|
- 每张卡片包含:标题、描述、功能特性列表
|
||||||
|
- 【已移除】"深入了解"链接
|
||||||
|
|
||||||
|
3. **使命、愿景、价值观**【新增模块】
|
||||||
|
- 使命:军工技术赋能实体经济,人工智能驱动万商互联
|
||||||
|
- 愿景:天下白马是一家,一起赚钱一起花
|
||||||
|
- 价值观:共创、共享、共富
|
||||||
|
- 三大核心板块,渐变色背景,悬停动画效果
|
||||||
|
- 支持中英文双语显示
|
||||||
|
|
||||||
|
4. **权威认证与技术实力**
|
||||||
|
- 资质证书展示(ISO认证、高新技术企业等)
|
||||||
|
- 专利技术展示(专利数量、软著)
|
||||||
|
- 荣誉奖项展示(行业认可)
|
||||||
|
- 响应式网格布局
|
||||||
|
|
||||||
|
5. **生态基础设施**
|
||||||
|
- 会员系统
|
||||||
|
- 供应链资源
|
||||||
|
- 数字资产体系
|
||||||
|
- 【已移除】智能监控(移至智能设备)
|
||||||
|
- 【已移除】"为上市合规打造的底层架构"描述文字
|
||||||
|
|
||||||
|
6. **页脚**
|
||||||
|
- 客服企业微信二维码(替代电话和邮箱)
|
||||||
|
- 产品中心链接
|
||||||
|
- 解决方案链接
|
||||||
|
- 公司地址:天津市武清区京津产业新城海达商务大厦
|
||||||
|
- 公司信息:天津白马晶选科技有限公司 | 天津白马家园健康科技有限公司
|
||||||
|
- 版权信息
|
||||||
|
- 【已移除】隐私政策、服务条款链接
|
||||||
|
|
||||||
|
#### 关于我们 (/about)
|
||||||
|
- 公司介绍
|
||||||
|
- 团队介绍
|
||||||
|
- 发展历程
|
||||||
|
- 资质认证
|
||||||
|
|
||||||
|
#### 产品矩阵 (/products)
|
||||||
|
- 产品详情页
|
||||||
|
- 产品对比
|
||||||
|
- 定价方案
|
||||||
|
- 客户案例
|
||||||
|
|
||||||
|
#### 新闻动态 (/news)
|
||||||
|
- 新闻列表(静态数据展示)
|
||||||
|
- 新闻详情
|
||||||
|
- 分类筛选
|
||||||
|
- 搜索功能
|
||||||
|
|
||||||
|
#### 联系加盟 (/contact)
|
||||||
|
- 公司信息
|
||||||
|
- 地图定位
|
||||||
|
- 客服企业微信二维码(引导用户扫码联系)
|
||||||
|
|
||||||
|
### 3.2 后台管理 (/admin)
|
||||||
|
|
||||||
|
#### 登录验证
|
||||||
|
- 密码保护:固定密码 `admin123`
|
||||||
|
- 简洁的登录界面
|
||||||
|
|
||||||
|
#### 新闻动态管理
|
||||||
|
- 发布新闻(静态数据示例)
|
||||||
|
- 编辑新闻
|
||||||
|
- 删除新闻
|
||||||
|
- 分类管理
|
||||||
|
- 状态跟踪
|
||||||
|
|
||||||
|
#### 自动抓取管理
|
||||||
|
- 手动触发抓取(静态数据示例)
|
||||||
|
- 待审核列表
|
||||||
|
- 审核操作(通过/拒绝)
|
||||||
|
- 抓取历史记录
|
||||||
|
- 配置管理
|
||||||
|
|
||||||
|
### 3.3 语言切换
|
||||||
|
|
||||||
|
- 支持中英文双语
|
||||||
|
- 导航栏语言切换按钮
|
||||||
|
- 中文首页:`/`
|
||||||
|
- 英文首页:`/en`
|
||||||
|
- 页面内容自动切换
|
||||||
|
- 移动端支持滑出式菜单切换
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📡 API 接口
|
||||||
|
|
||||||
|
### 4.1 新闻接口(静态数据)
|
||||||
|
|
||||||
|
**GET** `/api/news`
|
||||||
|
|
||||||
|
返回静态新闻数据示例,无需数据库支持。
|
||||||
|
|
||||||
|
### 4.2 自动抓取接口(静态数据)
|
||||||
|
|
||||||
|
**GET** `/api/auto-fetch`
|
||||||
|
|
||||||
|
返回静态抓取数据示例,无需数据库支持。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🤖 自动抓取系统
|
||||||
|
|
||||||
|
### 5.1 抓取策略(静态示例)
|
||||||
|
|
||||||
|
- **主要来源**:搜狗微信搜索(示例)
|
||||||
|
- **目标账号/关键词**:白马精选、白马家园
|
||||||
|
- **抓取频率**:每6小时自动抓取
|
||||||
|
- **手动触发**:管理员可随时手动抓取
|
||||||
|
|
||||||
|
### 5.2 智能过滤规则
|
||||||
|
|
||||||
|
#### 必须包含的关键词
|
||||||
|
- `白马精选`(必须)
|
||||||
|
- `数字经济`、`AI`、`人工智能`、`金融科技`、`小微企业`(至少一个)
|
||||||
|
|
||||||
|
#### 排除的关键词(房地产相关)
|
||||||
|
```
|
||||||
|
房地产、楼盘、房价、房产、住宅、商业地产
|
||||||
|
购房、租房、地产投资、物业、开盘、预售证
|
||||||
|
样板间、户型图、买房、卖房、出租、二手房
|
||||||
|
白马家园、白马花园、白马苑、白马小区(小区名称)
|
||||||
|
万科白马家园、恒大白马家园、碧桂园白马家园
|
||||||
|
别墅、豪宅、精装房、毛坯房
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 分类规则
|
||||||
|
- `产品发布`:包含发布、上线、新品等关键词
|
||||||
|
- `荣誉获奖`:包含获奖、认证、荣誉等关键词
|
||||||
|
- `行业洞察`:包含趋势、分析、洞察等关键词
|
||||||
|
- `媒体报道`:包含报道、媒体等关键词
|
||||||
|
- 默认:`公司新闻`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎨 设计规范
|
||||||
|
|
||||||
|
### 6.1 视觉风格
|
||||||
|
|
||||||
|
#### 配色方案
|
||||||
|
- **主色调**:橙色 `#FF6600`
|
||||||
|
- 用途:CTA按钮、强调文字、图标、链接
|
||||||
|
- **辅助色**:深蓝色 `#0A1931`
|
||||||
|
- 用途:背景、导航栏、文字
|
||||||
|
- **点缀色**:`#185ADB`(浅蓝)
|
||||||
|
- **背景色**:`#050A14`(深黑)
|
||||||
|
|
||||||
|
#### 字体规范
|
||||||
|
- **标题**:加粗加黑,层级分明
|
||||||
|
- **正文字体**:17px基础字号
|
||||||
|
- **英文字体**:Geist Sans
|
||||||
|
- **中文字体**:系统默认无衬线字体
|
||||||
|
|
||||||
|
### 6.2 响应式断点
|
||||||
|
|
||||||
|
```
|
||||||
|
移动端:< 640px
|
||||||
|
平板端:640px - 1024px
|
||||||
|
桌面端:> 1024px
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.3 组件规范
|
||||||
|
|
||||||
|
- **按钮**:圆角矩形,阴影效果,悬停动画
|
||||||
|
- **卡片**:圆角边框,阴影,悬停效果
|
||||||
|
- **导航栏**:固定定位,滚动变色,语言切换
|
||||||
|
- **页脚**:多列布局,响应式堆叠,客服二维码
|
||||||
|
- **模块间距**:统一规范,保持视觉平衡
|
||||||
|
|
||||||
|
### 6.4 页面布局优化
|
||||||
|
|
||||||
|
#### Logo 尺寸
|
||||||
|
- 导航栏:56px(h-14)
|
||||||
|
- 首页Hero:64px - 112px(响应式)
|
||||||
|
- 页脚:56px(h-14)
|
||||||
|
|
||||||
|
#### 使命愿景价值观模块
|
||||||
|
- 深蓝渐变背景
|
||||||
|
- 三栏卡片布局
|
||||||
|
- 彩色图标(橙/蓝/绿渐变)
|
||||||
|
- 悬停动画效果
|
||||||
|
- 中英文双语内容
|
||||||
|
|
||||||
|
#### 新闻卡片
|
||||||
|
- 卡片可点击,支持跳转详情页
|
||||||
|
- 分类标签+日期展示
|
||||||
|
- 摘要截断(最多3行)
|
||||||
|
- 阅读更多链接
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 功能实现
|
||||||
|
|
||||||
|
### 7.1 已完成功能
|
||||||
|
|
||||||
|
✅ **前台功能**
|
||||||
|
- 首页单页全景布局(中英文双语)
|
||||||
|
- 使命愿景价值观模块
|
||||||
|
- 响应式设计(全设备适配)
|
||||||
|
- 产品矩阵展示
|
||||||
|
- 资质荣誉展示
|
||||||
|
- 新闻动态模块(静态数据)
|
||||||
|
- 合作加盟表单
|
||||||
|
- 页脚优化(企微二维码)
|
||||||
|
|
||||||
|
✅ **技术功能**
|
||||||
|
- SEO优化
|
||||||
|
- 性能优化
|
||||||
|
- 错误处理
|
||||||
|
- 加载状态
|
||||||
|
- 中英文国际化
|
||||||
|
|
||||||
|
### 7.2 待实现功能
|
||||||
|
|
||||||
|
⏳ **内容功能**
|
||||||
|
- 新闻详情页完善
|
||||||
|
- 产品详情页
|
||||||
|
- 关于我们页面完善
|
||||||
|
|
||||||
|
⏳ **部署功能**
|
||||||
|
- Vercel部署
|
||||||
|
- 域名配置
|
||||||
|
- SSL证书
|
||||||
|
- 监控告警
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 测试用例
|
||||||
|
|
||||||
|
### 8.1 前台测试
|
||||||
|
|
||||||
|
#### 首页测试
|
||||||
|
- [x] Hero区域加载正常
|
||||||
|
- [x] 产品卡片显示完整
|
||||||
|
- [x] 使命愿景价值观模块显示
|
||||||
|
- [x] 资质荣誉网格布局
|
||||||
|
- [x] 新闻动态展示(静态数据)
|
||||||
|
- [x] 移动端响应式布局
|
||||||
|
- [x] 页面滚动动画效果
|
||||||
|
- [x] 中英文切换功能
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 部署计划
|
||||||
|
|
||||||
|
### 9.1 部署环境
|
||||||
|
|
||||||
|
- **开发环境**:本地 `localhost:3000`
|
||||||
|
- **测试环境**:Vercel Preview
|
||||||
|
- **生产环境**:Vercel Production
|
||||||
|
|
||||||
|
### 9.2 部署步骤
|
||||||
|
|
||||||
|
1. **代码推送**
|
||||||
|
```
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Vercel导入**
|
||||||
|
- 访问 https://vercel.com/new
|
||||||
|
- 导入 GitHub 仓库 `wygogogo19/baima-home`
|
||||||
|
|
||||||
|
3. **自动部署**
|
||||||
|
- Vercel自动检测并部署
|
||||||
|
- 预览环境生成
|
||||||
|
|
||||||
|
4. **生产发布**
|
||||||
|
- Vercel生产环境部署
|
||||||
|
- 域名绑定
|
||||||
|
- SSL证书配置
|
||||||
|
|
||||||
|
### 9.3 监控和维护
|
||||||
|
|
||||||
|
- **错误监控**:Vercel Error Tracking
|
||||||
|
- **性能监控**:Vercel Analytics
|
||||||
|
- **日志查看**:Vercel Logs
|
||||||
|
- **回滚机制**:Vercel Deployments
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 项目进度
|
||||||
|
|
||||||
|
### 9.1 当前进度
|
||||||
|
|
||||||
|
- ✅ **需求分析**:完成
|
||||||
|
- ✅ **UI设计**:完成
|
||||||
|
- ✅ **前端开发**:完成
|
||||||
|
- ✅ **后端开发**:完成
|
||||||
|
- ✅ **国际化(中英文)**:完成
|
||||||
|
- ✅ **测试调试**:完成
|
||||||
|
- ⏳ **部署上线**:进行中
|
||||||
|
|
||||||
|
### 9.2 下一步计划
|
||||||
|
|
||||||
|
1. **短期目标**
|
||||||
|
- [x] Vercel部署
|
||||||
|
- [x] 生产环境测试
|
||||||
|
|
||||||
|
2. **中期目标(1周内)**
|
||||||
|
- [ ] 完善前台页面
|
||||||
|
- [ ] 新闻详情页开发
|
||||||
|
- [ ] 绑定自定义域名
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 变更日志
|
||||||
|
|
||||||
|
### v3.3 (2025-01-16) - 当前版本
|
||||||
|
- 🔄 完全移除数据库依赖
|
||||||
|
- 删除 Prisma ORM 和所有数据库相关代码
|
||||||
|
- 所有 API 接口改为静态数据返回
|
||||||
|
- 删除 prisma/ 目录、lib/prisma.ts
|
||||||
|
- 从 package.json 移除 Prisma 依赖
|
||||||
|
- 不再需要 DATABASE_URL 环境变量
|
||||||
|
- 🔄 更新技术架构文档,移除数据库相关内容
|
||||||
|
- ✅ 简化部署流程,无需数据库配置
|
||||||
|
|
||||||
|
### v3.2 (2025-01-16)
|
||||||
|
- 🔄 更新资质认证描述
|
||||||
|
- "支付业务许可证" → "收单外包服务机构备案"
|
||||||
|
- 🔄 产品矩阵多项优化
|
||||||
|
- 支付能力:"主扫被扫全支持" → "主扫、被扫模式全支持"
|
||||||
|
- AI数字人:"7x24小时直播 / 数字员工导购" → "AI直播/AI导购/AI客服/AI私域"
|
||||||
|
- 企微私域(原消费券流转):"供应商进货 / 转赠他人使用" → "AI数字员工自动实现:社群运营/维护/导购/客服"
|
||||||
|
- 锁定客户:"一次锁定,终身受益" → "扫码即锁定推荐关系,终身享受消费分佣"
|
||||||
|
- 数字资产 → 数字资产体系
|
||||||
|
- RWA资产描述:"积分抵用券互转" → "积分、抵用券、金币等"
|
||||||
|
- 智能监控巡店移至智能设备
|
||||||
|
- 🔄 页面结构调整
|
||||||
|
- 删除首页"最新动态"模块
|
||||||
|
- 删除产品卡片"深入了解"链接
|
||||||
|
- ✅ 优化产品展示逻辑,提升用户体验
|
||||||
|
|
||||||
|
### v3.1 (2025-01-16)
|
||||||
|
- 🔄 删除"在线咨询留言"功能模块(Path A - 完全删除)
|
||||||
|
- 🗑️ 删除 Contact 数据模型及相关 API 路由
|
||||||
|
- 🗑️ 删除后台"客户留言管理"功能
|
||||||
|
- 🗑️ 删除前端"在线表单"提交功能
|
||||||
|
- ✅ 全站统一使用客服企业微信二维码作为对外联系入口
|
||||||
|
|
||||||
|
### v3.0 (2025-01-15)
|
||||||
|
- ✅ 新增使命愿景价值观模块
|
||||||
|
- ✅ 新增英文版首页 (/en)
|
||||||
|
- ✅ 新增中英文切换功能
|
||||||
|
- ✅ 新增自动抓取系统(搜狗微信)
|
||||||
|
- ✅ 新增智能过滤(排除房地产内容)
|
||||||
|
- ✅ 新闻卡片支持点击跳转详情页
|
||||||
|
- ✅ 页脚改为客服企业微信号码
|
||||||
|
- ✅ 移除"为上市合规打造的底层架构"
|
||||||
|
- ✅ 产品名称更新:爆客宝AI → AI拓客宝
|
||||||
|
- ✅ 移除页脚隐私政策、服务条款
|
||||||
|
- ✅ Logo尺寸优化放大
|
||||||
|
- ✅ 响应式设计优化
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 👥 团队
|
||||||
|
|
||||||
|
- **产品经理**:[待补充]
|
||||||
|
- **UI设计**:[待补充]
|
||||||
|
- **前端开发**:已完成
|
||||||
|
- **后端开发**:已完成
|
||||||
|
- **测试**:[待补充]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📞 联系方式
|
||||||
|
|
||||||
|
- **项目负责人**:[待补充]
|
||||||
|
- **技术对接**:[待补充]
|
||||||
|
- **更新日期**:2025年1月16日
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*本文档将持续更新,记录项目进展和需求变更。*
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
First, run the development server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
# or
|
||||||
|
yarn dev
|
||||||
|
# or
|
||||||
|
pnpm dev
|
||||||
|
# or
|
||||||
|
bun dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||||
|
|
||||||
|
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||||
|
|
||||||
|
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
||||||
|
|
||||||
|
## Learn More
|
||||||
|
|
||||||
|
To learn more about Next.js, take a look at the following resources:
|
||||||
|
|
||||||
|
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||||
|
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||||
|
|
||||||
|
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
||||||
|
|
||||||
|
## Deploy on Vercel
|
||||||
|
|
||||||
|
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||||
|
|
||||||
|
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
import { Team } from '@/components/about/Team'
|
||||||
|
import { Certifications } from '@/components/about/Certifications'
|
||||||
|
import { Badge } from '@/components/ui/badge'
|
||||||
|
|
||||||
|
export default function AboutPage() {
|
||||||
|
return (
|
||||||
|
<div className="pt-24 pb-20">
|
||||||
|
{/* Hero Section */}
|
||||||
|
<section className="container mx-auto px-4 md:px-6 mb-20">
|
||||||
|
<div className="max-w-4xl mx-auto text-center">
|
||||||
|
<Badge variant="outline" className="mb-4 border-primary text-primary bg-primary/5">
|
||||||
|
国资背景 · 军工技术
|
||||||
|
</Badge>
|
||||||
|
<h1 className="text-4xl md:text-5xl font-bold text-secondary mb-8">
|
||||||
|
相互成就 · 共创未来
|
||||||
|
</h1>
|
||||||
|
<p className="text-lg text-muted-foreground leading-relaxed mb-8">
|
||||||
|
白马家园(白马精选)是一家拥有国资背景的高新技术企业,已获五轮融资超 2 亿元。
|
||||||
|
我们致力于通过 AI 人工智能、大数据分析、区块链等前沿技术,解决实体商家"流量难、锁客难、变现难"的痛点,
|
||||||
|
构建万商互联的共享经济生态。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<Team />
|
||||||
|
<Certifications />
|
||||||
|
|
||||||
|
{/* Financing History */}
|
||||||
|
<section className="py-20 bg-secondary text-white">
|
||||||
|
<div className="container mx-auto px-4 md:px-6">
|
||||||
|
<h2 className="text-3xl font-bold text-center mb-16">资本历程</h2>
|
||||||
|
<div className="max-w-4xl mx-auto">
|
||||||
|
<div className="space-y-8 relative before:absolute before:inset-0 before:ml-5 before:-translate-x-px md:before:mx-auto md:before:translate-x-0 before:h-full before:w-0.5 before:bg-gradient-to-b before:from-transparent before:via-white/20 before:to-transparent">
|
||||||
|
{[
|
||||||
|
{ year: "B轮", title: "启迪之星投资", desc: "进一步夯实技术壁垒与市场版图" },
|
||||||
|
{ year: "A+轮", title: "沂景 / 创世伙伴 / 中测航天", desc: "多方资本加持,加速生态布局" },
|
||||||
|
{ year: "A轮", title: "创世伙伴 CCV 领投", desc: "获得知名风投机构青睐" },
|
||||||
|
{ year: "Pre-A", title: "中体基金领投", desc: "初步验证商业模式" },
|
||||||
|
{ year: "天使轮", title: "玖创 / 唯猎 / 天使湾", desc: "启动创业征程" }
|
||||||
|
].map((item, index) => (
|
||||||
|
<div key={index} className="relative flex items-center justify-between md:justify-normal md:odd:flex-row-reverse group is-active">
|
||||||
|
<div className="flex items-center justify-center w-10 h-10 rounded-full border border-white/20 bg-white/10 group-[.is-active]:bg-primary text-white shrink-0 md:order-1 md:group-odd:-translate-x-1/2 md:group-even:translate-x-1/2">
|
||||||
|
<div className="w-3 h-3 bg-current rounded-full"></div>
|
||||||
|
</div>
|
||||||
|
<div className="w-[calc(100%-4rem)] md:w-[calc(50%-2.5rem)] p-4 rounded border border-white/10 bg-white/5 shadow">
|
||||||
|
<div className="flex items-center justify-between space-x-2 mb-1">
|
||||||
|
<div className="font-bold text-white">{item.title}</div>
|
||||||
|
<time className="font-mono italic text-primary">{item.year}</time>
|
||||||
|
</div>
|
||||||
|
<div className="text-white/60 text-sm">{item.desc}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,571 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useState, useEffect } from 'react'
|
||||||
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||||
|
import { Input } from '@/components/ui/input'
|
||||||
|
import { Button } from '@/components/ui/button'
|
||||||
|
import { Textarea } from '@/components/ui/textarea'
|
||||||
|
import {
|
||||||
|
RefreshCw,
|
||||||
|
Lock,
|
||||||
|
Newspaper,
|
||||||
|
Plus,
|
||||||
|
Trash2,
|
||||||
|
LogOut,
|
||||||
|
Rss,
|
||||||
|
Settings,
|
||||||
|
Check,
|
||||||
|
X,
|
||||||
|
Eye,
|
||||||
|
Globe
|
||||||
|
} from 'lucide-react'
|
||||||
|
|
||||||
|
type News = {
|
||||||
|
id: number
|
||||||
|
title: string
|
||||||
|
category: string
|
||||||
|
excerpt: string
|
||||||
|
createdAt: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type AutoFetchedNews = {
|
||||||
|
id: number
|
||||||
|
title: string
|
||||||
|
source: string
|
||||||
|
url: string
|
||||||
|
imageUrl: string
|
||||||
|
excerpt: string
|
||||||
|
category: string
|
||||||
|
publishTime: string
|
||||||
|
status: string
|
||||||
|
isDigitalEconomy: boolean
|
||||||
|
createdAt: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function AdminPage() {
|
||||||
|
const [activeTab, setActiveTab] = useState<'news' | 'autofetch'>('news')
|
||||||
|
const [isAuthenticated, setIsAuthenticated] = useState(false)
|
||||||
|
const [password, setPassword] = useState('')
|
||||||
|
const [newsList, setNewsList] = useState<News[]>([])
|
||||||
|
const [autoFetchedNews, setAutoFetchedNews] = useState<AutoFetchedNews[]>([])
|
||||||
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
|
|
||||||
|
// 新闻发布表单状态
|
||||||
|
const [showAddNews, setShowAddNews] = useState(false)
|
||||||
|
const [newNews, setNewNews] = useState({
|
||||||
|
title: '',
|
||||||
|
category: '公司新闻',
|
||||||
|
excerpt: '',
|
||||||
|
content: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
// 自动抓取状态
|
||||||
|
const [isAutoFetching, setIsAutoFetching] = useState(false)
|
||||||
|
const [fetchStatus, setFetchStatus] = useState<{
|
||||||
|
lastFetch: string | null
|
||||||
|
nextFetch: string | null
|
||||||
|
}>({
|
||||||
|
lastFetch: null,
|
||||||
|
nextFetch: null
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleLogin = (e: React.FormEvent) => {
|
||||||
|
e.preventDefault()
|
||||||
|
if (password === 'admin123') {
|
||||||
|
setIsAuthenticated(true)
|
||||||
|
fetchAllData()
|
||||||
|
} else {
|
||||||
|
alert('密码错误')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchAllData = async () => {
|
||||||
|
setIsLoading(true)
|
||||||
|
try {
|
||||||
|
const [newsRes, autoFetchRes] = await Promise.all([
|
||||||
|
fetch('/api/news'),
|
||||||
|
fetch('/api/auto-fetch')
|
||||||
|
])
|
||||||
|
|
||||||
|
if (newsRes.ok) {
|
||||||
|
const data = await newsRes.json()
|
||||||
|
setNewsList(data.news || [])
|
||||||
|
}
|
||||||
|
if (autoFetchRes.ok) {
|
||||||
|
const data = await autoFetchRes.json()
|
||||||
|
// 合并待审核和已批准的内容
|
||||||
|
const allNews = [
|
||||||
|
...(data.pending || []),
|
||||||
|
...(data.approved || []).filter((a: AutoFetchedNews) =>
|
||||||
|
!data.pending?.some((p: AutoFetchedNews) => p.id === a.id)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
setAutoFetchedNews(allNews)
|
||||||
|
setFetchStatus({
|
||||||
|
lastFetch: data.lastFetch,
|
||||||
|
nextFetch: data.nextFetch
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取数据失败', error)
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAddNews = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault()
|
||||||
|
try {
|
||||||
|
const res = await fetch('/api/news', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(newNews)
|
||||||
|
})
|
||||||
|
if (res.ok) {
|
||||||
|
setNewNews({ title: '', category: '公司新闻', excerpt: '', content: '' })
|
||||||
|
setShowAddNews(false)
|
||||||
|
fetchAllData()
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
alert('发布失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自动抓取相关函数
|
||||||
|
const triggerAutoFetch = async () => {
|
||||||
|
setIsAutoFetching(true)
|
||||||
|
try {
|
||||||
|
const res = await fetch('/api/auto-fetch', { method: 'POST' })
|
||||||
|
const data = await res.json()
|
||||||
|
|
||||||
|
if (data.success) {
|
||||||
|
alert(`成功抓取 ${data.articles?.length || 0} 条资讯`)
|
||||||
|
fetchAllData()
|
||||||
|
} else {
|
||||||
|
alert('抓取失败:' + data.error)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
alert('抓取失败,请稍后重试')
|
||||||
|
} finally {
|
||||||
|
setIsAutoFetching(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const approveArticle = async (id: number) => {
|
||||||
|
try {
|
||||||
|
const res = await fetch(`/api/auto-fetch/${id}/approve`, { method: 'POST' })
|
||||||
|
if (res.ok) {
|
||||||
|
fetchAllData()
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
alert('操作失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const rejectArticle = async (id: number) => {
|
||||||
|
const reason = prompt('请输入拒绝原因:')
|
||||||
|
if (reason === null) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(`/api/auto-fetch/${id}/reject`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ reason })
|
||||||
|
})
|
||||||
|
if (res.ok) {
|
||||||
|
fetchAllData()
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
alert('操作失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteArticle = async (id: number) => {
|
||||||
|
if (!confirm('确定要删除这条资讯吗?')) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(`/api/auto-fetch/${id}`, { method: 'DELETE' })
|
||||||
|
if (res.ok) {
|
||||||
|
fetchAllData()
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
alert('删除失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isAuthenticated) {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen flex items-center justify-center bg-[#0A1931]">
|
||||||
|
<Card className="w-[350px] shadow-2xl border-0">
|
||||||
|
<CardHeader className="text-center pb-8 pt-10">
|
||||||
|
<CardTitle className="text-2xl font-black text-[#0A1931] flex flex-col items-center gap-4">
|
||||||
|
<div className="w-16 h-16 bg-[#FF6600] rounded-2xl flex items-center justify-center text-white shadow-lg">
|
||||||
|
<Lock className="w-8 h-8" />
|
||||||
|
</div>
|
||||||
|
白马家园后台管理
|
||||||
|
</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="pb-10 px-8">
|
||||||
|
<form onSubmit={handleLogin} className="space-y-6">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label className="text-sm font-bold text-gray-500">管理员密码</label>
|
||||||
|
<Input
|
||||||
|
type="password"
|
||||||
|
placeholder="请输入密码"
|
||||||
|
className="h-12 border-gray-200 focus:border-[#FF6600] focus:ring-[#FF6600]"
|
||||||
|
value={password}
|
||||||
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Button type="submit" className="w-full h-12 bg-[#0A1931] hover:bg-[#185ADB] font-bold text-lg rounded-xl transition-all">
|
||||||
|
进入管理中心
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gray-50 flex">
|
||||||
|
{/* Sidebar */}
|
||||||
|
<aside className="w-64 bg-[#0A1931] text-white hidden md:flex flex-col">
|
||||||
|
<div className="p-8 border-b border-white/10">
|
||||||
|
<span className="text-xl font-black">管理中心</span>
|
||||||
|
</div>
|
||||||
|
<nav className="flex-grow p-4 space-y-2">
|
||||||
|
<button
|
||||||
|
onClick={() => setActiveTab('news')}
|
||||||
|
className={`w-full flex items-center gap-3 px-4 py-3 rounded-xl transition-all font-bold ${activeTab === 'news' ? 'bg-[#FF6600] text-white shadow-lg' : 'hover:bg-white/5 text-gray-400'}`}
|
||||||
|
>
|
||||||
|
<Newspaper className="w-5 h-5" />
|
||||||
|
新闻动态
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setActiveTab('autofetch')}
|
||||||
|
className={`w-full flex items-center gap-3 px-4 py-3 rounded-xl transition-all font-bold ${activeTab === 'autofetch' ? 'bg-[#FF6600] text-white shadow-lg' : 'hover:bg-white/5 text-gray-400'}`}
|
||||||
|
>
|
||||||
|
<Rss className="w-5 h-5" />
|
||||||
|
自动抓取
|
||||||
|
</button>
|
||||||
|
</nav>
|
||||||
|
<div className="p-6">
|
||||||
|
<Button variant="ghost" className="w-full text-gray-400 hover:text-white" onClick={() => setIsAuthenticated(false)}>
|
||||||
|
<LogOut className="w-4 h-4 mr-2" /> 退出登录
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
{/* Main Content */}
|
||||||
|
<main className="flex-grow pt-24 pb-12 px-4 md:px-8 overflow-y-auto">
|
||||||
|
<div className="max-w-6xl mx-auto">
|
||||||
|
|
||||||
|
<div className="flex justify-between items-center mb-10">
|
||||||
|
<div>
|
||||||
|
<h1 className="text-3xl font-black text-[#0A1931]">
|
||||||
|
{activeTab === 'news' && '公司/行业动态'}
|
||||||
|
{activeTab === 'autofetch' && '资讯自动抓取'}
|
||||||
|
</h1>
|
||||||
|
<p className="text-gray-500 mt-1">
|
||||||
|
{activeTab === 'news' && '发布和管理最新的公司动态与行业资讯'}
|
||||||
|
{activeTab === 'autofetch' && '自动抓取白马精选公众号等资讯,智能筛选后展示'}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-3">
|
||||||
|
{activeTab === 'news' && (
|
||||||
|
<Button
|
||||||
|
onClick={() => setShowAddNews(!showAddNews)}
|
||||||
|
className="bg-[#FF6600] hover:bg-[#FF8C00] font-bold"
|
||||||
|
>
|
||||||
|
<Plus className="w-4 h-4 mr-2" /> 发布动态
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{activeTab === 'autofetch' && (
|
||||||
|
<Button
|
||||||
|
onClick={triggerAutoFetch}
|
||||||
|
disabled={isAutoFetching}
|
||||||
|
className="bg-[#FF6600] hover:bg-[#FF8C00] font-bold"
|
||||||
|
>
|
||||||
|
<RefreshCw className={`w-4 h-4 mr-2 ${isAutoFetching ? 'animate-spin' : ''}`} />
|
||||||
|
{isAutoFetching ? '抓取中...' : '立即抓取'}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
<Button variant="outline" onClick={fetchAllData} disabled={isLoading} className="border-gray-200">
|
||||||
|
<RefreshCw className={`w-4 h-4 mr-2 ${isLoading ? 'animate-spin' : ''}`} /> 刷新
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 新闻发布表单 */}
|
||||||
|
{activeTab === 'news' && showAddNews && (
|
||||||
|
<Card className="mb-10 border-2 border-[#FF6600]/20 shadow-xl overflow-hidden">
|
||||||
|
<CardHeader className="bg-[#FF6600]/5 border-b">
|
||||||
|
<CardTitle className="text-lg">撰写新动态</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="pt-6">
|
||||||
|
<form onSubmit={handleAddNews} className="space-y-4">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label className="text-sm font-bold">标题</label>
|
||||||
|
<Input
|
||||||
|
placeholder="输入新闻标题"
|
||||||
|
required
|
||||||
|
onChange={(e) => setNewNews({...newNews, title: e.target.value})}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label className="text-sm font-bold">分类</label>
|
||||||
|
<select
|
||||||
|
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm"
|
||||||
|
value={newNews.category}
|
||||||
|
onChange={(e) => setNewNews({...newNews, category: e.target.value})}
|
||||||
|
>
|
||||||
|
<option>公司新闻</option>
|
||||||
|
<option>行业洞察</option>
|
||||||
|
<option>媒体报道</option>
|
||||||
|
<option>产品发布</option>
|
||||||
|
<option>荣誉获奖</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label className="text-sm font-bold">摘要</label>
|
||||||
|
<Input
|
||||||
|
placeholder="输入新闻简介"
|
||||||
|
value={newNews.excerpt}
|
||||||
|
onChange={(e) => setNewNews({...newNews, excerpt: e.target.value})}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label className="text-sm font-bold">详细内容</label>
|
||||||
|
<Textarea
|
||||||
|
placeholder="输入详细报道内容..."
|
||||||
|
className="min-h-[150px]"
|
||||||
|
value={newNews.content}
|
||||||
|
onChange={(e) => setNewNews({...newNews, content: e.target.value})}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-3 justify-end">
|
||||||
|
<Button variant="ghost" onClick={() => setShowAddNews(false)}>取消</Button>
|
||||||
|
<Button type="submit" className="bg-[#0A1931] hover:bg-[#185ADB] px-8">立即发布</Button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 自动抓取状态面板 */}
|
||||||
|
{activeTab === 'autofetch' && (
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-10">
|
||||||
|
<Card className="bg-gradient-to-br from-[#FF6600] to-[#FF8C00] text-white">
|
||||||
|
<CardContent className="pt-6">
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<div className="w-12 h-12 bg-white/20 rounded-xl flex items-center justify-center">
|
||||||
|
<Rss className="w-6 h-6" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-sm opacity-80">上次抓取时间</p>
|
||||||
|
<p className="text-lg font-bold">
|
||||||
|
{fetchStatus.lastFetch
|
||||||
|
? new Date(fetchStatus.lastFetch).toLocaleString('zh-CN')
|
||||||
|
: '尚未抓取'}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card className="bg-gradient-to-br from-[#0A1931] to-[#185ADB] text-white">
|
||||||
|
<CardContent className="pt-6">
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<div className="w-12 h-12 bg-white/20 rounded-xl flex items-center justify-center">
|
||||||
|
<Settings className="w-6 h-6" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-sm opacity-80">下次抓取时间</p>
|
||||||
|
<p className="text-lg font-bold">
|
||||||
|
{fetchStatus.nextFetch
|
||||||
|
? new Date(fetchStatus.nextFetch).toLocaleString('zh-CN')
|
||||||
|
: '每6小时自动抓取'}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card className="bg-gradient-to-br from-green-500 to-emerald-600 text-white">
|
||||||
|
<CardContent className="pt-6">
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<div className="w-12 h-12 bg-white/20 rounded-xl flex items-center justify-center">
|
||||||
|
<Check className="w-6 h-6" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-sm opacity-80">待审核资讯</p>
|
||||||
|
<p className="text-2xl font-bold">
|
||||||
|
{autoFetchedNews.filter(n => n.status === 'PENDING').length} 条
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 数据列表 */}
|
||||||
|
<div className="bg-white rounded-2xl shadow-sm border border-gray-100 overflow-hidden">
|
||||||
|
{activeTab === 'news' && (
|
||||||
|
<div className="overflow-x-auto">
|
||||||
|
<table className="w-full text-sm text-left">
|
||||||
|
<thead className="text-xs text-gray-400 uppercase bg-gray-50/50 border-b">
|
||||||
|
<tr>
|
||||||
|
<th className="px-6 py-4">发布时间</th>
|
||||||
|
<th className="px-6 py-4">标题</th>
|
||||||
|
<th className="px-6 py-4">分类</th>
|
||||||
|
<th className="px-6 py-4">摘要</th>
|
||||||
|
<th className="px-6 py-4 text-right">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody className="divide-y">
|
||||||
|
{newsList.length === 0 ? (
|
||||||
|
<tr><td colSpan={5} className="text-center py-20 text-gray-400">暂无动态数据</td></tr>
|
||||||
|
) : (
|
||||||
|
newsList.map((n) => (
|
||||||
|
<tr key={n.id} className="hover:bg-gray-50 transition-colors">
|
||||||
|
<td className="px-6 py-4 text-xs text-gray-400 whitespace-nowrap">{new Date(n.createdAt).toLocaleDateString()}</td>
|
||||||
|
<td className="px-6 py-4 font-bold text-[#0A1931]">{n.title}</td>
|
||||||
|
<td className="px-6 py-4">
|
||||||
|
<span className="bg-orange-50 text-[#FF6600] px-2.5 py-1 rounded-full text-xs font-bold">{n.category}</span>
|
||||||
|
</td>
|
||||||
|
<td className="px-6 py-4 text-gray-500 max-w-xs truncate">{n.excerpt}</td>
|
||||||
|
<td className="px-6 py-4 text-right">
|
||||||
|
<Button variant="ghost" size="icon" className="text-gray-300 hover:text-red-500">
|
||||||
|
<Trash2 className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{activeTab === 'autofetch' && (
|
||||||
|
<div className="overflow-x-auto">
|
||||||
|
<table className="w-full text-sm text-left">
|
||||||
|
<thead className="text-xs text-gray-400 uppercase bg-gray-50/50 border-b">
|
||||||
|
<tr>
|
||||||
|
<th className="px-6 py-4">发布时间</th>
|
||||||
|
<th className="px-6 py-4">标题</th>
|
||||||
|
<th className="px-6 py-4">来源</th>
|
||||||
|
<th className="px-6 py-4">分类</th>
|
||||||
|
<th className="px-6 py-4">状态</th>
|
||||||
|
<th className="px-6 py-4 text-right">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody className="divide-y">
|
||||||
|
{autoFetchedNews.length === 0 ? (
|
||||||
|
<tr>
|
||||||
|
<td colSpan={6} className="text-center py-20">
|
||||||
|
<div className="flex flex-col items-center gap-4">
|
||||||
|
<Rss className="w-16 h-16 text-gray-300" />
|
||||||
|
<div>
|
||||||
|
<p className="text-gray-500 font-medium">暂无抓取数据</p>
|
||||||
|
<p className="text-gray-400 text-sm">点击"立即抓取"按钮开始抓取资讯</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
) : (
|
||||||
|
autoFetchedNews.map((news) => (
|
||||||
|
<tr key={news.id} className="hover:bg-gray-50 transition-colors">
|
||||||
|
<td className="px-6 py-4 text-xs text-gray-400 whitespace-nowrap">
|
||||||
|
{new Date(news.publishTime).toLocaleDateString()}
|
||||||
|
</td>
|
||||||
|
<td className="px-6 py-4">
|
||||||
|
<div className="font-bold text-[#0A1931] max-w-xs truncate">{news.title}</div>
|
||||||
|
{news.excerpt && (
|
||||||
|
<div className="text-gray-400 text-xs mt-1 max-w-xs truncate">{news.excerpt}</div>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
<td className="px-6 py-4">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Globe className="w-4 h-4 text-[#FF6600]" />
|
||||||
|
<span className="text-gray-600">{news.source}</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td className="px-6 py-4">
|
||||||
|
<span className="bg-blue-50 text-blue-600 px-2.5 py-1 rounded-full text-xs font-bold">
|
||||||
|
{news.category}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td className="px-6 py-4">
|
||||||
|
<span className={`px-2.5 py-1 rounded-full text-xs font-bold ${
|
||||||
|
news.status === 'APPROVED' ? 'bg-green-50 text-green-600' :
|
||||||
|
news.status === 'REJECTED' ? 'bg-red-50 text-red-600' :
|
||||||
|
'bg-yellow-50 text-yellow-600'
|
||||||
|
}`}>
|
||||||
|
{news.status === 'APPROVED' ? '已发布' :
|
||||||
|
news.status === 'REJECTED' ? '已拒绝' : '待审核'}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td className="px-6 py-4 text-right">
|
||||||
|
<div className="flex justify-end gap-2">
|
||||||
|
{news.status === 'PENDING' && (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
className="text-green-500 hover:text-green-600"
|
||||||
|
onClick={() => approveArticle(news.id)}
|
||||||
|
title="通过并发布"
|
||||||
|
>
|
||||||
|
<Check className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
className="text-red-500 hover:text-red-600"
|
||||||
|
onClick={() => rejectArticle(news.id)}
|
||||||
|
title="拒绝"
|
||||||
|
>
|
||||||
|
<X className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{news.url && (
|
||||||
|
<a
|
||||||
|
href={news.url}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="text-gray-400 hover:text-[#FF6600] p-2"
|
||||||
|
title="查看原文"
|
||||||
|
>
|
||||||
|
<Eye className="w-4 h-4" />
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
className="text-gray-300 hover:text-red-500"
|
||||||
|
onClick={() => deleteArticle(news.id)}
|
||||||
|
title="删除"
|
||||||
|
>
|
||||||
|
<Trash2 className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { NextResponse } from 'next/server'
|
||||||
|
|
||||||
|
export const dynamic = "force-static"
|
||||||
|
|
||||||
|
// 自动抓取接口(静态数据)
|
||||||
|
export async function GET(request: Request) {
|
||||||
|
return NextResponse.json({
|
||||||
|
lastFetch: null,
|
||||||
|
nextFetch: null,
|
||||||
|
pending: [],
|
||||||
|
approved: []
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 手动触发抓取(禁用)
|
||||||
|
export async function POST(request: Request) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: '自动抓取功能已禁用' },
|
||||||
|
{ status: 403 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
import { NextResponse } from 'next/server'
|
||||||
|
|
||||||
|
export const dynamic = "force-static"
|
||||||
|
|
||||||
|
// 获取新闻列表(静态数据)
|
||||||
|
export async function GET(request: Request) {
|
||||||
|
const { searchParams } = new URL(request.url)
|
||||||
|
const page = parseInt(searchParams.get('page') || '1')
|
||||||
|
const limit = parseInt(searchParams.get('limit') || '10')
|
||||||
|
const category = searchParams.get('category')
|
||||||
|
|
||||||
|
// 静态数据示例
|
||||||
|
const allNews = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
title: "白马家园荣获数字经济创新大奖",
|
||||||
|
category: "公司新闻",
|
||||||
|
excerpt: "白马家园在数字经济领域取得突破性进展,荣获行业创新大奖。",
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
source: '手动发布'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
title: "AI数字人技术引领新零售变革",
|
||||||
|
category: "行业洞察",
|
||||||
|
excerpt: "白马家园推出的AI数字人解决方案正在重塑新零售体验。",
|
||||||
|
createdAt: new Date(Date.now() - 86400000).toISOString(),
|
||||||
|
source: '白马精选'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
title: "收单外包服务机构备案正式获批",
|
||||||
|
category: "公司新闻",
|
||||||
|
excerpt: "白马家园成功获得收单外包服务机构备案,合规能力再上新台阶。",
|
||||||
|
createdAt: new Date(Date.now() - 172800000).toISOString(),
|
||||||
|
source: '手动发布'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
// 分类筛选
|
||||||
|
const filteredNews = category
|
||||||
|
? allNews.filter(item => item.category === category)
|
||||||
|
: allNews
|
||||||
|
|
||||||
|
// 分页
|
||||||
|
const total = filteredNews.length
|
||||||
|
const paginatedNews = filteredNews.slice((page - 1) * limit, page * limit)
|
||||||
|
|
||||||
|
return NextResponse.json({
|
||||||
|
news: paginatedNews,
|
||||||
|
pagination: {
|
||||||
|
page,
|
||||||
|
limit,
|
||||||
|
total,
|
||||||
|
totalPages: Math.ceil(total / limit),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建新闻(禁用)
|
||||||
|
export async function POST(request: Request) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: '新闻发布功能已禁用,请通过后台手动更新' },
|
||||||
|
{ status: 403 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 178 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
|
@ -0,0 +1,109 @@
|
||||||
|
import { Button } from '@/components/ui/button'
|
||||||
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||||
|
import { MapPin, UserPlus, Store, ArrowRight, MessageCircle, ScanQrCode } from 'lucide-react'
|
||||||
|
|
||||||
|
export default function ContactPage() {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="pt-24 pb-20 bg-white">
|
||||||
|
{/* Header */}
|
||||||
|
<section className="container mx-auto px-4 md:px-6 mb-16 text-center">
|
||||||
|
<h1 className="text-4xl font-bold text-secondary mb-4">合作加盟</h1>
|
||||||
|
<p className="text-lg text-muted-foreground max-w-2xl mx-auto">
|
||||||
|
无论您是希望成为区域合伙人,还是商家寻求数字化转型,我们都期待与您携手共赢。
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div className="container mx-auto px-4 md:px-6">
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12">
|
||||||
|
|
||||||
|
{/* Left: Partner Benefits & Info */}
|
||||||
|
<div className="space-y-8">
|
||||||
|
{/* Partner Benefits */}
|
||||||
|
<Card className="border-0 shadow-lg bg-accent">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="text-xl flex items-center gap-2">
|
||||||
|
<UserPlus className="w-5 h-5 text-primary" />
|
||||||
|
合伙人权益
|
||||||
|
</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="space-y-4">
|
||||||
|
<div className="flex gap-4">
|
||||||
|
<div className="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center shrink-0">
|
||||||
|
<Store className="w-5 h-5 text-primary" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="font-semibold">区域独家保护</h3>
|
||||||
|
<p className="text-sm text-muted-foreground">享受区域内所有商家流水的分润,建立持久管道收益。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-4">
|
||||||
|
<div className="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center shrink-0">
|
||||||
|
<ArrowRight className="w-5 h-5 text-primary" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="font-semibold">全套运营支持</h3>
|
||||||
|
<p className="text-sm text-muted-foreground">提供技术培训、物料支持、招商会销支持,助您快速展业。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* Contact Info */}
|
||||||
|
<div className="space-y-6">
|
||||||
|
<h2 className="text-2xl font-bold text-secondary">联系我们</h2>
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<div className="w-12 h-12 bg-primary/10 rounded-lg flex items-center justify-center">
|
||||||
|
<MapPin className="w-5 h-5 text-primary" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-sm text-muted-foreground">公司地址</p>
|
||||||
|
<p className="font-semibold text-lg">天津市武清区京津产业新城海达商务大厦</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<Card className="border-0 shadow-lg">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="flex items-center gap-2">
|
||||||
|
<MessageCircle className="w-5 h-5 text-primary" />
|
||||||
|
扫码联系客服
|
||||||
|
</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="text-center">
|
||||||
|
<div className="flex flex-col items-center space-y-6">
|
||||||
|
<div className="relative">
|
||||||
|
<img
|
||||||
|
src="/baima-qrcode.png"
|
||||||
|
alt="企业微信客服二维码"
|
||||||
|
className="w-64 h-64 object-contain rounded-2xl shadow-2xl border-4 border-primary/20"
|
||||||
|
/>
|
||||||
|
<div className="absolute -bottom-2 -right-2 w-12 h-12 bg-primary rounded-full flex items-center justify-center shadow-lg">
|
||||||
|
<ScanQrCode className="w-6 h-6 text-white" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-3">
|
||||||
|
<h3 className="text-xl font-bold text-gray-900">
|
||||||
|
立即扫码,一对一沟通
|
||||||
|
</h3>
|
||||||
|
<p className="text-muted-foreground max-w-md">
|
||||||
|
我们的专业团队将为您提供详细的产品咨询和合作方案,期待与您携手共赢。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-2 text-sm text-primary font-medium">
|
||||||
|
<div className="w-2 h-2 bg-primary rounded-full animate-pulse" />
|
||||||
|
客服在线中,快速响应
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
import { Hero } from '@/components/home/Hero'
|
||||||
|
import { ProductPreview } from '@/components/home/ProductPreview'
|
||||||
|
import { MissionVisionEN } from '@/components/home/MissionVisionEN'
|
||||||
|
import { HonorSection } from '@/components/home/HonorSection'
|
||||||
|
import { Infrastructure } from '@/components/home/Infrastructure'
|
||||||
|
import { Button } from '@/components/ui/button'
|
||||||
|
import Link from 'next/link'
|
||||||
|
|
||||||
|
export default function Home() {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col w-full overflow-x-hidden">
|
||||||
|
{/* 1. Brand Positioning & Hero */}
|
||||||
|
<Hero />
|
||||||
|
|
||||||
|
{/* 2. Core Product Matrix */}
|
||||||
|
<div id="products" className="scroll-mt-20">
|
||||||
|
<ProductPreview />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 3. Mission, Vision & Values */}
|
||||||
|
<MissionVisionEN />
|
||||||
|
|
||||||
|
{/* 4. Authority Certifications & Technical Strength */}
|
||||||
|
<HonorSection />
|
||||||
|
|
||||||
|
{/* 5. Ecological Infrastructure */}
|
||||||
|
<Infrastructure />
|
||||||
|
|
||||||
|
{/* 7. Call to Action & Contact */}
|
||||||
|
<section id="contact" className="py-24 bg-gradient-to-br from-[#0A1931] to-[#185ADB] text-white text-center scroll-mt-20">
|
||||||
|
<div className="container mx-auto px-4">
|
||||||
|
<h2 className="text-3xl md:text-5xl font-black mb-8 leading-tight">
|
||||||
|
Connect with 120,000+ Merchants<br/>Create a New Business Ecosystem
|
||||||
|
</h2>
|
||||||
|
<p className="text-lg md:text-xl text-gray-300 max-w-3xl mx-auto mb-12 leading-relaxed">
|
||||||
|
Whether you're a brick-and-mortar business seeking transformation or an individual aspiring to entrepreneurship,
|
||||||
|
Baima Home provides a broad platform. Our ecosystem is fully open to the public -
|
||||||
|
click the button below to get in touch with us.
|
||||||
|
</p>
|
||||||
|
<div className="flex flex-col sm:flex-row gap-6 justify-center">
|
||||||
|
<Link
|
||||||
|
href="/contact#form"
|
||||||
|
className="inline-flex h-14 items-center justify-center rounded-full bg-[#FF6600] px-10 text-xl font-black shadow-2xl shadow-[#FF6600]/40 transition-all hover:bg-[#FF8C00] hover:scale-105"
|
||||||
|
>
|
||||||
|
Join Baima Alliance
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
href="/contact"
|
||||||
|
className="inline-flex h-14 items-center justify-center rounded-full border-2 border-white/30 px-10 text-lg font-bold transition-all hover:bg-white/10"
|
||||||
|
>
|
||||||
|
Learn More
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 257 KiB |
|
|
@ -0,0 +1,173 @@
|
||||||
|
@import "tailwindcss";
|
||||||
|
@import "tw-animate-css";
|
||||||
|
|
||||||
|
@custom-variant dark (&:is(.dark *));
|
||||||
|
|
||||||
|
@theme inline {
|
||||||
|
--color-background: var(--background);
|
||||||
|
--color-foreground: var(--foreground);
|
||||||
|
--font-sans: var(--font-geist-sans);
|
||||||
|
--font-mono: var(--font-geist-mono);
|
||||||
|
|
||||||
|
/* Brand Colors */
|
||||||
|
--color-primary-blue: var(--primary-blue);
|
||||||
|
--color-accent-blue: var(--accent-blue);
|
||||||
|
--color-primary-orange: var(--primary-orange);
|
||||||
|
--color-secondary-orange: var(--secondary-orange);
|
||||||
|
|
||||||
|
/* UI Colors */
|
||||||
|
--color-primary: var(--primary);
|
||||||
|
--color-primary-foreground: var(--primary-foreground);
|
||||||
|
--color-secondary: var(--secondary);
|
||||||
|
--color-secondary-foreground: var(--secondary-foreground);
|
||||||
|
--color-accent: var(--accent);
|
||||||
|
--color-accent-foreground: var(--accent-foreground);
|
||||||
|
--color-destructive: var(--destructive);
|
||||||
|
--color-destructive-foreground: var(--destructive-foreground);
|
||||||
|
--color-muted: var(--muted);
|
||||||
|
--color-muted-foreground: var(--muted-foreground);
|
||||||
|
--color-card: var(--card);
|
||||||
|
--color-card-foreground: var(--card-foreground);
|
||||||
|
--color-popover: var(--popover);
|
||||||
|
--color-popover-foreground: var(--popover-foreground);
|
||||||
|
--color-border: var(--border);
|
||||||
|
--color-input: var(--input);
|
||||||
|
--color-ring: var(--ring);
|
||||||
|
|
||||||
|
/* Radius */
|
||||||
|
--radius-sm: calc(var(--radius) - 4px);
|
||||||
|
--radius-md: calc(var(--radius) - 2px);
|
||||||
|
--radius-lg: var(--radius);
|
||||||
|
--radius-xl: calc(var(--radius) + 4px);
|
||||||
|
--radius-2xl: calc(var(--radius) + 8px);
|
||||||
|
--radius-3xl: calc(var(--radius) + 12px);
|
||||||
|
--radius-4xl: calc(var(--radius) + 16px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 融合配色方案 */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
/* 品牌深蓝色调 */
|
||||||
|
--primary-blue: oklch(0.15 0.03 260);
|
||||||
|
--accent-blue: oklch(0.45 0.15 240);
|
||||||
|
|
||||||
|
/* 活力橙 */
|
||||||
|
--primary-orange: oklch(0.65 0.18 40);
|
||||||
|
--secondary-orange: oklch(0.7 0.18 45);
|
||||||
|
|
||||||
|
/* 基础色 */
|
||||||
|
--primary: var(--primary-orange);
|
||||||
|
--primary-foreground: oklch(0.99 0 0);
|
||||||
|
|
||||||
|
--secondary: var(--primary-blue);
|
||||||
|
--secondary-foreground: oklch(0.99 0 0);
|
||||||
|
|
||||||
|
--background: oklch(0.98 0.01 260);
|
||||||
|
--foreground: oklch(0.15 0.02 260);
|
||||||
|
|
||||||
|
--card: oklch(1 0 0);
|
||||||
|
--card-foreground: oklch(0.15 0.02 260);
|
||||||
|
|
||||||
|
--popover: oklch(1 0 0);
|
||||||
|
--popover-foreground: oklch(0.15 0.02 260);
|
||||||
|
|
||||||
|
--accent: oklch(0.96 0.01 260);
|
||||||
|
--accent-foreground: oklch(0.15 0.02 260);
|
||||||
|
|
||||||
|
--muted: oklch(0.94 0.01 260);
|
||||||
|
--muted-foreground: oklch(0.5 0.02 260);
|
||||||
|
|
||||||
|
--destructive: oklch(0.55 0.2 25);
|
||||||
|
--destructive-foreground: oklch(0.99 0 0);
|
||||||
|
|
||||||
|
--border: oklch(0.9 0.01 260);
|
||||||
|
--input: oklch(0.9 0.01 260);
|
||||||
|
--ring: var(--primary-orange);
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
* {
|
||||||
|
@apply border-border outline-ring/50;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
@apply bg-background text-foreground antialiased;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 全局字体放大 */
|
||||||
|
html {
|
||||||
|
font-size: 17px; /* 基础字体稍大 */
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
@apply font-black text-[#0A1931];
|
||||||
|
font-size: 2.75rem;
|
||||||
|
line-height: 1.2;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
@apply font-bold text-[#0A1931];
|
||||||
|
font-size: 2.25rem;
|
||||||
|
line-height: 1.25;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
@apply font-bold text-[#0A1931];
|
||||||
|
font-size: 1.5rem;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4, h5, h6 {
|
||||||
|
@apply font-semibold text-[#0A1931];
|
||||||
|
font-size: 1.125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
@apply leading-relaxed text-gray-600;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 通用卡片悬浮效果 */
|
||||||
|
.card-hover {
|
||||||
|
transition: all 0.4s ease;
|
||||||
|
}
|
||||||
|
.card-hover:hover {
|
||||||
|
transform: translateY(-15px);
|
||||||
|
box-shadow: 0 20px 50px rgba(24, 90, 219, 0.15);
|
||||||
|
border-color: var(--accent-blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 重点文字高亮样式 */
|
||||||
|
.highlight-text {
|
||||||
|
@apply text-[#FF6600] font-bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.key-point {
|
||||||
|
@apply font-bold text-[#0A1931] bg-gradient-to-r from-orange-50 to-orange-100 px-2 py-0.5 rounded;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式字体调整 */
|
||||||
|
@layer utilities {
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
html {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 2rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 1.75rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 1.25rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 0.95rem !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
import type { Metadata } from 'next'
|
||||||
|
import { Geist, Geist_Mono } from 'next/font/google'
|
||||||
|
import { Navbar } from '@/components/layout/Navbar'
|
||||||
|
import { Footer } from '@/components/layout/Footer'
|
||||||
|
import './globals.css'
|
||||||
|
|
||||||
|
const geistSans = Geist({
|
||||||
|
variable: '--font-geist-sans',
|
||||||
|
subsets: ['latin'],
|
||||||
|
})
|
||||||
|
|
||||||
|
const geistMono = Geist_Mono({
|
||||||
|
variable: '--font-geist-mono',
|
||||||
|
subsets: ['latin'],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: '白马家园—新质生产力产业集群',
|
||||||
|
description: 'AI时代小微创业+消费循环生态圈,军工技术赋能实体经济,人工智能驱动万商互联。',
|
||||||
|
icons: {
|
||||||
|
icon: '/logos.png',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function RootLayout({
|
||||||
|
children,
|
||||||
|
}: Readonly<{
|
||||||
|
children: React.ReactNode
|
||||||
|
}>) {
|
||||||
|
return (
|
||||||
|
<html lang="zh-CN" className="scroll-smooth">
|
||||||
|
<body
|
||||||
|
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||||
|
>
|
||||||
|
<Navbar />
|
||||||
|
<main>
|
||||||
|
{children}
|
||||||
|
</main>
|
||||||
|
<Footer />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,139 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useState, useEffect } from 'react'
|
||||||
|
import { motion } from 'framer-motion'
|
||||||
|
import { Calendar, Eye, ArrowRight, Loader2 } from 'lucide-react'
|
||||||
|
import { Card, CardContent } from '@/components/ui/card'
|
||||||
|
import Link from 'next/link'
|
||||||
|
|
||||||
|
type News = {
|
||||||
|
id: number
|
||||||
|
title: string
|
||||||
|
category: string
|
||||||
|
excerpt: string
|
||||||
|
createdAt: string
|
||||||
|
views: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const categories = ["全部", "公司新闻", "荣誉获奖", "产品发布", "媒体报道", "行业洞察"]
|
||||||
|
|
||||||
|
export default function NewsPage() {
|
||||||
|
const [news, setNews] = useState<News[]>([])
|
||||||
|
const [isLoading, setIsLoading] = useState(true)
|
||||||
|
const [activeCategory, setActiveCategory] = useState("全部")
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchNews = async () => {
|
||||||
|
try {
|
||||||
|
const url = activeCategory === "全部"
|
||||||
|
? '/api/news'
|
||||||
|
: `/api/news?category=${encodeURIComponent(activeCategory)}`
|
||||||
|
const res = await fetch(url)
|
||||||
|
if (res.ok) {
|
||||||
|
const data = await res.json()
|
||||||
|
setNews(data.news)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载新闻失败', error)
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fetchNews()
|
||||||
|
}, [activeCategory])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-white pt-24 pb-20">
|
||||||
|
<div className="container mx-auto px-4 md:px-6">
|
||||||
|
{/* Header */}
|
||||||
|
<div className="text-center mb-16">
|
||||||
|
<h1 className="text-4xl md:text-5xl font-black text-[#0A1931] mb-4">
|
||||||
|
最新动态
|
||||||
|
</h1>
|
||||||
|
<p className="text-lg text-gray-500 max-w-2xl mx-auto">
|
||||||
|
了解白马家园最新资讯,分享我们的成长与思考
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Category Filter */}
|
||||||
|
<div className="flex flex-wrap justify-center gap-2 mb-12">
|
||||||
|
{categories.map((category) => (
|
||||||
|
<button
|
||||||
|
key={category}
|
||||||
|
onClick={() => setActiveCategory(category)}
|
||||||
|
className={`px-6 py-2 rounded-full text-sm font-bold transition-all ${
|
||||||
|
activeCategory === category
|
||||||
|
? 'bg-[#FF6600] text-white shadow-lg'
|
||||||
|
: 'bg-gray-100 text-gray-500 hover:bg-gray-200'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{category}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Loading State */}
|
||||||
|
{isLoading ? (
|
||||||
|
<div className="flex justify-center items-center py-20">
|
||||||
|
<Loader2 className="w-8 h-8 animate-spin text-[#FF6600]" />
|
||||||
|
</div>
|
||||||
|
) : news.length === 0 ? (
|
||||||
|
<div className="text-center py-20 text-gray-400 font-medium">
|
||||||
|
该分类下暂无动态
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
/* News Grid */
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||||
|
{news.map((item, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={item.id}
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.5, delay: index * 0.1 }}
|
||||||
|
>
|
||||||
|
<Link href="#" className="group block h-full">
|
||||||
|
<Card className="h-full border-0 shadow-lg hover:shadow-xl transition-all duration-300 overflow-hidden card-hover">
|
||||||
|
{/* Placeholder Color Block */}
|
||||||
|
<div className="h-40 bg-gradient-to-br from-[#0A1931] to-[#185ADB] flex items-center justify-center">
|
||||||
|
<span className="text-white/10 text-6xl font-black">{item.id}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<CardContent className="p-6">
|
||||||
|
<div className="flex items-center justify-between mb-4">
|
||||||
|
<span className="text-xs font-bold text-[#FF6600] bg-orange-50 px-3 py-1 rounded-full">
|
||||||
|
{item.category}
|
||||||
|
</span>
|
||||||
|
<div className="flex items-center text-xs text-gray-400 font-mono">
|
||||||
|
<Calendar className="w-3 h-3 mr-1" />
|
||||||
|
{new Date(item.createdAt).toLocaleDateString()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3 className="text-lg font-bold text-[#0A1931] mb-3 group-hover:text-[#FF6600] transition-colors line-clamp-2">
|
||||||
|
{item.title}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<p className="text-sm text-gray-500 mb-6 line-clamp-3 leading-relaxed">
|
||||||
|
{item.excerpt}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="flex items-center justify-between pt-4 border-t border-gray-100">
|
||||||
|
<div className="flex items-center text-xs text-gray-400">
|
||||||
|
<Eye className="w-3 h-3 mr-1" />
|
||||||
|
{item.views} 次阅读
|
||||||
|
</div>
|
||||||
|
<span className="flex items-center text-sm font-bold text-[#FF6600] group-hover:translate-x-1 transition-transform">
|
||||||
|
阅读详情 <ArrowRight className="ml-1 w-4 h-4" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</Link>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { Hero } from '@/components/home/Hero'
|
||||||
|
import { ProductPreview } from '@/components/home/ProductPreview'
|
||||||
|
import { MissionVision } from '@/components/home/MissionVision'
|
||||||
|
import { HonorSection } from '@/components/home/HonorSection'
|
||||||
|
import { Infrastructure } from '@/components/home/Infrastructure'
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<main className="min-h-screen">
|
||||||
|
{/* 1. Hero首屏 */}
|
||||||
|
<Hero />
|
||||||
|
|
||||||
|
{/* 2. 产品矩阵 */}
|
||||||
|
<ProductPreview />
|
||||||
|
|
||||||
|
{/* 3. 使命、愿景、价值观 */}
|
||||||
|
<MissionVision />
|
||||||
|
|
||||||
|
{/* 4. 权威认证与技术实力 */}
|
||||||
|
<HonorSection />
|
||||||
|
|
||||||
|
{/* 5. 生态基础设施 */}
|
||||||
|
<Infrastructure />
|
||||||
|
|
||||||
|
{/* 6. 页脚 - 在 Layout.tsx 中 */}
|
||||||
|
</main>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 178 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
|
@ -0,0 +1,50 @@
|
||||||
|
import { ProductList } from '@/components/products/ProductList'
|
||||||
|
import { Button } from '@/components/ui/button'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import { ArrowRight } from 'lucide-react'
|
||||||
|
|
||||||
|
export default function ProductsPage() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-white pt-24 pb-20">
|
||||||
|
<div className="container mx-auto px-4 md:px-6">
|
||||||
|
{/* Page Header */}
|
||||||
|
<div className="max-w-3xl mx-auto text-center mb-16">
|
||||||
|
<h1 className="text-4xl md:text-5xl font-bold text-secondary mb-6">
|
||||||
|
产品服务
|
||||||
|
</h1>
|
||||||
|
<p className="text-lg text-muted-foreground leading-relaxed">
|
||||||
|
基于军工级技术底座,我们构建了从支付结算、私域运营到异业联盟的完整生态闭环,
|
||||||
|
助力小微企业在 AI 时代实现数字化升级与业绩倍增。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Navigation Tabs */}
|
||||||
|
<div className="sticky top-20 z-40 bg-white/95 backdrop-blur-md py-4 mb-8 border-b border-gray-100 hidden md:block">
|
||||||
|
<nav className="flex justify-center gap-8">
|
||||||
|
<a href="#fintech" className="text-sm font-medium text-muted-foreground hover:text-primary transition-colors">金融科技</a>
|
||||||
|
<a href="#ai" className="text-sm font-medium text-muted-foreground hover:text-primary transition-colors">私域运营</a>
|
||||||
|
<a href="#alliance" className="text-sm font-medium text-muted-foreground hover:text-primary transition-colors">异业联盟</a>
|
||||||
|
<a href="#infrastructure" className="text-sm font-medium text-muted-foreground hover:text-primary transition-colors">生态基建</a>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ProductList />
|
||||||
|
|
||||||
|
{/* CTA */}
|
||||||
|
<div className="mt-24 text-center bg-accent rounded-2xl p-12">
|
||||||
|
<h2 className="text-3xl font-bold text-secondary mb-4">准备好升级您的商业模式了吗?</h2>
|
||||||
|
<p className="text-muted-foreground mb-8 max-w-2xl mx-auto">
|
||||||
|
立即接入白马家园生态,开启数智化转型之旅。
|
||||||
|
</p>
|
||||||
|
<div className="flex justify-center gap-4">
|
||||||
|
<Button size="lg" asChild className="bg-primary hover:bg-primary/90 text-white rounded-full px-8">
|
||||||
|
<Link href="/contact">
|
||||||
|
立即咨询 <ArrowRight className="ml-2 h-4 w-4" />
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://ui.shadcn.com/schema.json",
|
||||||
|
"style": "new-york",
|
||||||
|
"rsc": true,
|
||||||
|
"tsx": true,
|
||||||
|
"tailwind": {
|
||||||
|
"config": "",
|
||||||
|
"css": "app/globals.css",
|
||||||
|
"baseColor": "neutral",
|
||||||
|
"cssVariables": true,
|
||||||
|
"prefix": ""
|
||||||
|
},
|
||||||
|
"iconLibrary": "lucide",
|
||||||
|
"aliases": {
|
||||||
|
"components": "@/components",
|
||||||
|
"utils": "@/lib/utils",
|
||||||
|
"ui": "@/components/ui",
|
||||||
|
"lib": "@/lib",
|
||||||
|
"hooks": "@/hooks"
|
||||||
|
},
|
||||||
|
"registries": {}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { Trophy, Award, FileText, Medal } from 'lucide-react'
|
||||||
|
|
||||||
|
const awards = [
|
||||||
|
"2023 科大讯飞 AI 开发者大赛数字人赛道冠军",
|
||||||
|
"2022 中国产业元宇宙创新大赛一等奖",
|
||||||
|
"2023 元宇宙应用场景大赛产业生态先锋奖",
|
||||||
|
"2024 退役军人创新创业大赛一等奖"
|
||||||
|
]
|
||||||
|
|
||||||
|
const patents = [
|
||||||
|
"发明专利:融合多信息的 AI 虚拟人与用户交互方法",
|
||||||
|
"发明专利:一种虚拟人物不同表情模型生成方法",
|
||||||
|
"80+ 项计算机软件著作权",
|
||||||
|
"50+ 项资质证书与备案"
|
||||||
|
]
|
||||||
|
|
||||||
|
export function Certifications() {
|
||||||
|
return (
|
||||||
|
<section className="py-20 bg-white" id="honor">
|
||||||
|
<div className="container mx-auto px-4 md:px-6">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-12 items-center">
|
||||||
|
{/* Text Content */}
|
||||||
|
<div className="space-y-8">
|
||||||
|
<div>
|
||||||
|
<h2 className="text-3xl font-bold text-secondary mb-6">荣誉与资质</h2>
|
||||||
|
<p className="text-muted-foreground mb-8">
|
||||||
|
凭借领先的技术实力与创新模式,白马家园荣获多项国家级大奖,并拥有完备的知识产权体系。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div className="flex gap-4">
|
||||||
|
<div className="w-12 h-12 rounded-lg bg-primary/10 flex items-center justify-center shrink-0">
|
||||||
|
<Trophy className="w-6 h-6 text-primary" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="font-bold text-lg mb-2">权威奖项</h3>
|
||||||
|
<ul className="space-y-2">
|
||||||
|
{awards.map((award, i) => (
|
||||||
|
<li key={i} className="flex items-center text-sm text-muted-foreground">
|
||||||
|
<span className="w-1.5 h-1.5 bg-primary rounded-full mr-2"></span>
|
||||||
|
{award}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex gap-4">
|
||||||
|
<div className="w-12 h-12 rounded-lg bg-primary/10 flex items-center justify-center shrink-0">
|
||||||
|
<FileText className="w-6 h-6 text-primary" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="font-bold text-lg mb-2">知识产权</h3>
|
||||||
|
<ul className="space-y-2">
|
||||||
|
{patents.map((patent, i) => (
|
||||||
|
<li key={i} className="flex items-center text-sm text-muted-foreground">
|
||||||
|
<span className="w-1.5 h-1.5 bg-primary rounded-full mr-2"></span>
|
||||||
|
{patent}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Certificate Cards */}
|
||||||
|
<div className="grid grid-cols-2 gap-4">
|
||||||
|
<div className="aspect-[3/4] bg-accent rounded-lg shadow-sm border border-gray-100 p-4 flex flex-col items-center justify-center text-center">
|
||||||
|
<Medal className="w-12 h-12 text-primary mb-4" />
|
||||||
|
<span className="text-xs font-medium text-muted-foreground">科大讯飞冠军证书</span>
|
||||||
|
</div>
|
||||||
|
<div className="aspect-[3/4] bg-accent rounded-lg shadow-sm border border-gray-100 p-4 flex flex-col items-center justify-center text-center mt-8">
|
||||||
|
<Award className="w-12 h-12 text-primary mb-4" />
|
||||||
|
<span className="text-xs font-medium text-muted-foreground">发明专利证书</span>
|
||||||
|
</div>
|
||||||
|
<div className="aspect-[3/4] bg-accent rounded-lg shadow-sm border border-gray-100 p-4 flex flex-col items-center justify-center text-center">
|
||||||
|
<Trophy className="w-12 h-12 text-primary mb-4" />
|
||||||
|
<span className="text-xs font-medium text-muted-foreground">创新大赛一等奖</span>
|
||||||
|
</div>
|
||||||
|
<div className="aspect-[3/4] bg-accent rounded-lg shadow-sm border border-gray-100 p-4 flex flex-col items-center justify-center text-center mt-8">
|
||||||
|
<FileText className="w-12 h-12 text-primary mb-4" />
|
||||||
|
<span className="text-xs font-medium text-muted-foreground">收单外包服务机构备案</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'
|
||||||
|
import { Badge } from '@/components/ui/badge'
|
||||||
|
import { User } from 'lucide-react'
|
||||||
|
|
||||||
|
const team = [
|
||||||
|
{
|
||||||
|
name: "汪洋",
|
||||||
|
role: "董事长",
|
||||||
|
badges: ["国防科大本硕博", "高级工程师", "上校转业"],
|
||||||
|
description: "深度参与神舟、嫦娥、北斗等航天任务。获中国青年科技奖,全网粉丝100万+ AIGC/元宇宙博主。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "段海龙",
|
||||||
|
role: "技术总监",
|
||||||
|
badges: ["国防科大学士", "中科大硕士", "高级工程师"],
|
||||||
|
description: "专注于人工智能、机器视觉方向。发表论文20多篇,软著及专利20余项。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "秦波",
|
||||||
|
role: "总经理",
|
||||||
|
badges: ["第一军医大学", "副主任医师", "正团职转业"],
|
||||||
|
description: "资深健康养老产业链专家,军队医院保健专家。10年以上市场招商渠道拓展经验。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "焦文军",
|
||||||
|
role: "CFO",
|
||||||
|
badges: ["中国十大杰出CFO", "天狮前副总裁"],
|
||||||
|
description: "多家港股、美股公司上市操盘手。中央财经大学、南开大学客座教授。"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export function Team() {
|
||||||
|
return (
|
||||||
|
<section className="py-20 bg-accent" id="team">
|
||||||
|
<div className="container mx-auto px-4 md:px-6">
|
||||||
|
<div className="text-center mb-16">
|
||||||
|
<h2 className="text-3xl font-bold text-secondary mb-4">核心精英团队</h2>
|
||||||
|
<p className="text-muted-foreground max-w-2xl mx-auto">
|
||||||
|
汇聚军工、医疗、金融等领域的顶尖人才,以硬核技术驱动商业创新。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
|
||||||
|
{team.map((member, index) => (
|
||||||
|
<Card key={index} className="border-0 shadow-lg hover:shadow-xl transition-all">
|
||||||
|
<CardHeader className="text-center pb-2">
|
||||||
|
<div className="w-24 h-24 mx-auto bg-white rounded-full flex items-center justify-center mb-4 shadow-md">
|
||||||
|
<User className="w-10 h-10 text-primary" />
|
||||||
|
</div>
|
||||||
|
<CardTitle className="text-xl font-bold">{member.name}</CardTitle>
|
||||||
|
<CardDescription className="text-primary font-medium">{member.role}</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="text-center">
|
||||||
|
<div className="flex flex-wrap justify-center gap-2 mb-4">
|
||||||
|
{member.badges.map((badge, bIndex) => (
|
||||||
|
<Badge key={bIndex} variant="secondary" className="text-xs bg-primary/10 text-primary">
|
||||||
|
{badge}
|
||||||
|
</Badge>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<p className="text-sm text-muted-foreground text-left leading-relaxed">
|
||||||
|
{member.description}
|
||||||
|
</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion'
|
||||||
|
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'
|
||||||
|
import { Badge } from '@/components/ui/badge'
|
||||||
|
import { User, ShieldCheck, TrendingUp } from 'lucide-react'
|
||||||
|
|
||||||
|
const team = [
|
||||||
|
{
|
||||||
|
name: "汪洋",
|
||||||
|
role: "董事长",
|
||||||
|
badges: ["国防科大本硕博", "航天级专家"],
|
||||||
|
description: "深度参与神舟、北斗任务。全网粉丝100万+ AIGC头部博主。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "段海龙",
|
||||||
|
role: "技术总监",
|
||||||
|
badges: ["国防科大学士", "高级工程师"],
|
||||||
|
description: "专注AI与机器视觉。发表论文20多篇,拥有专利20余项。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "秦波",
|
||||||
|
role: "总经理",
|
||||||
|
badges: ["第一军医大学", "正团职转业"],
|
||||||
|
description: "资深康养专家,10年以上市场招商渠道拓展经验。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "焦文军",
|
||||||
|
role: "CFO",
|
||||||
|
badges: ["十大杰出CFO", "操盘上市"],
|
||||||
|
description: "多家上市公司操盘手。中央财经大学、南开大学客座教授。"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export function AboutSection() {
|
||||||
|
return (
|
||||||
|
<section id="about" className="py-24 bg-white scroll-mt-20">
|
||||||
|
<div className="container mx-auto px-4 md:px-6">
|
||||||
|
<div className="max-w-4xl mx-auto text-center mb-20">
|
||||||
|
<Badge variant="outline" className="mb-4 border-[#FF6600] text-[#FF6600] bg-orange-50 font-bold">
|
||||||
|
关于白马家园
|
||||||
|
</Badge>
|
||||||
|
<h2 className="text-3xl md:text-5xl font-black text-[#0A1931] mb-6">
|
||||||
|
军工技术赋能实体经济
|
||||||
|
</h2>
|
||||||
|
<p className="text-lg text-gray-500 leading-relaxed">
|
||||||
|
白马家园是一家拥有国资背景的高新技术企业,已获五轮融资超 2 亿元。
|
||||||
|
我们致力于解决实体商家“流量难、锁客难、变现难”的痛点,
|
||||||
|
构建万商互联的共享经济生态。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 核心团队 */}
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6 md:gap-8">
|
||||||
|
{team.map((member, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={index}
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ delay: index * 0.1 }}
|
||||||
|
>
|
||||||
|
<Card className="border-0 shadow-lg hover:shadow-xl transition-all h-full bg-gray-50/50 group">
|
||||||
|
<CardHeader className="text-center pb-4">
|
||||||
|
<div className="w-20 h-20 mx-auto bg-white rounded-2xl flex items-center justify-center mb-4 shadow-sm group-hover:bg-[#FF6600] transition-colors duration-300">
|
||||||
|
<User className="w-10 h-10 text-[#0A1931] group-hover:text-white" />
|
||||||
|
</div>
|
||||||
|
<CardTitle className="text-xl font-bold text-[#0A1931]">{member.name}</CardTitle>
|
||||||
|
<CardDescription className="text-[#FF6600] font-bold">{member.role}</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="flex flex-wrap justify-center gap-1.5 mb-4">
|
||||||
|
{member.badges.map((badge, bIndex) => (
|
||||||
|
<span key={bIndex} className="text-[10px] font-bold bg-white px-2 py-0.5 rounded border border-gray-100 text-gray-500">
|
||||||
|
{badge}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<p className="text-sm text-gray-500 leading-relaxed text-center">
|
||||||
|
{member.description}
|
||||||
|
</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion'
|
||||||
|
import { CheckCircle2, TrendingUp, Users, Building2 } from 'lucide-react'
|
||||||
|
import { Button } from '@/components/ui/button'
|
||||||
|
import Link from 'next/link'
|
||||||
|
|
||||||
|
export function Ecosystem() {
|
||||||
|
return (
|
||||||
|
<section className="py-24 bg-secondary text-white relative overflow-hidden">
|
||||||
|
{/* Background Effects */}
|
||||||
|
<div className="absolute inset-0 overflow-hidden">
|
||||||
|
<div className="absolute -top-40 -right-40 w-80 h-80 bg-primary/20 rounded-full blur-3xl"></div>
|
||||||
|
<div className="absolute -bottom-40 -left-40 w-80 h-80 bg-primary/10 rounded-full blur-3xl"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="container px-4 md:px-6 mx-auto relative z-10">
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-16 items-center">
|
||||||
|
{/* Left Content */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, x: -50 }}
|
||||||
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.6 }}
|
||||||
|
>
|
||||||
|
<h2 className="text-3xl md:text-5xl font-bold mb-6">
|
||||||
|
数据收益
|
||||||
|
<span className="text-primary"> 优先分配</span>
|
||||||
|
</h2>
|
||||||
|
<p className="text-lg text-gray-300 mb-8 leading-relaxed">
|
||||||
|
白马家园首创"数据收益优先分配权",让创造数据的人优先分享数据带来的增值红利。
|
||||||
|
我们相信,只有相互成就,才能共建可持续发展的商业生态。
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{/* Features List */}
|
||||||
|
<div className="space-y-5 mb-10">
|
||||||
|
{[
|
||||||
|
{ icon: TrendingUp, text: '时时/单单/天天补贴,立即到账' },
|
||||||
|
{ icon: Users, text: '用户消费即参与利润分配' },
|
||||||
|
{ icon: Building2, text: '商家让利即获得流量回馈' },
|
||||||
|
{ icon: CheckCircle2, text: '透明公开,无泡沫正向拨比' }
|
||||||
|
].map((item, index) => (
|
||||||
|
<div key={index} className="flex items-center gap-4">
|
||||||
|
<div className="w-10 h-10 bg-primary/20 rounded-lg flex items-center justify-center">
|
||||||
|
<item.icon className="w-5 h-5 text-primary" />
|
||||||
|
</div>
|
||||||
|
<span className="text-gray-200">{item.text}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button asChild className="bg-primary hover:bg-primary/90 text-white rounded-full px-8 h-12">
|
||||||
|
<Link href="/contact">立即加入生态</Link>
|
||||||
|
</Button>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
{/* Right Visual */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, scale: 0.9 }}
|
||||||
|
whileInView={{ opacity: 1, scale: 1 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.6 }}
|
||||||
|
className="relative"
|
||||||
|
>
|
||||||
|
{/* Central Circle */}
|
||||||
|
<div className="relative aspect-square w-full max-w-md mx-auto">
|
||||||
|
{/* Outer Ring */}
|
||||||
|
<div className="absolute inset-0 border-2 border-white/10 rounded-full"></div>
|
||||||
|
|
||||||
|
{/* Inner Content */}
|
||||||
|
<div className="absolute inset-8 border border-white/10 rounded-full flex items-center justify-center">
|
||||||
|
<div className="w-32 h-32 bg-primary rounded-full flex items-center justify-center shadow-lg shadow-primary/30">
|
||||||
|
<span className="font-bold text-white text-lg">白马家园</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Orbiting Elements */}
|
||||||
|
{[
|
||||||
|
{ angle: 0, label: '消费者' },
|
||||||
|
{ angle: 90, label: '商家' },
|
||||||
|
{ angle: 180, label: '供应链' },
|
||||||
|
{ angle: 270, label: '平台' }
|
||||||
|
].map((item, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className="absolute w-20 h-20 bg-white/10 backdrop-blur-sm rounded-xl flex items-center justify-center border border-white/20"
|
||||||
|
style={{
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: `translate(-50%, -50%) rotate(${item.angle}deg) translateY(-140px) rotate(-${item.angle}deg)`
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="text-sm font-medium">{item.label}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{/* Connection Lines */}
|
||||||
|
<svg className="absolute inset-0 w-full h-full pointer-events-none opacity-20">
|
||||||
|
<circle cx="50%" cy="50%" r="140" fill="none" stroke="white" strokeWidth="1" strokeDasharray="5,5" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion'
|
||||||
|
import {
|
||||||
|
ShieldCheck,
|
||||||
|
Cpu,
|
||||||
|
TrendingUp,
|
||||||
|
Users,
|
||||||
|
Globe,
|
||||||
|
Award
|
||||||
|
} from 'lucide-react'
|
||||||
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||||
|
|
||||||
|
const features = [
|
||||||
|
{
|
||||||
|
icon: ShieldCheck,
|
||||||
|
title: "国资背景",
|
||||||
|
description: "获五轮融资超2亿元,中华财政部、社保基金理事会等间接持股,实力雄厚,稳健经营。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Cpu,
|
||||||
|
title: "军工技术",
|
||||||
|
description: "国防科大核心团队,拥有80+项发明专利。将航天级技术应用于实体经济数字化转型。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: TrendingUp,
|
||||||
|
title: "数据收益",
|
||||||
|
description: "首创'数据收益优先分配权',让用户和商家共享数据增值红利,打造可持续商业模式。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Users,
|
||||||
|
title: "顶尖团队",
|
||||||
|
description: "汇聚国防科大、中科大等名校精英,以及上市企业高管、杰出CFO等行业领袖。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Globe,
|
||||||
|
title: "合规保障",
|
||||||
|
description: "拥有收单外包服务机构备案,资金受银监会监管。数商备案接入,工商税务监管系统实时对接。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Award,
|
||||||
|
title: "权威认可",
|
||||||
|
description: "科大讯飞AI开发者大赛冠军、中国产业元宇宙创新大赛一等奖,央视等权威媒体多次报道。"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export function Features() {
|
||||||
|
return (
|
||||||
|
<section className="py-24 bg-white">
|
||||||
|
<div className="container px-4 md:px-6 mx-auto">
|
||||||
|
{/* Section Header */}
|
||||||
|
<div className="text-center mb-16">
|
||||||
|
<motion.h2
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
className="text-3xl md:text-4xl font-bold text-secondary mb-4"
|
||||||
|
>
|
||||||
|
核心优势
|
||||||
|
</motion.h2>
|
||||||
|
<motion.p
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ delay: 0.1 }}
|
||||||
|
className="text-lg text-muted-foreground max-w-2xl mx-auto"
|
||||||
|
>
|
||||||
|
依托强大的技术壁垒与资本实力,为实体经济数字化转型提供坚实保障
|
||||||
|
</motion.p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Features Grid */}
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||||
|
{features.map((feature, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={index}
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.5, delay: index * 0.1 }}
|
||||||
|
>
|
||||||
|
<Card className="h-full border-0 shadow-lg hover:shadow-xl transition-all duration-300 group bg-accent">
|
||||||
|
<CardHeader className="pb-4">
|
||||||
|
<div className="w-14 h-14 bg-primary/10 rounded-xl flex items-center justify-center mb-4 group-hover:bg-primary group-hover:text-white transition-all duration-300">
|
||||||
|
<feature.icon className="w-7 h-7 text-primary group-hover:text-white" />
|
||||||
|
</div>
|
||||||
|
<CardTitle className="text-xl font-bold text-secondary group-hover:text-primary transition-colors">
|
||||||
|
{feature.title}
|
||||||
|
</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<p className="text-muted-foreground leading-relaxed">
|
||||||
|
{feature.description}
|
||||||
|
</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,137 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion'
|
||||||
|
import Image from 'next/image'
|
||||||
|
import { ArrowRight } from 'lucide-react'
|
||||||
|
import Link from 'next/link'
|
||||||
|
|
||||||
|
export function Hero() {
|
||||||
|
return (
|
||||||
|
<section className="relative w-full min-h-screen flex items-center justify-center overflow-hidden bg-[#050A14] pt-16">
|
||||||
|
{/* Background Gradient */}
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-br from-[#0A1931] via-[#0d1f45] to-[#050A14]"></div>
|
||||||
|
|
||||||
|
{/* Grid Effect */}
|
||||||
|
<div className="absolute inset-0 opacity-20">
|
||||||
|
<svg className="w-full h-full hidden sm:block">
|
||||||
|
<defs>
|
||||||
|
<pattern id="grid-blue" width="60" height="60" patternUnits="userSpaceOnUse">
|
||||||
|
<path d="M 60 0 L 0 0 0 60" fill="none" stroke="white" strokeWidth="0.5" strokeOpacity="0.3"/>
|
||||||
|
</pattern>
|
||||||
|
</defs>
|
||||||
|
<rect width="100%" height="100%" fill="url(#grid-blue)" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Glow Effects */}
|
||||||
|
<div className="absolute top-1/4 left-1/4 w-64 h-64 md:w-96 md:h-96 bg-[#185ADB] rounded-full blur-[100px] md:blur-[150px] opacity-20 animate-pulse hidden sm:block"></div>
|
||||||
|
<div className="absolute bottom-1/4 right-1/4 w-48 h-48 md:w-80 md:h-80 bg-[#FF6600] rounded-full blur-[80px] md:blur-[120px] opacity-15 hidden sm:block"></div>
|
||||||
|
|
||||||
|
<div className="container relative z-10 px-4 md:px-6 mx-auto">
|
||||||
|
<div className="max-w-5xl mx-auto text-center mb-3">
|
||||||
|
|
||||||
|
{/* Logo */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.6 }}
|
||||||
|
className="mb-6 md:mb-10"
|
||||||
|
>
|
||||||
|
<div className="relative h-16 w-auto aspect-[2/1] mx-auto sm:h-20 md:h-28">
|
||||||
|
<Image
|
||||||
|
src="/baima-logo.png"
|
||||||
|
alt="白马家园 Logo"
|
||||||
|
fill
|
||||||
|
className="object-contain"
|
||||||
|
priority
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
{/* Tags - 放大并突出 */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.6 }}
|
||||||
|
className="flex flex-wrap justify-center gap-3 md:gap-4 mb-8 md:mb-10"
|
||||||
|
>
|
||||||
|
{[
|
||||||
|
"小微企业数智化升级",
|
||||||
|
"AI + Fintech 生态圈",
|
||||||
|
"军工技术赋能"
|
||||||
|
].map((tag, index) => (
|
||||||
|
<span
|
||||||
|
key={index}
|
||||||
|
className="px-4 py-2 md:px-5 md:py-2.5 bg-white/10 border border-white/20 rounded-full text-sm md:text-base font-bold text-white backdrop-blur-sm shadow-lg"
|
||||||
|
>
|
||||||
|
{tag}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
{/* Headline - 超大号字体,核心卖点突出 */}
|
||||||
|
<motion.h1
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.6, delay: 0.1 }}
|
||||||
|
className="text-3xl sm:text-5xl md:text-6xl lg:text-7xl font-black text-white mb-6 md:mb-8 leading-tight"
|
||||||
|
>
|
||||||
|
<span className="block mb-2 text-xl sm:text-2xl md:text-3xl font-light text-gray-300">
|
||||||
|
实体商业的
|
||||||
|
</span>
|
||||||
|
<span className="text-[#FF6600] text-4xl sm:text-6xl md:text-7xl lg:text-8xl block">
|
||||||
|
AI 数智增长引擎
|
||||||
|
</span>
|
||||||
|
</motion.h1>
|
||||||
|
|
||||||
|
{/* Subheadline - 核心价值主张,大字展示 */}
|
||||||
|
<motion.p
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.6, delay: 0.2 }}
|
||||||
|
className="text-xl sm:text-2xl md:text-3xl font-bold text-[#FF6600] mb-6 md:mb-8 tracking-wide"
|
||||||
|
>
|
||||||
|
支付即锁粉 · 让利即引流 · 跨界即分润
|
||||||
|
</motion.p>
|
||||||
|
|
||||||
|
{/* Description */}
|
||||||
|
<motion.p
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.6, delay: 0.3 }}
|
||||||
|
className="text-base sm:text-lg md:text-xl text-gray-300 mb-10 md:mb-12 max-w-4xl mx-auto leading-relaxed font-medium"
|
||||||
|
>
|
||||||
|
连接 <span className="text-white font-bold">120,000+</span> 实体商户,重构线下流量价值闭环。<br className="hidden sm:block"/>
|
||||||
|
军工技术赋能 · 人工智能驱动万商互联
|
||||||
|
</motion.p>
|
||||||
|
|
||||||
|
{/* CTA Button - 超大醒目按钮 */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.6, delay: 0.4 }}
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
href="/contact#form"
|
||||||
|
className="group relative inline-flex items-center gap-3 px-8 py-4 md:px-10 md:py-5 bg-gradient-to-r from-[#FF6600] to-[#FF8C00] text-lg md:text-xl font-black rounded-full shadow-2xl shadow-[#FF6600]/50 transition-all duration-300 hover:scale-105 hover:shadow-[#FF6600]/70"
|
||||||
|
>
|
||||||
|
<span className="text-lg md:text-xl">立即加入白马联盟</span>
|
||||||
|
<ArrowRight className="w-6 h-6 md:w-7 md:h-7 transition-transform group-hover:translate-x-1" />
|
||||||
|
</Link>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Scroll Indicator */}
|
||||||
|
<motion.div
|
||||||
|
animate={{ y: [0, 10, 0] }}
|
||||||
|
transition={{ duration: 2, repeat: Infinity }}
|
||||||
|
className="absolute bottom-4 md:bottom-8 left-1/2 -translate-x-1/2 text-white/30 hidden sm:block"
|
||||||
|
>
|
||||||
|
<div className="w-6 h-10 md:w-7 md:h-12 border-2 border-current rounded-full flex items-start justify-center p-1.5 md:p-2">
|
||||||
|
<div className="w-1.5 h-2 md:w-2 md:h-3 bg-current rounded-full"></div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,223 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion'
|
||||||
|
import { Trophy, Award, FileText, Medal, Shield, Zap, Users, Globe, CheckCircle2 } from 'lucide-react'
|
||||||
|
|
||||||
|
// 扩充后的资质和知识产权数据
|
||||||
|
const honors = [
|
||||||
|
{
|
||||||
|
icon: Trophy,
|
||||||
|
title: "科大讯飞 AI 开发者大赛",
|
||||||
|
subtitle: "数字人赛道冠军",
|
||||||
|
color: "bg-orange-100 text-orange-600"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Medal,
|
||||||
|
title: "中国产业元宇宙创新大赛",
|
||||||
|
subtitle: "一等奖",
|
||||||
|
color: "bg-blue-100 text-blue-600"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Award,
|
||||||
|
title: "退役军人创新创业大赛",
|
||||||
|
subtitle: "一等奖",
|
||||||
|
color: "bg-purple-100 text-purple-600"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Globe,
|
||||||
|
title: "元宇宙应用场景大赛",
|
||||||
|
subtitle: "产业生态先锋奖",
|
||||||
|
color: "bg-green-100 text-green-600"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const patents = [
|
||||||
|
{
|
||||||
|
title: "融合多信息的 AI 虚拟人与用户交互方法",
|
||||||
|
type: "发明专利"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "一种虚拟人物不同表情模型生成方法",
|
||||||
|
type: "发明专利"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "基于深度学习的智能收银系统",
|
||||||
|
type: "发明专利"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "多通道智能路由分配算法",
|
||||||
|
type: "发明专利"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "区块链数据确权与价值分配系统",
|
||||||
|
type: "发明专利"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "AI 驱动的精准营销推荐系统",
|
||||||
|
type: "发明专利"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const certifications = [
|
||||||
|
{
|
||||||
|
title: "收单外包服务机构备案",
|
||||||
|
desc: "中国支付清算协会备案,合规开展收单外包服务"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "ISO 9001 质量管理体系认证",
|
||||||
|
desc: "国际标准化组织认证"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "高新技术企业认定",
|
||||||
|
desc: "享受国家高新技术企业税收优惠"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "软件企业认定",
|
||||||
|
desc: "符合国家软件产业政策要求"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "信息安全管理系统认证",
|
||||||
|
desc: "保障用户数据安全"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "数商备案接入",
|
||||||
|
desc: "合规参与数据要素市场"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export function HonorSection() {
|
||||||
|
return (
|
||||||
|
<section id="honor" className="py-24 bg-[#F4F7FB] scroll-mt-20">
|
||||||
|
<div className="container mx-auto px-4 md:px-6">
|
||||||
|
|
||||||
|
{/* 大标题 */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
className="text-center mb-16"
|
||||||
|
>
|
||||||
|
<h2 className="text-3xl md:text-5xl font-black text-[#0A1931] mb-4">
|
||||||
|
权威认证 · 技术实力
|
||||||
|
</h2>
|
||||||
|
<p className="text-lg text-gray-500 max-w-3xl mx-auto">
|
||||||
|
白马家园拥有完备的知识产权体系和权威资质认证,为您的商业合作保驾护航
|
||||||
|
</p>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
{/* 1. 权威奖项展示 - 大卡片风格 */}
|
||||||
|
<div className="mb-20">
|
||||||
|
<h3 className="text-2xl font-bold text-[#0A1931] mb-8 flex items-center gap-3">
|
||||||
|
<Trophy className="w-8 h-8 text-[#FF6600]" />
|
||||||
|
权威奖项与认可
|
||||||
|
</h3>
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||||
|
{honors.map((item, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={index}
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ delay: index * 0.1 }}
|
||||||
|
className="bg-white p-8 rounded-2xl shadow-lg hover:shadow-xl transition-all hover:-translate-y-1 border border-gray-100"
|
||||||
|
>
|
||||||
|
<div className={`w-16 h-16 ${item.color} rounded-2xl flex items-center justify-center mb-6`}>
|
||||||
|
<item.icon className="w-8 h-8" />
|
||||||
|
</div>
|
||||||
|
<h4 className="text-xl font-bold text-[#0A1931] mb-2">{item.title}</h4>
|
||||||
|
<p className="text-[#FF6600] font-bold">{item.subtitle}</p>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 2. 知识产权展示 - 网格布局 */}
|
||||||
|
<div className="mb-20">
|
||||||
|
<h3 className="text-2xl font-bold text-[#0A1931] mb-8 flex items-center gap-3">
|
||||||
|
<FileText className="w-8 h-8 text-[#185ADB]" />
|
||||||
|
自主知识产权 (80+ 项)
|
||||||
|
</h3>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||||
|
{patents.map((item, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={index}
|
||||||
|
initial={{ opacity: 0, x: -20 }}
|
||||||
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ delay: index * 0.05 }}
|
||||||
|
className="bg-white p-5 rounded-xl border border-gray-200 hover:border-[#185ADB] hover:shadow-md transition-all flex items-start gap-4"
|
||||||
|
>
|
||||||
|
<div className="w-10 h-10 bg-[#185ADB]/10 rounded-lg flex items-center justify-center shrink-0 mt-1">
|
||||||
|
<Shield className="w-5 h-5 text-[#185ADB]" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4 className="font-bold text-[#0A1931] mb-1">{item.title}</h4>
|
||||||
|
<span className="text-xs font-bold text-[#185ADB] bg-[#185ADB]/10 px-2 py-0.5 rounded">{item.type}</span>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
{/* 更多专利提示 */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, x: -20 }}
|
||||||
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ delay: 0.4 }}
|
||||||
|
className="bg-gradient-to-br from-[#0A1931] to-[#185ADB] p-5 rounded-xl text-white flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<div className="text-center">
|
||||||
|
<Zap className="w-10 h-10 mx-auto mb-2 text-[#FF6600]" />
|
||||||
|
<p className="font-bold text-lg">80+ 项</p>
|
||||||
|
<p className="text-sm text-gray-300">软件著作权与专利</p>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 3. 资质认证展示 - 详情列表 */}
|
||||||
|
<div>
|
||||||
|
<h3 className="text-2xl font-bold text-[#0A1931] mb-8 flex items-center gap-3">
|
||||||
|
<CheckCircle2 className="w-8 h-8 text-green-600" />
|
||||||
|
权威资质认证
|
||||||
|
</h3>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
{certifications.map((item, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={index}
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ delay: index * 0.1 }}
|
||||||
|
className="bg-white p-6 rounded-2xl shadow-sm border border-gray-100 hover:shadow-md transition-all"
|
||||||
|
>
|
||||||
|
<div className="flex items-start gap-4">
|
||||||
|
<div className="w-12 h-12 bg-green-50 rounded-xl flex items-center justify-center shrink-0">
|
||||||
|
<CheckCircle2 className="w-6 h-6 text-green-600" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4 className="font-bold text-[#0A1931] mb-2">{item.title}</h4>
|
||||||
|
<p className="text-sm text-gray-500 leading-relaxed">{item.desc}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 底部强调 */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
className="mt-16 bg-gradient-to-r from-[#0A1931] to-[#185ADB] rounded-3xl p-10 text-white text-center"
|
||||||
|
>
|
||||||
|
<h4 className="text-2xl font-black mb-4">合规保障 · 安全无忧</h4>
|
||||||
|
<p className="text-lg text-gray-300 max-w-2xl mx-auto">
|
||||||
|
我们拥有收单外包服务机构备案,资金受银监会监管,数商备案接入,工商税务监管系统实时对接,
|
||||||
|
为您的每一笔交易保驾护航。
|
||||||
|
</p>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion'
|
||||||
|
import { Diamond, Truck, Eye, Coins } from 'lucide-react'
|
||||||
|
|
||||||
|
const infraItems = [
|
||||||
|
{
|
||||||
|
icon: Diamond,
|
||||||
|
title: "智慧会员体系",
|
||||||
|
description: "一次注册,全城打通<br/>全平台消费数据互通"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Truck,
|
||||||
|
title: "供应链赋能",
|
||||||
|
description: "积分当钱花,进货更便宜<br/>源头工厂直供去库存"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Eye,
|
||||||
|
title: "智能巡店系统",
|
||||||
|
description: "手机看店,AI管店<br/>客流热力图实时分析"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Coins,
|
||||||
|
title: "数智积分体系",
|
||||||
|
description: "基于真实消费产生<br/>拒绝泡沫,价值恒定"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export function Infrastructure() {
|
||||||
|
return (
|
||||||
|
<section className="py-12 md:py-16 lg:py-20 bg-[#F4F7FB]">
|
||||||
|
<div className="container px-4 md:px-6 mx-auto">
|
||||||
|
{/* Section Header - 响应式 */}
|
||||||
|
<div className="text-center mb-10 md:mb-16">
|
||||||
|
<h2 className="text-xl sm:text-2xl md:text-3xl lg:text-4xl font-bold text-[#0A1931] mb-3 md:mb-4">
|
||||||
|
统一高效的生态基础设施
|
||||||
|
</h2>
|
||||||
|
{/* 已移除:为上市合规打造的底层架构 */}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Grid - 响应式布局 */}
|
||||||
|
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4 md:gap-6">
|
||||||
|
{infraItems.map((item, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={index}
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.5, delay: index * 0.1 }}
|
||||||
|
className="bg-white p-4 md:p-6 lg:p-8 text-center rounded-lg md:rounded-xl border-b-4 border-transparent hover:border-[#FF6600] hover:shadow-lg transition-all duration-300"
|
||||||
|
>
|
||||||
|
{/* Icon - 响应式 */}
|
||||||
|
<div className="w-10 h-10 sm:w-12 sm:h-12 md:w-16 md:h-16 bg-[#0A1931]/5 rounded-lg md:rounded-xl flex items-center justify-center mx-auto mb-4 md:mb-6">
|
||||||
|
<item.icon className="w-5 h-5 sm:w-6 sm:h-6 md:w-8 md:h-8 text-[#185ADB]" />
|
||||||
|
</div>
|
||||||
|
{/* Title - 响应式 */}
|
||||||
|
<h3 className="text-sm sm:text-base md:text-lg font-bold text-[#0A1931] mb-2 md:mb-3">
|
||||||
|
{item.title}
|
||||||
|
</h3>
|
||||||
|
{/* Description - 响应式 */}
|
||||||
|
<p className="text-xs sm:text-sm text-gray-500 leading-relaxed"
|
||||||
|
dangerouslySetInnerHTML={{ __html: item.description }}>
|
||||||
|
</p>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,108 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion'
|
||||||
|
import { Target, Eye, Heart, Star, Shield, Users, TrendingUp } from 'lucide-react'
|
||||||
|
|
||||||
|
export function MissionVision() {
|
||||||
|
const coreValues = [
|
||||||
|
{
|
||||||
|
icon: Target,
|
||||||
|
title: "使命",
|
||||||
|
content: "军工技术赋能实体经济<br/>人工智能驱动万商互联",
|
||||||
|
color: "from-orange-500 to-red-500"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Eye,
|
||||||
|
title: "愿景",
|
||||||
|
content: "天下白马是一家<br/>一起赚钱一起花",
|
||||||
|
color: "from-blue-500 to-indigo-600"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Heart,
|
||||||
|
title: "价值观",
|
||||||
|
content: "共创 · 共享 · 共富",
|
||||||
|
color: "from-green-500 to-emerald-600"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="py-24 bg-gradient-to-br from-[#0A1931] via-[#0d1f45] to-[#050A14] relative overflow-hidden">
|
||||||
|
{/* 背景装饰 */}
|
||||||
|
<div className="absolute inset-0">
|
||||||
|
<div className="absolute top-1/4 left-1/4 w-96 h-96 bg-[#FF6600] rounded-full blur-[150px] opacity-10"></div>
|
||||||
|
<div className="absolute bottom-1/4 right-1/4 w-96 h-96 bg-[#185ADB] rounded-full blur-[150px] opacity-10"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="container mx-auto px-4 relative z-10">
|
||||||
|
{/* 标题 */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
className="text-center mb-16"
|
||||||
|
>
|
||||||
|
<h2 className="text-3xl md:text-5xl font-black text-white mb-4">
|
||||||
|
我们的信仰
|
||||||
|
</h2>
|
||||||
|
<p className="text-gray-400 text-lg max-w-2xl mx-auto">
|
||||||
|
坚守初心,砥砺前行,白马家园与您携手共创美好未来
|
||||||
|
</p>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
{/* 三大核心支柱 */}
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||||
|
{coreValues.map((item, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={index}
|
||||||
|
initial={{ opacity: 0, y: 30 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ delay: index * 0.2 }}
|
||||||
|
className="group"
|
||||||
|
>
|
||||||
|
<div className="bg-white/5 backdrop-blur-sm rounded-2xl p-8 border border-white/10 hover:border-[#FF6600]/50 transition-all duration-500 h-full">
|
||||||
|
{/* 图标 */}
|
||||||
|
<div className={`w-20 h-20 mx-auto mb-6 rounded-2xl bg-gradient-to-r ${item.color} flex items-center justify-center shadow-lg group-hover:scale-110 transition-transform duration-300`}>
|
||||||
|
<item.icon className="w-10 h-10 text-white" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 标题 */}
|
||||||
|
<h3 className="text-2xl font-bold text-white text-center mb-6">
|
||||||
|
{item.title}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
{/* 内容 */}
|
||||||
|
<div
|
||||||
|
className="text-center text-gray-300 leading-loose text-lg"
|
||||||
|
dangerouslySetInnerHTML={{ __html: item.content }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* 装饰线 */}
|
||||||
|
<div className="mt-6 flex justify-center">
|
||||||
|
<div className={`w-16 h-1 bg-gradient-to-r ${item.color} rounded-full opacity-50`}></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 底部标语 */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ delay: 0.5 }}
|
||||||
|
className="mt-16 text-center"
|
||||||
|
>
|
||||||
|
<div className="inline-flex items-center gap-4 bg-[#FF6600]/10 backdrop-blur-sm px-8 py-4 rounded-full border border-[#FF6600]/20">
|
||||||
|
<Star className="w-6 h-6 text-[#FF6600]" />
|
||||||
|
<span className="text-[#FF6600] font-bold text-lg">
|
||||||
|
数智连接万商 共创美好未来
|
||||||
|
</span>
|
||||||
|
<Star className="w-6 h-6 text-[#FF6600]" />
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,108 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion'
|
||||||
|
import { Target, Eye, Heart, Star } from 'lucide-react'
|
||||||
|
|
||||||
|
export function MissionVisionEN() {
|
||||||
|
const coreValues = [
|
||||||
|
{
|
||||||
|
icon: Target,
|
||||||
|
title: "Mission",
|
||||||
|
content: "Military-grade Technology Empowers Physical Economy<br/>AI Drives Universal Business Connectivity",
|
||||||
|
color: "from-orange-500 to-red-500"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Eye,
|
||||||
|
title: "Vision",
|
||||||
|
content: "One Baima Family Worldwide<br/>Grow Wealth Together, Spend Together",
|
||||||
|
color: "from-blue-500 to-indigo-600"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Heart,
|
||||||
|
title: "Values",
|
||||||
|
content: "Co-create · Share · Prosper Together",
|
||||||
|
color: "from-green-500 to-emerald-600"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="py-24 bg-gradient-to-br from-[#0A1931] via-[#0d1f45] to-[#050A14] relative overflow-hidden">
|
||||||
|
{/* 背景装饰 */}
|
||||||
|
<div className="absolute inset-0">
|
||||||
|
<div className="absolute top-1/4 left-1/4 w-96 h-96 bg-[#FF6600] rounded-full blur-[150px] opacity-10"></div>
|
||||||
|
<div className="absolute bottom-1/4 right-1/4 w-96 h-96 bg-[#185ADB] rounded-full blur-[150px] opacity-10"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="container mx-auto px-4 relative z-10">
|
||||||
|
{/* 标题 */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
className="text-center mb-16"
|
||||||
|
>
|
||||||
|
<h2 className="text-3xl md:text-5xl font-black text-white mb-4">
|
||||||
|
Our Beliefs
|
||||||
|
</h2>
|
||||||
|
<p className="text-gray-400 text-lg max-w-2xl mx-auto">
|
||||||
|
Staying True to Our Original Aspiration, Advancing with Determination - Baima Home Builds a Better Future Together
|
||||||
|
</p>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
{/* 三大核心支柱 */}
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||||
|
{coreValues.map((item, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={index}
|
||||||
|
initial={{ opacity: 0, y: 30 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ delay: index * 0.2 }}
|
||||||
|
className="group"
|
||||||
|
>
|
||||||
|
<div className="bg-white/5 backdrop-blur-sm rounded-2xl p-8 border border-white/10 hover:border-[#FF6600]/50 transition-all duration-500 h-full">
|
||||||
|
{/* 图标 */}
|
||||||
|
<div className={`w-20 h-20 mx-auto mb-6 rounded-2xl bg-gradient-to-r ${item.color} flex items-center justify-center shadow-lg group-hover:scale-110 transition-transform duration-300`}>
|
||||||
|
<item.icon className="w-10 h-10 text-white" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 标题 */}
|
||||||
|
<h3 className="text-2xl font-bold text-white text-center mb-6">
|
||||||
|
{item.title}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
{/* 内容 */}
|
||||||
|
<div
|
||||||
|
className="text-center text-gray-300 leading-loose text-lg"
|
||||||
|
dangerouslySetInnerHTML={{ __html: item.content }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* 装饰线 */}
|
||||||
|
<div className="mt-6 flex justify-center">
|
||||||
|
<div className={`w-16 h-1 bg-gradient-to-r ${item.color} rounded-full opacity-50`}></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 底部标语 */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ delay: 0.5 }}
|
||||||
|
className="mt-16 text-center"
|
||||||
|
>
|
||||||
|
<div className="inline-flex items-center gap-4 bg-[#FF6600]/10 backdrop-blur-sm px-8 py-4 rounded-full border border-[#FF6600]/20">
|
||||||
|
<Star className="w-6 h-6 text-[#FF6600]" />
|
||||||
|
<span className="text-[#FF6600] font-bold text-lg">
|
||||||
|
Digital Intelligence Connects Businesses, Creates Better Future
|
||||||
|
</span>
|
||||||
|
<Star className="w-6 h-6 text-[#FF6600]" />
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useState, useEffect } from 'react'
|
||||||
|
import { motion } from 'framer-motion'
|
||||||
|
import { Calendar, ArrowRight, Loader2 } from 'lucide-react'
|
||||||
|
import Link from 'next/link'
|
||||||
|
|
||||||
|
type News = {
|
||||||
|
id: number
|
||||||
|
title: string
|
||||||
|
category: string
|
||||||
|
excerpt: string
|
||||||
|
createdAt: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function NewsSection() {
|
||||||
|
const [news, setNews] = useState<News[]>([])
|
||||||
|
const [isLoading, setIsLoading] = useState(true)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch('/api/news?limit=3')
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(data => {
|
||||||
|
setNews(data.news)
|
||||||
|
setIsLoading(false)
|
||||||
|
})
|
||||||
|
.catch(() => setIsLoading(false))
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section id="news" className="py-24 bg-white scroll-mt-20">
|
||||||
|
<div className="container mx-auto px-4 md:px-6">
|
||||||
|
<div className="flex flex-col md:flex-row justify-between items-end mb-16 gap-6">
|
||||||
|
<div>
|
||||||
|
<h2 className="text-3xl md:text-5xl font-black text-[#0A1931] mb-4">最新动态</h2>
|
||||||
|
<p className="text-gray-500 text-lg">了解白马家园的成长足迹与行业洞察</p>
|
||||||
|
</div>
|
||||||
|
<Link href="/news" className="text-[#FF6600] font-bold flex items-center gap-2 hover:translate-x-1 transition-transform">
|
||||||
|
查看全部动态 <ArrowRight className="w-5 h-5" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{isLoading ? (
|
||||||
|
<div className="flex justify-center py-20"><Loader2 className="w-8 h-8 animate-spin text-[#FF6600]" /></div>
|
||||||
|
) : news.length === 0 ? (
|
||||||
|
<div className="text-center py-20 text-gray-400 bg-gray-50 rounded-2xl">后台尚未发布任何动态</div>
|
||||||
|
) : (
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||||
|
{news.map((item, index) => (
|
||||||
|
<Link href={`/news?id=${item.id}`} key={item.id}>
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ delay: index * 0.1 }}
|
||||||
|
className="group p-6 rounded-2xl border border-gray-100 bg-white hover:shadow-xl transition-all cursor-pointer h-full"
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2 mb-4">
|
||||||
|
<span className="text-[10px] font-black uppercase tracking-widest text-[#FF6600] bg-orange-50 px-2 py-0.5 rounded">
|
||||||
|
{item.category}
|
||||||
|
</span>
|
||||||
|
<span className="text-xs text-gray-400 flex items-center font-mono">
|
||||||
|
<Calendar className="w-3 h-3 mr-1" /> {new Date(item.createdAt).toLocaleDateString()}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<h3 className="text-xl font-bold text-[#0A1931] mb-4 group-hover:text-[#FF6600] transition-colors line-clamp-2">
|
||||||
|
{item.title}
|
||||||
|
</h3>
|
||||||
|
<p className="text-sm text-gray-500 leading-relaxed mb-6 line-clamp-3">
|
||||||
|
{item.excerpt}
|
||||||
|
</p>
|
||||||
|
<span className="text-sm font-bold text-[#0A1931] flex items-center gap-1 group-hover:gap-2 transition-all">
|
||||||
|
阅读更多 <ArrowRight className="w-4 h-4" />
|
||||||
|
</span>
|
||||||
|
</motion.div>
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,137 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion'
|
||||||
|
import { Button } from '@/components/ui/button'
|
||||||
|
import { CreditCard, Users, Network, Database } from 'lucide-react'
|
||||||
|
|
||||||
|
// 根据框图重构四大核心板块
|
||||||
|
const products = [
|
||||||
|
{
|
||||||
|
title: '高效安全的金融科技支撑',
|
||||||
|
enTitle: 'Fintech Support',
|
||||||
|
description: '收单-分销-结算一体化,多通道AI路由,保障资金安全与高效分账。',
|
||||||
|
icon: CreditCard,
|
||||||
|
color: 'bg-gradient-to-br from-[#0A1931] to-[#185ADB]',
|
||||||
|
features: [
|
||||||
|
{ title: "白马智付", desc: "锁粉 / 自动分佣 / AI路由" },
|
||||||
|
{ title: "智能设备", desc: "智慧收银系统 / 支持绿色积分 / 智能监控巡店" },
|
||||||
|
{ title: "支付能力", desc: "主扫、被扫模式全支持 / 强大技术底座" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '简单易用的私域运营工具',
|
||||||
|
enTitle: 'Private Domain Tools',
|
||||||
|
description: 'AI驱动的私域流量运营神器,让获客、留存、转化变得简单高效。',
|
||||||
|
icon: Users,
|
||||||
|
color: 'bg-gradient-to-br from-[#FF6600] to-[#FF8C00]',
|
||||||
|
features: [
|
||||||
|
{ title: "AI数字人", desc: "AI直播/AI导购/AI客服/AI私域" },
|
||||||
|
{ title: "积分权益", desc: "兑换AI直播 / 营销获客权益" },
|
||||||
|
{ title: "企微私域", desc: "AI数字员工自动实现:社群运营/维护/导购/客服" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '轻松锁客的异业联盟系统',
|
||||||
|
enTitle: 'Alliance System',
|
||||||
|
description: '打破单打独斗,通过异业联盟锁定客户终身价值,实现跨界收益。',
|
||||||
|
icon: Network,
|
||||||
|
color: 'bg-gradient-to-br from-[#185ADB] to-[#0A1931]',
|
||||||
|
features: [
|
||||||
|
{ title: "锁定客户", desc: "扫码即锁定推荐关系,终身享受消费分佣" },
|
||||||
|
{ title: "跨界分佣", desc: "赚360行的钱 / 跨门店收益" },
|
||||||
|
{ title: "供应链分佣", desc: "分享优质供应链商品获利" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '统一高效的生态基础设施',
|
||||||
|
enTitle: 'Ecological Infrastructure',
|
||||||
|
description: '为小微企业提供完整的数智化基建,打通会员、资产与供应链。',
|
||||||
|
icon: Database,
|
||||||
|
color: 'bg-gradient-to-br from-[#059669] to-[#10B981]',
|
||||||
|
features: [
|
||||||
|
{ title: "会员系统", desc: "跨平台生态融合 / 统一身份" },
|
||||||
|
{ title: "数字资产体系", desc: "RWA资产 / 积分、抵用券、金币等" },
|
||||||
|
{ title: "供应链资源", desc: "稳定安全靠谱" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export function ProductPreview() {
|
||||||
|
return (
|
||||||
|
<section className="py-12 md:py-20 lg:py-24 bg-white">
|
||||||
|
<div className="container px-4 md:px-6 mx-auto">
|
||||||
|
{/* Section Header */}
|
||||||
|
<div className="text-center mb-10 md:mb-16">
|
||||||
|
<motion.h2
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold text-[#0A1931] mb-3 md:mb-4"
|
||||||
|
>
|
||||||
|
AI时代小微创业 + 消费循环生态圈
|
||||||
|
</motion.h2>
|
||||||
|
<motion.p
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ delay: 0.1 }}
|
||||||
|
className="text-sm sm:text-base md:text-lg text-gray-500 px-4"
|
||||||
|
>
|
||||||
|
四大核心数智化产品矩阵,全方位赋能实体商业
|
||||||
|
</motion.p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Product Cards Grid - 2x2 Layout recommended for 4 items */}
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 md:gap-8 lg:gap-10">
|
||||||
|
{products.map((product, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={index}
|
||||||
|
initial={{ opacity: 0, y: 30 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.5, delay: index * 0.1 }}
|
||||||
|
className="group h-full"
|
||||||
|
>
|
||||||
|
<div className="card-hover bg-white rounded-xl md:rounded-2xl overflow-hidden border border-gray-100 h-full flex flex-col">
|
||||||
|
{/* Header with Icon */}
|
||||||
|
<div className="p-6 md:p-8 flex items-start justify-between border-b border-gray-50 bg-gray-50/50">
|
||||||
|
<div>
|
||||||
|
<h3 className="text-xl md:text-2xl font-bold text-[#0A1931] mb-1">
|
||||||
|
{product.title}
|
||||||
|
</h3>
|
||||||
|
<span className="text-xs font-semibold text-[#FF6600] uppercase tracking-wider">
|
||||||
|
{product.enTitle}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className={`w-12 h-12 md:w-14 md:h-14 rounded-xl flex items-center justify-center text-white shadow-md ${product.color}`}>
|
||||||
|
<product.icon className="w-6 h-6 md:w-7 md:h-7" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Content */}
|
||||||
|
<div className="p-6 md:p-8 flex-grow flex flex-col">
|
||||||
|
<p className="text-sm text-gray-500 mb-6 leading-relaxed">
|
||||||
|
{product.description}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{/* Features List */}
|
||||||
|
<ul className="space-y-3 md:space-y-4 mb-8 flex-grow">
|
||||||
|
{product.features.map((feature, fIndex) => (
|
||||||
|
<li key={fIndex} className="flex items-start text-sm">
|
||||||
|
<span className="w-1.5 h-1.5 bg-[#FF6600] rounded-full mr-3 mt-1.5 shrink-0"></span>
|
||||||
|
<div className="flex-1">
|
||||||
|
<strong className="text-[#0A1931] block mb-0.5">{feature.title}</strong>
|
||||||
|
<span className="text-gray-500 text-xs md:text-sm">{feature.desc}</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion'
|
||||||
|
|
||||||
|
const stats = [
|
||||||
|
{ value: "120,000+", label: "服务实体商户", highlight: "12万+" },
|
||||||
|
{ value: "500,000+", label: "日均交易笔数", highlight: "50万+" },
|
||||||
|
{ value: "300万+", label: "累计引流人次", highlight: "300万+" },
|
||||||
|
{ value: "20亿+", label: "平台年GMV流水", highlight: "20亿+" }
|
||||||
|
]
|
||||||
|
|
||||||
|
export function Stats() {
|
||||||
|
return (
|
||||||
|
<section className="py-0">
|
||||||
|
<div className="bg-gradient-to-r from-[#0A1931] via-[#185ADB] to-[#0A1931] text-white py-16 md:py-20">
|
||||||
|
<div className="container mx-auto px-4">
|
||||||
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-8 md:gap-12 items-center">
|
||||||
|
{stats.map((stat, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={index}
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.5, delay: index * 0.1 }}
|
||||||
|
className="text-center"
|
||||||
|
>
|
||||||
|
{/* 大号数字,突出显示 */}
|
||||||
|
<h3 className="text-3xl sm:text-4xl md:text-5xl lg:text-6xl font-black text-[#FF6600] mb-2 md:mb-3 leading-none">
|
||||||
|
{stat.highlight}
|
||||||
|
</h3>
|
||||||
|
{/* 下方详细说明 */}
|
||||||
|
<p className="text-sm sm:text-base md:text-lg text-gray-300 font-medium uppercase tracking-wider">
|
||||||
|
{stat.label}
|
||||||
|
</p>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
export function Trust() {
|
||||||
|
const partners = [
|
||||||
|
"微信支付认证服务商",
|
||||||
|
"支付宝ISV合作伙伴",
|
||||||
|
"中国银联",
|
||||||
|
"启迪之星(投资方)",
|
||||||
|
"中金资本生态成员",
|
||||||
|
"OTC Markets (拟)"
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="py-8 md:py-10 lg:py-12 bg-white border-t border-gray-100">
|
||||||
|
<div className="container px-4 mx-auto">
|
||||||
|
{/* 响应式标题 */}
|
||||||
|
<p className="text-center text-gray-400 text-xs sm:text-sm font-bold uppercase tracking-[1px] md:tracking-[2px] mb-6 md:mb-8">
|
||||||
|
Strategic Partners & Qualifications
|
||||||
|
</p>
|
||||||
|
{/* 响应式网格 */}
|
||||||
|
<div className="flex flex-wrap justify-center gap-2 md:gap-4 px-2">
|
||||||
|
{partners.map((partner, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className="px-3 py-2 md:px-6 md:py-3 bg-white border border-gray-200 rounded-full text-xs sm:text-sm font-semibold text-gray-500 hover:border-[#185ADB] hover:text-[#185ADB] transition-colors cursor-default whitespace-nowrap"
|
||||||
|
>
|
||||||
|
{partner}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,111 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import Link from 'next/link'
|
||||||
|
import Image from 'next/image'
|
||||||
|
import { Separator } from '@/components/ui/separator'
|
||||||
|
import { MapPin } from 'lucide-react'
|
||||||
|
|
||||||
|
export function Footer() {
|
||||||
|
const currentYear = new Date().getFullYear()
|
||||||
|
const hostname = typeof window !== 'undefined' ? window.location.hostname : ''
|
||||||
|
const icpNumber = hostname === 'www.baimajingxuan.com' ? '津ICP备2020008456号-1' : hostname === 'www.baimajiayuanjiankang.com' ? '津ICP备2023000762号' : '津ICP备99999999号'
|
||||||
|
|
||||||
|
return (
|
||||||
|
<footer className="bg-[#050A14] text-gray-400 pt-16 pb-8">
|
||||||
|
<div className="container mx-auto px-4">
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-4 gap-12 mb-12">
|
||||||
|
{/* Brand Info */}
|
||||||
|
<div className="lg:col-span-1">
|
||||||
|
{/* Logo Image */}
|
||||||
|
<div className="relative h-14 w-auto aspect-[2/1] mb-6">
|
||||||
|
<Image
|
||||||
|
src="/baima-logo.png"
|
||||||
|
alt="白马家园 Logo"
|
||||||
|
fill
|
||||||
|
className="object-contain"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p className="text-sm leading-relaxed mb-6 text-gray-500">
|
||||||
|
军工技术赋能实体经济,人工智能驱动万商互联。<br/>
|
||||||
|
打造AI时代小微创业与消费循环生态圈。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Quick Links */}
|
||||||
|
<div>
|
||||||
|
<h3 className="font-semibold text-white text-lg mb-6">产品中心</h3>
|
||||||
|
<ul className="space-y-3 text-sm">
|
||||||
|
<li><Link href="/products" className="hover:text-[#FF6600] transition-colors">白马智付</Link></li>
|
||||||
|
<li><Link href="/products" className="hover:text-[#FF6600] transition-colors">AI拓客宝</Link></li>
|
||||||
|
<li><Link href="/products" className="hover:text-[#FF6600] transition-colors">商家联盟</Link></li>
|
||||||
|
<li><Link href="/products" className="hover:text-[#FF6600] transition-colors">智能硬件</Link></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Solutions */}
|
||||||
|
<div>
|
||||||
|
<h3 className="font-semibold text-white text-lg mb-6">解决方案</h3>
|
||||||
|
<ul className="space-y-3 text-sm">
|
||||||
|
<li><Link href="#" className="hover:text-[#FF6600] transition-colors">餐饮行业</Link></li>
|
||||||
|
<li><Link href="#" className="hover:text-[#FF6600] transition-colors">零售商超</Link></li>
|
||||||
|
<li><Link href="#" className="hover:text-[#FF6600] transition-colors">美业丽人</Link></li>
|
||||||
|
<li><Link href="#" className="hover:text-[#FF6600] transition-colors">休闲娱乐</Link></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Contact Info - 客服企业微信二维码 */}
|
||||||
|
<div>
|
||||||
|
<h3 className="font-semibold text-white text-lg mb-6">联系我们</h3>
|
||||||
|
<div className="space-y-4">
|
||||||
|
{/* 企业微信二维码 */}
|
||||||
|
<div className="bg-white p-3 rounded-lg inline-block">
|
||||||
|
<div className="relative w-28 h-28">
|
||||||
|
<Image
|
||||||
|
src="/baima-qrcode.png"
|
||||||
|
alt="扫码添加客服企业微信"
|
||||||
|
fill
|
||||||
|
className="object-contain rounded"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-gray-500">
|
||||||
|
扫码添加客服企业微信<br/>
|
||||||
|
获取一对一专业服务
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{/* 地址保留 */}
|
||||||
|
<div className="flex items-start gap-3 pt-4 border-t border-gray-800">
|
||||||
|
<MapPin className="w-4 h-4 text-[#FF6600] mt-1 shrink-0" />
|
||||||
|
<p className="text-sm">天津市武清区京津产业新城<br/>海达商务大厦</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Separator className="bg-white/10 mb-8" />
|
||||||
|
|
||||||
|
{/* 底部公司名称 - 更新为两家公司 */}
|
||||||
|
<div className="text-center pb-4">
|
||||||
|
<p className="text-sm text-gray-500 font-medium">
|
||||||
|
天津白马晶选科技有限公司<br className="md:hidden" />
|
||||||
|
<span className="mx-2 hidden md:inline">|</span>
|
||||||
|
天津白马家园健康科技有限公司
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="text-center text-xs text-gray-600">
|
||||||
|
<p>© {currentYear} 白马家园 保留所有权利</p>
|
||||||
|
<a
|
||||||
|
href="https://beian.miit.gov.cn/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="hover:text-[#FF6600] transition-colors"
|
||||||
|
style={{ marginTop: '10px', fontSize: '16px', display: 'block' }}
|
||||||
|
>
|
||||||
|
{icpNumber}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,271 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import * as React from 'react'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import Image from 'next/image'
|
||||||
|
import { Menu, Globe, ArrowRight } from 'lucide-react'
|
||||||
|
import { Button } from '@/components/ui/button'
|
||||||
|
import {
|
||||||
|
Sheet,
|
||||||
|
SheetContent,
|
||||||
|
SheetTrigger,
|
||||||
|
} from '@/components/ui/sheet'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
|
// 导航结构 - 中文
|
||||||
|
const navigationCN = [
|
||||||
|
{ name: '首页', href: '/' },
|
||||||
|
{ name: '产品矩阵', href: '/products' },
|
||||||
|
{ name: '关于我们', href: '/about' },
|
||||||
|
{ name: '合作加盟', href: '/contact' },
|
||||||
|
]
|
||||||
|
|
||||||
|
// 导航结构 - 英文
|
||||||
|
const navigationEN = [
|
||||||
|
{ name: 'Home', href: '/en' },
|
||||||
|
{ name: 'Products', href: '/products' },
|
||||||
|
{ name: 'About', href: '/about' },
|
||||||
|
{ name: 'Contact', href: '/contact' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export function Navbar() {
|
||||||
|
const [isScrolled, setIsScrolled] = React.useState(false)
|
||||||
|
const [language, setLanguage] = React.useState<'zh' | 'en'>('zh')
|
||||||
|
const [mounted, setMounted] = React.useState(false)
|
||||||
|
const [currentPath, setCurrentPath] = React.useState('')
|
||||||
|
|
||||||
|
// 初始化语言状态和当前路径
|
||||||
|
React.useEffect(() => {
|
||||||
|
setMounted(true)
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
const path = window.location.pathname
|
||||||
|
setLanguage(path.startsWith('/en') ? 'en' : 'zh')
|
||||||
|
setCurrentPath(path)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
// 监听路由变化,更新当前路径
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
const handlePopState = () => {
|
||||||
|
setCurrentPath(window.location.pathname)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听浏览器前进后退
|
||||||
|
window.addEventListener('popstate', handlePopState)
|
||||||
|
|
||||||
|
// 保存原始的pushState和replaceState
|
||||||
|
const originalPushState = window.history.pushState
|
||||||
|
const originalReplaceState = window.history.replaceState
|
||||||
|
|
||||||
|
// 重写pushState和replaceState
|
||||||
|
window.history.pushState = function(...args) {
|
||||||
|
originalPushState.apply(this, args)
|
||||||
|
handlePopState()
|
||||||
|
}
|
||||||
|
|
||||||
|
window.history.replaceState = function(...args) {
|
||||||
|
originalReplaceState.apply(this, args)
|
||||||
|
handlePopState()
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('popstate', handlePopState)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
const handleScroll = () => {
|
||||||
|
setIsScrolled(window.scrollY > 20)
|
||||||
|
}
|
||||||
|
window.addEventListener('scroll', handleScroll)
|
||||||
|
return () => window.removeEventListener('scroll', handleScroll)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
// 根据语言选择导航
|
||||||
|
const navigation = language === 'zh' ? navigationCN : navigationEN
|
||||||
|
const currentLanguage = language
|
||||||
|
|
||||||
|
// 切换语言
|
||||||
|
const toggleLanguage = () => {
|
||||||
|
const newLang = currentLanguage === 'zh' ? 'en' : 'zh'
|
||||||
|
setLanguage(newLang)
|
||||||
|
|
||||||
|
// 跳转到对应语言版本
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
const path = window.location.pathname
|
||||||
|
let newPath = path
|
||||||
|
|
||||||
|
if (newLang === 'en') {
|
||||||
|
// 转到英文版(首页)
|
||||||
|
if (path === '/') {
|
||||||
|
newPath = '/en'
|
||||||
|
} else {
|
||||||
|
// 其他页面保持原样(暂时只有首页有英文版)
|
||||||
|
newPath = '/en'
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 转到中文版
|
||||||
|
if (path.startsWith('/en')) {
|
||||||
|
newPath = '/'
|
||||||
|
} else {
|
||||||
|
newPath = path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.location.href = newPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<header
|
||||||
|
className={cn(
|
||||||
|
'fixed top-0 left-0 right-0 z-50 transition-all duration-300',
|
||||||
|
isScrolled
|
||||||
|
? 'bg-white/98 backdrop-blur-md shadow-sm border-b border-gray-100 py-3'
|
||||||
|
: 'bg-transparent py-5'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className="container mx-auto px-4 flex items-center justify-between">
|
||||||
|
{/* Logo */}
|
||||||
|
<Link href={currentLanguage === 'zh' ? '/' : '/en'} className="flex items-center gap-3">
|
||||||
|
<div className="relative h-14 w-auto aspect-[2/1]">
|
||||||
|
<Image
|
||||||
|
src="/baima-logo.png"
|
||||||
|
alt="Baima Home Logo"
|
||||||
|
fill
|
||||||
|
className="object-contain"
|
||||||
|
priority
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* Desktop Navigation */}
|
||||||
|
<nav className="hidden lg:flex items-center gap-8">
|
||||||
|
{navigation.map((item) => {
|
||||||
|
// 检测当前活跃链接
|
||||||
|
const isActive = mounted && currentPath === item.href;
|
||||||
|
// 检测是否为首页
|
||||||
|
const isHomePage = item.href === '/' || item.href === '/en';
|
||||||
|
// 检测当前是否在指定的页面(/about、/products、/contact)
|
||||||
|
const isOnSpecificPage = currentPath.startsWith('/about') ||
|
||||||
|
currentPath.startsWith('/products') ||
|
||||||
|
currentPath.startsWith('/contact');
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
key={item.name}
|
||||||
|
href={item.href}
|
||||||
|
className={cn(
|
||||||
|
"text-sm font-medium transition-colors hover:text-[#FF6600]",
|
||||||
|
isActive
|
||||||
|
? "text-[#FF6600]"
|
||||||
|
: isOnSpecificPage || isScrolled
|
||||||
|
? "text-black"
|
||||||
|
: isHomePage ? "text-black" : "text-white"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{item.name}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
{/* Right Side Actions */}
|
||||||
|
<div className="hidden lg:flex items-center gap-4">
|
||||||
|
{/* <button
|
||||||
|
onClick={toggleLanguage}
|
||||||
|
className={cn(
|
||||||
|
"flex items-center gap-1.5 text-sm font-medium transition-colors hover:text-[#FF6600]",
|
||||||
|
isScrolled ? "text-[#555]" : "text-white/90 drop-shadow-md"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Globe className="w-4 h-4" />
|
||||||
|
<span>{currentLanguage === 'zh' ? 'English' : '中文'}</span>
|
||||||
|
</button> */}
|
||||||
|
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
className={cn(
|
||||||
|
"flex items-center gap-2 px-5 py-2.5 rounded-full text-sm font-bold transition-all shadow-md",
|
||||||
|
isScrolled
|
||||||
|
? "bg-[#FF6600] hover:bg-[#FF8C00] text-white"
|
||||||
|
: "bg-white text-[#FF6600] hover:bg-white/90"
|
||||||
|
)}
|
||||||
|
asChild
|
||||||
|
>
|
||||||
|
<Link href="/contact#form">
|
||||||
|
{currentLanguage === 'zh' ? '立即咨询' : 'Get Started'}
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Mobile Navigation */}
|
||||||
|
<div className="lg:hidden">
|
||||||
|
<Sheet>
|
||||||
|
<SheetTrigger asChild>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
className={cn(!isScrolled && "text-white drop-shadow-md")}
|
||||||
|
>
|
||||||
|
<Menu className="h-6 w-6" />
|
||||||
|
<span className="sr-only">Open menu</span>
|
||||||
|
</Button>
|
||||||
|
</SheetTrigger>
|
||||||
|
<SheetContent side="right" className="w-[300px] sm:w-[400px]">
|
||||||
|
<div className="flex flex-col gap-6 mt-8">
|
||||||
|
<div className="flex items-center gap-3 pb-4 border-b">
|
||||||
|
<div className="relative h-8 w-auto aspect-[2/1]">
|
||||||
|
<Image
|
||||||
|
src="./logos.png"
|
||||||
|
alt="Baima Home Logo"
|
||||||
|
fill
|
||||||
|
className="object-contain"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 语言切换 */}
|
||||||
|
<button
|
||||||
|
onClick={toggleLanguage}
|
||||||
|
className="flex items-center gap-2 text-sm font-medium text-[#FF6600] py-2 px-4 bg-orange-50 rounded-lg"
|
||||||
|
>
|
||||||
|
<Globe className="w-4 h-4" />
|
||||||
|
{currentLanguage === 'zh' ? 'Switch to English' : '切换到中文'}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
{navigation.map((item) => {
|
||||||
|
// 检测当前活跃链接
|
||||||
|
const isActive = mounted && currentPath === item.href;
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
key={item.name}
|
||||||
|
href={item.href}
|
||||||
|
className={cn(
|
||||||
|
"text-lg font-medium py-3 px-4 rounded-lg hover:bg-gray-100 transition-colors",
|
||||||
|
isActive ? "text-[#FF6600] bg-orange-50" : "text-gray-800"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{item.name}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="pt-4 mt-auto">
|
||||||
|
<Button className="w-full bg-[#FF6600] hover:bg-[#FF8C00] rounded-full" size="lg" asChild>
|
||||||
|
<Link href="/contact#form">
|
||||||
|
{currentLanguage === 'zh' ? '立即咨询' : 'Get Started'} <ArrowRight className="ml-2 w-4 h-4" />
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</SheetContent>
|
||||||
|
</Sheet>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,186 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion'
|
||||||
|
import {
|
||||||
|
CreditCard,
|
||||||
|
Smartphone,
|
||||||
|
Bot,
|
||||||
|
Users,
|
||||||
|
Network,
|
||||||
|
ShoppingBag,
|
||||||
|
LayoutGrid,
|
||||||
|
Coins,
|
||||||
|
Shield,
|
||||||
|
Camera,
|
||||||
|
Share2,
|
||||||
|
Gift
|
||||||
|
} from 'lucide-react'
|
||||||
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||||
|
|
||||||
|
// 完全基于框图重构的数据结构
|
||||||
|
const categories = [
|
||||||
|
{
|
||||||
|
id: "fintech",
|
||||||
|
title: "高效安全的金融科技支撑",
|
||||||
|
subtitle: "收单-分销-结算 一体化解决方案",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
title: "白马智付",
|
||||||
|
icon: CreditCard,
|
||||||
|
features: [
|
||||||
|
"强大的技术能力,保障交易稳定",
|
||||||
|
"多通道AI路由,智能选择最优通道",
|
||||||
|
"AI智慧收款码:支持输入文本",
|
||||||
|
"核心功能:锁粉、自动分佣"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "智能设备",
|
||||||
|
icon: Smartphone,
|
||||||
|
features: [
|
||||||
|
"智慧收银系统硬件支持",
|
||||||
|
"全场景支付:支持主扫、被扫",
|
||||||
|
"绿色积分:支持积分抵扣支付",
|
||||||
|
"设备联网与远程管理"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "ai",
|
||||||
|
title: "简单易用的私域运营工具",
|
||||||
|
subtitle: "AI赋能,让私域运营自动化、智能化",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
title: "AI营销数字人",
|
||||||
|
icon: Bot,
|
||||||
|
features: [
|
||||||
|
"数字员工:全天候导购、客服",
|
||||||
|
"AI直播:自动讲解商品,提升转化",
|
||||||
|
"AI营销获客:智能生成内容引流"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "积分与消费券体系",
|
||||||
|
icon: Gift,
|
||||||
|
features: [
|
||||||
|
"消费券:可从供应商进货,可流转他人",
|
||||||
|
"积分权益:兑换AI数字人/直播权益",
|
||||||
|
"企微私域运营:无缝打通微信生态"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "alliance",
|
||||||
|
title: "轻松锁客的异业联盟系统",
|
||||||
|
subtitle: "打破孤岛,实现跨界收益最大化",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
title: "锁定客户终身价值",
|
||||||
|
icon: Users,
|
||||||
|
features: [
|
||||||
|
"一次锁定,终身受益",
|
||||||
|
"赚360行的钱:跨行业收益共享",
|
||||||
|
"客户在联盟内任何消费均有关联"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "全维度分佣机制",
|
||||||
|
icon: Network,
|
||||||
|
features: [
|
||||||
|
"赚其他门店的分佣收益",
|
||||||
|
"赚其他供应链的分佣收益",
|
||||||
|
"构建真正的利益共同体"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "infrastructure",
|
||||||
|
title: "统一高效的生态基础设施",
|
||||||
|
subtitle: "以上生态均对外开放,共建数智化底座",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
title: "核心系统基建",
|
||||||
|
icon: LayoutGrid,
|
||||||
|
features: [
|
||||||
|
"统一会员系统:跨平台生态融合",
|
||||||
|
"专业小微数智化系统:积分支付年费",
|
||||||
|
"涵盖:收银/会员/营销/外卖/进销存/连锁等"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "数字资产体系 (RWA)",
|
||||||
|
icon: Coins,
|
||||||
|
features: [
|
||||||
|
"RWA数字资产化",
|
||||||
|
"资产转换:积分、抵用券、金币互转",
|
||||||
|
"数字藏品与RWA权益绑定"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "供应链与监控",
|
||||||
|
icon: Shield,
|
||||||
|
features: [
|
||||||
|
"供应链资源:稳定、安全、靠谱",
|
||||||
|
"智能监控巡店设备:远程管理门店",
|
||||||
|
"供应链陆续招募中"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export function ProductList() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-24 py-12">
|
||||||
|
{categories.map((category, catIndex) => (
|
||||||
|
<section key={category.id} id={category.id} className="scroll-mt-24">
|
||||||
|
{/* Section Header */}
|
||||||
|
<div className="flex flex-col md:flex-row md:items-center gap-4 md:gap-6 mb-12">
|
||||||
|
<div className="w-12 h-12 md:w-16 md:h-16 flex items-center justify-center bg-[#FF6600] text-white text-xl md:text-2xl font-bold rounded-2xl shadow-lg shrink-0">
|
||||||
|
0{catIndex + 1}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2 className="text-2xl md:text-3xl font-bold text-[#0A1931] mb-2">{category.title}</h2>
|
||||||
|
<p className="text-sm md:text-base text-gray-500 font-medium">{category.subtitle}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Products Grid */}
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 md:gap-8">
|
||||||
|
{category.items.map((item, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={index}
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.5, delay: index * 0.1 }}
|
||||||
|
>
|
||||||
|
<Card className="h-full border-0 shadow-md hover:shadow-xl transition-all duration-300 bg-white group hover:-translate-y-1">
|
||||||
|
<CardHeader className="flex flex-row items-center gap-4 pb-4 border-b border-gray-50">
|
||||||
|
<div className="w-12 h-12 bg-[#0A1931]/5 rounded-xl flex items-center justify-center text-[#FF6600] group-hover:bg-[#FF6600] group-hover:text-white transition-colors duration-300">
|
||||||
|
<item.icon className="w-6 h-6" />
|
||||||
|
</div>
|
||||||
|
<CardTitle className="text-lg font-bold text-[#0A1931]">{item.title}</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="pt-6">
|
||||||
|
<ul className="space-y-3">
|
||||||
|
{item.features.map((feature, fIndex) => (
|
||||||
|
<li key={fIndex} className="flex items-start text-sm text-gray-600">
|
||||||
|
<span className="w-1.5 h-1.5 bg-[#185ADB] rounded-full mr-3 mt-1.5 shrink-0"></span>
|
||||||
|
<span className="leading-relaxed">{feature}</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import * as AccordionPrimitive from "@radix-ui/react-accordion"
|
||||||
|
import { ChevronDownIcon } from "lucide-react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
function Accordion({
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof AccordionPrimitive.Root>) {
|
||||||
|
return <AccordionPrimitive.Root data-slot="accordion" {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
|
function AccordionItem({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof AccordionPrimitive.Item>) {
|
||||||
|
return (
|
||||||
|
<AccordionPrimitive.Item
|
||||||
|
data-slot="accordion-item"
|
||||||
|
className={cn("border-b last:border-b-0", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function AccordionTrigger({
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof AccordionPrimitive.Trigger>) {
|
||||||
|
return (
|
||||||
|
<AccordionPrimitive.Header className="flex">
|
||||||
|
<AccordionPrimitive.Trigger
|
||||||
|
data-slot="accordion-trigger"
|
||||||
|
className={cn(
|
||||||
|
"focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
<ChevronDownIcon className="text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200" />
|
||||||
|
</AccordionPrimitive.Trigger>
|
||||||
|
</AccordionPrimitive.Header>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function AccordionContent({
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof AccordionPrimitive.Content>) {
|
||||||
|
return (
|
||||||
|
<AccordionPrimitive.Content
|
||||||
|
data-slot="accordion-content"
|
||||||
|
className="data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<div className={cn("pt-0 pb-4", className)}>{children}</div>
|
||||||
|
</AccordionPrimitive.Content>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
import * as React from "react"
|
||||||
|
import { Slot } from "@radix-ui/react-slot"
|
||||||
|
import { cva, type VariantProps } from "class-variance-authority"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
const badgeVariants = cva(
|
||||||
|
"inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default:
|
||||||
|
"border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
|
||||||
|
secondary:
|
||||||
|
"border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
|
||||||
|
destructive:
|
||||||
|
"border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
||||||
|
outline:
|
||||||
|
"text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: "default",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
function Badge({
|
||||||
|
className,
|
||||||
|
variant,
|
||||||
|
asChild = false,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<"span"> &
|
||||||
|
VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
|
||||||
|
const Comp = asChild ? Slot : "span"
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Comp
|
||||||
|
data-slot="badge"
|
||||||
|
className={cn(badgeVariants({ variant }), className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Badge, badgeVariants }
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
import * as React from "react"
|
||||||
|
import { Slot } from "@radix-ui/react-slot"
|
||||||
|
import { cva, type VariantProps } from "class-variance-authority"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
const buttonVariants = cva(
|
||||||
|
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
||||||
|
destructive:
|
||||||
|
"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
||||||
|
outline:
|
||||||
|
"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
|
||||||
|
secondary:
|
||||||
|
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||||
|
ghost:
|
||||||
|
"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
||||||
|
link: "text-primary underline-offset-4 hover:underline",
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
||||||
|
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
|
||||||
|
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
||||||
|
icon: "size-9",
|
||||||
|
"icon-sm": "size-8",
|
||||||
|
"icon-lg": "size-10",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: "default",
|
||||||
|
size: "default",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
function Button({
|
||||||
|
className,
|
||||||
|
variant = "default",
|
||||||
|
size = "default",
|
||||||
|
asChild = false,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<"button"> &
|
||||||
|
VariantProps<typeof buttonVariants> & {
|
||||||
|
asChild?: boolean
|
||||||
|
}) {
|
||||||
|
const Comp = asChild ? Slot : "button"
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Comp
|
||||||
|
data-slot="button"
|
||||||
|
data-variant={variant}
|
||||||
|
data-size={size}
|
||||||
|
className={cn(buttonVariants({ variant, size, className }))}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Button, buttonVariants }
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
import * as React from "react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
function Card({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card"
|
||||||
|
className={cn(
|
||||||
|
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-header"
|
||||||
|
className={cn(
|
||||||
|
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-title"
|
||||||
|
className={cn("leading-none font-semibold", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-description"
|
||||||
|
className={cn("text-muted-foreground text-sm", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardAction({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-action"
|
||||||
|
className={cn(
|
||||||
|
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-content"
|
||||||
|
className={cn("px-6", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-footer"
|
||||||
|
className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
Card,
|
||||||
|
CardHeader,
|
||||||
|
CardFooter,
|
||||||
|
CardTitle,
|
||||||
|
CardAction,
|
||||||
|
CardDescription,
|
||||||
|
CardContent,
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,241 @@
|
||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import useEmblaCarousel, {
|
||||||
|
type UseEmblaCarouselType,
|
||||||
|
} from "embla-carousel-react"
|
||||||
|
import { ArrowLeft, ArrowRight } from "lucide-react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
|
||||||
|
type CarouselApi = UseEmblaCarouselType[1]
|
||||||
|
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>
|
||||||
|
type CarouselOptions = UseCarouselParameters[0]
|
||||||
|
type CarouselPlugin = UseCarouselParameters[1]
|
||||||
|
|
||||||
|
type CarouselProps = {
|
||||||
|
opts?: CarouselOptions
|
||||||
|
plugins?: CarouselPlugin
|
||||||
|
orientation?: "horizontal" | "vertical"
|
||||||
|
setApi?: (api: CarouselApi) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
type CarouselContextProps = {
|
||||||
|
carouselRef: ReturnType<typeof useEmblaCarousel>[0]
|
||||||
|
api: ReturnType<typeof useEmblaCarousel>[1]
|
||||||
|
scrollPrev: () => void
|
||||||
|
scrollNext: () => void
|
||||||
|
canScrollPrev: boolean
|
||||||
|
canScrollNext: boolean
|
||||||
|
} & CarouselProps
|
||||||
|
|
||||||
|
const CarouselContext = React.createContext<CarouselContextProps | null>(null)
|
||||||
|
|
||||||
|
function useCarousel() {
|
||||||
|
const context = React.useContext(CarouselContext)
|
||||||
|
|
||||||
|
if (!context) {
|
||||||
|
throw new Error("useCarousel must be used within a <Carousel />")
|
||||||
|
}
|
||||||
|
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
function Carousel({
|
||||||
|
orientation = "horizontal",
|
||||||
|
opts,
|
||||||
|
setApi,
|
||||||
|
plugins,
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<"div"> & CarouselProps) {
|
||||||
|
const [carouselRef, api] = useEmblaCarousel(
|
||||||
|
{
|
||||||
|
...opts,
|
||||||
|
axis: orientation === "horizontal" ? "x" : "y",
|
||||||
|
},
|
||||||
|
plugins
|
||||||
|
)
|
||||||
|
const [canScrollPrev, setCanScrollPrev] = React.useState(false)
|
||||||
|
const [canScrollNext, setCanScrollNext] = React.useState(false)
|
||||||
|
|
||||||
|
const onSelect = React.useCallback((api: CarouselApi) => {
|
||||||
|
if (!api) return
|
||||||
|
setCanScrollPrev(api.canScrollPrev())
|
||||||
|
setCanScrollNext(api.canScrollNext())
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const scrollPrev = React.useCallback(() => {
|
||||||
|
api?.scrollPrev()
|
||||||
|
}, [api])
|
||||||
|
|
||||||
|
const scrollNext = React.useCallback(() => {
|
||||||
|
api?.scrollNext()
|
||||||
|
}, [api])
|
||||||
|
|
||||||
|
const handleKeyDown = React.useCallback(
|
||||||
|
(event: React.KeyboardEvent<HTMLDivElement>) => {
|
||||||
|
if (event.key === "ArrowLeft") {
|
||||||
|
event.preventDefault()
|
||||||
|
scrollPrev()
|
||||||
|
} else if (event.key === "ArrowRight") {
|
||||||
|
event.preventDefault()
|
||||||
|
scrollNext()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[scrollPrev, scrollNext]
|
||||||
|
)
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!api || !setApi) return
|
||||||
|
setApi(api)
|
||||||
|
}, [api, setApi])
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!api) return
|
||||||
|
onSelect(api)
|
||||||
|
api.on("reInit", onSelect)
|
||||||
|
api.on("select", onSelect)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
api?.off("select", onSelect)
|
||||||
|
}
|
||||||
|
}, [api, onSelect])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CarouselContext.Provider
|
||||||
|
value={{
|
||||||
|
carouselRef,
|
||||||
|
api: api,
|
||||||
|
opts,
|
||||||
|
orientation:
|
||||||
|
orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
|
||||||
|
scrollPrev,
|
||||||
|
scrollNext,
|
||||||
|
canScrollPrev,
|
||||||
|
canScrollNext,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
onKeyDownCapture={handleKeyDown}
|
||||||
|
className={cn("relative", className)}
|
||||||
|
role="region"
|
||||||
|
aria-roledescription="carousel"
|
||||||
|
data-slot="carousel"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</CarouselContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CarouselContent({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
const { carouselRef, orientation } = useCarousel()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={carouselRef}
|
||||||
|
className="overflow-hidden"
|
||||||
|
data-slot="carousel-content"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"flex",
|
||||||
|
orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CarouselItem({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
const { orientation } = useCarousel()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
role="group"
|
||||||
|
aria-roledescription="slide"
|
||||||
|
data-slot="carousel-item"
|
||||||
|
className={cn(
|
||||||
|
"min-w-0 shrink-0 grow-0 basis-full",
|
||||||
|
orientation === "horizontal" ? "pl-4" : "pt-4",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CarouselPrevious({
|
||||||
|
className,
|
||||||
|
variant = "outline",
|
||||||
|
size = "icon",
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof Button>) {
|
||||||
|
const { orientation, scrollPrev, canScrollPrev } = useCarousel()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
data-slot="carousel-previous"
|
||||||
|
variant={variant}
|
||||||
|
size={size}
|
||||||
|
className={cn(
|
||||||
|
"absolute size-8 rounded-full",
|
||||||
|
orientation === "horizontal"
|
||||||
|
? "top-1/2 -left-12 -translate-y-1/2"
|
||||||
|
: "-top-12 left-1/2 -translate-x-1/2 rotate-90",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
disabled={!canScrollPrev}
|
||||||
|
onClick={scrollPrev}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<ArrowLeft />
|
||||||
|
<span className="sr-only">Previous slide</span>
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CarouselNext({
|
||||||
|
className,
|
||||||
|
variant = "outline",
|
||||||
|
size = "icon",
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof Button>) {
|
||||||
|
const { orientation, scrollNext, canScrollNext } = useCarousel()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
data-slot="carousel-next"
|
||||||
|
variant={variant}
|
||||||
|
size={size}
|
||||||
|
className={cn(
|
||||||
|
"absolute size-8 rounded-full",
|
||||||
|
orientation === "horizontal"
|
||||||
|
? "top-1/2 -right-12 -translate-y-1/2"
|
||||||
|
: "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
disabled={!canScrollNext}
|
||||||
|
onClick={scrollNext}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<ArrowRight />
|
||||||
|
<span className="sr-only">Next slide</span>
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
type CarouselApi,
|
||||||
|
Carousel,
|
||||||
|
CarouselContent,
|
||||||
|
CarouselItem,
|
||||||
|
CarouselPrevious,
|
||||||
|
CarouselNext,
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
import * as React from "react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
function Input({ className, type, ...props }: React.ComponentProps<"input">) {
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
type={type}
|
||||||
|
data-slot="input"
|
||||||
|
className={cn(
|
||||||
|
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||||
|
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
||||||
|
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Input }
|
||||||
|
|
@ -0,0 +1,168 @@
|
||||||
|
import * as React from "react"
|
||||||
|
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu"
|
||||||
|
import { cva } from "class-variance-authority"
|
||||||
|
import { ChevronDownIcon } from "lucide-react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
function NavigationMenu({
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
viewport = true,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof NavigationMenuPrimitive.Root> & {
|
||||||
|
viewport?: boolean
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<NavigationMenuPrimitive.Root
|
||||||
|
data-slot="navigation-menu"
|
||||||
|
data-viewport={viewport}
|
||||||
|
className={cn(
|
||||||
|
"group/navigation-menu relative flex max-w-max flex-1 items-center justify-center",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
{viewport && <NavigationMenuViewport />}
|
||||||
|
</NavigationMenuPrimitive.Root>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavigationMenuList({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof NavigationMenuPrimitive.List>) {
|
||||||
|
return (
|
||||||
|
<NavigationMenuPrimitive.List
|
||||||
|
data-slot="navigation-menu-list"
|
||||||
|
className={cn(
|
||||||
|
"group flex flex-1 list-none items-center justify-center gap-1",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavigationMenuItem({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof NavigationMenuPrimitive.Item>) {
|
||||||
|
return (
|
||||||
|
<NavigationMenuPrimitive.Item
|
||||||
|
data-slot="navigation-menu-item"
|
||||||
|
className={cn("relative", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const navigationMenuTriggerStyle = cva(
|
||||||
|
"group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:hover:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent data-[state=open]:bg-accent/50 focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1"
|
||||||
|
)
|
||||||
|
|
||||||
|
function NavigationMenuTrigger({
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof NavigationMenuPrimitive.Trigger>) {
|
||||||
|
return (
|
||||||
|
<NavigationMenuPrimitive.Trigger
|
||||||
|
data-slot="navigation-menu-trigger"
|
||||||
|
className={cn(navigationMenuTriggerStyle(), "group", className)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}{" "}
|
||||||
|
<ChevronDownIcon
|
||||||
|
className="relative top-[1px] ml-1 size-3 transition duration-300 group-data-[state=open]:rotate-180"
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
</NavigationMenuPrimitive.Trigger>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavigationMenuContent({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof NavigationMenuPrimitive.Content>) {
|
||||||
|
return (
|
||||||
|
<NavigationMenuPrimitive.Content
|
||||||
|
data-slot="navigation-menu-content"
|
||||||
|
className={cn(
|
||||||
|
"data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 top-0 left-0 w-full p-2 pr-2.5 md:absolute md:w-auto",
|
||||||
|
"group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:data-[state=open]:animate-in group-data-[viewport=false]/navigation-menu:data-[state=closed]:animate-out group-data-[viewport=false]/navigation-menu:data-[state=closed]:zoom-out-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:fade-in-0 group-data-[viewport=false]/navigation-menu:data-[state=closed]:fade-out-0 group-data-[viewport=false]/navigation-menu:top-full group-data-[viewport=false]/navigation-menu:mt-1.5 group-data-[viewport=false]/navigation-menu:overflow-hidden group-data-[viewport=false]/navigation-menu:rounded-md group-data-[viewport=false]/navigation-menu:border group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:duration-200 **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavigationMenuViewport({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof NavigationMenuPrimitive.Viewport>) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"absolute top-full left-0 isolate z-50 flex justify-center"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<NavigationMenuPrimitive.Viewport
|
||||||
|
data-slot="navigation-menu-viewport"
|
||||||
|
className={cn(
|
||||||
|
"origin-top-center bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border shadow md:w-[var(--radix-navigation-menu-viewport-width)]",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavigationMenuLink({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof NavigationMenuPrimitive.Link>) {
|
||||||
|
return (
|
||||||
|
<NavigationMenuPrimitive.Link
|
||||||
|
data-slot="navigation-menu-link"
|
||||||
|
className={cn(
|
||||||
|
"data-[active=true]:focus:bg-accent data-[active=true]:hover:bg-accent data-[active=true]:bg-accent/50 data-[active=true]:text-accent-foreground hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus-visible:ring-ring/50 [&_svg:not([class*='text-'])]:text-muted-foreground flex flex-col gap-1 rounded-sm p-2 text-sm transition-all outline-none focus-visible:ring-[3px] focus-visible:outline-1 [&_svg:not([class*='size-'])]:size-4",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavigationMenuIndicator({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof NavigationMenuPrimitive.Indicator>) {
|
||||||
|
return (
|
||||||
|
<NavigationMenuPrimitive.Indicator
|
||||||
|
data-slot="navigation-menu-indicator"
|
||||||
|
className={cn(
|
||||||
|
"data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<div className="bg-border relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm shadow-md" />
|
||||||
|
</NavigationMenuPrimitive.Indicator>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
NavigationMenu,
|
||||||
|
NavigationMenuList,
|
||||||
|
NavigationMenuItem,
|
||||||
|
NavigationMenuContent,
|
||||||
|
NavigationMenuTrigger,
|
||||||
|
NavigationMenuLink,
|
||||||
|
NavigationMenuIndicator,
|
||||||
|
NavigationMenuViewport,
|
||||||
|
navigationMenuTriggerStyle,
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import * as SeparatorPrimitive from "@radix-ui/react-separator"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
function Separator({
|
||||||
|
className,
|
||||||
|
orientation = "horizontal",
|
||||||
|
decorative = true,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
|
||||||
|
return (
|
||||||
|
<SeparatorPrimitive.Root
|
||||||
|
data-slot="separator"
|
||||||
|
decorative={decorative}
|
||||||
|
orientation={orientation}
|
||||||
|
className={cn(
|
||||||
|
"bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Separator }
|
||||||
|
|
@ -0,0 +1,139 @@
|
||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import * as SheetPrimitive from "@radix-ui/react-dialog"
|
||||||
|
import { XIcon } from "lucide-react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {
|
||||||
|
return <SheetPrimitive.Root data-slot="sheet" {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
|
function SheetTrigger({
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof SheetPrimitive.Trigger>) {
|
||||||
|
return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
|
function SheetClose({
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof SheetPrimitive.Close>) {
|
||||||
|
return <SheetPrimitive.Close data-slot="sheet-close" {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
|
function SheetPortal({
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof SheetPrimitive.Portal>) {
|
||||||
|
return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
|
function SheetOverlay({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof SheetPrimitive.Overlay>) {
|
||||||
|
return (
|
||||||
|
<SheetPrimitive.Overlay
|
||||||
|
data-slot="sheet-overlay"
|
||||||
|
className={cn(
|
||||||
|
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function SheetContent({
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
side = "right",
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof SheetPrimitive.Content> & {
|
||||||
|
side?: "top" | "right" | "bottom" | "left"
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<SheetPortal>
|
||||||
|
<SheetOverlay />
|
||||||
|
<SheetPrimitive.Content
|
||||||
|
data-slot="sheet-content"
|
||||||
|
className={cn(
|
||||||
|
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
|
||||||
|
side === "right" &&
|
||||||
|
"data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm",
|
||||||
|
side === "left" &&
|
||||||
|
"data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm",
|
||||||
|
side === "top" &&
|
||||||
|
"data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b",
|
||||||
|
side === "bottom" &&
|
||||||
|
"data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
<SheetPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none">
|
||||||
|
<XIcon className="size-4" />
|
||||||
|
<span className="sr-only">Close</span>
|
||||||
|
</SheetPrimitive.Close>
|
||||||
|
</SheetPrimitive.Content>
|
||||||
|
</SheetPortal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="sheet-header"
|
||||||
|
className={cn("flex flex-col gap-1.5 p-4", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function SheetFooter({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="sheet-footer"
|
||||||
|
className={cn("mt-auto flex flex-col gap-2 p-4", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function SheetTitle({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof SheetPrimitive.Title>) {
|
||||||
|
return (
|
||||||
|
<SheetPrimitive.Title
|
||||||
|
data-slot="sheet-title"
|
||||||
|
className={cn("text-foreground font-semibold", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function SheetDescription({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof SheetPrimitive.Description>) {
|
||||||
|
return (
|
||||||
|
<SheetPrimitive.Description
|
||||||
|
data-slot="sheet-description"
|
||||||
|
className={cn("text-muted-foreground text-sm", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
Sheet,
|
||||||
|
SheetTrigger,
|
||||||
|
SheetClose,
|
||||||
|
SheetContent,
|
||||||
|
SheetHeader,
|
||||||
|
SheetFooter,
|
||||||
|
SheetTitle,
|
||||||
|
SheetDescription,
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
import * as React from "react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
|
||||||
|
return (
|
||||||
|
<textarea
|
||||||
|
data-slot="textarea"
|
||||||
|
className={cn(
|
||||||
|
"border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Textarea }
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { defineConfig, globalIgnores } from "eslint/config";
|
||||||
|
import nextVitals from "eslint-config-next/core-web-vitals";
|
||||||
|
import nextTs from "eslint-config-next/typescript";
|
||||||
|
|
||||||
|
const eslintConfig = defineConfig([
|
||||||
|
...nextVitals,
|
||||||
|
...nextTs,
|
||||||
|
// Override default ignores of eslint-config-next.
|
||||||
|
globalIgnores([
|
||||||
|
// Default ignores of eslint-config-next:
|
||||||
|
".next/**",
|
||||||
|
"out/**",
|
||||||
|
"build/**",
|
||||||
|
"next-env.d.ts",
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
export default eslintConfig;
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { clsx, type ClassValue } from "clsx"
|
||||||
|
import { twMerge } from "tailwind-merge"
|
||||||
|
|
||||||
|
export function cn(...inputs: ClassValue[]) {
|
||||||
|
return twMerge(clsx(inputs))
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
/** @type {import('next').NextConfig} */
|
||||||
|
const nextConfig = {
|
||||||
|
output: 'export',
|
||||||
|
basePath: '',
|
||||||
|
trailingSlash: true, // 添加这一行
|
||||||
|
images: {
|
||||||
|
unoptimized: true,
|
||||||
|
remotePatterns: [
|
||||||
|
{
|
||||||
|
protocol: 'https',
|
||||||
|
hostname: '**',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
protocol: 'http',
|
||||||
|
hostname: 'localhost',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = nextConfig
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
/*
|
||||||
|
* @LastEditors: whitechiina 1293616053@qq.com
|
||||||
|
* @LastEditTime: 2026-07-15 18:04:31
|
||||||
|
*/
|
||||||
|
import type { NextConfig } from "next";
|
||||||
|
|
||||||
|
const nextConfig: NextConfig = {
|
||||||
|
output: "export",
|
||||||
|
trailingSlash: true // 添加这一行
|
||||||
|
};
|
||||||
|
|
||||||
|
export default nextConfig;
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
{
|
||||||
|
"name": "baima-home",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "next dev",
|
||||||
|
"build": "next build",
|
||||||
|
"start": "next start",
|
||||||
|
"lint": "next lint"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-accordion": "^1.2.12",
|
||||||
|
"@radix-ui/react-dialog": "^1.1.15",
|
||||||
|
"@radix-ui/react-navigation-menu": "^1.2.14",
|
||||||
|
"@radix-ui/react-separator": "^1.1.8",
|
||||||
|
"@radix-ui/react-slot": "^1.2.4",
|
||||||
|
"class-variance-authority": "^0.7.1",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"embla-carousel-react": "^8.6.0",
|
||||||
|
"framer-motion": "^12.26.2",
|
||||||
|
"lucide-react": "^0.562.0",
|
||||||
|
"next": "16.1.1",
|
||||||
|
"react": "19.2.3",
|
||||||
|
"react-dom": "19.2.3",
|
||||||
|
"tailwind-merge": "^3.4.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@tailwindcss/postcss": "^4",
|
||||||
|
"@types/node": "^20",
|
||||||
|
"@types/react": "^19",
|
||||||
|
"@types/react-dom": "^19",
|
||||||
|
"dotenv": "^17.2.3",
|
||||||
|
"eslint": "^9",
|
||||||
|
"eslint-config-next": "16.1.1",
|
||||||
|
"tailwindcss": "^4",
|
||||||
|
"tw-animate-css": "^1.4.0",
|
||||||
|
"typescript": "^5",
|
||||||
|
"vercel": "^50.4.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
const config = {
|
||||||
|
plugins: {
|
||||||
|
"@tailwindcss/postcss": {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
|
After Width: | Height: | Size: 178 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
|
@ -0,0 +1 @@
|
||||||
|
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
|
||||||
|
After Width: | Height: | Size: 391 B |
|
|
@ -0,0 +1 @@
|
||||||
|
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
|
|
@ -0,0 +1,8 @@
|
||||||
|
<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
|
||||||
|
<path d="M 40 0 L 0 0 0 40" fill="none" stroke="white" stroke-width="0.5" stroke-opacity="0.3"/>
|
||||||
|
</pattern>
|
||||||
|
</defs>
|
||||||
|
<rect width="100%" height="100%" fill="url(#grid)" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 345 B |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
|
|
@ -0,0 +1 @@
|
||||||
|
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
|
||||||
|
After Width: | Height: | Size: 128 B |
|
After Width: | Height: | Size: 407 KiB |
|
|
@ -0,0 +1 @@
|
||||||
|
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
|
||||||
|
After Width: | Height: | Size: 385 B |
|
|
@ -0,0 +1,34 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2017",
|
||||||
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strict": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"incremental": true,
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"name": "next"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"next-env.d.ts",
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.tsx",
|
||||||
|
".next/types/**/*.ts",
|
||||||
|
".next/dev/types/**/*.ts",
|
||||||
|
"**/*.mts"
|
||||||
|
],
|
||||||
|
"exclude": ["node_modules"]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"buildCommand": "npm run build",
|
||||||
|
"outputDirectory": ".next",
|
||||||
|
"framework": "nextjs"
|
||||||
|
}
|
||||||