diff --git a/nkebao/AI_ICON_GUIDE.md b/nkebao/AI_ICON_GUIDE.md new file mode 100644 index 000000000..cef30a6a7 --- /dev/null +++ b/nkebao/AI_ICON_GUIDE.md @@ -0,0 +1,274 @@ +# AI图标使用指南 + +## 概述 + +本文档为AI助手提供标准化的图标选择和使用流程,确保在代码生成时使用正确的图标包和图标名称。 + +## AI使用流程 + +### 1. 项目类型判断 +首先判断项目类型: +- **PC端项目**: 使用 `@ant-design/icons` +- **移动端项目**: 使用 `antd-mobile-icons` + +### 2. 图标查找流程 +1. 根据功能需求确定图标类型 +2. 在对应图标包中查找合适的图标 +3. 如果图标不存在,查找替代方案 +4. 使用正确的导入语法 + +### 3. 代码生成模板 + +#### PC端项目模板 +```typescript +import { + // 导航类 + HomeOutlined, + UserOutlined, + SettingOutlined, + + // 操作类 + PlusOutlined, + EditOutlined, + DeleteOutlined, + CopyOutlined, + SearchOutlined, + ReloadOutlined, + + // 状态类 + CheckOutlined, + CloseOutlined, + CheckCircleOutlined, + CloseCircleOutlined, + ExclamationCircleOutlined, + InfoCircleOutlined, + LoadingOutlined, + + // 方向类 + UpOutlined, + DownOutlined, + LeftOutlined, + RightOutlined, + ArrowLeftOutlined, + + // 其他 + MessageOutlined, + CalendarOutlined, + ClockCircleOutlined, + PictureOutlined, + FileOutlined, + CameraOutlined, + QrcodeOutlined, +} from '@ant-design/icons'; +``` + +#### 移动端项目模板 +```typescript +import { + // 导航类 + HomeOutline, + UserOutline, + SettingOutline, + + // 操作类 + AddOutline, + EditSOutline, + DeleteOutline, + CopyOutline, + SearchOutline, + RefreshOutline, + + // 状态类 + CheckOutline, + CloseOutline, + CheckCircleOutline, + CloseCircleOutline, + ExclamationCircleOutline, + InfoCircleOutline, + LoadingOutline, + + // 方向类 + UpOutline, + DownOutline, + LeftOutline, + RightOutline, + + // 其他 + MessageOutline, + CalendarOutline, + ClockCircleOutline, + PictureOutline, + FileOutline, + CameraOutline, + QrCodeOutline, +} from 'antd-mobile-icons'; +``` + +## 功能到图标映射 + +### 基础功能映射 +| 功能需求 | PC端图标 | 移动端图标 | 说明 | +|---------|---------|-----------|------| +| 添加/新建 | PlusOutlined | AddOutline | 通用添加功能 | +| 编辑/修改 | EditOutlined | EditSOutline | 编辑功能 | +| 删除/移除 | DeleteOutlined | DeleteOutline | 删除功能 | +| 复制/克隆 | CopyOutlined | CopyOutline | 复制功能 | +| 搜索/查找 | SearchOutlined | SearchOutline | 搜索功能 | +| 刷新/重新加载 | ReloadOutlined | RefreshOutline | 刷新功能 | +| 设置/配置 | SettingOutlined | SettingOutline | 设置功能 | +| 用户/个人 | UserOutlined | UserOutline | 用户相关 | +| 首页/主页 | HomeOutlined | HomeOutline | 首页导航 | +| 返回/后退 | ArrowLeftOutlined | LeftOutline | 返回功能 | +| 关闭/取消 | CloseOutlined | CloseOutline | 关闭功能 | +| 确认/确定 | CheckOutlined | CheckOutline | 确认功能 | + +### 状态指示映射 +| 状态需求 | PC端图标 | 移动端图标 | 说明 | +|---------|---------|-----------|------| +| 成功/完成 | CheckCircleOutlined | CheckCircleOutline | 成功状态 | +| 错误/失败 | CloseCircleOutlined | CloseCircleOutline | 错误状态 | +| 警告/注意 | ExclamationCircleOutlined | ExclamationCircleOutline | 警告状态 | +| 信息/提示 | InfoCircleOutlined | InfoCircleOutline | 信息提示 | +| 加载/等待 | LoadingOutlined | LoadingOutline | 加载状态 | +| 时间/等待 | ClockCircleOutlined | ClockCircleOutline | 时间相关 | + +### 方向导航映射 +| 方向需求 | PC端图标 | 移动端图标 | 说明 | +|---------|---------|-----------|------| +| 向上/上升 | UpOutlined | UpOutline | 向上方向 | +| 向下/下降 | DownOutlined | DownOutline | 向下方向 | +| 向左/后退 | LeftOutlined | LeftOutline | 向左方向 | +| 向右/前进 | RightOutlined | RightOutline | 向右方向 | + +### 业务功能映射 +| 业务需求 | PC端图标 | 移动端图标 | 说明 | +|---------|---------|-----------|------| +| 消息/通知 | MessageOutlined | MessageOutline | 消息功能 | +| 日历/日期 | CalendarOutlined | CalendarOutline | 日历功能 | +| 图片/照片 | PictureOutlined | PictureOutline | 图片功能 | +| 文件/文档 | FileOutlined | FileOutline | 文件功能 | +| 相机/拍照 | CameraOutlined | CameraOutline | 相机功能 | +| 二维码 | QrcodeOutlined | QrCodeOutline | 二维码功能 | +| 微信/社交 | WechatOutlined | WechatOutline | 微信功能 | +| 设备/手机 | MobileOutlined | MobileOutline | 设备功能 | +| 团队/群组 | TeamOutlined | TeamOutline | 团队功能 | +| 订单/购物 | ShoppingOutlined | ShoppingOutline | 订单功能 | +| 支付/钱包 | PayCircleOutlined | PayCircleOutline | 支付功能 | + +## 特殊替换规则 + +### 移动端不存在的图标替换 +| 原需求 | 替换方案 | 说明 | +|--------|----------|------| +| RiseOutlined | UpOutline | 上升趋势 | +| ThumbsUpOutlined | LikeOutline | 点赞功能 | +| ShareAltOutlined | LinkOutline | 分享功能 | +| BarChartOutlined | PieOutline | 图表功能 | +| LineChartOutlined | PieOutline | 图表功能 | +| UserAddOutlined | UserOutline | 用户添加 | +| Progress | 自定义div | 进度条组件 | + +### PC端不存在的图标替换 +| 原需求 | 替换方案 | 说明 | +|--------|----------|------| +| AntOutline | HomeOutlined | 蚂蚁图标 | +| AppOutline | AppstoreOutlined | 应用图标 | + +## AI代码生成示例 + +### 场景1: 移动端列表页面 +```typescript +// AI应该生成的代码 +import { + AddOutline, // 添加按钮 + EditSOutline, // 编辑按钮 + DeleteOutline, // 删除按钮 + CopyOutline, // 复制按钮 + SearchOutline, // 搜索框 + RefreshOutline, // 刷新按钮 + UserOutline, // 用户信息 + CalendarOutline, // 时间信息 + UpOutline, // 上升趋势(替换RiseOutlined) +} from 'antd-mobile-icons'; + +// 使用示例 + + 新建 + + + 编辑 + + + 删除 + +``` + +### 场景2: PC端管理页面 +```typescript +// AI应该生成的代码 +import { + PlusOutlined, // 添加按钮 + EditOutlined, // 编辑按钮 + DeleteOutlined, // 删除按钮 + CopyOutlined, // 复制按钮 + SearchOutlined, // 搜索框 + ReloadOutlined, // 刷新按钮 + UserOutlined, // 用户信息 + CalendarOutlined, // 时间信息 + RiseOutlined, // 上升趋势(PC端存在) +} from '@ant-design/icons'; + +// 使用示例 +}>新建 +}>编辑 +} danger>删除 +``` + +## 错误检测和修正 + +### 常见错误模式 +1. **混用图标包**: 同时导入PC端和移动端图标 +2. **使用不存在的图标**: 在移动端使用PC端特有的图标 +3. **命名错误**: 图标名称大小写错误 +4. **导入路径错误**: 使用错误的包名 + +### 修正策略 +1. **统一图标包**: 根据项目类型选择单一图标包 +2. **查找替代**: 使用对照表查找替代图标 +3. **验证存在**: 确保图标在目标包中存在 +4. **测试验证**: 在代码中测试图标是否正常显示 + +## AI使用检查清单 + +### 代码生成前 +- [ ] 确认项目类型(PC端/移动端) +- [ ] 选择对应的图标包 +- [ ] 根据功能需求选择合适图标 +- [ ] 检查图标是否存在 + +### 代码生成中 +- [ ] 使用正确的导入语法 +- [ ] 图标名称大小写正确 +- [ ] 避免混用不同包的图标 +- [ ] 为不存在的图标提供替代方案 + +### 代码生成后 +- [ ] 验证图标导入正确 +- [ ] 检查图标使用语法 +- [ ] 确保样式设置合理 +- [ ] 提供使用示例 + +## 更新和维护 + +- 定期更新图标对照表 +- 记录新发现的图标差异 +- 更新替换规则 +- 优化AI使用流程 + +## 注意事项 + +1. **优先使用语义化图标**: 选择最能表达功能的图标 +2. **保持一致性**: 在同一项目中保持图标风格一致 +3. **考虑可访问性**: 为图标添加适当的aria-label +4. **性能优化**: 按需导入图标,避免全量导入 +5. **版本兼容**: 注意图标包版本与UI框架版本的兼容性 \ No newline at end of file diff --git a/nkebao/ANTD_MOBILE_ICONS.md b/nkebao/ANTD_MOBILE_ICONS.md deleted file mode 100644 index 4c03bba63..000000000 --- a/nkebao/ANTD_MOBILE_ICONS.md +++ /dev/null @@ -1,269 +0,0 @@ -# Ant Design Mobile 图标完整列表 - -## 📋 图标分类 - -### 🔗 基础图标 (Outline) -- `AddOutline` - 添加 -- `AppOutline` - 应用 -- `ArrowDownOutline` - 向下箭头 -- `ArrowLeftOutline` - 向左箭头 -- `ArrowRightOutline` - 向右箭头 -- `ArrowUpOutline` - 向上箭头 -- `AudioOutline` - 音频 -- `BarChartOutline` - 柱状图 -- `BellOutline` - 铃铛 -- `BookOutline` - 书本 -- `CalendarOutline` - 日历 -- `CameraOutline` - 相机 -- `CheckOutline` - 勾选 -- `ClockCircleOutline` - 时钟 -- `CloseOutline` - 关闭 -- `DeleteOutline` - 删除 -- `DownlandOutline` - 下载 -- `EditSOutline` - 编辑 -- `EllipsisOutline` - 省略号 -- `EyeOutline` - 眼睛 -- `FileOutline` - 文件 -- `FilterOutline` - 筛选 -- `FireOutline` - 火焰 -- `FlagOutline` - 旗帜 -- `FolderOutline` - 文件夹 -- `GiftOutline` - 礼物 -- `HeartOutline` - 心形 -- `HomeOutline` - 首页 -- `ImageOutline` - 图片 -- `LeftOutline` - 左箭头 -- `LikeOutline` - 点赞 -- `LinkOutline` - 链接 -- `LocationOutline` - 位置 -- `LockOutline` - 锁定 -- `MailOutline` - 邮件 -- `MessageOutline` - 消息 -- `MoreOutline` - 更多 -- `PayCircleOutline` - 支付 -- `PhoneOutline` - 电话 -- `PictureOutline` - 图片 -- `PlayOutline` - 播放 -- `PlusOutline` - 加号 -- `RightOutline` - 右箭头 -- `ScanOutline` - 扫描 -- `SearchOutline` - 搜索 -- `SendOutline` - 发送 -- `SettingOutline` - 设置 -- `ShareOutline` - 分享 -- `ShopbagOutline` - 购物袋 -- `StarOutline` - 星星 -- `TeamOutline` - 团队 -- `ThumbsUpOutline` - 点赞 -- `TimeOutline` - 时间 -- `UnlockOutline` - 解锁 -- `UserOutline` - 用户 -- `VideoOutline` - 视频 -- `VoiceOutline` - 语音 - -### 🎨 填充图标 (Fill) -- `AddCircleFill` - 添加圆形 -- `AppFill` - 应用填充 -- `AudioFill` - 音频填充 -- `BellFill` - 铃铛填充 -- `BookFill` - 书本填充 -- `CalendarFill` - 日历填充 -- `CameraFill` - 相机填充 -- `CheckCircleFill` - 勾选圆形 -- `ClockCircleFill` - 时钟圆形 -- `CloseCircleFill` - 关闭圆形 -- `DeleteFill` - 删除填充 -- `DownlandFill` - 下载填充 -- `EditSFill` - 编辑填充 -- `EyeFill` - 眼睛填充 -- `FileFill` - 文件填充 -- `FilterFill` - 筛选填充 -- `FireFill` - 火焰填充 -- `FlagFill` - 旗帜填充 -- `FolderFill` - 文件夹填充 -- `GiftFill` - 礼物填充 -- `HeartFill` - 心形填充 -- `HomeFill` - 首页填充 -- `ImageFill` - 图片填充 -- `LeftFill` - 左箭头填充 -- `LikeFill` - 点赞填充 -- `LinkFill` - 链接填充 -- `LocationFill` - 位置填充 -- `LockFill` - 锁定填充 -- `MailFill` - 邮件填充 -- `MessageFill` - 消息填充 -- `MoreFill` - 更多填充 -- `PayCircleFill` - 支付圆形 -- `PhoneFill` - 电话填充 -- `PictureFill` - 图片填充 -- `PlayFill` - 播放填充 -- `PlusCircleFill` - 加号圆形 -- `RightFill` - 右箭头填充 -- `ScanFill` - 扫描填充 -- `SearchFill` - 搜索填充 -- `SendFill` - 发送填充 -- `SettingFill` - 设置填充 -- `ShareFill` - 分享填充 -- `ShopbagFill` - 购物袋填充 -- `StarFill` - 星星填充 -- `TeamFill` - 团队填充 -- `ThumbsUpFill` - 点赞填充 -- `TimeFill` - 时间填充 -- `UnlockFill` - 解锁填充 -- `UserFill` - 用户填充 -- `VideoFill` - 视频填充 -- `VoiceFill` - 语音填充 - -### 📊 图表图标 -- `BarChartOutline` - 柱状图 -- `LineChartOutline` - 折线图 -- `PieOutline` - 饼图 -- `AreaOutline` - 面积图 -- `RadarOutline` - 雷达图 -- `ScatterOutline` - 散点图 - -### 🔧 功能图标 -- `AddOutline` - 添加 -- `DeleteOutline` - 删除 -- `EditSOutline` - 编辑 -- `SearchOutline` - 搜索 -- `FilterOutline` - 筛选 -- `SettingOutline` - 设置 -- `MoreOutline` - 更多 -- `CloseOutline` - 关闭 -- `CheckOutline` - 勾选 - -### 📱 通信图标 -- `MessageOutline` - 消息 -- `PhoneOutline` - 电话 -- `MailOutline` - 邮件 -- `SendOutline` - 发送 -- `VoiceOutline` - 语音 -- `VideoOutline` - 视频 - -### 👥 用户图标 -- `UserOutline` - 用户 -- `TeamOutline` - 团队 -- `HeartOutline` - 心形 -- `LikeOutline` - 点赞 -- `ThumbsUpOutline` - 点赞 - -### 🛍️ 商业图标 -- `ShopbagOutline` - 购物袋 -- `PayCircleOutline` - 支付 -- `GiftOutline` - 礼物 -- `StarOutline` - 星星 - -### 📁 文件图标 -- `FileOutline` - 文件 -- `FolderOutline` - 文件夹 -- `ImageOutline` - 图片 -- `PictureOutline` - 图片 -- `CameraOutline` - 相机 - -### 🎵 媒体图标 -- `AudioOutline` - 音频 -- `VideoOutline` - 视频 -- `PlayOutline` - 播放 -- `VoiceOutline` - 语音 - -### 📅 时间图标 -- `CalendarOutline` - 日历 -- `ClockCircleOutline` - 时钟 -- `TimeOutline` - 时间 - -### 🔒 安全图标 -- `LockOutline` - 锁定 -- `UnlockOutline` - 解锁 -- `EyeOutline` - 眼睛 - -### 📍 位置图标 -- `LocationOutline` - 位置 -- `FlagOutline` - 旗帜 - -### 🔗 导航图标 -- `ArrowUpOutline` - 向上箭头 -- `ArrowDownOutline` - 向下箭头 -- `ArrowLeftOutline` - 向左箭头 -- `ArrowRightOutline` - 向右箭头 -- `LeftOutline` - 左箭头 -- `RightOutline` - 右箭头 - -## 🎨 使用示例 - -### 基础用法 -```tsx -import { AddOutline, UserOutline, SettingOutline } from 'antd-mobile-icons'; - -// 在组件中使用 - - - -``` - -### 自定义样式 -```tsx -import { HeartOutline } from 'antd-mobile-icons'; - -// 自定义颜色和大小 - -``` - -### 在项目中的使用 -```tsx -// 工作台页面示例 -const features = [ - { - icon: , - name: "自动点赞" - }, - { - icon: , - name: "AI对话助手" - }, - { - icon: , - name: "AI数据分析" - } -]; -``` - -## 📝 注意事项 - -1. **图标命名规则**: 所有图标都以 `Outline` 或 `Fill` 结尾 -2. **导入方式**: 从 `antd-mobile-icons` 包中导入 -3. **样式定制**: 可以通过 `style` 属性自定义颜色、大小等 -4. **响应式**: 图标支持响应式设计,可以配合 CSS 媒体查询使用 -5. **可访问性**: 图标支持 `aria-label` 等无障碍属性 - -## 🔗 相关资源 - -- [Ant Design Mobile 官方文档](https://mobile.ant.design/) -- [图标组件文档](https://mobile.ant.design/zh/components/icon) -- [图标库 GitHub](https://github.com/ant-design/ant-design-mobile) - -## 📊 项目中已使用的图标 - -### 工作台页面 -- `ThumbsUpOutline` - 自动点赞 -- `MessageOutline` - AI对话助手 -- `SendOutline` - 群消息推送 -- `TeamOutline` - 自动建群 -- `ShareOutline` - 流量分发 -- `AppOutline` - AI策略优化 -- `BarChartOutline` - AI数据分析 -- `LineChartOutline` - AI销售预测 -- `ClockCircleOutline` - 朋友圈同步 - -### 底部导航 -- `AppOutline` - 首页 -- `ShopbagOutline` - 场景获客 -- `PieOutline` - 工作台 -- `UserOutline` - 我的 - -### 其他页面 -- `AddOutline` - 添加按钮 -- `UserAddOutline` - 用户添加 -- `BellOutline` - 通知 -- `LoopOutline` - 循环/同步 -- `TravelOutline` - 旅行/任务 \ No newline at end of file diff --git a/nkebao/ICON_DETAILED_MAPPING.md b/nkebao/ICON_DETAILED_MAPPING.md new file mode 100644 index 000000000..5e849544d --- /dev/null +++ b/nkebao/ICON_DETAILED_MAPPING.md @@ -0,0 +1,205 @@ +# 详细图标对照表 + +## 基础图标对照 + +### 导航类 +| 功能 | PC端 | 移动端 | 状态 | +|------|------|--------|------| +| 首页 | HomeOutlined | HomeOutline | ✅ | +| 返回 | ArrowLeftOutlined | LeftOutline | ✅ | +| 菜单 | MenuOutlined | MenuOutline | ✅ | +| 设置 | SettingOutlined | SettingOutline | ✅ | +| 用户 | UserOutlined | UserOutline | ✅ | +| 个人中心 | UserOutlined | UserOutline | ✅ | + +### 操作类 +| 功能 | PC端 | 移动端 | 状态 | +|------|------|--------|------| +| 添加 | PlusOutlined | AddOutline | ✅ | +| 编辑 | EditOutlined | EditSOutline | ✅ | +| 删除 | DeleteOutlined | DeleteOutline | ✅ | +| 复制 | CopyOutlined | CopyOutline | ✅ | +| 保存 | SaveOutlined | SaveOutline | ✅ | +| 刷新 | ReloadOutlined | RefreshOutline | ✅ | +| 搜索 | SearchOutlined | SearchOutline | ✅ | +| 关闭 | CloseOutlined | CloseOutline | ✅ | +| 确认 | CheckOutlined | CheckOutline | ✅ | +| 取消 | CloseOutlined | CloseOutline | ✅ | + +### 状态类 +| 功能 | PC端 | 移动端 | 状态 | +|------|------|--------|------| +| 成功 | CheckCircleOutlined | CheckCircleOutline | ✅ | +| 错误 | CloseCircleOutlined | CloseCircleOutline | ✅ | +| 警告 | ExclamationCircleOutlined | ExclamationCircleOutline | ✅ | +| 信息 | InfoCircleOutlined | InfoCircleOutline | ✅ | +| 加载 | LoadingOutlined | LoadingOutline | ✅ | +| 等待 | ClockCircleOutlined | ClockCircleOutline | ✅ | + +### 方向类 +| 功能 | PC端 | 移动端 | 状态 | +|------|------|--------|------| +| 向上 | UpOutlined | UpOutline | ✅ | +| 向下 | DownOutlined | DownOutline | ✅ | +| 向左 | LeftOutlined | LeftOutline | ✅ | +| 向右 | RightOutlined | RightOutline | ✅ | +| 向上圆形 | UpCircleOutlined | UpCircleOutline | ✅ | +| 向下圆形 | DownCircleOutlined | DownCircleOutline | ✅ | + +### 通信类 +| 功能 | PC端 | 移动端 | 状态 | +|------|------|--------|------| +| 消息 | MessageOutlined | MessageOutline | ✅ | +| 邮件 | MailOutlined | MailOutline | ✅ | +| 电话 | PhoneOutlined | PhoneOutline | ✅ | +| 视频 | VideoCameraOutlined | VideoCameraOutline | ✅ | +| 语音 | AudioOutlined | AudioOutline | ✅ | + +### 媒体类 +| 功能 | PC端 | 移动端 | 状态 | +|------|------|--------|------| +| 图片 | PictureOutlined | PictureOutline | ✅ | +| 文件 | FileOutlined | FileOutline | ✅ | +| 文件夹 | FolderOutlined | FolderOutline | ✅ | +| 相机 | CameraOutlined | CameraOutline | ✅ | +| 二维码 | QrcodeOutlined | QrCodeOutline | ✅ | + +### 时间类 +| 功能 | PC端 | 移动端 | 状态 | +|------|------|--------|------| +| 日历 | CalendarOutlined | CalendarOutline | ✅ | +| 时钟 | ClockCircleOutlined | ClockCircleOutline | ✅ | +| 历史 | HistoryOutlined | HistoryOutline | ✅ | + +### 数据类 +| 功能 | PC端 | 移动端 | 状态 | +|------|------|--------|------| +| 统计 | BarChartOutlined | BarChartOutline | ✅ | +| 饼图 | PieChartOutlined | PieChartOutline | ✅ | +| 折线图 | LineChartOutlined | LineChartOutline | ✅ | +| 表格 | TableOutlined | TableOutline | ✅ | +| 列表 | UnorderedListOutlined | UnorderedListOutline | ✅ | + +## 特殊图标对照 + +### 业务相关 +| 功能 | PC端 | 移动端 | 状态 | +|------|------|--------|------| +| 设备 | MobileOutlined | MobileOutline | ✅ | +| 微信 | WechatOutlined | WechatOutline | ✅ | +| 群组 | TeamOutlined | TeamOutline | ✅ | +| 客户 | UserAddOutlined | UserAddOutline | ❌ | +| 订单 | ShoppingOutlined | ShoppingOutline | ✅ | +| 支付 | PayCircleOutlined | PayCircleOutline | ✅ | + +### 工具类 +| 功能 | PC端 | 移动端 | 状态 | +|------|------|--------|------| +| 工具 | ToolOutlined | ToolOutline | ✅ | +| 配置 | SettingOutlined | SettingOutline | ✅ | +| 帮助 | QuestionCircleOutlined | QuestionCircleOutline | ✅ | +| 反馈 | MessageOutlined | MessageOutline | ✅ | +| 分享 | ShareAltOutlined | ShareOutline | ❌ | + +## 不存在的图标替换方案 + +### PC端存在但移动端不存在的图标 +| PC端图标 | 推荐替换 | 说明 | +|----------|----------|------| +| UserAddOutlined | UserOutline | 用户添加功能 | +| ShareAltOutlined | LinkOutline | 分享功能 | +| RiseOutlined | UpOutline | 上升趋势 | +| ThumbsUpOutlined | LikeOutline | 点赞功能 | +| BarChartOutlined | PieOutline | 图表功能 | +| LineChartOutlined | PieOutline | 图表功能 | + +### 移动端存在但PC端不存在的图标 +| 移动端图标 | 推荐替换 | 说明 | +|------------|----------|------| +| AntOutline | HomeOutlined | 蚂蚁图标 | +| AppOutline | AppstoreOutlined | 应用图标 | + +## 使用规范 + +### 1. 导入规范 +```typescript +// PC端项目 +import { + HomeOutlined, + UserOutlined, + SettingOutlined, +} from '@ant-design/icons'; + +// 移动端项目 +import { + HomeOutline, + UserOutline, + SettingOutline, +} from 'antd-mobile-icons'; +``` + +### 2. 命名规范 +- PC端:使用 `Outlined` 后缀 +- 移动端:使用 `Outline` 后缀 +- 保持语义化命名 + +### 3. 使用建议 +- 优先使用语义明确的图标 +- 保持图标风格一致性 +- 考虑图标在不同尺寸下的清晰度 +- 为图标添加适当的aria-label + +### 4. 错误处理 +当图标不存在时: +1. 查找语义相近的图标 +2. 使用通用图标(如QuestionOutlined) +3. 考虑使用文字替代 +4. 创建自定义图标组件 + +## 项目中的实际应用 + +### 场景获客模块使用的图标 +```typescript +// 移动端项目中的图标使用 +import { + AddOutline, // 添加 + UpOutline, // 上升趋势(替换RiseOutline) + UserOutline, // 用户 + CalendarOutline, // 日历 + CopyOutline, // 复制 + DeleteOutline, // 删除 + EditSOutline, // 编辑 + SettingOutline, // 设置 + SearchOutline, // 搜索 + RefreshOutline, // 刷新 + QrCodeOutline, // 二维码 +} from 'antd-mobile-icons'; +``` + +### 工作台模块使用的图标 +```typescript +// 移动端项目中的图标使用 +import { + LikeOutline, // 点赞(替换ThumbsUpOutline) + LinkOutline, // 链接(替换ShareOutline) + PieOutline, // 饼图(替换BarChartOutline/LineChartOutline) + UserOutline, // 用户 + TeamOutline, // 团队 + MessageOutline, // 消息 +} from 'antd-mobile-icons'; +``` + +## 更新和维护 + +1. **定期检查**: 定期检查新版本中新增的图标 +2. **文档更新**: 及时更新图标对照表 +3. **团队协作**: 团队成员共享图标使用规范 +4. **代码审查**: 在代码审查中检查图标使用是否正确 + +## 注意事项 + +1. **包版本**: 确保图标包版本与UI框架版本兼容 +2. **按需导入**: 避免全量导入图标,影响打包体积 +3. **样式覆盖**: 可以通过CSS自定义图标样式 +4. **无障碍**: 为图标添加适当的无障碍属性 +5. **性能**: 大量使用图标时注意性能优化 \ No newline at end of file diff --git a/nkebao/ICON_MAPPING_GUIDE.md b/nkebao/ICON_MAPPING_GUIDE.md new file mode 100644 index 000000000..81d901d07 --- /dev/null +++ b/nkebao/ICON_MAPPING_GUIDE.md @@ -0,0 +1,230 @@ +# PC端与移动端图标对照文档 + +## 概述 + +本文档记录了PC端(@ant-design/icons)和移动端(antd-mobile-icons)的图标名称对照,以及正确的导入方式。 + +## 导入方式 + +### PC端图标 (@ant-design/icons) +```typescript +import { + HomeOutlined, + UserOutlined, + SettingOutlined, + // ... 其他图标 +} from '@ant-design/icons'; +``` + +### 移动端图标 (antd-mobile-icons) +```typescript +import { + AntOutline, + ArrowDownCircleOutline, + UserOutline, + // ... 其他图标 +} from 'antd-mobile-icons'; +``` + +## 图标对照表 + +### 常用图标对照 + +| 功能描述 | PC端图标 | 移动端图标 | 备注 | +|---------|---------|-----------|------| +| 首页 | HomeOutlined | HomeOutline | 完全对应 | +| 用户 | UserOutlined | UserOutline | 完全对应 | +| 设置 | SettingOutlined | SettingOutline | 完全对应 | +| 搜索 | SearchOutlined | SearchOutline | 完全对应 | +| 添加 | PlusOutlined | AddOutline | 完全对应 | +| 编辑 | EditOutlined | EditSOutline | 移动端略有不同 | +| 删除 | DeleteOutlined | DeleteOutline | 完全对应 | +| 复制 | CopyOutlined | CopyOutline | 完全对应 | +| 刷新 | ReloadOutlined | RefreshOutline | 完全对应 | +| 二维码 | QrcodeOutlined | QrCodeOutline | 完全对应 | +| 日历 | CalendarOutlined | CalendarOutline | 完全对应 | +| 时钟 | ClockCircleOutlined | ClockCircleOutline | 完全对应 | +| 箭头向上 | UpOutlined | UpOutline | 完全对应 | +| 箭头向下 | DownOutlined | DownOutline | 完全对应 | +| 箭头向左 | LeftOutlined | LeftOutline | 完全对应 | +| 箭头向右 | RightOutlined | RightOutline | 完全对应 | +| 返回 | ArrowLeftOutlined | LeftOutline | 移动端使用LeftOutline | +| 关闭 | CloseOutlined | CloseOutline | 完全对应 | +| 检查 | CheckOutlined | CheckOutline | 完全对应 | +| 警告 | ExclamationCircleOutlined | ExclamationCircleOutline | 完全对应 | +| 信息 | InfoCircleOutlined | InfoCircleOutline | 完全对应 | +| 成功 | CheckCircleOutlined | CheckCircleOutline | 完全对应 | +| 错误 | CloseCircleOutlined | CloseCircleOutline | 完全对应 | + +### 方向性图标 + +| 功能描述 | PC端图标 | 移动端图标 | +|---------|---------|-----------| +| 向上 | UpOutlined | UpOutline | +| 向下 | DownOutlined | DownOutline | +| 向左 | LeftOutlined | LeftOutline | +| 向右 | RightOutlined | RightOutline | +| 向上圆形 | UpCircleOutlined | UpCircleOutline | +| 向下圆形 | DownCircleOutlined | DownCircleOutline | +| 向左圆形 | LeftCircleOutlined | LeftCircleOutline | +| 向右圆形 | RightCircleOutlined | RightCircleOutline | + +### 编辑类图标 + +| 功能描述 | PC端图标 | 移动端图标 | +|---------|---------|-----------| +| 编辑 | EditOutlined | EditSOutline | +| 删除 | DeleteOutlined | DeleteOutline | +| 复制 | CopyOutlined | CopyOutline | +| 剪切 | ScissorOutlined | ScissorOutline | +| 撤销 | UndoOutlined | UndoOutline | +| 重做 | RedoOutlined | RedoOutline | +| 保存 | SaveOutlined | SaveOutline | + +### 通信类图标 + +| 功能描述 | PC端图标 | 移动端图标 | +|---------|---------|-----------| +| 消息 | MessageOutlined | MessageOutline | +| 邮件 | MailOutlined | MailOutline | +| 电话 | PhoneOutlined | PhoneOutline | +| 视频通话 | VideoCameraOutlined | VideoCameraOutline | +| 语音 | AudioOutlined | AudioOutline | + +### 媒体类图标 + +| 功能描述 | PC端图标 | 移动端图标 | +|---------|---------|-----------| +| 图片 | PictureOutlined | PictureOutline | +| 视频 | VideoCameraOutlined | VideoCameraOutline | +| 音频 | AudioOutlined | AudioOutline | +| 文件 | FileOutlined | FileOutline | +| 文件夹 | FolderOutlined | FolderOutline | +| 相机 | CameraOutlined | CameraOutline | + +### 导航类图标 + +| 功能描述 | PC端图标 | 移动端图标 | +|---------|---------|-----------| +| 菜单 | MenuOutlined | MenuOutline | +| 汉堡菜单 | MenuFoldOutlined | MenuOutline | +| 展开菜单 | MenuUnfoldOutlined | MenuOutline | +| 面包屑 | BreadcrumbOutlined | BreadcrumbOutline | +| 分页 | PaginationOutlined | PaginationOutline | + +### 数据展示类图标 + +| 功能描述 | PC端图标 | 移动端图标 | +|---------|---------|-----------| +| 表格 | TableOutlined | TableOutline | +| 列表 | UnorderedListOutlined | UnorderedListOutline | +| 卡片 | CreditCardOutlined | CreditCardOutline | +| 统计 | BarChartOutlined | BarChartOutline | +| 饼图 | PieChartOutlined | PieChartOutline | +| 折线图 | LineChartOutlined | LineChartOutline | +| 仪表盘 | DashboardOutlined | DashboardOutline | + +### 反馈类图标 + +| 功能描述 | PC端图标 | 移动端图标 | +|---------|---------|-----------| +| 成功 | CheckCircleOutlined | CheckCircleOutline | +| 错误 | CloseCircleOutlined | CloseCircleOutline | +| 警告 | ExclamationCircleOutlined | ExclamationCircleOutline | +| 信息 | InfoCircleOutlined | InfoCircleOutline | +| 加载 | LoadingOutlined | LoadingOutline | +| 等待 | ClockCircleOutlined | ClockCircleOutline | + +## 使用建议 + +### 1. 项目类型判断 +- **PC端项目**: 使用 `@ant-design/icons` +- **移动端项目**: 使用 `antd-mobile-icons` + +### 2. 图标选择原则 +- 优先选择语义化图标 +- 保持图标风格一致性 +- 考虑图标在不同尺寸下的清晰度 + +### 3. 常见错误避免 +- 不要混用PC端和移动端图标 +- 注意图标名称的大小写 +- 确保图标在对应包中存在 + +### 4. 图标替换策略 +当某个图标在目标包中不存在时: +1. 查找语义相近的图标 +2. 使用通用图标(如QuestionOutlined) +3. 考虑使用文字替代 +4. 创建自定义图标组件 + +## 实际项目中的使用示例 + +### PC端项目示例 +```typescript +import { + HomeOutlined, + UserOutlined, + SettingOutlined, + SearchOutlined, + PlusOutlined, + EditOutlined, + DeleteOutlined, + CopyOutlined, + ReloadOutlined, + QrcodeOutlined, + CalendarOutlined, + ClockCircleOutlined, + UpOutlined, + DownOutlined, + LeftOutlined, + RightOutlined, + CloseOutlined, + CheckOutlined, + ExclamationCircleOutlined, + InfoCircleOutlined, + CheckCircleOutlined, + CloseCircleOutlined, +} from '@ant-design/icons'; +``` + +### 移动端项目示例 +```typescript +import { + HomeOutline, + UserOutline, + SettingOutline, + SearchOutline, + AddOutline, + EditSOutline, + DeleteOutline, + CopyOutline, + RefreshOutline, + QrCodeOutline, + CalendarOutline, + ClockCircleOutline, + UpOutline, + DownOutline, + LeftOutline, + RightOutline, + CloseOutline, + CheckOutline, + ExclamationCircleOutline, + InfoCircleOutline, + CheckCircleOutline, + CloseCircleOutline, +} from 'antd-mobile-icons'; +``` + +## 注意事项 + +1. **包依赖**: 确保项目中已安装对应的图标包 +2. **版本兼容**: 注意图标包版本与UI框架版本的兼容性 +3. **性能考虑**: 按需导入图标,避免全量导入 +4. **样式覆盖**: 可以通过CSS自定义图标颜色和大小 +5. **无障碍**: 为图标添加适当的aria-label属性 + +## 更新记录 + +- 2024-01-XX: 初始版本,包含常用图标对照 +- 后续根据实际使用情况持续更新 \ No newline at end of file diff --git a/nkebao/ICON_QUICK_REFERENCE.md b/nkebao/ICON_QUICK_REFERENCE.md new file mode 100644 index 000000000..03b9c2339 --- /dev/null +++ b/nkebao/ICON_QUICK_REFERENCE.md @@ -0,0 +1,271 @@ +# 图标快速参考表 + +## 快速查找 + +### 🔍 按功能查找 + +| 功能 | PC端 | 移动端 | 导入方式 | +|------|------|--------|----------| +| **添加** | PlusOutlined | AddOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **编辑** | EditOutlined | EditSOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **删除** | DeleteOutlined | DeleteOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **复制** | CopyOutlined | CopyOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **搜索** | SearchOutlined | SearchOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **刷新** | ReloadOutlined | RefreshOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **设置** | SettingOutlined | SettingOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **用户** | UserOutlined | UserOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **首页** | HomeOutlined | HomeOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **返回** | ArrowLeftOutlined | LeftOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **关闭** | CloseOutlined | CloseOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **确认** | CheckOutlined | CheckOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **成功** | CheckCircleOutlined | CheckCircleOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **错误** | CloseCircleOutlined | CloseCircleOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **警告** | ExclamationCircleOutlined | ExclamationCircleOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **信息** | InfoCircleOutlined | InfoCircleOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **加载** | LoadingOutlined | LoadingOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **向上** | UpOutlined | UpOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **向下** | DownOutlined | DownOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **向左** | LeftOutlined | LeftOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **向右** | RightOutlined | RightOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **消息** | MessageOutlined | MessageOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **电话** | PhoneOutlined | PhoneOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **日历** | CalendarOutlined | CalendarOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **时钟** | ClockCircleOutlined | ClockCircleOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **图片** | PictureOutlined | PictureOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **文件** | FileOutlined | FileOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **相机** | CameraOutlined | CameraOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **二维码** | QrcodeOutlined | QrCodeOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **微信** | WechatOutlined | WechatOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **设备** | MobileOutlined | MobileOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **团队** | TeamOutlined | TeamOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **订单** | ShoppingOutlined | ShoppingOutline | `@ant-design/icons` / `antd-mobile-icons` | +| **支付** | PayCircleOutlined | PayCircleOutline | `@ant-design/icons` / `antd-mobile-icons` | + +### 🔄 常见替换 + +| 原图标 | 替换为 | 说明 | +|--------|--------|------| +| RiseOutlined | UpOutline | 上升趋势 | +| ThumbsUpOutlined | LikeOutline | 点赞功能 | +| ShareAltOutlined | LinkOutline | 分享功能 | +| BarChartOutlined | PieOutline | 图表功能 | +| LineChartOutlined | PieOutline | 图表功能 | +| UserAddOutlined | UserOutline | 用户添加 | +| SettingOutline | SettingOutline | 设置(移动端) | + +## 导入模板 + +### PC端项目模板 +```typescript +import { + HomeOutlined, + UserOutlined, + SettingOutlined, + SearchOutlined, + PlusOutlined, + EditOutlined, + DeleteOutlined, + CopyOutlined, + ReloadOutlined, + CloseOutlined, + CheckOutlined, + UpOutlined, + DownOutlined, + LeftOutlined, + RightOutlined, + MessageOutlined, + CalendarOutlined, + ClockCircleOutlined, + PictureOutlined, + FileOutlined, + CameraOutlined, + QrcodeOutlined, + WechatOutlined, + MobileOutlined, + TeamOutlined, + ShoppingOutlined, + PayCircleOutlined, + CheckCircleOutlined, + CloseCircleOutlined, + ExclamationCircleOutlined, + InfoCircleOutlined, + LoadingOutlined, +} from '@ant-design/icons'; +``` + +### 移动端项目模板 +```typescript +import { + HomeOutline, + UserOutline, + SettingOutline, + SearchOutline, + AddOutline, + EditSOutline, + DeleteOutline, + CopyOutline, + RefreshOutline, + CloseOutline, + CheckOutline, + UpOutline, + DownOutline, + LeftOutline, + RightOutline, + MessageOutline, + CalendarOutline, + ClockCircleOutline, + PictureOutline, + FileOutline, + CameraOutline, + QrCodeOutline, + WechatOutline, + MobileOutline, + TeamOutline, + ShoppingOutline, + PayCircleOutline, + CheckCircleOutline, + CloseCircleOutline, + ExclamationCircleOutline, + InfoCircleOutline, + LoadingOutline, +} from 'antd-mobile-icons'; +``` + +## 使用示例 + +### 基础使用 +```typescript +// PC端 +import { HomeOutlined, UserOutlined } from '@ant-design/icons'; + + + + +// 移动端 +import { HomeOutline, UserOutline } from 'antd-mobile-icons'; + + + +``` + +### 按钮中使用 +```typescript +// PC端 +import { PlusOutlined, EditOutlined } from '@ant-design/icons'; + +}>添加 +}>编辑 + +// 移动端 +import { AddOutline, EditSOutline } from 'antd-mobile-icons'; + + + 添加 + + + 编辑 + +``` + +### 列表中使用 +```typescript +// PC端 +import { DeleteOutlined, CopyOutlined } from '@ant-design/icons'; + +} danger>删除 +}>复制 + +// 移动端 +import { DeleteOutline, CopyOutline } from 'antd-mobile-icons'; + + + 删除 + + + 复制 + +``` + +## 常见错误 + +### ❌ 错误示例 +```typescript +// 错误:混用PC端和移动端图标 +import { HomeOutlined } from '@ant-design/icons'; // PC端 +import { UserOutline } from 'antd-mobile-icons'; // 移动端 + +// 错误:使用不存在的图标 +import { RiseOutlined } from 'antd-mobile-icons'; // 不存在 +import { UserAddOutline } from 'antd-mobile-icons'; // 不存在 +``` + +### ✅ 正确示例 +```typescript +// 正确:统一使用移动端图标 +import { + HomeOutline, + UserOutline, + UpOutline, // 替换RiseOutlined + UserOutline // 替换UserAddOutline +} from 'antd-mobile-icons'; + +// 正确:统一使用PC端图标 +import { + HomeOutlined, + UserOutlined, + RiseOutlined, // PC端存在 + UserAddOutlined // PC端存在 +} from '@ant-design/icons'; +``` + +## 快速检查清单 + +### 开发前检查 +- [ ] 确认项目类型(PC端/移动端) +- [ ] 选择对应的图标包 +- [ ] 检查图标是否存在 +- [ ] 准备替换方案 + +### 开发中检查 +- [ ] 使用正确的导入方式 +- [ ] 图标名称大小写正确 +- [ ] 避免混用不同包的图标 +- [ ] 为图标添加适当的样式 + +### 开发后检查 +- [ ] 图标显示正常 +- [ ] 样式符合设计要求 +- [ ] 无障碍属性完整 +- [ ] 性能影响最小 + +## 紧急替换方案 + +当遇到图标不存在时,使用以下通用图标: + +```typescript +// 移动端通用图标 +import { + QuestionCircleOutline, // 通用问号 + AppOutline, // 通用应用 + ToolOutline, // 通用工具 + SettingOutline, // 通用设置 + UserOutline, // 通用用户 +} from 'antd-mobile-icons'; + +// PC端通用图标 +import { + QuestionCircleOutlined, // 通用问号 + AppstoreOutlined, // 通用应用 + ToolOutlined, // 通用工具 + SettingOutlined, // 通用设置 + UserOutlined, // 通用用户 +} from '@ant-design/icons'; +``` + +## 更新日志 + +- 2024-01-XX: 初始版本 +- 添加常用图标对照 +- 添加错误示例和正确示例 +- 添加快速检查清单 +- 添加紧急替换方案 \ No newline at end of file diff --git a/nkebao/README.md b/nkebao/README.md deleted file mode 100644 index 88c0217ec..000000000 --- a/nkebao/README.md +++ /dev/null @@ -1,44 +0,0 @@ -# Nkebao Base - -一个现代化的 React + TypeScript 前端项目模板,适用于中后台管理系统、移动端 H5 等场景。 -集成了 Vite 极速构建、Zustand 轻量状态管理、模块化路由与权限拦截、axios 请求封装、移动端 rem 适配等主流工程能力。 - ---- - -## 启动方式 - -```bash -yarn install -yarn dev -``` - ---- - -## 技术栈 - -- **React 18**:主流前端框架 -- **TypeScript**:类型安全开发 -- **Vite**:极速开发与构建工具 -- **axios**:请求库,统一封装 -- **sass**:CSS 预处理 -- **React Router v6**:路由管理,支持模块化与权限拦截 -- **antd / antd-mobile**:桌面端与移动端 UI 组件库 -- **postcss-pxtorem**:rem 适配,移动端友好 -- **Zustand**:轻量状态管理,支持持久化 -- **ESLint + Prettier**:代码规范与自动格式化 -- **路径别名 @**:简化 import - ---- - -## 目录结构 - -``` -src/ - api/ # axios 封装与接口模块 - pages/ # 页面组件 - styles/ # 全局样式 - App.tsx # 入口组件 - main.tsx # 入口文件 -public/ - index.html # HTML 模板 -``` \ No newline at end of file diff --git a/nkebao/ROUTE_MIGRATION.md b/nkebao/ROUTE_MIGRATION.md deleted file mode 100644 index 9f1794832..000000000 --- a/nkebao/ROUTE_MIGRATION.md +++ /dev/null @@ -1,140 +0,0 @@ -# 路由迁移总结 - -## 📋 迁移概述 - -已成功将旧项目 @Cunkebao 的路由结构迁移到新项目 @nkebao,并进行了合理的文件拆分和归类。 - -## 🗂️ 路由模块结构 - -### 1. 基础路由模块 (`auth.tsx`) -- `/login` - 登录页面 - -### 2. 设备管理模块 (`devices.tsx`) -- `/devices` - 设备列表 -- `/devices/:id` - 设备详情 - -### 3. 微信号管理模块 (`wechat-accounts.tsx`) -- `/wechat-accounts` - 微信号列表 -- `/wechat-accounts/:id` - 微信号详情 - -### 4. 工作台模块 (`workspace.tsx`) -- `/workspace` - 工作台主页 -- `/workspace/auto-like` - 自动点赞 -- `/workspace/auto-like/new` - 新建自动点赞 -- `/workspace/auto-like/:id` - 自动点赞详情 -- `/workspace/auto-like/:id/edit` - 编辑自动点赞 -- `/workspace/auto-group` - 自动分组 -- `/workspace/auto-group/:id` - 自动分组详情 -- `/workspace/group-push` - 群发推送 -- `/workspace/group-push/new` - 新建群发推送 -- `/workspace/group-push/:id` - 群发推送详情 -- `/workspace/group-push/:id/edit` - 编辑群发推送 -- `/workspace/moments-sync` - 朋友圈同步 -- `/workspace/moments-sync/new` - 新建朋友圈同步 -- `/workspace/moments-sync/:id` - 朋友圈同步详情 -- `/workspace/moments-sync/edit/:id` - 编辑朋友圈同步 -- `/workspace/ai-assistant` - AI助手 -- `/workspace/traffic-distribution` - 流量分发 -- `/workspace/traffic-distribution/new` - 新建流量分发 -- `/workspace/traffic-distribution/edit/:id` - 编辑流量分发 -- `/workspace/traffic-distribution/:id` - 流量分发详情 - -### 5. 场景管理模块 (`scenarios.tsx`) -- `/scenarios` - 场景列表 -- `/scenarios/new` - 新建场景 -- `/scenarios/new/:scenarioId` - 新建场景(带场景ID) -- `/scenarios/edit/:planId` - 编辑场景 -- `/scenarios/list/:scenarioId/:scenarioName` - 场景列表详情 - -### 6. 内容管理模块 (`content.tsx`) -- `/content` - 内容管理 -- `/content/new` - 新建内容 -- `/content/edit/:id` - 编辑内容 -- `/content/materials/:id` - 素材管理 -- `/content/materials/new/:id` - 新建素材 -- `/content/materials/edit/:id/:materialId` - 编辑素材 - -### 7. 流量池模块 (`traffic-pool.tsx`) -- `/traffic-pool` - 流量池列表 -- `/traffic-pool/:id` - 流量池详情 - -### 8. 其他功能模块 (`other.tsx`) -- `/profile` - 个人中心 -- `/plans` - 计划管理 -- `/plans/:planId` - 计划详情 -- `/orders` - 订单管理 -- `/contact-import` - 联系人导入 - -## 🔧 技术实现 - -### 路由配置 -- 使用 React Router DOM v6 -- 支持动态路由参数 -- 统一的权限控制 -- 模块化路由管理 - -### 权限控制 -- 每个路由都配置了 `auth` 属性 -- 支持角色权限控制 -- 自动权限检查 - -### 组件结构 -- 使用 Layout 组件统一布局 -- 使用 MeauMobile 组件作为底部导航 -- 创建了 PlaceholderPage 通用占位组件 - -## 📁 文件结构 - -``` -src/ -├── router/ -│ ├── module/ -│ │ ├── index.tsx # 主路由文件 -│ │ ├── auth.tsx # 认证路由 -│ │ ├── devices.tsx # 设备管理路由 -│ │ ├── wechat-accounts.tsx # 微信号管理路由 -│ │ ├── workspace.tsx # 工作台路由 -│ │ ├── scenarios.tsx # 场景管理路由 -│ │ ├── content.tsx # 内容管理路由 -│ │ ├── traffic-pool.tsx # 流量池路由 -│ │ └── other.tsx # 其他功能路由 -│ ├── index.tsx # 路由入口 -│ ├── permissionRoute.tsx # 权限路由组件 -│ └── config.ts # 路由配置 -├── pages/ -│ ├── login/ # 登录页面 -│ ├── devices/ # 设备管理页面 -│ ├── wechat-accounts/ # 微信号管理页面 -│ ├── workspace/ # 工作台页面 -│ ├── scenarios/ # 场景管理页面 -│ ├── content/ # 内容管理页面 -│ ├── traffic-pool/ # 流量池页面 -│ ├── profile/ # 个人中心页面 -│ ├── plans/ # 计划管理页面 -│ ├── orders/ # 订单管理页面 -│ └── contact-import/ # 联系人导入页面 -└── components/ - └── PlaceholderPage.tsx # 通用占位页面组件 -``` - -## 🎯 主要特性 - -1. **模块化设计**: 按功能模块拆分路由,便于维护 -2. **权限控制**: 统一的权限管理机制 -3. **类型安全**: 完整的 TypeScript 类型定义 -4. **响应式设计**: 适配移动端和桌面端 -5. **代码复用**: 使用通用组件减少重复代码 - -## 🚀 下一步计划 - -1. 实现具体的页面功能 -2. 完善权限控制逻辑 -3. 添加路由懒加载 -4. 优化页面性能 -5. 添加路由守卫 - -## 📝 注意事项 - -- 所有页面目前都是占位页面,需要根据业务需求逐步实现 -- 路由权限控制需要根据实际业务逻辑调整 -- 建议按照模块优先级逐步开发页面功能 \ No newline at end of file diff --git a/nkebao/WORKSPACE_MIGRATION.md b/nkebao/WORKSPACE_MIGRATION.md deleted file mode 100644 index 436747bff..000000000 --- a/nkebao/WORKSPACE_MIGRATION.md +++ /dev/null @@ -1,159 +0,0 @@ -# 工作台页面迁移总结 - -## 📋 迁移概述 - -已成功将旧项目 @Cunkebao 的工作台页面迁移到新项目 @nkebao,并进行了技术栈转换和样式优化。 - -## 🔄 技术栈转换 - -### 旧项目技术栈 -- React + TypeScript -- Lucide React 图标库 -- Tailwind CSS -- React Router DOM v6 -- 自定义UI组件库 - -### 新项目技术栈 -- React + TypeScript -- Ant Design Mobile -- SCSS Modules -- React Router DOM v6 -- 统一的Layout组件 - -## 📱 页面结构 - -### 主要功能模块 - -1. **任务统计卡片** - - 总任务数(带进度条) - - 今日任务(带活跃度指标) - -2. **常用功能** - - 自动点赞(New标签) - - 朋友圈同步 - - 群消息推送 - - 自动建群 - - 流量分发 - - AI对话助手(New标签) - -3. **AI智能助手** - - AI数据分析(New标签) - - AI策略优化(New标签) - - AI销售预测 - -## 🎨 设计优化 - -### 视觉改进 -- 使用Ant Design Mobile组件,保持移动端一致性 -- 采用SCSS Modules进行样式管理 -- 统一的颜色主题和间距规范 -- 响应式设计,适配不同屏幕尺寸 - -### 交互优化 -- 卡片悬停效果 -- 统一的图标样式和颜色 -- 清晰的层级结构 -- 流畅的页面跳转 - -## 📁 文件结构 - -``` -src/pages/workspace/ -├── Workspace.tsx # 工作台主页 -├── Workspace.module.scss # 工作台样式 -├── auto-like/ # 自动点赞模块 -├── auto-group/ # 自动分组模块 -├── group-push/ # 群发推送模块 -├── moments-sync/ # 朋友圈同步模块 -├── ai-assistant/ # AI助手模块 -└── traffic-distribution/ # 流量分发模块 -``` - -## 🔗 路由配置 - -### 主要路由 -- `/workspace` - 工作台主页 -- `/workspace/auto-like` - 自动点赞 -- `/workspace/group-push` - 群发推送 -- `/workspace/moments-sync` - 朋友圈同步 -- `/workspace/auto-group` - 自动分组 -- `/workspace/traffic-distribution` - 流量分发 -- `/workspace/ai-assistant` - AI助手 - -### AI功能路由 -- `/workspace/ai-analyzer` - AI数据分析 -- `/workspace/ai-strategy` - AI策略优化 -- `/workspace/ai-forecast` - AI销售预测 - -## 🎯 功能特性 - -### 数据展示 -- 实时任务统计 -- 进度条可视化 -- 活跃度指标 -- 功能分类展示 - -### 导航优化 -- 底部导航集成 -- 路由自动激活 -- 页面跳转优化 -- 返回按钮处理 - -### 用户体验 -- 加载状态处理 -- 错误边界处理 -- 响应式布局 -- 触摸友好设计 - -## 🔧 技术实现 - -### 组件化设计 -- 使用Layout组件统一布局 -- 复用PlaceholderPage组件 -- 模块化的功能卡片 -- 统一的样式规范 - -### 状态管理 -- 模拟数据展示 -- 路由状态同步 -- 组件生命周期管理 -- 性能优化 - -### 样式系统 -- SCSS Modules避免样式冲突 -- CSS变量统一主题 -- 响应式断点设计 -- 移动端优化 - -## 🚀 下一步计划 - -1. **数据集成** - - 连接真实API接口 - - 实现数据获取和更新 - - 添加加载状态 - - 错误处理机制 - -2. **功能完善** - - 实现具体功能页面 - - 添加表单验证 - - 完善交互逻辑 - - 优化用户体验 - -3. **性能优化** - - 路由懒加载 - - 组件代码分割 - - 图片资源优化 - - 缓存策略 - -4. **测试完善** - - 单元测试 - - 集成测试 - - 端到端测试 - - 性能测试 - -## 📝 注意事项 - -- 所有功能页面目前使用占位组件 -- 需要根据实际业务需求调整数据展示 -- 建议按照用户使用频率优先开发核心功能 -- 注意保持与整体设计风格的一致性 \ No newline at end of file diff --git a/nkebao/src/components/Layout/Layout.tsx b/nkebao/src/components/Layout/Layout.tsx index 2cef351d8..eea22b398 100644 --- a/nkebao/src/components/Layout/Layout.tsx +++ b/nkebao/src/components/Layout/Layout.tsx @@ -1,5 +1,7 @@ import React from "react"; +import { SpinLoading } from "antd-mobile"; import styles from "./layout.module.scss"; + interface LayoutProps { loading?: boolean; children?: React.ReactNode; @@ -7,11 +9,25 @@ interface LayoutProps { footer?: React.ReactNode; } -const Layout: React.FC = ({ children, header, footer }) => { +const Layout: React.FC = ({ + children, + header, + footer, + loading = false, +}) => { return ( {header && {header}} - {children} + + {loading ? ( + + + 加载中... + + ) : ( + children + )} + {footer && } ); diff --git a/nkebao/src/components/Layout/layout.module.scss b/nkebao/src/components/Layout/layout.module.scss index 796b26365..ed336f6fe 100644 --- a/nkebao/src/components/Layout/layout.module.scss +++ b/nkebao/src/components/Layout/layout.module.scss @@ -8,4 +8,21 @@ .container main { flex: 1; overflow: auto; +} + +.loadingContainer { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100%; + min-height: 300px; + background: rgba(255, 255, 255, 0.8); +} + +.loadingText { + margin-top: 16px; + color: #666; + font-size: 14px; + text-align: center; } \ No newline at end of file diff --git a/nkebao/src/components/MeauMobile/MeauMoible.tsx b/nkebao/src/components/MeauMobile/MeauMoible.tsx index 52a71d209..5f6f80869 100644 --- a/nkebao/src/components/MeauMobile/MeauMoible.tsx +++ b/nkebao/src/components/MeauMobile/MeauMoible.tsx @@ -1,81 +1,81 @@ -import React, { useState, useEffect } from "react"; -import { TabBar } from "antd-mobile"; -import { - AppOutline, - ShopbagOutline, - PieOutline, - UserOutline, -} from "antd-mobile-icons"; -import { useLocation, useNavigate } from "react-router-dom"; - -const tabs = [ - { - key: "home", - title: "首页", - icon: , - path: "/", - }, - { - key: "scene", - title: "场景获客", - icon: , - path: "/scene", - }, - { - key: "work", - title: "工作台", - icon: , - path: "/workspace", - }, - { - key: "mine", - title: "我的", - icon: , - path: "/mine", - }, -]; - -// 需要展示菜单的路由白名单(可根据实际业务调整) -const menuPaths = ["/", "/scene", "/workspace", "/mine"]; - -const MeauMobile: React.FC = () => { - const location = useLocation(); - const navigate = useNavigate(); - const [activeKey, setActiveKey] = useState("home"); - - // 根据当前路由自动设置 activeKey,支持嵌套路由 - useEffect(() => { - const found = tabs.find((tab) => - tab.path === "/" - ? location.pathname === "/" - : location.pathname.startsWith(tab.path) - ); - if (found) setActiveKey(found.key); - }, [location.pathname]); - - // 判断当前路由是否需要展示菜单 - const showMenu = menuPaths.some((path) => - path === "/" - ? location.pathname === "/" - : location.pathname.startsWith(path) - ); - if (!showMenu) return null; - - return ( - { - setActiveKey(key); - const tab = tabs.find((t) => t.key === key); - if (tab && tab.path) navigate(tab.path); - }} - > - {tabs.map((item) => ( - - ))} - - ); -}; - -export default MeauMobile; +import React, { useState, useEffect } from "react"; +import { TabBar } from "antd-mobile"; +import { + AppOutline, + ShopbagOutline, + PieOutline, + UserOutline, +} from "antd-mobile-icons"; +import { useLocation, useNavigate } from "react-router-dom"; + +const tabs = [ + { + key: "home", + title: "首页", + icon: , + path: "/", + }, + { + key: "scene", + title: "场景获客", + icon: , + path: "/scene", + }, + { + key: "work", + title: "工作台", + icon: , + path: "/workspace", + }, + { + key: "mine", + title: "我的", + icon: , + path: "/mine", + }, +]; + +// 需要展示菜单的路由白名单(可根据实际业务调整) +const menuPaths = ["/", "/scene", "/workspace", "/mine"]; + +const MeauMobile: React.FC = () => { + const location = useLocation(); + const navigate = useNavigate(); + const [activeKey, setActiveKey] = useState("home"); + + // 根据当前路由自动设置 activeKey,支持嵌套路由 + useEffect(() => { + const found = tabs.find((tab) => + tab.path === "/" + ? location.pathname === "/" + : location.pathname.startsWith(tab.path) + ); + if (found) setActiveKey(found.key); + }, [location.pathname]); + + // 判断当前路由是否需要展示菜单 + const showMenu = menuPaths.some((path) => + path === "/" + ? location.pathname === "/" + : location.pathname.startsWith(path) + ); + if (!showMenu) return null; + + return ( + { + setActiveKey(key); + const tab = tabs.find((t) => t.key === key); + if (tab && tab.path) navigate(tab.path); + }} + > + {tabs.map((item) => ( + + ))} + + ); +}; + +export default MeauMobile; diff --git a/nkebao/src/components/PlaceholderPage.tsx b/nkebao/src/components/PlaceholderPage.tsx index 1e5f87d73..4eec7f2f8 100644 --- a/nkebao/src/components/PlaceholderPage.tsx +++ b/nkebao/src/components/PlaceholderPage.tsx @@ -1,56 +1,56 @@ -import React from "react"; -import { NavBar, Button } from "antd-mobile"; -import { AddOutline } from "antd-mobile-icons"; -import Layout from "@/components/Layout/Layout"; -import MeauMobile from "@/components/MeauMobile/MeauMoible"; - -interface PlaceholderPageProps { - title: string; - showBack?: boolean; - showAddButton?: boolean; - addButtonText?: string; - showFooter?: boolean; -} - -const PlaceholderPage: React.FC = ({ - title, - showBack = true, - showAddButton = false, - addButtonText = "新建", - showFooter = true, -}) => { - return ( - window.history.back() : undefined} - left={ - - {title} - - } - right={ - showAddButton ? ( - - - - {addButtonText} - - - ) : undefined - } - /> - } - footer={showFooter ? : undefined} - > - - {title}页面 - 此页面正在开发中... - - - ); -}; - -export default PlaceholderPage; +import React from "react"; +import { NavBar, Button } from "antd-mobile"; +import { PlusOutlined } from "@ant-design/icons"; +import Layout from "@/components/Layout/Layout"; +import MeauMobile from "@/components/MeauMobile/MeauMoible"; + +interface PlaceholderPageProps { + title: string; + showBack?: boolean; + showAddButton?: boolean; + addButtonText?: string; + showFooter?: boolean; +} + +const PlaceholderPage: React.FC = ({ + title, + showBack = true, + showAddButton = false, + addButtonText = "新建", + showFooter = true, +}) => { + return ( + window.history.back() : undefined} + left={ + + {title} + + } + right={ + showAddButton ? ( + + + + {addButtonText} + + + ) : undefined + } + /> + } + footer={showFooter ? : undefined} + > + + {title}页面 + 此页面正在开发中... + + + ); +}; + +export default PlaceholderPage; diff --git a/nkebao/src/pages/scenarios/ScenarioList.module.scss b/nkebao/src/pages/scenarios/ScenarioList.module.scss new file mode 100644 index 000000000..67292ac1d --- /dev/null +++ b/nkebao/src/pages/scenarios/ScenarioList.module.scss @@ -0,0 +1,250 @@ +.scenario-list-page { + padding: 16px; + background: #f5f5f5; + min-height: 100vh; +} + +.nav-title { + font-size: 18px; + font-weight: 600; + color: #333; +} + +.new-plan-btn { + font-size: 14px; + height: 32px; + padding: 0 12px; +} + +.loading { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 60vh; + gap: 16px; +} + +.loading-text { + color: #666; + font-size: 14px; +} + +.scenario-card { + margin-bottom: 16px; + border-radius: 12px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); +} + +.scenario-info { + padding: 16px; +} + +.scenario-name { + font-size: 18px; + font-weight: 600; + color: #333; + margin-bottom: 8px; +} + +.scenario-desc { + font-size: 14px; + color: #666; + line-height: 1.5; + margin-bottom: 16px; +} + +.scenario-stats { + display: flex; + gap: 24px; +} + +.stat-item { + display: flex; + align-items: center; + gap: 6px; + font-size: 14px; + color: #666; + + svg { + font-size: 16px; + color: #1890ff; + } +} + +.search-bar { + display: flex; + gap: 12px; + margin-bottom: 16px; + align-items: center; + + .adm-input { + flex: 1; + border-radius: 8px; + } +} + +.refresh-btn { + height: 40px; + width: 40px; + padding: 0; + border-radius: 8px; +} + +.plan-list { + background: transparent; + border-radius: 12px; + overflow: hidden; +} + +.plan-item { + background: white; + margin-bottom: 12px; + border-radius: 12px; + padding: 16px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + cursor: pointer; + transition: all 0.2s ease; + + &:hover { + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + } + + &:last-child { + margin-bottom: 0; + } +} + +.plan-content { + flex: 1; +} + +.plan-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 12px; +} + +.plan-name { + font-size: 16px; + font-weight: 600; + color: #333; + flex: 1; + margin-right: 12px; +} + +.plan-meta { + display: flex; + flex-direction: column; + gap: 4px; + font-size: 12px; + color: #999; +} + +.plan-actions { + margin-top: 12px; + display: flex; + justify-content: flex-end; +} + +.empty-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 60px 20px; + text-align: center; +} + +.empty-text { + color: #999; + font-size: 14px; + margin-bottom: 20px; +} + +.create-first-btn { + height: 40px; + padding: 0 24px; + border-radius: 20px; +} + +.api-dialog { + background: white; + border-radius: 16px 16px 0 0; + padding: 20px; + height: 100%; + display: flex; + flex-direction: column; +} + +.dialog-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 20px; + padding-bottom: 16px; + border-bottom: 1px solid #f0f0f0; + + h3 { + margin: 0; + font-size: 18px; + font-weight: 600; + color: #333; + } +} + +.dialog-content { + flex: 1; + overflow-y: auto; +} + +.api-item { + margin-bottom: 20px; + + label { + display: block; + font-size: 14px; + color: #333; + margin-bottom: 8px; + font-weight: 500; + } + + .adm-input { + border-radius: 8px; + } +} + +.qr-dialog { + background: white; + border-radius: 16px; + padding: 20px; + width: 300px; + max-width: 90vw; +} + +.qr-loading { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 40px 20px; + gap: 16px; + color: #666; + font-size: 14px; +} + +.qr-image { + width: 100%; + max-width: 200px; + height: auto; + border-radius: 8px; +} + +.qr-error { + text-align: center; + color: #ff4d4f; + font-size: 14px; + padding: 40px 20px; +} \ No newline at end of file diff --git a/nkebao/src/pages/scenarios/ScenarioList.tsx b/nkebao/src/pages/scenarios/ScenarioList.tsx index f1088dc79..30e3710b8 100644 --- a/nkebao/src/pages/scenarios/ScenarioList.tsx +++ b/nkebao/src/pages/scenarios/ScenarioList.tsx @@ -1,8 +1,618 @@ -import React from "react"; -import PlaceholderPage from "@/components/PlaceholderPage"; - -const ScenarioList: React.FC = () => { - return ; -}; - -export default ScenarioList; +import React, { useEffect, useState, useCallback } from "react"; +import { useParams, useNavigate, useSearchParams } from "react-router-dom"; +import { + NavBar, + List, + Button, + Toast, + SpinLoading, + Dialog, + Input, + Popup, + Card, + Tag, + Space, + Divider, +} from "antd-mobile"; +import { + PlusOutlined, + UserOutlined, + CalendarOutlined, + CopyOutlined, + DeleteOutlined, + EditOutlined, + SettingOutlined, + SearchOutlined, + ReloadOutlined, + QrcodeOutlined, + UpOutlined, +} from "@ant-design/icons"; + +import Layout from "@/components/Layout/Layout"; +import MeauMobile from "@/components/MeauMobile/MeauMoible"; +import { + getPlanList, + getPlanDetail, + copyPlan, + deletePlan, + getWxMinAppCode, +} from "./api"; +import style from "./ScenarioList.module.scss"; + +interface Task { + id: string; + name: string; + status: number; + created_at: string; + updated_at: string; + enabled: boolean; + total_customers?: number; + today_customers?: number; +} + +interface ScenarioData { + id: string; + name: string; + image: string; + description: string; + totalPlans: number; + totalCustomers: number; + todayCustomers: number; + growth: string; +} + +interface ApiSettings { + apiKey: string; + webhookUrl: string; + taskId: string; +} + +const ScenarioList: React.FC = () => { + const { scenarioId, scenarioName } = useParams<{ + scenarioId: string; + scenarioName: string; + }>(); + const navigate = useNavigate(); + const [searchParams] = useSearchParams(); + const [scenario, setScenario] = useState(null); + const [tasks, setTasks] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(""); + const [showApiDialog, setShowApiDialog] = useState(false); + const [currentApiSettings, setCurrentApiSettings] = useState({ + apiKey: "", + webhookUrl: "", + taskId: "", + }); + const [searchTerm, setSearchTerm] = useState(""); + const [loadingTasks, setLoadingTasks] = useState(false); + const [showQrDialog, setShowQrDialog] = useState(false); + const [qrLoading, setQrLoading] = useState(false); + const [qrImg, setQrImg] = useState(""); + + // 获取渠道中文名称 + const getChannelName = (channel: string) => { + const channelMap: Record = { + douyin: "抖音直播获客", + kuaishou: "快手直播获客", + xiaohongshu: "小红书种草获客", + weibo: "微博话题获客", + haibao: "海报扫码获客", + phone: "电话号码获客", + gongzhonghao: "公众号引流获客", + weixinqun: "微信群裂变获客", + payment: "付款码获客", + api: "API接口获客", + }; + return channelMap[channel] || `${channel}获客`; + }; + + // 获取场景描述 + const getScenarioDescription = (channel: string) => { + const descriptions: Record = { + douyin: "通过抖音平台进行精准获客,利用短视频内容吸引目标用户", + xiaohongshu: "利用小红书平台进行内容营销获客,通过优质内容建立品牌形象", + gongzhonghao: "通过微信公众号进行获客,建立私域流量池", + haibao: "通过海报分享进行获客,快速传播品牌信息", + phone: "通过电话营销进行获客,直接与客户沟通", + weixinqun: "通过微信群进行获客,利用社交裂变效应", + payment: "通过付款码进行获客,便捷的支付方式", + api: "通过API接口进行获客,支持第三方系统集成", + }; + return descriptions[channel] || "通过该平台进行获客"; + }; + + useEffect(() => { + const fetchScenarioData = async () => { + if (!scenarioId) return; + + setLoading(true); + setError(""); + + try { + // 获取计划列表 + const response = await getPlanList(scenarioId, 1, 20); + + // 设置计划列表 + if (response && response.data && response.data.list) { + setTasks(response.data.list); + } else { + setTasks([]); + } + + // 构建场景数据 + const scenarioData: ScenarioData = { + id: scenarioId, + name: scenarioName || "", + image: "", + description: getScenarioDescription(scenarioId), + totalPlans: response?.data?.list?.length || 0, + totalCustomers: 0, + todayCustomers: 0, + growth: "", + }; + + setScenario(scenarioData); + } catch (error) { + console.error("获取场景数据失败:", error); + // 即使API失败也要创建基本的场景数据 + const scenarioData: ScenarioData = { + id: scenarioId, + name: getScenarioName(), + image: "", + description: getScenarioDescription(scenarioId), + totalPlans: 0, + totalCustomers: 0, + todayCustomers: 0, + growth: "", + }; + setScenario(scenarioData); + setTasks([]); + } finally { + setLoading(false); + } + }; + + fetchScenarioData(); + }, [scenarioId]); + + // 获取场景名称 + const getScenarioName = useCallback(() => { + const urlName = searchParams.get("name"); + if (urlName) { + return urlName; + } + return getChannelName(scenarioId || ""); + }, [searchParams, scenarioId]); + + // 更新场景数据中的名称 + useEffect(() => { + setScenario((prev) => + prev + ? { + ...prev, + name: (() => { + const urlName = searchParams.get("name"); + if (urlName) return urlName; + return getChannelName(scenarioId || ""); + })(), + } + : null + ); + }, [searchParams, scenarioId]); + + const handleCopyPlan = async (taskId: string) => { + const taskToCopy = tasks.find((task) => task.id === taskId); + if (!taskToCopy) return; + + try { + const response = await copyPlan(taskId); + if (response && response.code === 200) { + Toast.show({ + content: `已成功复制"${taskToCopy.name}"`, + position: "top", + }); + // 刷新列表 + handleRefresh(); + } else { + Toast.show({ + content: response?.msg || "复制失败", + position: "top", + }); + } + } catch (error) { + Toast.show({ + content: "复制失败,请重试", + position: "top", + }); + } + }; + + const handleDeletePlan = async (taskId: string) => { + const taskToDelete = tasks.find((task) => task.id === taskId); + if (!taskToDelete) return; + + const result = await Dialog.confirm({ + content: `确定要删除"${taskToDelete.name}"吗?`, + confirmText: "删除", + cancelText: "取消", + }); + + if (result) { + try { + const response = await deletePlan(taskId); + if (response && response.code === 200) { + Toast.show({ + content: "计划已删除", + position: "top", + }); + // 刷新列表 + handleRefresh(); + } else { + Toast.show({ + content: response?.msg || "删除失败", + position: "top", + }); + } + } catch (error) { + Toast.show({ + content: "删除失败,请重试", + position: "top", + }); + } + } + }; + + const handleOpenApiSettings = async (taskId: string) => { + try { + const response = await getPlanDetail(taskId); + if (response && response.code === 200 && response.data) { + const detail = response.data; + setCurrentApiSettings({ + apiKey: detail.apiKey || "", + webhookUrl: detail.webhookUrl || "", + taskId: taskId, + }); + setShowApiDialog(true); + } + } catch (error) { + Toast.show({ + content: "获取API设置失败", + position: "top", + }); + } + }; + + const handleCopyApiUrl = (url: string) => { + navigator.clipboard.writeText(url); + Toast.show({ + content: "API地址已复制到剪贴板", + position: "top", + }); + }; + + const handleCreateNewPlan = () => { + navigate(`/scenarios/new/${scenarioId}`); + }; + + const handleShowQrCode = async (taskId: string) => { + setQrLoading(true); + setShowQrDialog(true); + + try { + const response = await getWxMinAppCode(taskId); + if (response && response.code === 200 && response.data) { + setQrImg(response.data.qrCode || ""); + } else { + Toast.show({ + content: "获取二维码失败", + position: "top", + }); + } + } catch (error) { + Toast.show({ + content: "获取二维码失败", + position: "top", + }); + } finally { + setQrLoading(false); + } + }; + + const getStatusColor = (status: number) => { + switch (status) { + case 1: + return "success"; + case 0: + return "default"; + case -1: + return "danger"; + default: + return "default"; + } + }; + + const getStatusText = (status: number) => { + switch (status) { + case 1: + return "运行中"; + case 0: + return "已暂停"; + case -1: + return "已停止"; + default: + return "未知"; + } + }; + + const handleRefresh = async () => { + setLoadingTasks(true); + try { + const response = await getPlanList(scenarioId!, 1, 20); + if (response && response.data && response.data.list) { + setTasks(response.data.list); + } + } catch (error) { + Toast.show({ + content: "刷新失败", + position: "top", + }); + } finally { + setLoadingTasks(false); + } + }; + + const filteredTasks = tasks.filter((task) => + task.name.toLowerCase().includes(searchTerm.toLowerCase()) + ); + + if (loading) { + return ( + + 场景详情 + + } + footer={} + > + + + 加载场景数据中... + + + ); + } + + return ( + {scenario?.name}} + right={ + + 新建计划 + + } + /> + } + footer={} + > + + {/* 场景信息卡片 */} + {scenario && ( + + + {scenario.name} + + {scenario.description} + + + + + 计划数: {scenario.totalPlans} + + + + 今日获客: {scenario.todayCustomers} + + + + + )} + + {/* 搜索栏 */} + + + + + + + + + + + {/* 计划列表 */} + + {filteredTasks.length === 0 ? ( + + + {searchTerm ? "没有找到匹配的计划" : "暂无计划"} + + + 创建第一个计划 + + + ) : ( + filteredTasks.map((task) => ( + navigate(`/scenarios/edit/${task.id}`)} + > + + + {task.name} + + {getStatusText(task.status)} + + + + 创建时间: {task.created_at} + {task.total_customers !== undefined && ( + 总获客: {task.total_customers} + )} + {task.today_customers !== undefined && ( + 今日获客: {task.today_customers} + )} + + + + + { + e.stopPropagation(); + handleCopyPlan(task.id); + }} + > + + + { + e.stopPropagation(); + handleShowQrCode(task.id); + }} + > + + + { + e.stopPropagation(); + handleOpenApiSettings(task.id); + }} + > + + + { + e.stopPropagation(); + handleDeletePlan(task.id); + }} + > + + + + + + )) + )} + + + {/* API设置弹窗 */} + setShowApiDialog(false)} + position="bottom" + bodyStyle={{ height: "60vh" }} + > + + + API设置 + setShowApiDialog(false)}> + 关闭 + + + + + API Key: + + + handleCopyApiUrl(currentApiSettings.apiKey)} + > + 复制 + + + + + Webhook URL: + + + + handleCopyApiUrl(currentApiSettings.webhookUrl) + } + > + 复制 + + + + + + + + {/* 二维码弹窗 */} + setShowQrDialog(false)} + position="bottom" + > + + + 小程序二维码 + setShowQrDialog(false)}> + 关闭 + + + + {qrLoading ? ( + + + 生成二维码中... + + ) : qrImg ? ( + + ) : ( + 二维码生成失败 + )} + + + + + + ); +}; + +export default ScenarioList; diff --git a/nkebao/src/pages/scenarios/api.ts b/nkebao/src/pages/scenarios/api.ts new file mode 100644 index 000000000..e7ae1867b --- /dev/null +++ b/nkebao/src/pages/scenarios/api.ts @@ -0,0 +1,51 @@ +import request from "@/api/request"; + +// 获取计划列表 +export const getPlanList = async (scenarioId: string, page: number = 1, limit: number = 20) => { + return request(`/api/scenarios/${scenarioId}/plans`, { page, limit }, 'GET'); +}; + +// 获取计划详情 +export const getPlanDetail = async (planId: string) => { + return request(`/api/scenarios/plans/${planId}`, undefined, 'GET'); +}; + +// 复制计划 +export const copyPlan = async (planId: string) => { + return request(`/api/scenarios/plans/${planId}/copy`, undefined, 'POST'); +}; + +// 删除计划 +export const deletePlan = async (planId: string) => { + return request(`/api/scenarios/plans/${planId}`, undefined, 'DELETE'); +}; + +// 创建计划 +export const createPlan = async (data: any) => { + return request('/api/scenarios/plans', data, 'POST'); +}; + +// 更新计划 +export const updatePlan = async (planId: string, data: any) => { + return request(`/api/scenarios/plans/${planId}`, data, 'PUT'); +}; + +// 获取小程序二维码 +export const getWxMinAppCode = async (planId: string) => { + return request(`/api/scenarios/plans/${planId}/qrcode`, undefined, 'GET'); +}; + +// 获取场景类型列表 +export const getScenarioTypes = async () => { + return request('/api/scenarios/types', undefined, 'GET'); +}; + +// 获取设备列表 +export const getDevices = async () => { + return request('/api/devices', undefined, 'GET'); +}; + +// 获取海报列表 +export const getPosters = async () => { + return request('/api/posters', undefined, 'GET'); +}; \ No newline at end of file diff --git a/nkebao/src/pages/scenarios/new/page.module.scss b/nkebao/src/pages/scenarios/new/page.module.scss new file mode 100644 index 000000000..eaff99f16 --- /dev/null +++ b/nkebao/src/pages/scenarios/new/page.module.scss @@ -0,0 +1,43 @@ +.new-plan-page { + background: #f5f5f5; + min-height: 100vh; +} + +.nav-title { + font-size: 18px; + font-weight: 600; + color: #333; +} + +.back-btn { + height: 32px; + width: 32px; + padding: 0; + border-radius: 50%; +} + +.loading { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 60vh; + gap: 16px; +} + +.loading-text { + color: #666; + font-size: 14px; +} + +.steps-container { + background: white; + padding: 20px 16px; + margin-bottom: 12px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); +} + +.step-content { + flex: 1; + padding: 0 16px; +} \ No newline at end of file diff --git a/nkebao/src/pages/scenarios/new/page.tsx b/nkebao/src/pages/scenarios/new/page.tsx index b79b30fee..f9cb25bb7 100644 --- a/nkebao/src/pages/scenarios/new/page.tsx +++ b/nkebao/src/pages/scenarios/new/page.tsx @@ -1,8 +1,293 @@ -import React from "react"; -import PlaceholderPage from "@/components/PlaceholderPage"; - -const NewPlan: React.FC = () => { - return ; -}; - -export default NewPlan; +import React, { useState, useEffect } from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import { NavBar, Button, Toast, SpinLoading, Steps, Popup } from "antd-mobile"; +import { LeftOutline } from "antd-mobile-icons"; +import Layout from "@/components/Layout/Layout"; +import MeauMobile from "@/components/MeauMobile/MeauMoible"; +import BasicSettings from "./steps/BasicSettings"; +import FriendRequestSettings from "./steps/FriendRequestSettings"; +import MessageSettings from "./steps/MessageSettings"; +import { + getScenarioTypes, + createPlan, + updatePlan, + getPlanDetail, +} from "../api"; +import style from "./page.module.scss"; + +// 步骤定义 +const steps = [ + { id: 1, title: "步骤一", subtitle: "基础设置" }, + { id: 2, title: "步骤二", subtitle: "好友申请设置" }, + { id: 3, title: "步骤三", subtitle: "消息设置" }, +]; + +// 类型定义 +interface FormData { + name: string; + scenario: number; + posters: any[]; + device: string[]; + remarkType: string; + greeting: string; + addInterval: number; + startTime: string; + endTime: string; + enabled: boolean; + sceneId: string | number; + remarkFormat: string; + addFriendInterval: number; +} + +const NewPlan: React.FC = () => { + const navigate = useNavigate(); + const [currentStep, setCurrentStep] = useState(1); + const [formData, setFormData] = useState({ + name: "", + scenario: 1, + posters: [], + device: [], + remarkType: "phone", + greeting: "你好,请通过", + addInterval: 1, + startTime: "09:00", + endTime: "18:00", + enabled: true, + sceneId: "", + remarkFormat: "", + addFriendInterval: 1, + }); + const [sceneList, setSceneList] = useState([]); + const [sceneLoading, setSceneLoading] = useState(true); + const { scenarioId, planId } = useParams<{ + scenarioId: string; + planId: string; + }>(); + const [isEdit, setIsEdit] = useState(false); + const [saving, setSaving] = useState(false); + + useEffect(() => { + loadData(); + }, []); + + const loadData = async () => { + setSceneLoading(true); + try { + // 获取场景类型 + const res = await getScenarioTypes(); + if (res?.data) { + setSceneList(res.data); + } + + if (planId) { + setIsEdit(true); + // 获取计划详情 + const detailRes = await getPlanDetail(planId); + if (detailRes.code === 200 && detailRes.data) { + const detail = detailRes.data; + setFormData((prev) => ({ + ...prev, + name: detail.name ?? "", + scenario: Number(detail.scenario) || 1, + posters: detail.posters ?? [], + device: detail.device ?? [], + remarkType: detail.remarkType ?? "phone", + greeting: detail.greeting ?? "", + addInterval: detail.addInterval ?? 1, + startTime: detail.startTime ?? "09:00", + endTime: detail.endTime ?? "18:00", + enabled: detail.enabled ?? true, + sceneId: Number(detail.scenario) || 1, + remarkFormat: detail.remarkFormat ?? "", + addFriendInterval: detail.addFriendInterval ?? 1, + })); + } + } else if (scenarioId) { + setFormData((prev) => ({ + ...prev, + scenario: Number(scenarioId) || 1, + })); + } + } catch (error) { + Toast.show({ + content: "加载数据失败", + position: "top", + }); + } finally { + setSceneLoading(false); + } + }; + + // 更新表单数据 + const onChange = (data: any) => { + setFormData((prev) => ({ ...prev, ...data })); + }; + + // 处理保存 + const handleSave = async () => { + if (!formData.name.trim()) { + Toast.show({ + content: "请输入计划名称", + position: "top", + }); + return; + } + + setSaving(true); + try { + let result; + if (isEdit && planId) { + // 编辑 + const editData = { + ...formData, + id: Number(planId), + planId: Number(planId), + }; + result = await updatePlan(planId, editData); + } else { + // 新建 + result = await createPlan(formData); + } + + if (result.code === 200) { + Toast.show({ + content: isEdit ? "计划已更新" : "获客计划已创建", + position: "top", + }); + const sceneItem = sceneList.find((v) => formData.scenario === v.id); + navigate( + `/scenarios/list/${formData.sceneId}/${sceneItem?.name || ""}` + ); + } else { + Toast.show({ + content: result.msg || "操作失败", + position: "top", + }); + } + } catch (error) { + Toast.show({ + content: isEdit ? "更新计划失败,请重试" : "创建计划失败,请重试", + position: "top", + }); + } finally { + setSaving(false); + } + }; + + // 下一步 + const handleNext = () => { + if (currentStep === steps.length) { + handleSave(); + } else { + setCurrentStep((prev) => prev + 1); + } + }; + + // 上一步 + const handlePrev = () => { + setCurrentStep((prev) => Math.max(prev - 1, 1)); + }; + + // 渲染当前步骤内容 + const renderStepContent = () => { + switch (currentStep) { + case 1: + return ( + + ); + case 2: + return ( + + ); + case 3: + return ( + + ); + default: + return null; + } + }; + + if (sceneLoading) { + return ( + + + {isEdit ? "编辑计划" : "新建计划"} + + + } + footer={} + > + + + 加载数据中... + + + ); + } + + return ( + + {isEdit ? "编辑计划" : "新建计划"} + + } + right={ + navigate(-1)} + className={style["back-btn"]} + > + + + } + /> + } + footer={} + > + + {/* 步骤指示器 */} + + + {steps.map((step) => ( + + ))} + + + + {/* 步骤内容 */} + {renderStepContent()} + + + ); +}; + +export default NewPlan; diff --git a/nkebao/src/pages/scenarios/new/steps/BasicSettings.module.scss b/nkebao/src/pages/scenarios/new/steps/BasicSettings.module.scss new file mode 100644 index 000000000..5720527de --- /dev/null +++ b/nkebao/src/pages/scenarios/new/steps/BasicSettings.module.scss @@ -0,0 +1,63 @@ +.basic-settings { + padding: 16px 0; +} + +.form-card { + margin-bottom: 20px; + border-radius: 12px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); +} + +.form-item { + margin-bottom: 20px; + + &:last-child { + margin-bottom: 0; + } + + .adm-form-item-label { + font-size: 14px; + font-weight: 500; + color: #333; + margin-bottom: 8px; + } + + .adm-input { + border-radius: 8px; + } + + .adm-selector { + border-radius: 8px; + } +} + +.time-input { + width: 120px; + border-radius: 8px; +} + +.loading { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 40vh; + gap: 16px; +} + +.loading-text { + color: #666; + font-size: 14px; +} + +.actions { + padding: 20px 0; +} + +.next-btn { + width: 100%; + height: 48px; + border-radius: 24px; + font-size: 16px; + font-weight: 500; +} \ No newline at end of file diff --git a/nkebao/src/pages/scenarios/new/steps/BasicSettings.tsx b/nkebao/src/pages/scenarios/new/steps/BasicSettings.tsx new file mode 100644 index 000000000..7b4343fde --- /dev/null +++ b/nkebao/src/pages/scenarios/new/steps/BasicSettings.tsx @@ -0,0 +1,210 @@ +import React, { useState, useEffect } from "react"; +import { + Form, + Input, + Selector, + Button, + SpinLoading, + Toast, + Card, + Space, +} from "antd-mobile"; +import { getDevices, getPosters } from "../../api"; +import style from "./BasicSettings.module.scss"; + +interface BasicSettingsProps { + formData: any; + onChange: (data: any) => void; + onNext: () => void; + sceneList: any[]; + sceneLoading: boolean; +} + +const BasicSettings: React.FC = ({ + formData, + onChange, + onNext, + sceneList, + sceneLoading, +}) => { + const [devices, setDevices] = useState([]); + const [posters, setPosters] = useState([]); + const [loading, setLoading] = useState(false); + + useEffect(() => { + loadData(); + }, []); + + const loadData = async () => { + setLoading(true); + try { + // 获取设备列表 + const devicesRes = await getDevices(); + if (devicesRes?.data) { + setDevices(devicesRes.data); + } + + // 获取海报列表 + const postersRes = await getPosters(); + if (postersRes?.data) { + setPosters(postersRes.data); + } + } catch (error) { + Toast.show({ + content: "加载数据失败", + position: "top", + }); + } finally { + setLoading(false); + } + }; + + const handleNext = () => { + if (!formData.name.trim()) { + Toast.show({ + content: "请输入计划名称", + position: "top", + }); + return; + } + + if (!formData.scenario) { + Toast.show({ + content: "请选择场景类型", + position: "top", + }); + return; + } + + if (formData.device.length === 0) { + Toast.show({ + content: "请选择设备", + position: "top", + }); + return; + } + + onNext(); + }; + + if (loading || sceneLoading) { + return ( + + + 加载数据中... + + ); + } + + return ( + + + + {/* 计划名称 */} + + onChange({ name: value })} + clearable + /> + + + {/* 场景类型 */} + + ({ + label: scene.name, + value: scene.id, + }))} + value={[formData.scenario]} + onChange={(value) => { + const selectedScene = sceneList.find( + (scene) => scene.id === value[0] + ); + onChange({ + scenario: value[0], + sceneId: value[0], + name: selectedScene?.name || "", + }); + }} + /> + + + {/* 选择设备 */} + + ({ + label: device.name, + value: device.id, + }))} + value={formData.device} + onChange={(value) => onChange({ device: value })} + multiple + /> + + + {/* 选择海报 */} + + ({ + label: poster.name, + value: poster.id, + }))} + value={formData.posters} + onChange={(value) => onChange({ posters: value })} + multiple + /> + + + {/* 工作时间 */} + + + onChange({ startTime: value })} + className={style["time-input"]} + /> + 至 + onChange({ endTime: value })} + className={style["time-input"]} + /> + + + + {/* 添加间隔 */} + + + onChange({ addInterval: Number(value) || 1 }) + } + min={1} + max={60} + /> + + + + + {/* 操作按钮 */} + + + 下一步 + + + + ); +}; + +export default BasicSettings; diff --git a/nkebao/src/pages/scenarios/new/steps/FriendRequestSettings.module.scss b/nkebao/src/pages/scenarios/new/steps/FriendRequestSettings.module.scss new file mode 100644 index 000000000..67047ef14 --- /dev/null +++ b/nkebao/src/pages/scenarios/new/steps/FriendRequestSettings.module.scss @@ -0,0 +1,56 @@ +.friend-request-settings { + padding: 16px 0; +} + +.form-card { + margin-bottom: 20px; + border-radius: 12px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); +} + +.form-item { + margin-bottom: 20px; + + &:last-child { + margin-bottom: 0; + } + + .adm-form-item-label { + font-size: 14px; + font-weight: 500; + color: #333; + margin-bottom: 8px; + } + + .adm-input { + border-radius: 8px; + } + + .adm-selector { + border-radius: 8px; + } + + .adm-text-area { + border-radius: 8px; + } +} + +.actions { + padding: 20px 0; +} + +.prev-btn { + flex: 1; + height: 48px; + border-radius: 24px; + font-size: 16px; + font-weight: 500; +} + +.next-btn { + flex: 1; + height: 48px; + border-radius: 24px; + font-size: 16px; + font-weight: 500; +} \ No newline at end of file diff --git a/nkebao/src/pages/scenarios/new/steps/FriendRequestSettings.tsx b/nkebao/src/pages/scenarios/new/steps/FriendRequestSettings.tsx new file mode 100644 index 000000000..fcb0bb63b --- /dev/null +++ b/nkebao/src/pages/scenarios/new/steps/FriendRequestSettings.tsx @@ -0,0 +1,113 @@ +import React from "react"; +import { + Form, + Input, + Selector, + Button, + Card, + Space, + TextArea, +} from "antd-mobile"; +import style from "./FriendRequestSettings.module.scss"; + +interface FriendRequestSettingsProps { + formData: any; + onChange: (data: any) => void; + onNext: () => void; + onPrev: () => void; +} + +const FriendRequestSettings: React.FC = ({ + formData, + onChange, + onNext, + onPrev, +}) => { + const remarkTypeOptions = [ + { label: "手机号", value: "phone" }, + { label: "微信号", value: "wechat" }, + { label: "QQ号", value: "qq" }, + { label: "自定义", value: "custom" }, + ]; + + const handleNext = () => { + if (!formData.greeting.trim()) { + // 可以添加验证逻辑 + } + onNext(); + }; + + return ( + + + + {/* 备注类型 */} + + onChange({ remarkType: value[0] })} + /> + + + {/* 备注格式 */} + {formData.remarkType === "custom" && ( + + onChange({ remarkFormat: value })} + clearable + /> + + )} + + {/* 打招呼消息 */} + + onChange({ greeting: value })} + rows={4} + maxLength={200} + showCount + /> + + + {/* 好友申请间隔 */} + + + onChange({ addFriendInterval: Number(value) || 1 }) + } + min={1} + max={60} + /> + + + + + {/* 操作按钮 */} + + + + 上一步 + + + 下一步 + + + + + ); +}; + +export default FriendRequestSettings; diff --git a/nkebao/src/pages/scenarios/new/steps/MessageSettings.module.scss b/nkebao/src/pages/scenarios/new/steps/MessageSettings.module.scss new file mode 100644 index 000000000..f5728a188 --- /dev/null +++ b/nkebao/src/pages/scenarios/new/steps/MessageSettings.module.scss @@ -0,0 +1,64 @@ +.message-settings { + padding: 16px 0; +} + +.form-card { + margin-bottom: 20px; + border-radius: 12px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); +} + +.form-item { + margin-bottom: 20px; + + &:last-child { + margin-bottom: 0; + } + + .adm-form-item-label { + font-size: 14px; + font-weight: 500; + color: #333; + margin-bottom: 8px; + } + + .adm-input { + border-radius: 8px; + } + + .adm-text-area { + border-radius: 8px; + } +} + +.switch-item { + display: flex; + justify-content: space-between; + align-items: center; + padding: 12px 0; + + span { + font-size: 14px; + color: #333; + } +} + +.actions { + padding: 20px 0; +} + +.prev-btn { + flex: 1; + height: 48px; + border-radius: 24px; + font-size: 16px; + font-weight: 500; +} + +.save-btn { + flex: 1; + height: 48px; + border-radius: 24px; + font-size: 16px; + font-weight: 500; +} \ No newline at end of file diff --git a/nkebao/src/pages/scenarios/new/steps/MessageSettings.tsx b/nkebao/src/pages/scenarios/new/steps/MessageSettings.tsx new file mode 100644 index 000000000..4f405446c --- /dev/null +++ b/nkebao/src/pages/scenarios/new/steps/MessageSettings.tsx @@ -0,0 +1,140 @@ +import React from "react"; +import { + Form, + Input, + Selector, + Button, + Card, + Space, + TextArea, + Switch, +} from "antd-mobile"; +import style from "./MessageSettings.module.scss"; + +interface MessageSettingsProps { + formData: any; + onChange: (data: any) => void; + onNext: () => void; + onPrev: () => void; + saving: boolean; +} + +const MessageSettings: React.FC = ({ + formData, + onChange, + onNext, + onPrev, + saving, +}) => { + const handleSave = () => { + onNext(); + }; + + return ( + + + + {/* 启用状态 */} + + + 启用计划 + onChange({ enabled: checked })} + /> + + + + {/* 自动回复消息 */} + + onChange({ autoReply: value })} + rows={4} + maxLength={500} + showCount + /> + + + {/* 关键词回复 */} + + onChange({ keywordReply: value })} + rows={4} + maxLength={1000} + showCount + /> + + + {/* 群发消息 */} + + onChange({ groupMessage: value })} + rows={4} + maxLength={500} + showCount + /> + + + {/* 消息发送间隔 */} + + + onChange({ messageInterval: Number(value) || 5 }) + } + min={1} + max={300} + /> + + + {/* 每日发送限制 */} + + + onChange({ dailyLimit: Number(value) || 100 }) + } + min={1} + max={1000} + /> + + + + + {/* 操作按钮 */} + + + + 上一步 + + + {saving ? "保存中..." : "保存计划"} + + + + + ); +}; + +export default MessageSettings; diff --git a/nkebao/src/pages/scene/index.tsx b/nkebao/src/pages/scene/index.tsx index a5d12b8dc..23948fa2b 100644 --- a/nkebao/src/pages/scene/index.tsx +++ b/nkebao/src/pages/scene/index.tsx @@ -1,8 +1,7 @@ import React, { useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; import { NavBar, Button, Toast, SpinLoading } from "antd-mobile"; -import { AddOutline } from "antd-mobile-icons"; -import { RiseOutlined } from "@ant-design/icons"; +import { PlusOutlined, UpOutlined } from "@ant-design/icons"; import MeauMobile from "@/components/MeauMobile/MeauMoible"; import Layout from "@/components/Layout/Layout"; import { getScenarios } from "./api"; @@ -91,7 +90,7 @@ const Scene: React.FC = () => { className={style["new-plan-btn"]} style={{ marginLeft: "auto" }} > - 新建计划 + 新建计划 } @@ -118,7 +117,7 @@ const Scene: React.FC = () => { className={style["new-plan-btn"]} style={{ marginLeft: "auto" }} > - 新建计划 + 新建计划 } @@ -149,7 +148,7 @@ const Scene: React.FC = () => { className={style["new-plan-btn"]} style={{ marginLeft: "auto" }} > - 新建计划 + 新建计划 } > @@ -189,7 +188,7 @@ const Scene: React.FC = () => { 今日: {scenario.count} - {scenario.growth} diff --git a/nkebao/src/pages/wechat-accounts/WechatAccounts.tsx b/nkebao/src/pages/wechat-accounts/WechatAccounts.tsx index 5354b8267..57b008635 100644 --- a/nkebao/src/pages/wechat-accounts/WechatAccounts.tsx +++ b/nkebao/src/pages/wechat-accounts/WechatAccounts.tsx @@ -1,37 +1,37 @@ -import React from "react"; -import { NavBar, Button } from "antd-mobile"; -import { AddOutline } from "antd-mobile-icons"; -import Layout from "@/components/Layout/Layout"; -import MeauMobile from "@/components/MeauMobile/MeauMoible"; - -const WechatAccounts: React.FC = () => { - return ( - - 微信号管理 - - } - right={ - - - 添加微信号 - - } - /> - } - footer={} - > - - 微信号管理页面 - 此页面正在开发中... - - - ); -}; - -export default WechatAccounts; +import React from "react"; +import { NavBar, Button } from "antd-mobile"; +import { PlusOutlined } from "@ant-design/icons"; +import Layout from "@/components/Layout/Layout"; +import MeauMobile from "@/components/MeauMobile/MeauMoible"; + +const WechatAccounts: React.FC = () => { + return ( + + 微信号管理 + + } + right={ + + + 添加微信号 + + } + /> + } + footer={} + > + + 微信号管理页面 + 此页面正在开发中... + + + ); +}; + +export default WechatAccounts; diff --git a/nkebao/src/pages/workspace/Workspace.tsx b/nkebao/src/pages/workspace/Workspace.tsx index f83779058..50f39db2d 100644 --- a/nkebao/src/pages/workspace/Workspace.tsx +++ b/nkebao/src/pages/workspace/Workspace.tsx @@ -2,15 +2,15 @@ import React from "react"; import { Link } from "react-router-dom"; import { Card, NavBar, Badge } from "antd-mobile"; import { - LikeOutline, - MessageOutline, - SendOutline, - TeamOutline, - LinkOutline, - AppOutline, - PieOutline, - ClockCircleOutline, -} from "antd-mobile-icons"; + LikeOutlined, + MessageOutlined, + SendOutlined, + TeamOutlined, + LinkOutlined, + AppstoreOutlined, + PieChartOutlined, + ClockCircleOutlined, +} from "@ant-design/icons"; import Layout from "@/components/Layout/Layout"; import MeauMobile from "@/components/MeauMobile/MeauMoible"; import styles from "./Workspace.module.scss"; @@ -32,7 +32,7 @@ const Workspace: React.FC = () => { name: "自动点赞", description: "智能自动点赞互动", icon: ( - + ), path: "/workspace/auto-like", bgColor: "#fff2f0", @@ -43,7 +43,7 @@ const Workspace: React.FC = () => { name: "朋友圈同步", description: "自动同步朋友圈内容", icon: ( - @@ -56,7 +56,7 @@ const Workspace: React.FC = () => { name: "群消息推送", description: "智能群发助手", icon: ( - + ), path: "/workspace/group-push", bgColor: "#fff7e6", @@ -66,7 +66,7 @@ const Workspace: React.FC = () => { name: "自动建群", description: "智能拉好友建群", icon: ( - + ), path: "/workspace/auto-group", bgColor: "#f6ffed", @@ -76,7 +76,7 @@ const Workspace: React.FC = () => { name: "流量分发", description: "管理流量分发和分配", icon: ( - + ), path: "/workspace/traffic-distribution", bgColor: "#e6f7ff", @@ -86,7 +86,7 @@ const Workspace: React.FC = () => { name: "AI对话助手", description: "智能回复,提高互动质量", icon: ( - + ), path: "/workspace/ai-assistant", bgColor: "#e6f7ff", @@ -100,7 +100,12 @@ const Workspace: React.FC = () => { id: "ai-analyzer", name: "AI数据分析", description: "智能分析客户行为特征", - icon: , + icon: ( + + ), path: "/workspace/ai-analyzer", bgColor: "#f0f0ff", isNew: true, @@ -109,7 +114,12 @@ const Workspace: React.FC = () => { id: "ai-strategy", name: "AI策略优化", description: "智能优化获客策略", - icon: , + icon: ( + + ), path: "/workspace/ai-strategy", bgColor: "#e6fffb", isNew: true, @@ -118,7 +128,12 @@ const Workspace: React.FC = () => { id: "ai-forecast", name: "AI销售预测", description: "智能预测销售趋势", - icon: , + icon: ( + + ), path: "/workspace/ai-forecast", bgColor: "#fffbe6", }, diff --git a/nkebao/src/pages/workspace/auto-like/AutoLike.tsx b/nkebao/src/pages/workspace/auto-like/AutoLike.tsx index 35f84a96c..cc452a1c4 100644 --- a/nkebao/src/pages/workspace/auto-like/AutoLike.tsx +++ b/nkebao/src/pages/workspace/auto-like/AutoLike.tsx @@ -1,38 +1,38 @@ -import React from "react"; -import { NavBar, Button } from "antd-mobile"; -import { AddOutline } from "antd-mobile-icons"; -import Layout from "@/components/Layout/Layout"; -import MeauMobile from "@/components/MeauMobile/MeauMoible"; - -const AutoLike: React.FC = () => { - return ( - window.history.back()} - left={ - - 自动点赞 - - } - right={ - - - 新建任务 - - } - /> - } - footer={} - > - - 自动点赞页面 - 此页面正在开发中... - - - ); -}; - -export default AutoLike; +import React from "react"; +import { NavBar, Button } from "antd-mobile"; +import { PlusOutlined } from "@ant-design/icons"; +import Layout from "@/components/Layout/Layout"; +import MeauMobile from "@/components/MeauMobile/MeauMoible"; + +const AutoLike: React.FC = () => { + return ( + window.history.back()} + left={ + + 自动点赞 + + } + right={ + + + 新建任务 + + } + /> + } + footer={} + > + + 自动点赞页面 + 此页面正在开发中... + + + ); +}; + +export default AutoLike; diff --git a/nkebao/src/pages/workspace/main/index.tsx b/nkebao/src/pages/workspace/main/index.tsx index dc673c00b..cc027d5ad 100644 --- a/nkebao/src/pages/workspace/main/index.tsx +++ b/nkebao/src/pages/workspace/main/index.tsx @@ -1,12 +1,12 @@ import React, { useState } from "react"; import { Card, NavBar, TabBar, Grid } from "antd-mobile"; import { - AppOutline, - UserOutline, - PieOutline, // 替换 BarChartOutline - ShopbagOutline, - BellOutline, -} from "antd-mobile-icons"; + AppstoreOutlined, + UserOutlined, + PieChartOutlined, + ShoppingOutlined, + BellOutlined, +} from "@ant-design/icons"; import MeauMobile from "@/components/MeauMobile/MeauMoible"; import Layout from "@/components/Layout/Layout"; import style from "./index.module.scss"; @@ -14,22 +14,22 @@ const sceneStats = [ { label: "公众号获客", value: 234, - icon: , + icon: , }, { label: "海报获客", value: 167, - icon: , + icon: , }, { label: "抖音获客", value: 156, - icon: , + icon: , }, { label: "小红书获客", value: 89, - icon: , + icon: , }, ]; diff --git a/nkebao/src/router/module/scenarios.tsx b/nkebao/src/router/module/scenarios.tsx index ff561561a..a1b9ff5b3 100644 --- a/nkebao/src/router/module/scenarios.tsx +++ b/nkebao/src/router/module/scenarios.tsx @@ -1,3 +1,4 @@ +import Scene from "@/pages/scene"; import Scenarios from "@/pages/scenarios/Scenarios"; import NewPlan from "@/pages/scenarios/new/page"; import ScenarioList from "@/pages/scenarios/ScenarioList"; @@ -5,12 +6,12 @@ import ScenarioList from "@/pages/scenarios/ScenarioList"; const scenarioRoutes = [ { path: "/scene", - element: , + element: , auth: true, }, { path: "/scenarios", - element: , + element: , auth: true, }, { diff --git a/nkebao/src/router/permissionRoute.tsx b/nkebao/src/router/permissionRoute.tsx index 95d8b89d4..42690dc76 100644 --- a/nkebao/src/router/permissionRoute.tsx +++ b/nkebao/src/router/permissionRoute.tsx @@ -24,7 +24,7 @@ const PermissionRoute: React.FC = ({ } // 检查角色权限(如果需要) - if (requiredRole && user.role !== requiredRole) { + if (requiredRole && user.isAdmin !== 1) { navigate("/"); return; } @@ -36,7 +36,7 @@ const PermissionRoute: React.FC = ({ } // 如果角色不匹配,不渲染子组件 - if (requiredRole && user.role !== requiredRole) { + if (requiredRole && user.isAdmin !== 1) { return null; } diff --git a/nkebao/迁移提示词.md b/nkebao/迁移提示词.md deleted file mode 100644 index f0e587b68..000000000 --- a/nkebao/迁移提示词.md +++ /dev/null @@ -1,28 +0,0 @@ -迁移提示词(Checklist) -当你将其他项目迁移到 nkebao 项目结构时,可参考以下提示词进行自适应改造: -1. 目录与文件结构 -按 nkebao 目录规范拆分:api、router/module、store/module、pages、styles 等 -公共样式、reset、rem 适配、兼容性样式统一放到 styles/global.scss -2. 路由迁移 -将原有路由配置拆分为 module 目录下的多个路由模块,导出数组 -路由配置中增加 auth/requiredRole 字段,适配权限拦截 -如有嵌套路由,按 useRoutes 结构组织 -3. 状态管理迁移 -将原有全局状态拆分为多个 zustand store,放到 store/module 下 -如需持久化,使用 createPersistStore 工具 -组件中统一用 useXxxStore 访问和修改状态 -4. 请求管理迁移 -所有接口请求统一用 src/api/request.ts 封装 -需要防抖的接口可自定义 debounceGap 参数 -错误提示统一用 Toast,必要时细分错误类型 -需要 token 的接口无需手动加 header,自动注入 -5. 组件与样式迁移 -组件按业务拆分到 pages/ 下 -样式统一用 scss,变量、reset、兼容性样式集中管理 -移动端适配用 rem,PC 端可用媒体查询补充 -6. 工程化与规范 -路径引用统一用 @/xxx -保持 tsconfig.json、vite.config.ts、.eslintrc.js、postcss.config.js 配置一致 -代码风格、格式化、类型声明与 nkebao 保持一致 -7. 其他 -如有全局 loading、消息、权限等需求,建议用 zustand/store 单独模块管理 \ No newline at end of file
此页面正在开发中...