1387 Commits

Author SHA1 Message Date
Manus AI
f7a7c56ce4 chore(触客宝): 全量构建部署 kr-kf 生产并通过线上 smoke
Docker 构建 touchkebao-web、发布 dist 与 Nginx 反代;验收 17/17 + Playwright ok。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-03 21:18:18 +08:00
Manus AI
2753265edb sync(本地→GitHub): 2026-06-03 21:17 全量单向同步
## GitHub 同步说明

| 项 | 内容 |
|:---|:---|
| 仓库 | https://github.com/fnvtk/cunkebao_v3 |
| 分支 | develop |
| 方向 | 本地 → GitHub(单向 push) |
| 是否拉取远程 | 否(未 fetch / pull / merge) |
| 是否改本地源文件 | 否(仅 git add/commit,未编辑业务/文档正文) |
| 远程基准 | origin/develop @ b5b40e8b |
| 本批工作区变更 | 999 files, +47622 / -4007 lines |

## 一并推送的本地已有 commit(此前未 push)

1. 3aa7ecf8 deploy: 官网 ckb.quwanzhi.com 宝塔上线 DNS+SSL+验收文档
2. 16a70045 fix(官网): 桌面导航仅保留一个留资 CTA 并重新上线
3. dbe7b7aa fix(官网): Hero 改为主 CTA 按钮并去掉重复 1200+ 数据条
4. ac82726e chore(部署): 五端上线验收46项并统一留资与缓存版本

## 本 commit 目录统计

| 目录 | 文件数 | 说明 |
|:---|---:|:---|
| 开发文档/ | 639 | 10、项目管理、未完成项跨仓汇总、五端需求/部署/接口 |
| Server/ | 129 | 后端 API、迁移、部署相关 |
| Touchkebao/ | 80 | PC 工作台、获客、算力 |
| 官网/ | 61 | ckb.quwanzhi.com 静态站与 CTA 迭代 |
| Cunkebao/ | 49 | 移动端场景/设置/流量池 |
| SuperAdmin/ | 26 | 超管后台 |
| .cursor/ | 11 | 规则与 Skill |
| 其他 | 14 | docker-compose、.obsidian、.codegraph 等 |

## 重点文件(本地为准)

- 开发文档/1、需求/修改/未完成项与跨仓验收汇总.md
- 开发文档/10、项目管理/账号密码与登录环境一览.md
- 开发文档/10、项目管理/(新建项目管理目录与截图)
- 官网/ 全站 + 宝塔上线文档
- 五端上线验收 46 项(见 ac82726e)

## 刻意未上传

- node_modules/、.DS_Store、.smart-env/
- .开发文档_nested_git_backup/
- **/__pycache__/

## 验收

- 提交页(含本说明): https://github.com/fnvtk/cunkebao_v3/commit/HEAD
- 分支树: https://github.com/fnvtk/cunkebao_v3/tree/develop

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-03 21:17:41 +08:00
Manus AI
ac82726e12 chore(部署): 五端上线验收46项并统一留资与缓存版本
扩展官网验收覆盖 Hero/JSON/AI 组件;留资弹窗试用文案改为300积分;静态资源 v=20260603。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-03 21:11:21 +08:00
Manus AI
dbe7b7aa7c fix(官网): Hero 改为主 CTA 按钮并去掉重复 1200+ 数据条
副标题下改为「7天免费试用每天送300积分」试用按钮,移除 hero-stats 与 social 行。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 21:26:44 +08:00
Manus AI
16a700459e fix(官网): 桌面导航仅保留一个留资 CTA 并重新上线
宽屏不再注入移动端克隆按钮,并加固 CSS 与缓存版本号,避免顶栏出现两个「领取资料并咨询」。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 21:25:06 +08:00
Manus AI
3aa7ecf8c0 deploy: 官网 ckb.quwanzhi.com 宝塔上线 DNS+SSL+验收文档
阿里云 A 记录指向存客宝宝塔,Nginx 443 泛域名证书,部署脚本补 SSL/DNS 步骤。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-31 19:15:04 +08:00
Manus AI
b5b40e8bf3 docs: 记录 AI数智员工 kr-phone 宝塔部署进度
standalone 挂载 aistaff:prod Docker :3104,验收 27/28。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-30 22:19:04 +08:00
Manus AI
7793093d0a fix: workphone BFF 在 SDK 不可用时降级返回 200
connection/status 不再因 workphone.quwanzhi.com 502 报 500;补 20260530 部署进度。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-30 22:03:04 +08:00
Manus AI
5182529a58 sync(本地→GitHub): 2026-05-30 21:41 全量单向同步
## GitHub 同步说明

| 项 | 内容 |
|:---|:---|
| 仓库 | https://github.com/fnvtk/cunkebao_v3 |
| 分支 | develop |
| 方向 | 本地 → GitHub(单向 push) |
| 是否拉取远程 | 否(未 fetch / pull / merge) |
| 是否改本地文件 | 否(仅 git add/commit,未编辑任何源文件正文) |
| 基准 commit | 0643e78a |
| 变更规模 | 709 files, +26436 / -3407 lines |

## 目录变更统计

| 目录 | 文件数 | 说明 |
|:---|---:|:---|
| 开发文档/ | 404 | 四端进行中/已完成需求、接口文档、官网需求、部署脚本 |
| Server/ | 95 | 后端 API、迁移脚本、触客宝/超管/存客宝服务 |
| Cunkebao/ | 85 | 移动端 H5、设备绑定、客服、转号审批等 |
| Touchkebao/ | 68 | PC 工作台、AI 获客、算力中心、Glass UI |
| SuperAdmin/ | 33 | 超管项目中心、算力计费、内容库 |
| 官网/ | 19 | 新增存客宝官网静态页(index/pricing/solutions 等) |
| .cursor/ | 3 | Cursor 规则与 Skill |
| .obsidian/ | 2 | Obsidian 工作区配置 |

## 重点新增/更新(本地为准)

- 官网/: 完整静态站点(index、pricing、manual、solutions、api)
- 开发文档/1、需求/修改/*_进行中_20260530.md(存客宝/触客宝/AI数智员工)
- 开发文档/1、需求/官网需求.md
- 开发文档/5、接口/开发进度_接口文档.md 等接口文档迭代
- Touchkebao Glass UI 与 P0 收尾、通道获客算力
- SuperAdmin 算力计费规则、项目工作台

## 刻意未上传(本地保留)

- node_modules/
- .DS_Store、.smart-env/
- .开发文档_nested_git_backup/(旧嵌套 git 备份)
- **/__pycache__/

## 验收

GitHub 浏览: https://github.com/fnvtk/cunkebao_v3/tree/develop

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-30 21:41:40 +08:00
Manus AI
0643e78a79 docs: 补推四端需求汇总、进行中需求与 workspace 最新态
以本地为准,未拉取远程。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-30 04:25:29 +08:00
Manus AI
5517457929 sync: 以本地为准同步全量变更至 GitHub
含四端需求文档、前端/后端/超管/触客宝迭代及部署脚本更新;未拉取远程。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-30 04:24:56 +08:00
Manus AI
711783baf5 部署:超管改宝塔 Node API 托管,弃 PM2 superadmin
全量 deploy 步骤 9 切至 deploy_superadmin_baota_node_api.sh;更新防治总表与开发进度。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 23:03:38 +08:00
Manus AI
11ad2df6f3 部署:三端重发与超管 standalone tar 修复
超管 PM2 改为 SuperAdmin 子目录 + tar 保留 pnpm 链接,避免 rsync 断链导致 next 模块缺失。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 21:48:06 +08:00
Manus AI
751543ab7a 触客宝:修复包名冲突并更新生产环境变量
Touchkebao 独立命名为 touchkebao,.env.production 对齐 /s2api 与 WS 配置,便于本地 vite 构建后部署。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 21:15:17 +08:00
Manus AI
2f6187d2fa 部署:DB配置迁移幂等化与场景媒体OSS同步命令
新增 config:sync-media 与 sync_db_config_tencent,部署流程接入 2f 步骤;修复 workbench/内容库迁移 SQL 在生产库可重复执行。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 21:10:24 +08:00
Manus AI
42e597349a docs: 4、前端/UI 配图 batch final 2026-05-26 22:21:38 +08:00
Manus AI
949ec2ec6a docs: 4、前端/UI 配图 batch 4 2026-05-26 22:21:25 +08:00
Manus AI
0a7604f9ab docs: 4、前端/UI 配图 batch 3 2026-05-26 22:21:16 +08:00
Manus AI
fd38980751 docs: 4、前端/UI 配图 batch 2 2026-05-26 22:21:07 +08:00
Manus AI
0264644c2a docs: 4、前端/UI 配图 batch 1 2026-05-26 22:20:58 +08:00
Manus AI
10396c9ac9 docs: 开发文档配图 工作手机对接
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 22:20:40 +08:00
Manus AI
b83ee46978 docs: 开发文档配图 images
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 22:20:33 +08:00
Manus AI
99251dcef8 docs: 开发文档配图 9、手册
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 22:20:26 +08:00
Manus AI
4c8174d75d docs: 开发文档配图 8、部署/scripts
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 22:20:17 +08:00
Manus AI
06a7a7be5c docs: 开发文档配图 8、部署/images
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 22:20:09 +08:00
Manus AI
93387f64e0 docs: 开发文档配图 7、数据库
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 22:20:01 +08:00
Manus AI
fa5185952d docs: 开发文档配图 6、后端
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 22:19:54 +08:00
Manus AI
3df3bcd9a5 docs: 开发文档配图 5、接口
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 22:19:41 +08:00
Manus AI
c49dc76a04 docs: 开发文档配图 4、前端/images
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 22:19:33 +08:00
Manus AI
1daae21236 docs: 开发文档配图 3、原型
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 22:19:25 +08:00
Manus AI
63963b5ee6 docs: 2、架构配图 AI开发流程.jpg
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 22:19:09 +08:00
Manus AI
ec45da57cf docs: 2、架构配图 architecture-overview
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 22:18:49 +08:00
Manus AI
1775f0d45a docs: 2、架构配图 architecture
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 22:18:41 +08:00
Manus AI
3a4a09eedb docs: 2、架构配图 doc-headers
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 22:18:33 +08:00
Manus AI
ea226961bd docs: 开发文档配图 1、需求
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 22:17:45 +08:00
Manus AI
7f5b96b88f docs: 开发文档配图 10、使用手册
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 22:17:34 +08:00
Manus AI
2815287c2e docs: flatten 开发文档 MD/脚本并同步 obsidian workspace
第一批:207+ Markdown、脚本与 .obsidian/workspace.json;以本地为准。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 22:16:19 +08:00
Manus AI
03ae8c07b6 feat: 同步本地全量开发到 GitHub(前端/后端/超管/开发文档规则)
含 AI 助手、抖音 OAuth、流量池推送、支付获客、SuperAdmin 设备与场景管理等本地迭代;以本地为准单向推送,未拉取远程。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 22:12:40 +08:00
Manus AI
a3bda0ccac fix: API获客 sceneId=11 列表500与小宝AI网关联通
Query whereIn 合并 legacy 场景;karuoAi 120s 超时,避免误降级 doubao 欠费。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 16:08:15 +08:00
Manus AI
1cd7027e1a 部署:扩展验收脚本、支付证书同步与生产全量上线复盘
补齐宝塔生产 payment.overlay/证书同步流程,新增 extended 验收覆盖 AI/支付/海报,并修复 smoke 测试对生产 BASE 与 scene8 计划的适配。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 15:51:21 +08:00
Manus AI
84c5085955 fix(home): 修复首页空白——补全 CkbIconShell 导入与登录态恢复
homeIcons 缺少 CkbIconShell 导致首页 React 崩溃;PermissionRoute 支持 token 会话并等待 hydration;persist getItem 兼容旧格式。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 12:40:58 +08:00
Manus AI
c9bd563fed fix(web): 修复部署后空白页与 index.html 缓存问题
登录态 hydration 期间显示加载态而非 null;index.html 禁缓存;本地跳过更新检测误报。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 12:10:33 +08:00
Manus AI
0df622bbfd fix(ui): 付款码获客图标与文案强调留资获客语义
场景获客首页改用齿轮全局设置,今日获客与付款码场景图标更清晰,计划卡片与弹窗文案突出支付后留资/跳转。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 11:33:37 +08:00
Manus AI
148962cbc2 feat(场景获客): 付款码mock验收+计划编辑对齐+场景字典修正
本地无威富通时可 mock 下单/模拟支付;更新计划与创建规则对齐;编辑回填 sceneConf;抖音 env 合并。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 20:19:16 +08:00
Manus AI
a3179fae9d style(场景获客): 空状态新建计划按钮间距统一
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 20:12:57 +08:00
Manus AI
beb13bb280 fix(场景获客): 统一新建计划按钮与 payment notify 配置
好友迁移等全场景列表展示新建计划;PaymentConfigService 默认 notify 指向 /v1/pay/notify;非 API 计划创建后回列表便于付款码验收。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 20:12:35 +08:00
Manus AI
5b0766d2b4 fix(场景获客): API获客去重并合并legacy统计到id=11
旧库 sceneId 6/9 若 DB 名仍含 API,统计并入规范 API 卡片,展示名强制用目录,避免两张「API获客」。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 20:10:12 +08:00
Manus AI
448662cce7 fix: BasicSettings sceneCatalog 导入路径修正以通过 Docker 构建
steps 目录下 ../../sceneCatalog 无法解析,改用 @/pages/mobile/scenarios/sceneCatalog。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 19:56:18 +08:00
Manus AI
a6ba0af9f8 feat(付款码获客): 微信Native支付全链路+开放对接+前端付款码弹窗
复用 PaymentService 生成付款码;支付回调后小程序授权手机号入池;开放 /v1/open/payment 供第三方对接。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 19:45:14 +08:00
Manus AI
17ac4da44a feat(场景获客): 参考存客宝补齐全量场景与前端独占计划页
全量场景卡片+AI Beta区;抖音/小红书/扫码/付款码/公众号走 localStorage 计划管理;后端场景保持原 API 列表。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 19:39:37 +08:00
Manus AI
9614a3138d fix(场景获客): 仅展示已实现场景,修复列表接口500
过滤未落地场景;修复 scenarioTags 已是数组时 json_decode 报错;接口失败时降级展示可用场景。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 19:35:45 +08:00
Manus AI
b5facefde8 feat(场景获客): 补全11种场景含扫码获客,统一渐变图标
后端合并 SCENE_CATALOG 保证列表完整;前端 SceneIcon 替换杂乱图片;附 plan_scene 落库迁移。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 19:32:42 +08:00
Manus AI
48fc5a7a7d fix(统计): 场景今日真实获客数,首页简化,编辑计划直达计划接口
场景列表 count 改为 task_customer 今日统计;首页汇总三指标+紧凑场景卡;已有计划自动补 apiKey 并开放计划接口面板。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 18:46:13 +08:00
Manus AI
cd7d00b4f8 fix(海报获客): 暂停计划仍可扫码留资,列表支持批量启用
已暂停不再返回「任务已结束」;修正 posters 数组 URL 解析;Tab 改为已启用/已暂停/全部并支持独立计划批量启用。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 16:23:06 +08:00
Manus AI
f9d6c3034f deploy: 三端宝塔部署 kr-op/kr-kf/kr-admin 及全栈验收
SuperAdmin standalone + PM2:3000;acceptance_tencent_all 23 项全通过。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 14:14:57 +08:00
Manus AI
175f9942e1 fix: AssignGroupModal 从 traffic-pool/api 导入分组接口
list/components 下 ../api 指向 list/api.ts 无 getGroups 导出,导致 Docker build 失败。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 14:05:21 +08:00
Manus AI
3e0cc92cfc ui(plan): 计划状态三标签筛选,导出按钮单行三列
客资弹窗底部文档/表格/Webhook 并排;计划列表增加全部/已启动/已暂停筛选。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 13:19:33 +08:00
Manus AI
db85605352 fix(plan): 修复客资列表500并支持全局Webhook回退
traffic_pool_company 查询改用 identifier|phone|ownerWechatId;扩展查询失败降级不抛500;计划未配 Webhook 时回退全局配置。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 13:17:46 +08:00
Manus AI
434d09183b feat(plan): 客资列表支持一键推送到 Webhook
新增 export-batch 接口,弹窗底部增加全宽 Webhook 推送按钮,与文档/表格导出并列布局。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 13:15:51 +08:00
Manus AI
c553198d5a feat(plan): 海报获客客资列表筛选与导出
已获客/已添加弹窗统一为客户列表,支持状态筛选、旅程详情,以及 Markdown/CSV 导出。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 13:14:19 +08:00
Manus AI
c05fe80b89 feat(设备管理): 功能开关与手机端 device_taskconf 同步
统一 DeviceTaskConfigService 读写;修复 task-config 校验与布尔转换;详情返回 features;autoAddFriend 与 autoCustomerDev 联动。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 13:04:31 +08:00
Manus AI
700f3ab5d2 fix(设备管理): 修复扫码二维码获取失败与本地 Docker 缺配置
补 device_bind 默认配置与 .env.docker [api] 段;新增 POST /v1/devices/qrcode BFF;前端弹窗即拉码并展示真实错误。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 12:47:08 +08:00
Manus AI
4a8ef1aec8 fix: 双环境 Docker 部署——本地 /api 与线上 ckbapi 分离
- docker-compose.yml 本地 VITE_API_BASE_URL=/api,Server 选择性挂载保留 vendor
- 新增 docker-compose.prod.yml 供宝塔构建用 ckbapi 直连
- Server Dockerfile 修复 composer(插件白名单、git/unzip、.dockerignore)
- composer.json 与 lock 对齐 5.1.*

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 12:35:42 +08:00
Manus AI
82bc96884a fix(local): 修复本地首页 dashboard 500 并接通 dev API
.env.docker 注释中的 h5= 导致 parse_ini_file 失败,异常页模板路径为空进而全站 500;同步 npm dev 反代与 dashboard 路由别名。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 12:33:36 +08:00
Manus AI
745d14c93f fix(设备管理): 默认在线Tab,扫码未绑微信设备在全部可见
列表查询改为 LEFT JOIN,避免无微信登录记录的扫码设备被过滤;前端 Tab 顺序调整为在线/离线/全部。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 12:21:30 +08:00
Manus AI
b838ae8fc1 fix: 设备管理获取二维码 Endroid 3.9 枚举调用修复
生产 endroid/qr-code 3.9 要求 ErrorCorrectionLevel::HIGH() 实例化调用,
旧写法传字符串导致 /v1/api/device/add 返回 HTTP 500。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 12:20:34 +08:00
Manus AI
06ca494e02 fix: 海报获客手机号解密改直连微信 API
EasyWeChat phone_number 未注册导致 decryptphone 500,阻断入池与 Webhook。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 10:28:47 +08:00
Manus AI
4ed9821c5d fix: 海报小程序码 AppId 改回 wx789850448e26c91d
存客宝小程序 ID 以用户确认为准;落地页保持 pages/poster/index2,缓存前缀升 v5。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 10:21:01 +08:00
Manus AI
f0ba9b387d fix: 海报小程序码落地页改回 pages/poster/index2
误将小程序码指向表单页 input2;恢复获客海报页,生产切换存客宝 AppId。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 10:14:59 +08:00
Manus AI
12cd0808bc fix: 海报获客弹窗改为小程序码,H5表单链接隔离
默认 poster_qrcode_mode=miniprogram;弹窗主区展示微信无限码,
H5获客表单仅作下方可复制链接,与小程序码分离。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 10:05:33 +08:00
Manus AI
07bfc890c2 fix: 场景获客容错、海报二维码URL与部署Skill沉淀
去掉二维码URL的.png后缀(Nginx静态404);删除老游条文案;401优先跳登录;
新增存客宝宝塔部署Skill汇总历次踩坑。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 09:59:44 +08:00
Manus AI
67dfc0a87c perf: 海报获客二维码缓存与 PNG 直链,加快弹窗与扫码页
二维码 Redis 缓存、qrImageUrl 可缓存 PNG、海报 getone GET+缓存,管理端弹窗秒开。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 09:49:26 +08:00
Manus AI
ffd66d0f5e fix: MiniProgramQrCodeService 使用全局 config() 并完善 smoke 测试
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 09:44:32 +08:00
Manus AI
afe4dbd131 fix: 海报获客二维码默认改 H5,避免扫码进老游条小程序
wx789850448e26c91d 微信侧绑定老游条首页;posterQrcodeMode=h5 生成存客宝表单二维码。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 09:44:14 +08:00
Manus AI
1f46065ebc fix(workbench): 朋友圈列表 config 改直连查询并 setAttr
修复 relation 未挂载导致 config 为空;避免 data[] 触发 Model::data 报错。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 06:48:16 +08:00
Manus AI
597941fbd1 fix(workbench): 朋友圈列表改用 setAttr 写入 config
避免 $item->data[] 触发 ThinkPHP Model::data() 参数错误。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 06:47:30 +08:00
Manus AI
ec2d4957e4 fix(workbench): 修复朋友圈同步列表500与token stale
朋友圈列表改用 data.config 数组避免 Model 属性异常;getList 加 try/catch;
JwtAuthTrait 补 getUserInfo 别名;前端 request 每次读取最新 token。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 06:05:43 +08:00
Manus AI
5c1463ffa9 fix: 运营报告推送真实数据并附带鉴权详情链接
飞书/企微不再误用客资变更模板;推送含汇总数据与 HMAC token 详情页,支持今日/近3日/近7日查看。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 05:59:25 +08:00
Manus AI
6ec8df94dc fix(api): 修复工作台 JWT 鉴权与流量池分页 count 污染
Workbench 等控制器改用 JwtAuthTrait 替代失效的 request->userInfo;
TrafficPoolGroupService 与 getUserList 使用 clone count,避免 500 与错误分页。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 05:50:04 +08:00
Manus AI
a72772d5ee fix(touchkebao): 405/500 修复 — s2api 反代 + 错误进通知中心
宝塔 kr-kf 增加 /s2api 反代;axios 错误写入通知中心;chukebao 接口 nullable 与 count 修复。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 05:44:26 +08:00
Manus AI
ac47668016 fix(chukebao): 修复触客宝 PC 页 500 — count 污染 query 与 nullable 字段
wechatFriend/chatroom/notice/followUp/todo 等接口在生产环境返回 500,改用 clone count 与字段兜底。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 05:38:09 +08:00
Manus AI
3f7e1a4af6 fix(touchkebao): 接口错误汇总到通知中心,不再弹 Toast
将 axios 拦截器中的 500 等错误写入铃铛通知「接口异常」Tab,同类错误合并计数,避免聊天页被 Toast 打断。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 05:34:29 +08:00
Manus AI
f40649a534 fix(api): StatsController 改用 JwtUtil 鉴权,生产 Dashboard 接口恢复
docker-compose 生产构建固定 VITE_API_BASE_URL=ckbapi,修复宝塔部署 405 与首页接口错误。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 05:32:03 +08:00
Manus AI
99cbabbaaf fix: 修复生产 JWT 鉴权导致全站数据接口 500
getUserInfo 改从 Authorization 解析 token,避免 userInfo 写入 param 触发
variable type error;补齐 app\http\middleware\jwt 并统一 middleware 别名。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 05:27:07 +08:00
Manus AI
04747667b5 docs(obsidian): 8、部署 01~05 子目录侧栏配色
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 05:13:38 +08:00
Manus AI
9eaedd2c28 fix: 场景获客 Webhook 推送改为简洁双块 IM 格式
飞书/企微仅标题+客户信息+用户旅程,去掉计划归因与 JSON 附录;HTTP 改为精简 JSON。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 05:07:22 +08:00
Manus AI
667a4ea656 fix: 修正 OpsReportSection 的 api 导入路径以通过 Docker 构建
../api 无法解析导致 cunkebao-web 镜像 build 失败,改为同目录 ./api。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 05:05:27 +08:00
Manus AI
2e856b1922 feat: 场景获客总设置新增运营报告定时推送(默认09:00)
按公司汇总各平台客资数据,支持 Webhook/飞书定时与立即发送,含预览面板。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 05:02:33 +08:00
Manus AI
e403704ab3 ui: 编辑计划高级设置改为默认折叠的图标入口
分销/Webhook/计划接口/拉群四块合并为 4 宫格图标,点击展开后再编辑。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 04:59:18 +08:00
Manus AI
d1c926205a fix: 全局 Webhook 推送增加公司边界校验并写入开发铁律
推送前校验 plan.companyId 与 customer.task_id,跨公司或不归属本计划的客资不推送。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 04:56:53 +08:00
Manus AI
b8fa23b6a5 feat(plan): 新建计划保存后跳转编辑页展示计划接口区块
创建成功后进入 /scenarios/edit/:planId 第一步并提示 Webhook/API 配置。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 04:54:30 +08:00
Manus AI
96b828b1bf ui: 将 Webhook/计划接口移入编辑计划并加强删除确认
操作菜单仅保留编辑/复制/删除;Webhook 与入站计划接口配置整合到基础设置步骤。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 04:49:53 +08:00
Manus AI
9ddcf79bac ui: 场景获客右上角设置改为纯图标按钮
移除「总设置」文字,保留齿轮图标置于导航栏右侧,与「新建计划」并列。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 04:47:26 +08:00
Manus AI
65fa2986b1 fix: 存客宝小程序码 opcache 与接口结构化返回
Docker opcache 缓存旧 EasyWeChat 代码导致 500;开启 validate_timestamps,接口返回存客宝小程序元数据+qrCode,前端兼容解析。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 04:42:03 +08:00
Manus AI
69e7c282ca fix: 海报获客小程序码改用 curl 直连微信 API
Docker 挂载后无 vendor 导致 EasyWeChat 不可用;新增 MiniProgramQrCodeService 直连 getwxacodeunlimit,失败时 H5 二维码兜底。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 04:37:04 +08:00
Manus AI
109e9fef37 fix: 飞书 Webhook 自动转 msg_type 并校验响应体 code
飞书机器人返回 HTTP 200 但 code=19002(缺少 msg_type)时原先误判为成功;现自动适配飞书文本格式并在 body code≠0 时报错。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 04:33:01 +08:00
Manus AI
8ce1455555 fix(deploy): 修复首页500错误与runtime日志权限
runtime/log 目录 root 属主导致 PHP-FPM 写日志 Fatal Error 返回500;启动时 chown/chmod runtime,前端 user-info 改走 /v1/auth/info。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 04:27:12 +08:00
Manus AI
69bdce481f 增强场景获客 Webhook 载荷:计划归因、时间线与标签汇总
推送 JSON 现包含 attribution(来源计划/场景/入计划时间)、planTimeline、tags 合并及带 planId 的行为轨迹,便于外部系统识别客资从哪条计划来、做了什么。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 04:23:46 +08:00
Manus AI
10527ecfa8 feat(场景获客): 总设置页(全局 Webhook / 默认设备 / 统一流量池)
公司级配置与单计划并存:全局 Webhook 叠加推送、新建计划预填设备、客资自动入指定流量池分组。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 04:19:31 +08:00
Manus AI
82c15699cc fix(场景获客): 补全 Webhook 批量导入触发与校验
订单 Excel/电话场景批量客资、计划创建更新 URL 校验、smoke 测试脚本。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 04:13:22 +08:00
Manus AI
092161316e chore(cursor): 存客宝 v3 开发文档先行规则 alwaysApply
开发前必读开发铁律与 5、接口;收尾回写文档与进度。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 04:11:59 +08:00
Manus AI
faf907b61b feat(场景获客): 计划级客资出站 Webhook 推送与配置 UI
计划可配置出站 URL,客资进入或状态变更时 POST 完整数字化客资(电话、标签、行为轨迹);操作菜单与编辑计划均可配置。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 04:09:42 +08:00
Manus AI
2ecf9e331d fix(deploy): 恢复 Docker 编排与配置文件,修复登录路由
docker-compose.yml 被清空导致前端退出、后端 .env 挂载失效;从 git 历史与镜像反编译重建全套 Docker 配置,修复 nginx 登录重写走 ThinkPHP 路由。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 03:26:17 +08:00
Manus AI
1537b06278 docs(obsidian): 存客宝开发文档侧栏目录配色
对齐工作手机四类分类色,启用 cunkebao-devdoc CSS snippet 与图谱着色。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 03:24:54 +08:00
wong
bcbc92ad57 sync: Cunkebao 自动点赞页与记录;Touchkebao 会话列表与存储、文档清理
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-13 09:43:36 +08:00
wong
41ffb8a220 自动点赞提交 2026-05-12 16:58:46 +08:00
wong
1d11f01115 bug优化 2026-04-29 16:27:53 +08:00
wong
1deebf3f5c feat(media): 微信消息媒体 OSS 归档与下载地址回写
- 新增 MediaArchiveJob、MediaOssArchiveService、WechatMediaArchiveService 与回填命令
- Message/DataProcessing 等支持归档调度与持久化下载 URL
- WebSocket 控制器整理;朋友圈与文档/定时任务说明更新

Made-with: Cursor
2026-04-14 09:37:00 +08:00
wong
ae1120f1e3 11111 2026-04-09 11:07:54 +08:00
wong
b597ed2275 素材允许添加小程序 2026-04-07 16:08:44 +08:00
wong
1ecfacce49 发送小程序打通 2026-04-03 16:53:50 +08:00
wong
b20f00be53 处理存客宝内容库无法采集问题 2026-04-01 10:54:23 +08:00
wong
168fff56c1 1111 2026-03-24 11:09:13 +08:00
wong
689705ef70 111 2026-03-11 14:22:14 +08:00
wong
6629a9ad14 11 2026-03-11 14:20:30 +08:00
wong
af79d1e860 代码提交 2026-03-11 14:01:50 +08:00
wong
38379fac65 触客宝功能提交 2026-02-04 11:53:28 +08:00
wong
7534dd79fa 新版流量池服务端提交 2026-02-04 10:58:56 +08:00
wong
f956fc949b 存客宝新版流量池提交 2026-02-04 10:58:02 +08:00
wong
442be3b02c 代码优化 2026-02-02 17:02:49 +08:00
wong
208c25b2f7 流量池详情 2026-02-02 14:53:06 +08:00
wong
dd4b43c10e 流量池更新优化 2026-02-02 14:51:25 +08:00
wong
519a9b1d1b 流量池服务端 2026-02-02 11:00:26 +08:00
wong
f0c278a35f 流量池前端 2026-02-02 10:59:12 +08:00
wong
ab5885f2a0 代码兼容性提交 2026-01-31 15:19:11 +08:00
wong
9bc1d7d7bf 存客宝代码优化 2026-01-31 15:08:42 +08:00
wong
4d8fd96190 111 2026-01-20 11:04:28 +08:00
wong
7f7a5357a0 朋友圈优化 2026-01-19 14:29:01 +08:00
wong
28adf38f2f 代码同步 2026-01-19 14:21:19 +08:00
wong
b2abe9f570 代码提交 2026-01-19 11:36:42 +08:00
wong
5aa8657640 去除无用代码 2026-01-19 11:31:35 +08:00
wong
44dbe20b03 代码优化 2026-01-19 11:11:36 +08:00
wong
3a0621aab8 1 2026-01-19 10:51:18 +08:00
wong
28f4479d3c 111 2026-01-19 10:43:11 +08:00
wong
e356ae67c7 优化 2026-01-19 10:39:51 +08:00
wong
6b31889261 代码优化 2026-01-19 10:30:09 +08:00
wong
16aec83f02 消息优化 2026-01-19 10:01:40 +08:00
wong
9fe0f9f677 代码优化 2026-01-19 09:48:53 +08:00
wong
ee4dcb1b8b 测试 2026-01-19 09:26:55 +08:00
wong
5dfaba943b 优化 2026-01-17 17:20:23 +08:00
wong
bac66de046 代码优化 2026-01-17 17:03:48 +08:00
wong
9b8f3b1b2b 代码优化 2026-01-17 15:58:57 +08:00
wong
56d5f0b5a3 优化 2026-01-17 15:42:00 +08:00
wong
51a731ea68 任务调度器提交 2026-01-17 15:17:05 +08:00
wong
002f03e037 优化 2026-01-16 16:51:00 +08:00
wong
a250819d87 代码优化 2026-01-16 16:42:51 +08:00
wong
135e58f1e2 修改默认朋友圈分页 2026-01-16 11:55:45 +08:00
wong
58b6cd2340 支持定时采集所有朋友圈 2026-01-16 11:55:07 +08:00
wong
b21f40942e 好友迁移由30分钟改为10分钟 2026-01-16 10:17:47 +08:00
wong
dd9fa3d0f2 缓存问题 2026-01-15 14:24:50 +08:00
wong
430b8eee91 全局配置服务功能提交 2026-01-15 14:24:25 +08:00
wong
cec64b889b 全局配置前端功能提交 2026-01-15 14:22:23 +08:00
wong
443ef6ad2d 好友迁移 + 定时器优化 2026-01-13 15:22:19 +08:00
wong
3e8b607948 好友切换 2026-01-13 10:20:33 +08:00
wong
9eeaaa70c4 1111 2026-01-12 17:02:31 +08:00
wong
80ae205cb3 1111 2026-01-12 14:38:29 +08:00
wong
cd38e0eedd 去除无用代码 2026-01-12 09:44:12 +08:00
wong
66d217d5f1 入群欢迎语功能提交 2026-01-09 17:05:17 +08:00
wong
2b128195bf 代码同步 2026-01-08 11:50:32 +08:00
wong
e469537ac5 场景获客支持拉群 2026-01-08 10:45:41 +08:00
wong
b2e84a2259 1、新增一个所有好友的流量池
2、旧版场景获客数据迁移
3、场景获客功能兼容旧版数据
2026-01-07 10:41:39 +08:00
wong
228d59402f 测试表单可修改 2026-01-06 11:07:53 +08:00
wong
ea2dd8cab2 代码提交 2026-01-06 10:58:29 +08:00
乘风
efcbb06eb2 Merge branch 'develop' of https://gitee.com/cunkebao/cunkebao_v3 into develop 2026-01-05 11:11:54 +08:00
乘风
61e720c247 去掉重复文件 2026-01-05 11:11:49 +08:00
wong
88418386a4 Merge branch 'develop' of https://gitee.com/cunkebao/cunkebao_v3 into develop 2026-01-05 11:04:39 +08:00
wong
f096e07ec8 同步 2026-01-05 11:04:08 +08:00
乘风
046b00404e 同步 2026-01-05 10:52:26 +08:00
乘风
9bb6390f9a Merge branch 'develop' of https://gitee.com/cunkebao/cunkebao_v3 into develop 2026-01-05 10:47:16 +08:00
乘风
cb612746a6 数据中心变化 2026-01-05 10:47:10 +08:00
wong
8beb2cb6fe Merge branch 'develop' of https://gitee.com/cunkebao/cunkebao_v3 into develop 2026-01-05 10:44:17 +08:00
wong
aabd8037a6 同步 2026-01-05 10:44:08 +08:00
乘风
408c6a2029 数据同步 2026-01-05 10:19:51 +08:00
乘风
ba0ebcf273 数据中心同步 2026-01-05 10:16:20 +08:00
乘风
0457528dd0 同步 2026-01-05 09:59:07 +08:00
乘风
e6037ccfd5 Merge branch 'develop' into feature/yongpxu-dev 2026-01-05 09:55:03 +08:00
wong
ce1c434ea8 代码提交 2026-01-05 09:34:48 +08:00
wong
b4c813311b 自动建群提交 + 触客宝发布朋友圈优化 2026-01-04 17:03:51 +08:00
wong
08d2a811b7 触客保优化 2026-01-04 15:58:47 +08:00
乘风
256afaee12 可以的 2026-01-04 12:19:12 +08:00
乘风
198c62081b 构建触客宝CKB 2026-01-04 12:14:17 +08:00
乘风
53b679aeb6 Refactor MomentPublish component: update styling for account cards, enhance selected state visuals, and switch to customer store for account data management. 2026-01-04 12:07:17 +08:00
wong
64358df1c1 内容库采集支持链接类型 2025-12-30 11:06:46 +08:00
wong
b0d9481cdb 提现bug处理 2025-12-29 18:00:46 +08:00
wong
db0985504a 新版群添加功能 2025-12-29 16:09:22 +08:00
wong
82f9b9371a 提现优化 2025-12-29 16:02:24 +08:00
wong
d9ee7e9402 分销优化 2025-12-29 15:25:04 +08:00
wong
b609eeb0eb 1 2025-12-29 15:18:39 +08:00
wong
203e8c8eaf 渠道新增用户权限 2025-12-29 15:12:57 +08:00
wong
2c90f6f33c 场景获客优化子账号只能展示自己的数据 2025-12-29 15:01:44 +08:00
wong
88bc7ef3cd 金额处理 2025-12-29 10:59:32 +08:00
乘风
5ae0d997d9 小问问题处理一下 2025-12-26 18:15:33 +08:00
wong
879396e91c 代码提交 2025-12-26 10:42:33 +08:00
wong
b8754f6174 内容库群选择功能 + 场景获客分页修复 2025-12-25 15:39:57 +08:00
wong
302617cd81 1、修复场景获客数据统计问题
2、修复默认头像破图问题
3、修复健康分展示问题
4、修复获客场景_好友迁移编辑会跳到其他类目问题
2025-12-24 15:27:57 +08:00
wong
79fd133821 Merge branch 'develop' of https://gitee.com/cunkebao/cunkebao_v3 into develop 2025-12-23 17:02:12 +08:00
wong
4f2b34522f 代码提交 2025-12-23 17:01:59 +08:00
乘风
853a7f32d2 Merge branch 'feature/yongpxu-dev' into develop 2025-12-23 16:07:57 +08:00
乘风
eea18cc0c7 Merge branch 'develop' of https://gitee.com/cunkebao/cunkebao_v3 into develop 2025-12-23 16:07:48 +08:00
乘风
0e173668c5 接触所有限制 2025-12-23 16:07:33 +08:00
乘风
abdcff813c 处理 2025-12-23 15:45:15 +08:00
wong
0ac84bd033 Merge branch 'feature/bug' into develop 2025-12-23 15:33:30 +08:00
wong
4c12619f0e 流量分发展示数据优化 2025-12-23 15:30:08 +08:00
乘风
dc1f194bcc Merge branch 'feature/yongpxu-dev' into develop 2025-12-23 11:53:24 +08:00
乘风
7a89b80c8f feat: 配置挪到外边 2025-12-23 11:52:06 +08:00
wong
7a4f40de54 1111 2025-12-23 11:38:25 +08:00
wong
988d7fcdd3 1 2025-12-23 11:26:29 +08:00
wong
236ef09538 1111 2025-12-23 11:22:28 +08:00
wong
d914f097c0 1 2025-12-23 10:09:42 +08:00
wong
c37e5aca35 111 2025-12-23 09:57:50 +08:00
wong
5e198d1021 去除多余的日志输出 2025-12-23 09:52:08 +08:00
wong
cc91552c36 朋友圈采集自己的任务完成 2025-12-22 16:35:08 +08:00
wong
f208bbdb9a 优化渠道 2025-12-20 16:45:25 +08:00
wong
20f567da37 渠道功能完善 2025-12-20 11:27:47 +08:00
wong
9b45ebea0e 去除多余的日志 2025-12-20 11:17:30 +08:00
wong
7a0ae54705 代码提交优化新增的渠道码限制24小时有效 2025-12-20 11:09:04 +08:00
wong
3f5a2189ce 代码优化 2025-12-20 10:34:09 +08:00
wong
36d6f94177 1 2025-12-19 17:26:55 +08:00
wong
c046bdab30 优化内容库 2025-12-19 17:25:56 +08:00
wong
0c8f1d6419 优化界面 + 新增修改密码功能 2025-12-19 14:46:14 +08:00
乘风
f8810f5199 去掉无用工作区 2025-12-18 16:49:54 +08:00
wong
bc6421b1af Merge branch 'develop' of https://gitee.com/cunkebao/cunkebao_v3 into develop 2025-12-18 16:23:10 +08:00
wong
2f00ee176b 分销提交 2025-12-18 16:23:01 +08:00
乘风
44da1feed3 Merge branch 'yongpxu-wechatFriends' into feature/yongpxu-dev 2025-12-18 15:46:19 +08:00
wong
66c8623138 11111 2025-12-18 15:36:25 +08:00
乘风
e12fbad859 Merge branch 'develop' into yongpxu-wechatFriends 2025-12-18 15:13:45 +08:00
乘风
183df2cac3 Merge branch 'develop' into yongpxu-dev 2025-12-18 15:11:13 +08:00
乘风
7f1fda40dc 增强GroupContextMenu和VirtualContactList组件:在GroupContextMenu中添加遮罩层右键事件回调以支持菜单在新位置打开,优化SidebarMenu中的右键菜单逻辑以避免闪烁,提升用户体验。 2025-12-18 15:09:58 +08:00
wong
d42a2df286 1 2025-12-18 15:09:51 +08:00
wong
1a345fff79 1 2025-12-18 10:50:50 +08:00
乘风
7724d60a05 更新联系人上下文菜单和朋友圈组件:修复移动分组成功消息的重复调用,优化样式以增强用户体验,重构相关组件以使用currentCustomer替代currentKf,确保数据一致性和可读性。 2025-12-18 10:44:38 +08:00
wong
1cb7903e37 渠道代码提交 2025-12-18 10:34:50 +08:00
wong
d8183909ca 1111 2025-12-17 17:58:08 +08:00
wong
7f7d5d5c39 代码优化 2025-12-17 17:04:57 +08:00
乘风
72cf3fd81c 重构VirtualContactList组件:统一项目高度以实现一致的布局,并通过重构代码格式来提高可读性。此更改通过确保所有项目类型共享相同的高度来增强虚拟滚动期间的视觉稳定性。 2025-12-17 16:39:47 +08:00
乘风
65167be7f8 更新联系人分组逻辑:将分组类型从“group”更改为“chatroom”,并在联系人上下文菜单中添加移动分组的回调函数。调整相关组件以支持新的分组管理功能,确保在移动分组时使用正确的类型。 2025-12-17 16:20:58 +08:00
wong
7dda34a779 分销功能提交 2025-12-17 16:20:46 +08:00
乘风
bde1d36005 重构GroupContextMenu组件:调整上下文菜单的样式并增强组处理逻辑,以禁用默认组或未分组组的编辑/删除操作。更新联系人组的排序逻辑,以区分默认组和未分组组的优先级。 2025-12-16 16:42:00 +08:00
乘风
631e8d00e2 增强应用组件中的ErrorFallback UI,并更新SidebarMenu以实现新的联系人存储集成。重构微信组件,支持虚拟滚动,提升性能。在微信好友组件中实现新的群组管理功能。 2025-12-16 16:24:10 +08:00
乘风
3720987997 Refactor FriendsCircle component: Simplified onError handler for image loading 2025-12-12 10:24:29 +08:00
wong
8e4ce2aee2 Merge branch 'feature/bug' into develop 2025-12-11 17:35:22 +08:00
wong
08fc18da86 php代码提交 2025-12-11 17:32:59 +08:00
wong
b2760cde0e 群、好友支持客服微信号筛选 2025-12-11 17:32:27 +08:00
wong
61926503cf 流量分发筛选状态功能 2025-12-11 17:31:33 +08:00
wong
84a51b8f91 好友转移 2025-12-11 17:30:40 +08:00
乘风
4f8a69a511 1 2025-12-11 09:40:54 +08:00
wong
4537305dfc Merge branch 'develop' of https://gitee.com/cunkebao/cunkebao_v3 into develop 2025-12-11 09:37:44 +08:00
wong
be901a92f6 Merge branch 'feature/test' into develop 2025-12-11 09:37:12 +08:00
wong
1067a15916 朋友圈导出默认30天 2025-12-11 09:36:37 +08:00
乘风
2a41d88ce3 STEP:10 2025-12-11 09:36:35 +08:00
乘风
80027e8fa3 STEP:9 2025-12-11 09:36:22 +08:00
乘风
df893296ba STEP:8 2025-12-11 09:36:09 +08:00
乘风
77e9f763cd STEP:7 2025-12-11 09:35:59 +08:00
乘风
c531957ce8 STEP:6 2025-12-11 09:35:47 +08:00
乘风
257ca5014b STEP:4 2025-12-11 09:35:10 +08:00
wong
1c3e567b9a test 2025-12-11 09:35:03 +08:00
乘风
4aacb7bcb6 STEP:3 2025-12-11 09:34:59 +08:00
乘风
e7fef596d4 STEP:2 2025-12-11 09:34:48 +08:00
乘风
5d95ca6f53 STEP:1 2025-12-11 09:34:38 +08:00
wong
3cd6bf9dba test 2025-12-11 09:33:53 +08:00
wong
67a4bd6e3a Merge tag 'v1.1.2' into develop 2025-12-11 09:31:26 +08:00
wong
c33c62aa6d Merge branch 'release/v1.1.2' 2025-12-11 09:31:19 +08:00
乘风
581e09d45b Merge branch 'develop' into yongpxu-dev 2025-12-10 18:05:11 +08:00
乘风
688a200999 go 2025-12-10 18:03:51 +08:00
wong
cc89df7957 Merge branch 'feature/group' into develop 2025-12-10 17:58:34 +08:00
wong
198e0434b3 群发 2025-12-10 17:58:08 +08:00
wong
55fe2b46df 代码优化 2025-12-10 17:56:55 +08:00
乘风
c7e934f23d 重构MessageRecord组件以支持虚拟化,从而提高大型消息列表的性能。引入VirtualizedMessageList以实现高效渲染,并使用React.memo优化渲染逻辑以防止不必要的重新渲染。 2025-12-10 17:09:08 +08:00
乘风
7752dd136f 重构消息处理逻辑以提高同步和性能,并增强ProfileCard组件以实现快速回复功能。 2025-12-10 16:02:01 +08:00
乘风
af2f32da4a Update package.json to set module type, refactor postcss.config.js to use ES module syntax, and remove vite.config.ts file. 2025-12-10 15:57:02 +08:00
乘风
81859dfacb gogoo 2025-12-10 11:58:47 +08:00
wong
3e145ca123 算力功能改版 2025-12-09 15:01:38 +08:00
wong
c9a5d3091f 内容库优化 + 内容库导入功能 2025-12-09 14:59:24 +08:00
乘风
4374ad5036 1 2025-12-09 11:55:53 +08:00
乘风
1ca2ca7058 更新技术栈文档,新增TanStack Query和Sentry组件,优化项目结构说明,添加关于兼容性和工程化的详细信息。 2025-12-09 11:11:53 +08:00
wong
9fe15b1bec Merge branch 'feature/groupCreate' into develop 2025-12-06 17:13:53 +08:00
wong
a557319b3e 算力功能 2025-12-06 17:13:07 +08:00
wong
f06eb0e9d7 消息同步 2025-12-06 17:12:07 +08:00
乘风
1be091522e 新增asyncMessageStatus接口以获取消息状态,并在消息处理逻辑中集成该接口以优化消息同步。调整ProfileCard组件的状态管理以支持快速回复功能。 2025-12-06 17:10:57 +08:00
wong
63df35b79c 代码优化 2025-12-05 11:36:03 +08:00
wong
2697da15aa 消息聊天自动分配好友 2025-12-05 10:45:21 +08:00
wong
ced0f993de 分组及好友列表优化 2025-12-05 10:44:43 +08:00
wong
55629a8ce4 Merge branch 'feature/groupPush' into develop 2025-12-04 16:05:38 +08:00
wong
923c6a5904 Merge branch 'feature/bug' into feature/groupPush 2025-12-04 16:02:25 +08:00
wong
b63e87d0cf 1 2025-12-04 16:01:51 +08:00
wong
96caa71f03 内容库可以选择设备 2025-12-04 15:56:19 +08:00
wong
b9b1877e04 自动点赞功能优化 2025-12-04 11:10:55 +08:00
wong
81daa8cfdc 修复备注 2025-12-04 09:43:25 +08:00
乘风
903ea005e3 通过向UpdateDataInfoParams添加conRemark并重构相关组件,增强好友信息更新功能。删除未使用的本地数据库更新逻辑并简化DetailValue组件中的数据处理。 2025-12-03 18:44:42 +08:00
乘风
580e9f4f73 Remove package.json file from MCP directory 2025-12-03 16:56:02 +08:00
乘风
51e08d1b2a Merge branch 'develop' into yongpxu-dev2 2025-12-03 16:55:35 +08:00
乘风
3708f5a61e 优化消息同步处理逻辑,提升系统性能和稳定性。 2025-12-03 16:54:21 +08:00
wong
58377b4670 代码提交 2025-12-03 16:29:40 +08:00
wong
5bb5aa3d5a 代码优化 2025-12-03 16:18:10 +08:00
wong
71def21369 消息优化 2025-12-03 14:06:07 +08:00
乘风
1ea565fbdf 先写好接口 2025-12-03 11:03:38 +08:00
乘风
56a9a015f1 重构ChatWindow和MessageEnter组件以提高性能和可维护性。利用useCallback和useMemo进行备忘录化,增强文件类型处理,并简化消息呈现逻辑。在MessageList中引入SessionItem组件以更好地管理会话。 2025-12-03 09:46:19 +08:00
wong
0708b5a134 Merge branch 'develop' of https://gitee.com/cunkebao/cunkebao_v3 into develop 2025-12-02 17:47:32 +08:00
wong
242065d298 微信分组及消息置顶 2025-12-02 17:47:22 +08:00
乘风
b5d6214521 Remove pin/unpin chat session API methods and update message list handling for pinning sessions. 2025-12-02 15:28:57 +08:00
乘风
9c5bccb23c Merge branch 'develop' into yongpxu-dev 2025-12-02 10:54:28 +08:00
wong
5f5b567749 调整消息同步处理 2025-12-02 10:51:27 +08:00
wong
354d6c4f62 代码优化 2025-12-01 18:09:06 +08:00
wong
2c37314c4f 代码优化 2025-12-01 17:41:57 +08:00
乘风
1dbdee155e 添加高频轮询接口白名单,优化请求截流逻辑以支持特定接口的无截流请求。允许通过配置控制截流功能,提升请求处理的灵活性和用户体验。 2025-12-01 16:58:58 +08:00
wong
2939b63998 1 2025-12-01 16:47:57 +08:00
wong
ff7097f2d9 1 2025-12-01 16:46:23 +08:00
wong
33cd4de3c5 Merge branch 'develop' of https://gitee.com/cunkebao/cunkebao_v3 into wong-dev 2025-12-01 16:44:38 +08:00
wong
0bc6c3a22a 代码优化 2025-12-01 16:41:40 +08:00
wong
44edfe7a81 消息同步优化 2025-12-01 16:25:15 +08:00
wong
d3fae3bbd0 队列优化 2025-12-01 15:42:54 +08:00
乘风
11a4ec8c67 在MessageList组件中添加未知联系人补充功能,异步拉取缺失的头像和昵称信息,并更新会话和联系人数据库,以提升用户信息的准确性和完整性。 2025-12-01 15:09:25 +08:00
乘风
75aab08a72 在MessageList组件中实现对丢失头像或昵称的详细获取,并相应更新会话状态和数据库,以确保准确显示用户信息。 2025-12-01 14:43:33 +08:00
乘风
2cc2184002 增强MessageRecord组件以管理消息加载期间的滚动行为。为消息容器和加载状态引入引用,通过在加载更多消息时保留滚动位置来确保平滑的用户体验。 2025-12-01 14:34:19 +08:00
乘风
57c398f537 更新MessageRecord组件中的消息过滤逻辑,以包括其他消息类型(-10001),以改进系统消息的处理并增强用户体验。 2025-12-01 14:27:39 +08:00
乘风
7d9f94984c 在MessageRecord组件中实现parseSystemMessage实用程序,从系统消息中提取纯文本,通过删除HTML标签并为相关内容添加红包图标来增强消息渲染。 2025-12-01 14:23:10 +08:00
乘风
8659049ae9 增强MessageRecord组件以支持RedPacketMessage和TransferMessage的额外道具,从而更好地处理单击事件和套接字请求。更新禁用的转接消息的样式以改善用户体验。 2025-12-01 12:23:19 +08:00
乘风
1ca5b30c15 Refactor TransferMessage component to improve layout and styling. Adjust icon size and add status display for better user experience. 2025-12-01 10:59:50 +08:00
乘风
b9bc0a71a9 在MessageRecord组件中增加微信转账消息支持,更新消息过滤逻辑。调整RedPacketMessage样式以获得更好的布局。 2025-12-01 10:56:05 +08:00
乘风
13ae8bd76f Enhance message filtering to support WeChat red packet messages, allowing for sender identification in chat records. 2025-12-01 10:38:27 +08:00
wong
31fdabaa15 Merge branch 'develop' of https://gitee.com/cunkebao/cunkebao_v3 into wong-dev
# Conflicts:
#	Server/composer.json
2025-12-01 10:27:35 +08:00
wong
43e9930b45 Merge tag 'v1.1.1-a' into develop 2025-12-01 10:17:25 +08:00
wong
a77192ebc2 Merge branch 'release/v1.1.1-a' 2025-12-01 10:17:18 +08:00
wong
181a792d0a Merge branch 'develop' of https://gitee.com/cunkebao/cunkebao_v3 into develop
# Conflicts:
#	Cunkebao/src/pages/mobile/mine/wechat-accounts/detail/index.tsx
2025-12-01 10:15:45 +08:00
wong
43f6a061e1 解决代码冲突问题 2025-12-01 10:05:26 +08:00
超级老白兔
05bba1a461 Merge branch 'develop' of https://gitee.com/cunkebao/cunkebao_v3 into develop 2025-11-28 23:00:44 +08:00
超级老白兔
97fc9959bb Refactor cache clearing functionality in settings page to improve user feedback and error handling. Update WeChat API functions to support debounce options for contact and group list retrieval. Enhance message rendering logic to include red packet messages and improve user identification in chat records. 2025-11-28 23:00:40 +08:00
wong
ad2d1c27ab 优化代码 2025-11-28 17:03:05 +08:00
wong
97144e4ebe Merge tag 'v1.1.1' into develop 2025-11-28 16:55:27 +08:00
wong
0cc30e5cb1 Merge branch 'release/v1.1.1' 2025-11-28 16:55:20 +08:00
超级老白兔
eebb73f49e Merge branch 'develop' into yongpxu-dev
# Conflicts:
#	Cunkebao/src/pages/mobile/mine/wechat-accounts/detail/index.tsx   resolved by yongpxu-dev version
2025-11-28 16:52:00 +08:00
超级老白兔
72626e3367 优化AI触发条件,确保只有对方发送的文字消息才会触发AI处理,提升消息处理逻辑的准确性。 2025-11-28 16:50:30 +08:00
wong
07a44e104d 导出表格优化兼容 2025-11-28 16:48:35 +08:00
wong
e4a8975baa 代码提交 2025-11-28 16:44:08 +08:00
超级老白兔
23de3cac7e 新增同步状态提示栏,优化消息列表组件的同步逻辑,支持逐页同步并即时更新UI,提升用户体验和代码可读性。 2025-11-28 16:32:23 +08:00
wong
0244871fc1 好友/群聊迁移优化 2025-11-28 16:04:29 +08:00
wong
5691d78004 朋友圈表格导出 2025-11-28 16:03:56 +08:00
超级老白兔
9e76d39707 移除ToContract组件中的一键转回按钮,调整代码以改善可读性和维护性。 2025-11-28 15:49:35 +08:00
wong
5087190816 代码提交 2025-11-28 15:46:21 +08:00
超级老白兔
ce47856c81 优化消息列表组件,增加加载状态的视觉反馈,支持根据微信号进行会话筛选,并重构相关逻辑以提升用户体验和代码可读性。 2025-11-28 15:33:32 +08:00
wong
a03c162962 111 2025-11-28 15:32:02 +08:00
wong
e658a32244 1 2025-11-27 18:10:23 +08:00
wong
637dcddee2 聊天消息记录状态 + 表格导出底层 2025-11-27 17:09:53 +08:00
超级老白兔
5c7940538d 更新QuickWords组件的默认选项,将活动标签从公共快捷语调整为个人快捷语,以改善用户体验。 2025-11-27 17:07:48 +08:00
超级老白兔
499b36b03b 新增公共快捷语选项并调整部门快捷语标签,优化QuickWords组件的用户体验。 2025-11-27 17:06:20 +08:00
超级老白兔
9e101e924e 新增最终消息同步处理逻辑,确保在消息发送后正确更新消息状态和相关数据。 2025-11-27 17:00:36 +08:00
超级老白兔
10f876f2f6 新增获取群聊成员列表API,优化消息记录组件以支持群聊成员信息展示,调整状态管理以防止跨联系人数据串联。 2025-11-27 16:38:28 +08:00
超级老白兔
ed4d305165 更新数据处理参数类型,调整消息处理逻辑以支持异步数据库同步,确保消息发送时正确传递群聊和个人信息。 2025-11-27 16:06:40 +08:00
超级老白兔
a5cc4e5e18 优化AI消息处理逻辑,区分AI辅助模式与AI接管模式,确保在接管模式下直接发送消息而不经过MessageEnter组件。同时,调整相关组件的状态管理,提升代码可读性和维护性。 2025-11-27 15:07:34 +08:00
超级老白兔
65da14032b 1、发起群聊全选✔ 2025-11-27 10:45:13 +08:00
wong
7e2dd2914d 健康分功能提交 + 微信客服页面改版 2025-11-26 11:17:23 +08:00
超级老白兔
644dd8912d 重构CustomerList组件样式和结构。更新了用户头像样式,以获得在线/离线状态的更好视觉反馈,添加了头像包装以保持布局一致性,并调整了在线指示器的尺寸和颜色。 2025-11-25 16:05:30 +08:00
超级老白兔
d7e08fe420 Merge branch 'yongpxu-dev' into yongpxu-dev2 2025-11-25 15:38:59 +08:00
超级老白兔
cd27506388 cf 2025-11-25 15:37:51 +08:00
超级老白兔
78de6c92b7 新增好友添加任务列表API,优化NavCommon组件,移除未使用的消息处理逻辑,简化代码结构,提升可读性和维护性。 2025-11-25 15:36:43 +08:00
wong
cd41190663 好友添加记录 2025-11-25 14:52:46 +08:00
wong
bbdfdc136b Merge branch 'develop' of https://gitee.com/cunkebao/cunkebao_v3 into develop 2025-11-24 17:19:06 +08:00
wong
5a52b56d89 代码优化 2025-11-24 17:18:49 +08:00
超级老白兔
d8d1003d7a Merge branch 'develop' of https://gitee.com/cunkebao/cunkebao_v3 into develop 2025-11-24 15:38:20 +08:00
超级老白兔
c801490c2f 删除腾讯地图定位服务修复说明文档,更新CustomerList组件样式以支持离线用户状态,调整MessageList组件的加载状态管理,增强filter工具以支持XML格式位置消息的识别。 2025-11-24 15:37:57 +08:00
wong
30b33ec974 朋友圈采集优化 2025-11-24 11:03:31 +08:00
wong
4140e6d3d7 Merge branch 'feature/rating' into develop 2025-11-24 10:14:06 +08:00
wong
1786dec900 代码优化 2025-11-24 10:13:30 +08:00
超级老白兔
bda57a84e8 优化LocationMessage组件,添加经纬度格式化功能,生成静态地图预览图URL,改进位置信息展示,增强用户体验和视觉效果。 2025-11-22 16:15:33 +08:00
超级老白兔
deac306f69 修正SelectMap组件中的经纬度标记顺序,更新XML生成逻辑以确保特殊字符转义,提升地图位置选择的准确性和稳定性。 2025-11-22 15:57:16 +08:00
超级老白兔
43b60a0049 优化SelectMap组件,增强TMap API加载和初始化逻辑,添加API可用性检查,改进标记样式创建和错误处理,提升用户体验和稳定性。 2025-11-22 14:16:40 +08:00
超级老白兔
ab2ee050de 优化SelectMap组件,更新IP定位服务的实现,增强错误处理逻辑,确保用户位置获取更加准确和稳定,同时调整样式以提升用户体验。 2025-11-22 11:53:54 +08:00
超级老白兔
21de87ca32 更新SelectMap组件以使用新版腾讯地图API,优化地图加载和用户位置获取逻辑,增强错误处理和用户体验。 2025-11-22 11:45:53 +08:00
超级老白兔
782031cbc6 增强SelectMap组件,添加用户当前位置获取功能,优化地址解析逻辑和错误处理,改进加载状态显示,提升用户体验。 2025-11-21 19:02:41 +08:00
超级老白兔
6c9551be05 腾讯地图功能锁定 2025-11-21 18:30:12 +08:00
wong
36eb67a217 客服评分体系优化 2025-11-21 17:22:33 +08:00
超级老白兔
7dcbcfacc1 重置一下 2025-11-21 16:33:02 +08:00
超级老白兔
2c9bda734e 重构SelectMap组件,集成腾讯地图API,替换AMap。更新了标记处理和地址检索逻辑,以利用腾讯的地理编码和位置建议服务。增强的错误处理和加载状态,以改善用户体验。 2025-11-21 15:51:50 +08:00
超级老白兔
d296d019e5 Enhance MessageEnter component by adding a map selection feature. Introduced a new button for map visibility and integrated SelectMap component for improved user interaction. 2025-11-21 14:55:56 +08:00
wong
ccf947c64d Merge branch 'release/rating' into develop 2025-11-21 14:47:42 +08:00
wong
3faee0d8be 客服健康分提交 2025-11-21 14:38:29 +08:00
超级老白兔
fe12f78c1d 优化MessageRecord组件的自动滚动逻辑,确保在新消息到达且没有视频状态变化时才滚动到底部,同时修复了对消息长度的引用以提高性能。 2025-11-21 10:34:55 +08:00
超级老白兔
a2b0041490 更新NavCommon组件中的按钮图标和文本,将内容管理按钮的图标更改为SendOutlined,并将其文本更改为“发朋友圈”。同时,调整powerCenter模块中的数据结构,注释掉内容库配置部分,并优化样式代码。更新ContentManagement组件的标题为“发朋友圈”。 2025-11-20 16:50:20 +08:00
wong
235e3ed994 代码优化 2025-11-20 16:18:16 +08:00
wong
4baa82449c Merge branch 'develop' of https://gitee.com/cunkebao/cunkebao_v3 into wong-dev
# Conflicts:
#	Server/composer.json
2025-11-20 16:15:30 +08:00
超级老白兔
84ced0c32a 优化ProfileModules组件中的状态管理,使用选择器函数订阅匹配的客服对象,避免不必要的重新渲染。同时在DetailValue组件中引入useRef进行深度比较,确保只有在值真正变化时才更新编辑状态。 2025-11-20 16:13:57 +08:00
wong
beabe1c191 Merge branch 'develop' of https://gitee.com/cunkebao/cunkebao_v3 into release/friend 2025-11-20 16:12:09 +08:00
wong
719ed98996 代码提交 2025-11-20 16:11:27 +08:00
wong
b0a60e428c 账号评分 2025-11-20 16:07:57 +08:00
超级老白兔
16a8656b49 从消息推送助手任务创建中删除弃用的提示示例,更新推送历史API以使用pushTypeCode和状态,并通过改进的类型处理和UI调整来增强PushHistory组件。 2025-11-20 15:52:05 +08:00
超级老白兔
7fdb993f57 Merge branch 'develop' of https://gitee.com/cunkebao/cunkebao_v3 into develop 2025-11-20 14:59:03 +08:00
超级老白兔
0e56f0808c 在NavCommon组件中实现缓存清除功能,包括localStorage、sessionStorage和IndexedDB。在缓存清除期间添加加载消息并相应地更新菜单选项。 2025-11-20 14:57:18 +08:00
超级老白兔
bd45a9252a 存一下 2025-11-20 14:32:24 +08:00
wong
5a5160b92d 代码优化 2025-11-20 11:48:31 +08:00
wong
3e78122659 composer依赖提交 2025-11-20 11:45:53 +08:00
wong
57d85765c3 1 2025-11-20 10:43:29 +08:00
wong
067ae0fd10 1 2025-11-20 10:36:17 +08:00
wong
bf421e1a49 1 2025-11-19 17:58:54 +08:00
wong
339f06e630 1 2025-11-19 17:53:03 +08:00
wong
367a250fba 代码优化 2025-11-19 15:52:47 +08:00
wong
73110acb37 Merge branch 'develop' of https://gitee.com/cunkebao/cunkebao_v3 into wong-dev 2025-11-19 15:32:43 +08:00
wong
0912a0067e 内容库优化 2025-11-19 15:28:24 +08:00
wong
5faf83e437 内容库优化 2025-11-19 15:02:10 +08:00
超级老白兔
3f76f37a4c 从pnpm-lock.yaml中删除dexie依赖项,并更新PushHistory组件中的列标题,以提高清晰度。 2025-11-19 14:39:03 +08:00
wong
f0574ef555 Merge tag 'v1.1.0' into develop 2025-11-19 10:38:29 +08:00
超级老白兔
304059bef7 Merge branch 'develop'
# Conflicts:
#	.gitignore   resolved by develop version
#	Moncter/.gitignore   resolved by develop version
#	Touchkebao/.gitignore   resolved by develop version
#	Touchkebao/.vite/deps/_metadata.json   resolved by develop version
2025-11-19 10:29:40 +08:00
超级老白兔
c60e361aa3 gogo 2025-11-19 10:27:21 +08:00
wong
273ea73b1b 代码优化 2025-11-19 10:22:19 +08:00
超级老白兔
faae2906b2 Merge branch 'develop' into yongpxu-dev2 2025-11-19 10:17:39 +08:00
超级老白兔
4db65c2cbf Merge branch 'yongpxu-dev' into yongpxu-dev2 2025-11-19 10:06:09 +08:00
超级老白兔
bb2b681ae0 重构充值订单管理:更新OrderList接口以支持灵活的数据类型,增强订单状态处理,并改进订单记录的UI交互。实现付款连续逻辑,并通过更好的状态表示来优化订单详细信息呈现。 2025-11-19 10:04:32 +08:00
超级老白兔
e9aa500800 优化消息推送助手组件中的代码格式,统一导航路径的换行方式,更新描述文本以改善用户体验。 2025-11-19 09:43:06 +08:00
超级老白兔
6eeabe4203 重构ProfileCard组件以支持新的DetailValue组件,优化个人资料和群组信息的编辑逻辑。引入状态管理以处理contract的变化,确保数据一致性。更新样式以改善用户体验,并移除不再使用的状态和逻辑。 2025-11-18 18:02:30 +08:00
超级老白兔
caef9d7d46 增强TwoColumnSelection组件,添加加载更多功能和状态管理,优化好友列表的分页逻辑。重构联系人数据获取逻辑,移除不再使用的状态管理,确保组件性能和用户体验。更新ProfileCard组件以支持新的联系人加载方式。 2025-11-18 14:22:42 +08:00
wong
f7c0679abc 在线更新换位置 2025-11-18 14:14:29 +08:00
wong
fb9e61aafe 数据统计 2025-11-18 14:14:09 +08:00
wong
316cac8149 好友迁移 2025-11-18 14:13:52 +08:00
wong
4ca75d4907 内容库AI提示词 2025-11-18 14:13:08 +08:00
超级老白兔
7d9f9fbd08 feat: 添加成员功能完成 2025-11-18 11:57:54 +08:00
wong
95eed69b66 依赖提交 2025-11-17 17:52:42 +08:00
wong
8fccc61e38 bug优化 2025-11-17 17:34:46 +08:00
超级老白兔
1582e22756 优化MessageRecord组件中的条件渲染逻辑,使用双重否定确保isOwn状态的正确判断。移除多余的换行以简化代码结构。 2025-11-14 18:54:04 +08:00
超级老白兔
4684e880b1 重构聊天消息处理和分页逻辑。为消息记录参数引入一个新的接口,以增强类型安全性。更新获取聊天消息和聊天室消息的API调用,以支持分页。通过删除不必要的刷新触发器和优化会话状态管理来优化MessageList组件。改进加载状态处理,并确保组件之间消息加载行为的一致性。 2025-11-14 18:23:54 +08:00
wong
227fcae39d 代码优化 2025-11-14 18:19:08 +08:00
超级老白兔
8d5869e6c2 /v1/kefu/message/details 2025-11-14 17:09:43 +08:00
超级老白兔
eca5549592 优化SidebarMenu组件的内容渲染逻辑,使用useRef缓存选项卡内容以提高性能。更新联系人状态管理,添加搜索关键词的防抖处理,确保搜索请求不会频繁触发。引入当前用户ID的检查以优化搜索结果的处理。 2025-11-14 16:19:18 +08:00
超级老白兔
01bf7ee271 添加WebSocket状态管理中的活跃状态请求逻辑,防止频繁请求。引入新的状态变量以跟踪最后请求时间,并在发送活跃状态请求时进行时间间隔检查。清理相关状态以确保一致性。 2025-11-14 15:30:00 +08:00
wong
240743c563 创建部门的同时设置其权限 2025-11-14 14:30:20 +08:00
wong
94fa7a8279 代码提交 2025-11-14 14:14:00 +08:00
wong
5715849de5 代码提交 2025-11-14 11:39:20 +08:00
超级老白兔
dbe4ee692c 更新WeChat API以使用新端点,调整获取可转移客服列表的逻辑。重构ProfileCard组件以更改默认活动选项卡为“profile”,并优化状态管理。移除未使用的状态和逻辑,简化代码结构。 2025-11-14 11:00:21 +08:00
超级老白兔
b3924cdb71 优化CreatePushTask组件中的联系人过滤功能,添加基于标签、城市和昵称/备注的过滤模态。更新过滤模态的样式并增强过滤值的状态管理,以改善用户体验。 2025-11-14 10:07:38 +08:00
超级老白兔
c41d8125da 更新ContractData接口以使extendFields可选并修改相关序列化逻辑。增强数据库模式以支持extendFields作为JSON字符串,并确保在数据操作期间进行正确处理。改进ContactManager中的比较逻辑以包含extendFields。 2025-11-13 17:51:22 +08:00
wong
58243d9c17 手动录入表单新增备注功能 2025-11-13 16:11:56 +08:00
wong
3200f09836 订单明细优化 2025-11-13 16:11:19 +08:00
wong
93b4834539 群推送 2025-11-13 16:10:47 +08:00
wong
268da6e47c 文件上传大小修改为50MB 2025-11-13 16:09:09 +08:00
wong
a74f9b9557 优化客服列表(30天没有在线不显示) 2025-11-13 16:08:44 +08:00
wong
dfe4ff076d 新增更新用户扩展字段 2025-11-13 16:08:12 +08:00
超级老白兔
a6ee45f3e3 重构ProfileCard组件以增强选项卡管理并改善用户体验。引入基于可用键的动态选项卡呈现,并更新选项卡标题的样式。调整活动关键帧和渲染关键帧的状态管理。更新QuickWords和ProfileModules集成。修改GroupModal和QuickReplyModal以使用“destroyOnHidden”以获得更好的模式处理。 2025-11-13 16:07:52 +08:00
wong
cec0eff031 数据同步新增设备更新时间及微信更新时间(在线) 2025-11-13 16:06:39 +08:00
超级老白兔
ae4a165b07 重构数据库管理逻辑,简化用户数据库初始化流程。引入新的数据库管理类以支持动态数据库名称和用户状态管理。更新应用启动逻辑以确保在用户登录时正确初始化数据库。增强持久化数据恢复功能,确保用户数据的可靠性和一致性。 2025-11-13 11:58:12 +08:00
wong
bfaf21a180 Merge branch 'develop' of https://gitee.com/cunkebao/cunkebao_v3 into develop 2025-11-12 17:44:42 +08:00
wong
75e35f52ab 修改上传文上限 2025-11-12 17:43:57 +08:00
超级老白兔
eb5dbe5066 重构推送历史记录API以使用新端点并更新响应处理。增强PushHistory组件中的错误处理和分页逻辑,以改善用户体验。 2025-11-12 16:17:29 +08:00
超级老白兔
5da3bc3000 Merge branch 'yongpxu-dev' into yongpxu-dev2 2025-11-12 14:02:01 +08:00
超级老白兔
d6a003c3e2 通过添加AI重写功能增强StepSendMessage组件。为AI重写引入新的状态管理,为内容修改实现新的AiRewrite方法,并更新AI操作按钮的样式。通过加载指示符和验证消息改善用户体验。 2025-11-12 12:30:57 +08:00
超级老白兔
f28f9049d5 重构PushTaskModal和PushTask组件以实现好友和消息发送的默认间隔。增强间隔状态管理,并在联系步骤中集成流量池选择。更新样式以改进布局和用户体验。 2025-11-12 12:21:04 +08:00
超级老白兔
e9994bcd8a Merge branch 'yongpxu-dev' into yongpxu-dev2 2025-11-12 11:40:39 +08:00
超级老白兔
b1b68f4397 Add FloatingVideoHelp component to AppRouter for enhanced user assistance. 2025-11-12 11:40:05 +08:00
超级老白兔
87d1e1c44f 重构PushTask组件以支持用于消息管理的脚本组。引入新的状态变量来处理脚本消息和组,更新消息发送逻辑,并增强用于添加和管理脚本组的UI。清理样式,改善消息输入区的用户体验。 2025-11-11 16:20:46 +08:00
超级老白兔
bb72038e2b Implement contact filtering functionality in CreatePushTask component. Add modal for filtering contacts by tags, cities, and nickname/remark. Update styles for filter modal and enhance state management for filter values. 2025-11-11 11:56:38 +08:00
超级老白兔
2f804c7d40 聊天记录列表优化补齐 2025-11-11 10:26:51 +08:00
超级老白兔
5a287a42ac Refactor CreatePushTask component to streamline account and contact selection process. Update styles for layout consistency, enhance user experience with improved step indicators, and simplify state management for selected accounts and contacts. 2025-11-10 18:08:53 +08:00
超级老白兔
d940d36123 Refactor styles and structure for account selection in CreatePushTask component. Update account list display to use a grid layout, enhance account card styling, and improve status indicators for online/offline status. Implement customer list fetching logic on component mount. 2025-11-10 15:55:14 +08:00
超级老白兔
a8b0add92b Merge branch 'yongpxu-dev' into develop 2025-11-08 18:05:15 +08:00
超级老白兔
49d8c4f818 Enhance PopChatRoom component to include a modal for entering chatroom name before group creation, update page size to 10, and improve state management for selected contacts and loading status. 2025-11-08 17:57:28 +08:00
wong
674bbe1c3e 代码提交 2025-11-08 17:29:33 +08:00
超级老白兔
daf504d5fd Add dropdown menu in SidebarMenu for adding friends and creating group chats, including modals for each action 2025-11-08 17:00:40 +08:00
超级老白兔
d722c03744 Add a primary button with a Plus icon to the SidebarMenu and adjust styles for better layout 2025-11-08 16:16:32 +08:00
超级老白兔
6eddf2f6db 同步 2025-11-08 16:02:16 +08:00
超级老白兔
02398e9ced Merge branch 'yongpxu-dev' of https://gitee.com/cunkebao/cunkebao_v3 into yongpxu-dev
# Conflicts:
#	Moncter/app/controller/UserController.php   resolved by yongpxu-dev version
2025-11-08 16:02:05 +08:00
超级老白兔
35c9369d3d Refactor IndexController to return a simple message instead of an iframe. Update AudioRecorder and SimpleFileUpload components to include file name in the upload callback. Modify MessageEnter component to handle new file structure and improve message handling logic. Clean up unused state and enhance video message rendering. Update websocket message management to handle message IDs more robustly. 2025-11-08 15:13:20 +08:00
wong
018a6162da 1 2025-11-08 14:17:10 +08:00
wong
b46c808aa8 代码提交 2025-11-07 17:57:18 +08:00
超级老白兔
921ce713fa 基础数据库建设,数据中心对接数据库 2025-11-07 15:40:33 +08:00
wong
cf75ee4150 代码提交 2025-11-07 15:25:50 +08:00
超级老白兔
a997734c5c 添加 go.sh 脚本以自动执行 PHP 脚本并处理权限检查 2025-11-07 11:31:14 +08:00
超级老白兔
f9c08b6091 重构状态管理:将 useWeChatStore 更名为 useDataCenterStore,并更新相关引用 2025-11-06 18:08:49 +08:00
wong
8daa0a5d5c 门店端优化 2025-11-06 10:34:13 +08:00
超级老白兔
a3af9de4a9 Update typeId in login parameters to a fixed value for consistency in Login component. 2025-11-06 10:21:53 +08:00
超级老白兔
e467a8e6e0 Add typeId to login parameters for session verification in Login component. 2025-11-06 10:20:39 +08:00
wong
46c67e3bfd Merge branch 'develop' of https://gitee.com/cunkebao/cunkebao_v3 into develop 2025-11-05 16:06:02 +08:00
wong
a6e39c32c1 代码优化 2025-11-05 16:05:45 +08:00
超级老白兔
fa802b50ad Add 404 Not Found route to the router configuration to handle unmatched paths. 2025-11-05 10:37:39 +08:00
超级老白兔
e163ada783 Merge branch 'develop' into yongpxu-dev 2025-11-04 19:34:12 +08:00
超级老白兔
888e2b376a Merge branch 'yongpxu-dev' into yongpxu-dev2 2025-11-04 19:33:36 +08:00
wong
adc22c7d19 代码提交 2025-11-04 17:48:51 +08:00
超级老白兔
ac605baa24 Refactor TrafficDistributionForm component to improve state management and error handling. Update time range parsing logic for better validation and user feedback. Adjust form submission handling and enhance device selection logic. Modify slider maximum value for daily distribution limits. 2025-11-04 16:40:53 +08:00
超级老白兔
05c5915e7b Add description field to PowerPackage interface and update UI to display package descriptions. Enhance styles for description tags in Buy Power component. 2025-11-04 15:09:09 +08:00
wong
a4060fec1b 代码提交 2025-11-03 14:42:16 +08:00
wong
469ab4a085 门店端优化 2025-11-03 14:07:15 +08:00
wong
367a76a54f 代码提交优化 2025-11-03 14:06:58 +08:00
超级老白兔
998e65d98d Update WebSocket configuration to use environment variable for URL instead of hardcoded value. 2025-11-03 10:31:31 +08:00
超级老白兔
a8ba45c08a Merge branch 'yongpxu-dev' of https://gitee.com/cunkebao/cunkebao_v3 into yongpxu-dev 2025-11-03 10:11:16 +08:00
超级老白兔
055b300c5a Update API URLs in development and production environment files to new server endpoints for consistency across environments. 2025-11-03 10:11:12 +08:00
超级老白兔
baf389ec65 Merge branch 'yongpxu-dev' into yongpxu-dev2 2025-11-03 10:04:09 +08:00
超级老白兔
ca7a2e954f Implement power statistics API and enhance Power Management component. Add new Statistics interface and update UI to display formatted usage data. Adjust styles for better readability. 2025-10-31 16:32:04 +08:00
超级老白兔
eada5fe8b1 Refactor AIKnowledgeDetail and AIKnowledgeList components to improve user navigation and search functionality. Update deletion logic to navigate back on success and enhance search with debouncing and keyword handling. Adjust API to support keyword filtering in fetchKnowledgeBaseList. 2025-10-31 16:18:12 +08:00
超级老白兔
fe347965ff Enhance FileUpload component to support additional file types including PDF, TXT, MD, MP4, and AVI. Refactor file type handling logic for improved accuracy and user feedback. Update styles in AIKnowledgeDetail for better layout and user experience, including new sections for prompt rules and independent prompts. 2025-10-31 15:46:51 +08:00
超级老白兔
8d017ed2cb Integrate FileUpload component for material uploads in AIKnowledgeDetail. Update upload logic to handle file types and improve user feedback on upload success or failure. Adjust tab rendering order for better clarity. 2025-10-30 17:04:11 +08:00
超级老白兔
eafca9ae85 Replace custom close button in GlobalPromptModal with Ant Design's CloseOutlined icon for improved consistency and user experience. Simplify the onClose functionality while maintaining existing styles. 2025-10-30 16:44:17 +08:00
超级老白兔
990c7a2693 Refactor API interactions in GlobalPromptModal to utilize new initGlobalPrompt and saveGlobalPrompt functions. Update modal logic to handle prompt configuration more effectively, removing deprecated state management for enabling prompts. Enhance user experience with improved input handling and feedback mechanisms. 2025-10-30 16:42:42 +08:00
超级老白兔
da87f9a865 Refactor GlobalPromptModal to use antd-mobile Popup for improved mobile experience. Update styles for modal footer and enhance user feedback with Toast notifications. Remove deprecated Ant Design Modal components and adjust layout for better usability. 2025-10-30 16:26:15 +08:00
超级老白兔
515c85e600 Enhance Buy Power and Recharge components with loading states and pagination. Update styles for better layout and introduce new pagination UI in the Power Management section. Remove outdated AI knowledge interface documentation. 2025-10-30 16:08:43 +08:00
超级老白兔
6b3948d454 Refactor Power Management component to enhance user experience with improved power package and consumption record management. Introduce new API interfaces for power statistics and consumption records, and update UI elements for better navigation and interaction. 2025-10-30 15:26:48 +08:00
wong
e3afa24795 代码优化 2025-10-30 11:41:22 +08:00
wong
903a29ed09 app更新提示 2025-10-30 10:58:45 +08:00
超级老白兔
6a64e3854c Refactor Recharge component to support custom recharge amounts and quick selection options. Remove version package data and enhance payment handling with improved user feedback. Add AI knowledge management routes and UI elements in the workspace section. 2025-10-29 17:49:51 +08:00
超级老白兔
0d1d082d9e Add manual AI response generation feature in MessageEnter component. Implement handleManualTriggerAi function to allow users to trigger AI replies on demand. Update weChat store with manualTriggerAi function to manage AI request logic and context retrieval. Enhance UI with a reload button for AI responses in AI modes. 2025-10-29 16:56:44 +08:00
wong
8ae8e66a3a 代码优化 2025-10-29 15:48:48 +08:00
wong
f684c4cb3f 代码提交 2025-10-29 15:31:43 +08:00
超级老白兔
44a8fbe0c9 用户操作绝对优先 - 任何用户行为立即打断AI
唯一ID验证 - 防止过期回复覆盖
状态互斥保护 - AI生成 ⇄ 用户输入互斥
智能防抖 - 3秒延迟合并多条消息
2025-10-29 15:21:27 +08:00
超级老白兔
9c5e253d75 Refactor MessageEnter component to streamline AI message handling. Update message sending logic to prioritize passed content, ensuring better integration with AI-assisted and AI takeover modes. Clean up unused code and enhance console logging for improved debugging. 2025-10-29 14:53:15 +08:00
超级老白兔
5fb15592ff Refactor MessageEnter component to handle AI-assisted and AI takeover scenarios. Update weChat store to support multiple AI types for message processing. Remove unnecessary console log in message response handler for cleaner output. 2025-10-29 14:50:55 +08:00
wong
da8bcb04c9 免密登录代码提交 2025-10-29 11:48:02 +08:00
wong
1862b11c0d 修复bug 2025-10-29 10:52:44 +08:00
wong
942f08bbf2 111 2025-10-29 10:38:11 +08:00
wong
175c78c3d0 数智员工免密登录 2025-10-29 10:30:50 +08:00
超级老白兔
0decc34593 Enhance file upload process in devlop.py with progress tracking and remote file validation. Add aiType field to weChatGroup and ContractData interfaces for AI type differentiation. Update ChatWindow component to handle AI configuration changes and ensure proper database updates for contact and message management. Implement database versioning to include aiType in chatSessions and contactsUnified tables, with migration logic for existing data. Improve error handling and user feedback during configuration updates. 2025-10-28 16:55:55 +08:00
wong
18a7055a4e 消息新增ai类型字段 2025-10-28 16:46:38 +08:00
超级老白兔
5638d8c66a Merge branch 'yongpxu-dev' into yongpxu-dev2 2025-10-28 14:32:37 +08:00
wong
1644e478c7 AI对话功能优化 2025-10-28 09:25:39 +08:00
超级老白兔
d1c35b480f Merge branch 'yongpxu-dev' into yongxu-dev3 2025-10-27 17:13:24 +08:00
超级老白兔
3d8c656224 加载动画优化 2025-10-27 17:08:37 +08:00
超级老白兔
364a52b553 Remove Dexie database implementation and related initialization logic. Update Recharge component to fetch and display subscription packages dynamically, enhancing user experience with improved payment handling and UI updates. 2025-10-27 17:07:10 +08:00
超级老白兔
8cff6750f9 Implement AI loading animation in MessageEnter component and enhance user interface. Remove unused loading icon and streamline input area for better user experience during AI response generation. 2025-10-27 16:57:26 +08:00
超级老白兔
d01c91e6ee 只有文字消息才会触发ai回复 2025-10-27 15:49:52 +08:00
超级老白兔
e1893e1506 增加消息类型 2025-10-27 15:45:07 +08:00
超级老白兔
ae4b592bb6 转给他人逻辑处理,包括关闭和删除联系人、联系会话 2025-10-27 15:38:01 +08:00
超级老白兔
c65001399f 完整的wechatAccountId处理
接口查询获取
字段映射兜底(accountId)
保证每个会话都有正确的账号ID
 头像正确显示
好友:avatar 字段
群聊:chatroomAvatar 字段
统一存储到 ChatSession.avatar
 三层兜底机制
从联系人表查询(最快)
从接口获取详情(完整)
使用消息数据创建(兜底)
 数据持久化
联系人数据存入 contactsUnified 表
会话数据存入 chatSessions 表
下次收到消息直接从本地读取
 静默更新机制
所有数据库操作在后台完成
通过 triggerRefresh() 触发UI更新
用户体验流畅无感知
2025-10-27 15:30:27 +08:00
超级老白兔
494ccbbe5e 修复消息列表 2025-10-27 14:49:05 +08:00
超级老白兔
8b28194d00 优化头像兼容 2025-10-27 11:48:22 +08:00
超级老白兔
3ff3e40d8e Enhance MessageList component to include complete contact information during message updates. Implement a new method in ContactManager for retrieving contacts by ID and type, ensuring accurate avatar and nickname display. Trigger UI refresh on data changes to improve user experience. 2025-10-27 11:43:35 +08:00
超级老白兔
77072594d2 Add debug logging for quote message content and session selection in MessageEnter and MessageList components. Update WeChat store to handle empty message content gracefully, improving error handling during message reception. 2025-10-27 11:11:24 +08:00
超级老白兔
3c2fec2122 Refactor MessageRecord component to replace ckchat store with customer store for improved data handling. This change enhances the retrieval of customer information based on the wechatAccountId, streamlining the message processing logic. 2025-10-27 10:38:39 +08:00
超级老白兔
f58070495f Refactor WeChat store logic to enable AI chat processing. Reintroduce data processing and AI chat request handling, improving message handling flow and user experience. 2025-10-27 10:00:32 +08:00
超级老白兔
51c60c55b0 Merge branch 'develop' into yongpxu-dev 2025-10-27 09:55:09 +08:00
超级老白兔
781662026a 优化消息过滤逻辑,新增对语音消息的处理条件,支持通过URL和持续时间判断,同时增强对特殊格式消息的识别,提升代码可读性和用户体验。 2025-10-25 19:15:00 +08:00
超级老白兔
422fed2719 新增音频转文字功能,更新相关API和组件逻辑,优化消息处理流程,提升用户体验和代码可读性。 2025-10-25 19:11:08 +08:00
超级老白兔
27a108027b 移除MessageList组件中的调试日志,新增通过ID查找消息的功能,优化消息处理逻辑,提升代码可读性和用户体验。 2025-10-25 19:00:20 +08:00
超级老白兔
5f1a1e9f0e 新增消息序列号支持,优化消息发送和接收逻辑,更新消息状态处理,提升代码可读性和用户体验。 2025-10-25 18:42:17 +08:00
wong
aa3c07a0b2 ai对话功能提交 2025-10-25 17:41:20 +08:00
超级老白兔
e409618b7a 增强SidebarMenu和MessageList组件,新增对currentContact变化的监听,自动切换聊天tab并显示加载状态,优化消息列表的加载逻辑,提升用户体验和代码可读性。 2025-10-24 17:46:44 +08:00
超级老白兔
7d8573b52a 优化联系人分组统计逻辑,分别提取好友和群组标签ID以提高准确性,更新相关注释以增强代码可读性,同时调整数据库查询条件以支持更灵活的分组查询。 2025-10-24 17:20:09 +08:00
超级老白兔
28cbcea4f9 重构数据库管理逻辑,新增旧数据库清理功能,优化数据库初始化流程,更新联系人管理和消息处理逻辑,提升代码可读性和用户体验。 2025-10-24 16:14:13 +08:00
超级老白兔
e1d4f678ab 重构MessageRecord组件,更新样式文件引用,优化消息转发逻辑,新增消息过滤功能以提升用户体验和代码可读性。 2025-10-24 14:44:25 +08:00
超级老白兔
bb6453d3a2 重构加载更多功能,更新样式和逻辑,优化联系人列表组件的加载状态处理,提升用户体验和代码可读性。 2025-10-24 12:01:01 +08:00
超级老白兔
1b02666531 增强SidebarMenu和MessageList组件,新增对currentContact变化的监听,自动切换聊天tab,优化联系人点击处理逻辑,调整置顶标识为数字类型,提升代码可读性和用户体验。 2025-10-24 11:28:01 +08:00
超级老白兔
3b82908e8a 重构SidebarMenu组件,移除不必要的useEffect,优化消息列表和联系人组件的加载逻辑,合并样式文件以提升代码可读性和维护性。 2025-10-23 20:42:29 +08:00
超级老白兔
8941b87e03 优化消息列表组件,更新刷新状态提示样式,提升用户体验和可读性。 2025-10-23 20:18:45 +08:00
超级老白兔
1f081cdddc 重构联系人分组逻辑,新增获取分组统计信息和分页获取联系人功能,优化联系人列表组件以提升用户体验和代码可读性。 2025-10-23 20:15:59 +08:00
超级老白兔
dc58109829 重构联系人管理逻辑,新增联系人状态管理和数据同步功能,优化联系人列表组件以提升用户体验和代码可读性。 2025-10-23 19:56:57 +08:00
超级老白兔
3b36b19d01 更新TypeScript配置和Vite配置,新增模块路径别名支持,同时优化数据库初始化逻辑,提升代码可读性和结构。 2025-10-23 18:56:16 +08:00
超级老白兔
26af225fff 优化消息排序逻辑,更新生成排序键的注释,明确置顶标识、时间戳和显示名称的处理方式,提升代码可读性。 2025-10-23 18:00:07 +08:00
超级老白兔
1c9f986a97 优化消息列表组件,更新已读标记逻辑,确保仅更新未读数量而不影响时间和排序,提升代码可读性。 2025-10-23 17:30:30 +08:00
超级老白兔
7056e00fcc 更新消息列表组件,新增当前客户状态管理,优化消息筛选逻辑以提升用户体验和代码可读性。 2025-10-23 17:21:25 +08:00
超级老白兔
5c86c2fbf2 优化消息排序逻辑,调整置顶和时间戳的处理方式,以确保置顶消息优先显示,提升消息列表的可读性和用户体验。 2025-10-23 17:14:48 +08:00
超级老白兔
7f4bc0487e 新增消息列表API,优化消息列表组件以支持加载状态和数据同步,提升用户体验和代码可读性。 2025-10-23 17:02:33 +08:00
超级老白兔
75e62cce72 优化消息管理逻辑,新增消息状态管理功能,提升代码结构和可读性。 2025-10-23 15:51:05 +08:00
wong
a5b1861e7d 性能优化 2025-10-23 14:12:40 +08:00
超级老白兔
68a5350c19 移除未使用的客服列表相关代码,优化消息管理逻辑,新增消息状态管理功能,提升代码结构和可读性。 2025-10-23 12:55:57 +08:00
超级老白兔
81f225d9cb 更新TypeScript配置以支持新的模块路径别名,重命名获取客服列表的API函数,替换相关组件,移除不再使用的垂直用户列表组件及其样式,提升代码结构和可读性。 2025-10-23 12:35:30 +08:00
wong
268aedbb6e 代码统一大小写 2025-10-23 09:51:43 +08:00
wong
c2dce8344b 代码提交 2025-10-23 09:34:43 +08:00
超级老白兔
ef45bedf83 新增AI对话加载状态管理,优化消息输入组件以支持加载指示,提升用户体验。 2025-10-22 17:05:35 +08:00
超级老白兔
35b38e8542 Merge branch 'yongpxu-dev' into develop 2025-10-22 16:36:17 +08:00
超级老白兔
c3f1433868 新增AI对话和数据处理接口,优化消息发送逻辑以支持群组和个人消息的处理,提升聊天功能的灵活性和用户体验。 2025-10-22 16:36:02 +08:00
超级老白兔
f137bd2c07 优化消息列表组件,新增消息内容展示和时间格式处理逻辑,更新API以支持分页,提升用户体验和代码可读性。 2025-10-22 15:32:53 +08:00
超级老白兔
5b9ae2b805 优化消息列表组件,新增消息内容展示,调整消息时间格式处理逻辑,更新获取消息列表的API以支持分页,提升用户体验和代码可读性。 2025-10-22 15:28:03 +08:00
超级老白兔
eef514bea1 Merge branch 'yongpxu-dev' into develop 2025-10-22 10:43:36 +08:00
wong
9be85c4c2d 代码优化 2025-10-22 10:42:37 +08:00
超级老白兔
17e81cafc2 更新内容管理模块,调整数据结构以使用更具描述性的字段名,移除不再使用的备注输入,优化定时发布功能的时间格式处理,提升用户体验和代码可读性。 2025-10-22 10:41:19 +08:00
超级老白兔
b6b1d581a3 1 2025-10-22 10:03:25 +08:00
wong
7db48facbd 表单提交功能优化 2025-10-22 09:55:49 +08:00
wong
0958c5f9c7 消息接收数据 2025-10-21 16:48:00 +08:00
wong
7475dbd07c 代码提交 2025-10-21 16:46:55 +08:00
wong
19734415f0 【门店端 - AI数智员工】 代码优化 2025-10-21 11:06:53 +08:00
wong
252d02e7b9 【触客宝】内容管理代码优化 2025-10-21 11:05:57 +08:00
超级老白兔
64ad480bbb 重构内容管理模块,移除不再使用的管理组件和模态框,优化样式布局,新增发布和计划功能组件,提升用户体验和界面一致性。 2025-10-20 15:36:32 +08:00
超级老白兔
4df670d1c9 重构流量池表单组件:添加预设方案选择功能,优化用户数据生成逻辑,增强提交状态管理,提升用户体验和代码可维护性。 2025-10-20 15:04:41 +08:00
wong
52f4a2b1e1 代码提交 2025-10-20 14:52:10 +08:00
wong
527d5341db 代码提交 2025-10-20 14:22:20 +08:00
超级老白兔
a775596719 优化流量池列表样式:调整卡片内边距和菜单按钮位置,提升布局美观性和用户体验。 2025-10-17 18:24:50 +08:00
超级老白兔
3fbf54df99 移除流量池列表样式:删除不必要的样式规则,简化代码结构,提升可维护性和用户体验。 2025-10-17 18:22:38 +08:00
超级老白兔
fbb78ebd50 移除流量池详情及相关组件:删除流量池详情页面、API、数据类型和样式文件,简化代码结构,提升可维护性和用户体验。 2025-10-17 18:18:17 +08:00
wong
87bf284943 代码提交 2025-10-16 16:04:53 +08:00
wong
d319264349 数据同步 2025-10-16 15:36:44 +08:00
超级老白兔
3230bbe2e5 重构流量池模块:更新路由配置,移除流量池列表组件及相关API和样式文件,简化代码结构,提升可维护性和用户体验。 2025-10-16 14:13:36 +08:00
超级老白兔
fc5ae31b2b 优化流量池列表样式:重构样式文件,增加卡片样式和布局,提升视觉效果和用户体验;更新组件逻辑,简化代码结构,增强可维护性。 2025-10-16 14:11:26 +08:00
wong
8bf6cbe1d4 代码提交 2025-10-16 11:42:59 +08:00
wong
1083822513 代码提交 2025-10-16 10:59:08 +08:00
wong
db22100846 代码同步 2025-10-15 16:39:10 +08:00
超级老白兔
d751bbfcd4 优化会话置顶功能,更新状态切换逻辑并添加删除会话功能;新增样式以突出置顶会话,提升用户体验。 2025-10-15 15:50:31 +08:00
超级老白兔
ceffea4c5b 重构流量池模块:更新API接口,优化数据结构,移除不必要的组件,简化代码逻辑,提升可维护性和用户体验。 2025-10-15 15:47:34 +08:00
超级老白兔
a716315311 新增右键菜单功能,支持会话置顶、删除和修改备注操作;更新样式以提升用户交互体验,优化会话信息展示逻辑。 2025-10-15 15:04:48 +08:00
超级老白兔
edf5abcec9 新增消息记录组件对特定消息类型的处理逻辑,支持解析JSON格式内容并优先显示解析后的内容;优化消息过滤条件,确保正确展示消息记录。 2025-10-15 14:37:24 +08:00
wong
d26e5a324d 代码提交 2025-10-15 14:08:56 +08:00
超级老白兔
0275eea6e7 优化聊天会话排序逻辑:新增按置顶状态排序功能,优先显示置顶会话,其次按未读消息数量和显示名称排序,提升用户体验。 2025-10-15 14:08:53 +08:00
超级老白兔
7091adb6a0 更新 weChatGroup 接口,新增 top 字段为可选项,调整 unreadCount 字段为可选;修改 getNewContractList 方法返回类型为 Promise;新增 addCtrlUser 方法以控制终端用户;修复 deleteChatSession 方法参数类型为 number。 2025-10-15 10:49:44 +08:00
wong
f11bc7f686 好友数据同步优化 2025-10-15 10:47:48 +08:00
超级老白兔
3b0b83aae1 删除流量池相关组件:移除BatchAddModal、DataAnalysisPanel、FilterModal及其相关逻辑,简化代码结构,提升维护性。 2025-10-15 10:16:12 +08:00
超级老白兔
038c4149d8 更新聊天窗口和消息列表组件,优先显示用户备注名(conRemark)而非昵称,提升用户信息展示的准确性。 2025-10-14 18:20:51 +08:00
超级老白兔
811ebff52f 新增用户列表数据字段,更新导航组件图标和功能,优化内容管理界面,调整微信页面加载逻辑,移除ProfileCard组件中的调试信息。 2025-10-14 18:13:38 +08:00
wong
8908da5baf 代码提交 2025-10-14 17:45:03 +08:00
wong
204791075e Merge branch 'develop' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into develop 2025-10-14 17:03:27 +08:00
wong
da63930f5e 代码提交 2025-10-14 17:03:05 +08:00
超级老白兔
892e82c1d6 修复未读消息计数逻辑:将未读消息计数从 session.unreadCount 移动到 session.config.unreadCount,确保消息状态正确更新。 2025-10-14 15:29:17 +08:00
超级老白兔
806df16a0b 新增系统推荐备注消息组件,并在消息记录中处理该消息类型;优化未读消息计数逻辑,确保正确显示。 2025-10-14 14:34:50 +08:00
超级老白兔
077f4fd488 Merge branch 'yongpxu-dev' into develop 2025-10-14 10:05:32 +08:00
超级老白兔
0b30cc3ae7 gogogo 2025-10-14 10:05:19 +08:00
超级老白兔
b31e1a47f0 新增快捷回复功能:引入WebSocket支持,优化快捷语发送逻辑,增加发送确认预览,提升用户体验和代码可读性。 2025-10-13 17:28:51 +08:00
超级老白兔
7c36100553 重构快捷语组件:引入Layout组件,优化界面结构和样式,提升用户体验和代码可读性。 2025-10-13 17:23:31 +08:00
wong
f2c25927eb 客服朋友圈配置信息 2025-10-13 17:00:03 +08:00
wong
6e2fc369e2 客服端 内容管理功能 2025-10-13 16:14:33 +08:00
超级老白兔
57f2e0d649 重构快捷语管理模块:新增快捷回复和分组管理功能,优化数据展示和交互逻辑,提升用户体验和代码可读性。 2025-10-13 14:52:10 +08:00
wong
381eb37f1a 代码提交 2025-10-13 11:36:45 +08:00
超级老白兔
2c46cb956f 优化客户管理模块:调整标签页样式,重构联系人展示为表格形式,提升用户体验和代码可读性。 2025-10-11 15:54:39 +08:00
超级老白兔
31c7980a9a 优化客户管理模块:更新标签页样式,调整按钮组件,重构联系人展示为表格形式,提升用户体验和代码可读性。 2025-10-11 15:49:05 +08:00
超级老白兔
b067134ae7 新增聊天记录搜索功能:在聊天窗口中引入ChatRecordSearch组件,优化消息输入区域,更新状态管理以支持聊天记录模型的显示与隐藏,提升用户体验和代码可读性。 2025-10-10 15:45:28 +08:00
超级老白兔
be5a848342 更新功能中心模块:重构KPI统计区域,优化数据展示和样式,提升用户体验和代码可读性。 2025-10-10 14:38:35 +08:00
超级老白兔
1f3d39a1bd 重构功能中心模块:更新功能卡片数据结构,新增KPI统计区域,优化样式和布局,提升用户体验和代码可读性。 2025-10-09 15:42:46 +08:00
wong
e96c65c1ab 代码提交 2025-10-09 15:36:46 +08:00
wong
80495c3594 [] 算力扣款记录优化 2025-09-30 16:10:43 +08:00
wong
1667e5240d 算力套餐列表优化 2025-09-30 16:00:19 +08:00
wong
afb8ba0ef3 套餐优惠计算 2025-09-30 15:20:18 +08:00
wong
ddc3e855d4 支付回调优化 2025-09-30 14:47:26 +08:00
wong
d8f5771dcb 代码提交 2025-09-30 10:47:14 +08:00
wong
5313bc6a18 代码提交 2025-09-30 10:36:51 +08:00
wong
ff7b583f07 算力功能提交 2025-09-29 17:37:21 +08:00
wong
e1fce63876 消息提醒功能优化 2025-09-29 17:36:59 +08:00
超级老白兔
85149e5af0 优化导航组件:新增消息列表功能,定时获取未读消息数量,支持标记消息为已读和全部已读,提升用户体验和代码可读性。 2025-09-29 17:12:17 +08:00
超级老白兔
713956aa4f 更新关键词管理模块:调整关键词请求参数,优化关键词列表的获取逻辑,移除本地筛选功能,改为服务端搜索,提升代码可读性和用户体验。 2025-09-29 16:38:36 +08:00
wong
0da8a75fbe bug修复 2025-09-29 11:57:35 +08:00
wong
4a946062b3 bug修复 2025-09-29 11:57:17 +08:00
wong
5f0c1c8b97 代码优化 2025-09-29 11:46:37 +08:00
wong
0e6b885095 消息中心提交 2025-09-29 11:34:01 +08:00
超级老白兔
f5480bdc58 更新关键词管理模块:新增素材选择功能,优化回复类型切换逻辑,提升用户体验和代码可读性。 2025-09-29 11:05:52 +08:00
wong
5102f02083 消息提醒提交 2025-09-29 09:44:43 +08:00
超级老白兔
e38b0fde51 更新敏感词管理模块:将状态参数类型从字符串改为数字,优化状态切换逻辑,提升代码可读性和类型安全性。 2025-09-28 18:22:17 +08:00
超级老白兔
340f074f01 调整右侧区域的布局样式:移除flex-direction属性以简化样式定义,提升代码可读性。 2025-09-28 18:11:40 +08:00
超级老白兔
cb0256c820 优化素材管理模块:重构数据获取逻辑,使用useRef存储分页状态,简化fetchMaterials函数,提升代码可读性和性能。 2025-09-28 18:11:00 +08:00
超级老白兔
ed43e67047 添加分页功能到关键词、素材和敏感词管理模块:引入Pagination组件,更新请求参数以支持分页,优化数据获取逻辑,提升用户体验。 2025-09-28 18:08:50 +08:00
wong
a923615190 bug修改 2025-09-28 18:06:18 +08:00
超级老白兔
d8074502e0 重构关键词管理模块:更新关键词和敏感词的请求参数类型为数字,增强类型安全性;优化关键词管理界面,改进状态切换和删除功能,增加确认删除的弹窗,提升用户体验。 2025-09-28 17:41:01 +08:00
超级老白兔
1bd3883b18 更新敏感词管理模块:将操作类型参数类型从字符串改为数字,以提高类型安全性和代码可读性。 2025-09-28 16:37:58 +08:00
超级老白兔
0ae2265c50 更新敏感词管理模块:将敏感词管理组件转换为使用forwardRef,增强与父组件的交互能力;修复敏感词状态更新接口的请求方法;优化删除功能,增加确认删除的弹窗;改进敏感词详情获取逻辑,提升用户体验。 2025-09-28 16:36:17 +08:00
超级老白兔
9fa09bb743 Merge branch 'yongpxu-dev' into develop 2025-09-28 16:04:44 +08:00
超级老白兔
c90628a71f 重构关键词管理模块:将关键词管理组件转换为使用forwardRef,增强与父组件的交互能力;优化关键词列表的获取和处理逻辑,提升用户体验。 2025-09-28 16:04:32 +08:00
wong
7b3df95152 修复微信管理数据展示问题 2025-09-28 16:02:03 +08:00
wong
372847f398 修复群成员及好友数据展示问题 2025-09-28 16:01:31 +08:00
wong
f9dd2c6bd6 允许上传ppt格式的文件 2025-09-28 16:00:51 +08:00
wong
34083441d4 修复内容管理素材无法上传的问题 2025-09-28 16:00:28 +08:00
wong
8796ec5fbc 路由提交 2025-09-28 15:59:56 +08:00
超级老白兔
c6639a8259 增强文件和视频上传功能:添加上传成功和失败的反馈信息,检查响应状态以确保上传结果的准确性;更新素材管理模块,优化删除和编辑功能,增加确认删除的弹窗,提升用户体验。 2025-09-28 15:38:06 +08:00
超级老白兔
3b063ff64c 移除冗余文件并重构内容管理模块:删除技术栈和兼容性说明文档,移除多个模态框组件,整合管理组件为统一结构,优化代码组织,提升可维护性。 2025-09-28 14:52:05 +08:00
wong
ef71d83321 代码同步 2025-09-28 10:17:42 +08:00
超级老白兔
a73481808c 同步 2025-09-27 16:59:30 +08:00
超级老白兔
8ff912a4a7 更新接待設置功能:修改API請求路徑以支持新的流量池設置,新增批量設置功能並優化用戶界面,添加空狀態提示以提升用戶體驗。 2025-09-26 17:33:36 +08:00
超级老白兔
c22ab933c7 更新小程序鏈接:將鏈接中的頁面路徑從「input」更改為「input2」,以反映最新的功能需求。 2025-09-26 17:14:11 +08:00
wong
31354272e7 代码提交 2025-09-26 17:06:14 +08:00
超级老白兔
0b50724b2f 調整Ckbox頁面標題及優化CommonConfig組件:將標題更改為「觸客寶」,並重構標籤頁內容顯示邏輯,新增佔位符以顯示未開發功能,提升用戶體驗。 2025-09-26 17:00:26 +08:00
超级老白兔
43209882e4 新增待辦事項相關API接口及聊天窗口功能:在API中添加待辦事項列表、添加和處理功能,並在聊天窗口中整合好友ID以支持待辦事項管理,提升用戶互動體驗。 2025-09-26 16:41:48 +08:00
超级老白兔
5ea49ef6f1 新增跟進提醒相關API接口及聊天窗口功能:在API中添加跟進提醒列表、添加和處理功能,並在聊天窗口中整合好友ID以支持提醒功能,提升用戶互動體驗。 2025-09-26 16:31:32 +08:00
超级老白兔
7699397bda 新增跟進提醒和待辦事項模態框功能:在聊天窗口中添加相應的狀態管理和事件處理,提升用戶互動體驗。 2025-09-26 16:13:02 +08:00
超级老白兔
31217c6fd7 新增聊天窗口擴展功能:在樣式中添加擴展區域,並在聊天窗口中新增「跟進提醒」和「待辦事項」按鈕,提升用戶互動性。 2025-09-26 15:42:18 +08:00
wong
acabbf30da 自动问候功能提交 2025-09-26 15:37:15 +08:00
超级老白兔
adc5dd1742 優化導航組件:調整按鈕顯示內容,新增用戶信息顯示,並在樣式中增加間距設置,提升用戶界面友好性。 2025-09-26 15:36:52 +08:00
超级老白兔
0b398b372e 簡化ProfileCard組件的屬性,移除不必要的onToggleProfile回調,優化個人資料顯示邏輯。 2025-09-26 15:08:44 +08:00
超级老白兔
1d5d46c9ce 優化個人資料顯示邏輯:移除不必要的onToggleProfile回調,簡化ProfileCard組件的屬性,並調整按鈕顯示內容。 2025-09-26 15:06:39 +08:00
超级老白兔
0beeb15245 修正API請求方法:將getChatMessages函數中的request方法替換為request2,以統一請求處理方式。 2025-09-26 14:57:11 +08:00
超级老白兔
43b63908b5 修正API請求方法:將clearUnreadCount和updateConfig函數中的request方法替換為request2,以統一請求處理方式。 2025-09-26 14:56:53 +08:00
超级老白兔
c40d3fe044 Merge branch 'yongpxu-dev' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into yongpxu-dev 2025-09-26 14:56:45 +08:00
超级老白兔
52c93b80f6 feat(微信功能加載優化): 在微信功能中新增isLoadWeChat狀態管理,優化聯絡人及群列表的加載邏輯,根據狀態決定數據來源,提升性能與用戶體驗。 2025-09-26 14:55:39 +08:00
超级老白兔
30fd27e570 Merge branch 'yongpxu-dev' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into yongpxu-dev 2025-09-26 14:35:44 +08:00
超级老白兔
6d7c5202c2 Merge branch 'yongpxu-dev' into yongxu-dev3 2025-09-26 14:34:56 +08:00
超级老白兔
4e63e533d3 Merge branch 'yongpxu-dev' into yongpxu-dev2 2025-09-26 14:34:49 +08:00
超级老白兔
e0feb6dff1 2025-09-26 14:33:43 +08:00
超级老白兔
8e9313eafa 2025-09-26 14:33:31 +08:00
超级老白兔
fa602f3efa Merge branch 'yongpxu-dev' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into yongpxu-dev 2025-09-26 14:23:55 +08:00
超级老白兔
f96377ff12 Merge branch 'yongpxu-dev' into yongpxu-dev4 2025-09-26 12:46:48 +08:00
超级老白兔
7a01efaa52 feat(自動問候功能開發): 新增自動問候功能界面,包含問候規則創建、編輯及列表展示,並優化樣式以提升用戶體驗。更新了PowerNavigation組件以支持右側內容顯示。 2025-09-26 12:46:15 +08:00
wong
1e1b65684d 触客宝 内容管理提交 2025-09-25 17:52:56 +08:00
超级老白兔
e506334689 FEAT => 本次更新项目为: 2025-09-25 15:50:00 +08:00
超级老白兔
d2ab632f2f FEAT => 本次更新项目为: 2025-09-25 15:47:45 +08:00
超级老白兔
5acdd13966 feat(客戶管理頁面優化): 更新客戶管理頁面,調整聯絡人卡片的最小高度,移除不必要的樣式,並整合聯絡人數據加載邏輯,提升頁面性能與用戶體驗。 2025-09-25 15:39:44 +08:00
超级老白兔
b3bf342320 feat(客戶管理與微信功能增強): 在客戶管理頁面中,整合了從狀態管理獲取的聯絡人數據,並動態計算各分類的聯絡人數量。此外,新增了獲取分組列表的API,優化了聯絡人顯示邏輯,提升了用戶體驗。 2025-09-25 15:00:17 +08:00
超级老白兔
27dfb17e70 FEAT => 本次更新项目为: 2025-09-25 14:32:42 +08:00
超级老白兔
6fa17a8f81 Merge branch 'yongpxu-dev' into yongpxu-dev4 2025-09-25 11:31:48 +08:00
超级老白兔
0b48be15aa Merge branch 'yongpxu-dev' into yongxu-dev3
# Conflicts:
#	Touchkebao/src/pages/pc/ckbox/powerCenter/sop-send/index.module.scss   resolved by yongpxu-dev version
#	Touchkebao/src/pages/pc/ckbox/powerCenter/sop-send/index.tsx   resolved by yongpxu-dev version
2025-09-25 11:31:41 +08:00
超级老白兔
0159a246ac FEAT => 本次更新项目为: 2025-09-25 11:28:17 +08:00
超级老白兔
e00bbf576a feat(功能中心新增溝通記錄與樣式調整): 在功能中心中新增「溝通記錄」功能,並對樣式進行調整,包括功能卡片的佈局和顏色設置,以提升視覺效果和用戶體驗。 2025-09-25 11:19:18 +08:00
超级老白兔
88653c1656 feat(功能中心重構與樣式優化): 將功能卡片結構重組為分類展示,新增熱門與新功能標籤,並優化樣式以提升用戶體驗。同時,新增通用配置頁面路由。 2025-09-25 11:08:03 +08:00
wong
31dad88078 兼容性提交 2025-09-25 10:50:43 +08:00
wong
ebc24432ff 去除好友和群的旧数据 2025-09-24 16:22:24 +08:00
超级老白兔
664d86838d Merge branch 'yongpxu-dev' into develop 2025-09-24 16:12:38 +08:00
超级老白兔
58dfbe3084 同步 2025-09-24 16:12:25 +08:00
wong
5a1c0321a6 去除测试代码 2025-09-24 15:05:50 +08:00
wong
1cc5605291 支付回调提交 2025-09-24 15:03:34 +08:00
超级老白兔
fb0cce836d feat(導航組件整合與樣式優化): 將PowerNavigation組件整合至多個頁面,替代冗餘的標題和描述結構,並在樣式上進行優化,提升整體用戶體驗。 2025-09-24 14:23:38 +08:00
wong
55be0c18e2 支付提交 2025-09-24 14:09:27 +08:00
wong
a9680d2464 消息列表 2025-09-24 14:09:09 +08:00
超级老白兔
7060bcce01 feat(接口整合與NavCommon優化): 將多個API請求從request2轉為request,簡化代碼結構。同時,刪除不再使用的NavCommon組件數據,並優化導航邏輯以提升用戶體驗。 2025-09-24 12:00:36 +08:00
wong
3c89d312c6 临时版本提交 2025-09-24 10:37:39 +08:00
超级老白兔
8e9b2920ed Merge branch 'yongpxu-dev' into yongpxu-dev2 2025-09-24 10:12:39 +08:00
超级老白兔
1b2a6d5acd FEAT => 本次更新项目为: 2025-09-23 19:16:02 +08:00
超级老白兔
c32ff2cf29 feat(導航組件優化): 移除NavCommon組件中的冗餘onMenuClick屬性,並優化菜單圖標點擊邏輯以實現路由切換,提升用戶體驗。 2025-09-23 19:15:31 +08:00
超级老白兔
424fc518ff feat(聊天窗口重構與個人資料卡片優化): 刪除冗餘的ChatWindow組件代碼,重構ProfileCard以支持選項卡功能,並整合快捷語錄及朋友圈模塊,提升用戶界面友好性和功能性。 2025-09-23 19:03:55 +08:00
wong
ac5c445b6f 代码提交 2025-09-23 17:43:36 +08:00
wong
59115fbf69 代码提交 2025-09-23 17:42:23 +08:00
wong
7560389e35 回调地址修改 2025-09-23 16:55:18 +08:00
wong
74b39ac480 代码提交 2025-09-23 16:50:34 +08:00
wong
7ed368a137 支付提交 2025-09-23 16:43:18 +08:00
wong
a8a9cf76df bug修复 2025-09-23 16:21:19 +08:00
超级老白兔
fe82be5f21 fix(個人資料卡片邏輯修正): 將群管理權限判斷邏輯中的wechatId改為nickname,以正確反映群主的識別方式,提升功能準確性。 2025-09-23 16:15:55 +08:00
超级老白兔
65fe93421b feat(好友接待配置與聊天窗口優化): 新增獲取好友接待配置的API,並在聊天窗口中整合AI接管狀態的更新邏輯。同時,優化了NavCommon組件,新增設置圖標,提升用戶界面友好性。移除不再使用的NavCommon樣式文件,簡化代碼結構。 2025-09-23 15:49:24 +08:00
超级老白兔
f0cd287f9a feat(未讀消息清除功能): 將清除未讀消息的API函數重命名並新增第二個清除未讀消息的API,優化代碼結構以提升可讀性和維護性。 2025-09-23 14:49:20 +08:00
超级老白兔
4c2c3db052 feat(聊天会话更新): 优化聊天会话处理逻辑,简化未读消息清除和会话更新的代码结构,提高可读性和维护性。 2025-09-23 14:40:36 +08:00
超级老白兔
3a90b1d163 feat(接口更新): 將多個API請求從request轉為request2,並調整相關邏輯以支持新結構,優化代碼可讀性。同時,更新了聊天記錄的排序邏輯,根據未讀消息數量和時間進行排序,提升用戶體驗。 2025-09-23 14:34:19 +08:00
超级老白兔
0eb6716263 FEAT => 本次更新项目为: 2025-09-23 11:54:10 +08:00
超级老白兔
92242bb8ff feat(未讀消息數據結構優化): 更新多個接口和數據結構,將unreadCount移入config對象中,並調整相關邏輯以支持新結構,提升代碼可讀性和維護性。 2025-09-23 11:51:14 +08:00
超级老白兔
8742560e6c feat(好友接待配置): 新增好友接待配置功能及流量池列表获取接口
在api.ts中新增了设置好友接待配置的API接口,并在ChatWindow组件中实现了配置选择功能,允许用户选择接待类型并保存配置。同时,新增了获取流量池列表的接口,优化了用户体验。
2025-09-23 11:20:35 +08:00
wong
fbfe0ba1fd 流量池字段同步 2025-09-22 18:03:45 +08:00
超级老白兔
7b39e68363 FEAT => 本次更新项目为: 2025-09-22 17:59:47 +08:00
超级老白兔
8f0c6c30dc FEAT => 本次更新项目为: 2025-09-22 17:51:09 +08:00
超级老白兔
1423b28663 FEAT => 本次更新项目为: 2025-09-22 17:50:42 +08:00
超级老白兔
1b15125bee 修正聯絡人導入和流量分配模組中的變數名稱,將所有的「pools」更改為「poolGroups」,以統一命名規範並提升代碼可讀性。新增流量池選擇功能,並更新相關表單數據處理邏輯。 2025-09-22 17:47:25 +08:00
超级老白兔
c6adee4502 更新 index.html 和 manifest.json 中的脚本文件名,替换为新的构建版本 index-ROCKxzay.js,以确保正确加载最新的资源。 2025-09-22 16:40:33 +08:00
超级老白兔
51a7f4f2ee FEAT => 本次更新项目为: 2025-09-22 14:44:36 +08:00
超级老白兔
0c846a86b9 1 2025-09-22 14:18:03 +08:00
超级老白兔
0fe7f86ad6 Merge branch 'yongpxu-dev' into yongpxu-dev2
# Conflicts:
#	Cunkebao/dist/.vite/manifest.json
#	Cunkebao/dist/index.html
2025-09-22 14:17:17 +08:00
超级老白兔
69613450c7 FEAT => 本次更新项目为: 2025-09-22 14:15:58 +08:00
超级老白兔
a9b769e510 FEAT => 本次更新项目为: 2025-09-22 14:15:23 +08:00
超级老白兔
deb0eb85b5 feat(流量池管理): 新增流量池添加功能及筛选条件优化
在流量池管理模块中,新增了添加流量池的API接口,并更新了筛选条件的结构,支持初始值的设置和状态的同步。优化了筛选条件的管理逻辑,提升了用户体验和代码可读性。
2025-09-22 11:51:37 +08:00
超级老白兔
ce1eddad68 FEAT => 本次更新项目为: 2025-09-22 10:49:21 +08:00
超级老白兔
a9c41aa9c3 feat(批量加入分组): 更新BatchAddModal组件以支持确认操作
在BatchAddModal组件中新增了确认按钮,优化了用户体验。更新onConfirm函数以接收选项参数,并调整了组件结构以提升可读性。同时,移除了未使用的Toast提示逻辑,简化了批量加入的处理逻辑。
2025-09-22 10:37:11 +08:00
超级老白兔
b0d5068192 Merge branch 'develop' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into develop 2025-09-22 10:24:24 +08:00
wong
2bd82fc6ef bug修复 2025-09-19 17:50:53 +08:00
超级老白兔
17279390d4 FEAT => 本次更新项目为: 2025-09-19 17:45:09 +08:00
超级老白兔
91a95e20a2 Merge branch 'yongpxu-dev' into yongpxu-dev2 2025-09-19 17:44:34 +08:00
超级老白兔
cb7a37fe9e feat(流量分发表单): 优化流量池选择逻辑
移除未使用的流量池列表和搜索功能,改为使用受控组件管理流量池选择。新增流量池选择的校验逻辑,确保用户至少选择一个流量池。同时,简化了目标设置的逻辑,提升了代码可读性和用户体验。
2025-09-19 17:43:32 +08:00
超级老白兔
4498f3542b feat(引用消息功能): 更新群组消息引用逻辑
在消息记录组件中优化了群组消息的引用逻辑,确保引用内容正确显示用户昵称,并移除了不必要的调试日志,提升了代码整洁性。
2025-09-19 17:33:27 +08:00
超级老白兔
fab5204c56 feat(流量分发表单): 添加流量池选择功能
在流量分发表单中引入流量池选择组件,优化了流量池的管理逻辑。新增状态以存储流量池选项,并实现流量池的搜索和选择功能,提升用户体验。同时,移除未使用的输入同步函数,简化代码结构。
2025-09-19 17:14:40 +08:00
wong
24bb2adc70 Merge branch 'develop' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into develop 2025-09-19 17:00:36 +08:00
wong
75230dd3b8 代码同步 2025-09-19 17:00:09 +08:00
超级老白兔
4440da92bf Merge branch 'yongpxu-dev' into develop 2025-09-19 16:59:38 +08:00
超级老白兔
07c22e06ba 同步下 2025-09-19 16:59:08 +08:00
超级老白兔
ef839f65c1 feat(流量分发表单): 优化表单管理和数据获取逻辑
重构流量分发表单组件,使用Form管理字段并引入useWatch以简化状态管理。移除未使用的状态和函数,优化了获取详情数据的逻辑。同时,更新了API请求方法以符合RESTful标准,确保删除计划时使用DELETE请求。
2025-09-19 16:58:40 +08:00
wong
ce6e752905 算力扣费及列表接口 2025-09-19 16:51:03 +08:00
wong
9c1cfda40b 代办事件及提示事项接口 2025-09-19 16:50:32 +08:00
wong
d87d3ed9e1 AI对话接口 2025-09-19 16:49:25 +08:00
wong
c21387874b 好友新增ai接管字段 2025-09-19 16:48:42 +08:00
wong
5b35786c5c ai群公告接口提交包含扣费功能 2025-09-19 16:47:41 +08:00
wong
3829da428c AI改写群公告接口改写 2025-09-19 16:46:06 +08:00
超级老白兔
d8ef4d522c fix(weChat): 移除调试日志以清理代码
在weChat模块中移除了不必要的调试日志,优化了代码整洁性。
2025-09-19 16:35:16 +08:00
超级老白兔
26b7eb7cd8 feat(消息输入与记录): 增强引用消息功能与状态管理
在消息输入组件中添加引用消息的逻辑,确保引用内容能够正确显示。同时,在消息记录组件中实现引用功能的处理,优化了状态管理,提升了用户体验。
2025-09-19 16:34:56 +08:00
超级老白兔
f69659309d Merge branch 'yongpxu-dev' into yongpxu-dev2 2025-09-19 15:49:34 +08:00
超级老白兔
18f2ebf455 feat(消息转发): 更新转发逻辑并优化状态管理
在消息记录和转发模态框中添加了选中聊天记录的更新逻辑,确保转发功能的正确性。同时,简化了转发模态框的参数传递,移除了不必要的回调,提升了用户体验。
2025-09-19 15:40:47 +08:00
超级老白兔
c625e12075 feat(TransmitModal): 添加分页功能并优化联系人显示
在转发模态框中实现了联系人列表的分页功能,提升了用户体验。同时,优化了联系人信息的显示方式,增加了备注信息的样式支持。
2025-09-19 14:54:52 +08:00
超级老白兔
ed58b824ac fix(TransmitModal): 更新转发确认逻辑并优化联系人显示
修正了转发确认时的参数传递,确保选中的微信好友能够正确传递给onConfirm回调。同时,在联系人显示中添加了备注信息的支持,提升了用户体验。
2025-09-19 14:44:51 +08:00
超级老白兔
6fa89dbdf4 fix(TransmitModal): 修复联系人选择时的事件处理逻辑
在联系人项中添加onChange事件处理,确保选择状态能够正确更新。此更改优化了用户交互体验。
2025-09-19 14:35:04 +08:00
超级老白兔
8dc19a522f refactor(TransmitModal): 简化联系人数据结构并优化状态管理
移除冗余的Contact接口,直接使用原始数据类型
使用组件内部状态替代zustand store管理选中联系人
优化搜索和选择逻辑,减少不必要的转换
2025-09-19 14:18:52 +08:00
超级老白兔
dd18b32a09 fix(TransmitModal): 修复联系人选择和禁用状态的逻辑错误
修复了联系人选择时参数命名不一致的问题
调整了禁用状态的判断逻辑,现在已选择的联系人会被正确禁用
2025-09-19 11:37:22 +08:00
超级老白兔
b916180ccd refactor(TransmitModal): 重构转发模态框组件并集成到消息记录
- 删除旧版转发模态框组件及相关文件
- 实现新版转发模态框组件,支持联系人搜索和多选
- 集成转发功能到消息记录组件
- 更新状态管理以支持转发功能
- 优化样式和响应式设计
2025-09-19 11:30:46 +08:00
超级老白兔
593e6c4670 feat(微信聊天): 添加消息转发功能
实现消息多选转发功能,包括:
1. 新增转发模态框组件,支持联系人搜索和多选
2. 在消息记录组件中添加转发操作逻辑
3. 在消息输入区域添加转发操作栏
4. 在微信状态管理中新增转发相关状态和方法
2025-09-19 10:24:25 +08:00
超级老白兔
8a7a717801 fix(MessageEnter): 修复多转发模块显示条件判断错误 2025-09-18 18:34:10 +08:00
超级老白兔
a53460b4cc feat(微信聊天): 实现消息撤回功能并优化右键菜单
添加消息撤回API接口及状态管理
在右键菜单中根据消息发送时间和归属显示撤回选项
优化消息记录组件与状态管理的交互逻辑
2025-09-18 17:58:33 +08:00
超级老白兔
f0f64dd118 feat(weChat): 添加消息多选转发功能
- 在微信聊天记录组件中添加复选框支持多选消息
- 新增showCheckbox状态和updateShowCheckbox方法控制复选框显示
- 重构右键菜单处理逻辑,统一使用onCommad回调
- 添加EnterModule状态管理不同功能模块
- 调整消息项布局样式以适配复选框
2025-09-18 16:38:18 +08:00
超级老白兔
ac53861a85 refactor(websocket): 优化消息处理器并清理认证失败时的缓存数据
- 移除未使用的WebSocket状态检查代码
- 重新组织导入语句顺序
- 改进CmdNotify处理器,在认证失败时清除所有本地存储和数据库
- 将消息处理器调整为异步函数以支持数据库操作
2025-09-18 15:25:33 +08:00
超级老白兔
85c73a5069 refactor(weChat): 移除WebSocket重复连接检查逻辑
不再检查WebSocket连接状态,直接进行连接操作
2025-09-18 15:13:05 +08:00
超级老白兔
94d40308d2 refactor: 移除调试用的console.log语句
清理代码中用于调试的console.log语句,保持代码整洁
2025-09-18 15:12:37 +08:00
超级老白兔
e9fbebdfad refactor(ckchat): 移除调试用的console.log语句
清理代码中用于调试的console.log输出,保持代码整洁
2025-09-18 15:10:50 +08:00
超级老白兔
f58b95cd95 refactor(ckchat): 优化联系人列表创建逻辑并移除调试日志
- 将重复的kfSelected过滤逻辑提取到公共位置
- 为groupType=2的情况添加未分组联系人查询支持
- 移除不必要的console.log调试输出
2025-09-18 15:06:25 +08:00
超级老白兔
d110c97424 feat(数据库): 扩展数据库查询操作符并优化联系人分组逻辑
- 在 DatabaseService 中添加新的查询操作符(notEqual, aboveOrEqual, belowOrEqual, contains, anyOf, notIn, between)
- 修改 createContractList 方法以支持未分组联系人的查询
- 添加调试日志用于跟踪缓存结果和真实分组
2025-09-18 15:04:06 +08:00
超级老白兔
5b5a05d8c5 fix(weChat): 修复消息记录显示和右键菜单问题
- 修正消息记录中自己消息的显示样式
- 更新右键菜单图标和功能项
- 优化联系人列表加载逻辑
- 移除无用代码和注释
2025-09-18 14:39:37 +08:00
超级老白兔
dc93c7f9f4 feat(MessageRecord): 添加右键菜单功能支持消息操作
实现消息记录的右键菜单功能,包括复制、转发、删除和重发等操作。添加ClickMenu组件处理菜单显示和位置调整,并在MessageRecord中集成右键事件处理逻辑。支持暗色主题适配和边界检测防止菜单溢出屏幕。
2025-09-18 10:59:33 +08:00
超级老白兔
065b516bd7 refactor(MessageRecord): 移除未使用的JSON解析函数
该函数未被组件使用,清理冗余代码以保持代码整洁
2025-09-18 10:17:14 +08:00
超级老白兔
7935936da1 FEAT => 本次更新项目为: 2025-09-18 10:09:14 +08:00
超级老白兔
bedd05c6ae fix(朋友圈): 修复删除评论时条件判断错误的问题
refactor(表情资源): 添加新的表情映射文件并更新表情资源
2025-09-18 10:02:36 +08:00
超级老白兔
a32d0781fc refactor(weChat): 重构朋友圈相关类型定义和组件导入路径
将朋友圈相关的类型定义从分散的文件集中到index.data.ts中
更新组件中类型导入路径以保持一致性
添加评论更新逻辑到朋友圈组件
2025-09-17 17:21:20 +08:00
超级老白兔
15a17b5e1d refactor(weChat): 优化朋友圈数据类型和更新逻辑
- 导出 likeListItem 和 CommentItem 接口供其他模块使用
- 重构 CommentItem 接口字段,增加注释说明
- 简化 updateLikeMoment 方法实现
- 新增 updateComment 方法用于更新评论列表
2025-09-17 17:02:27 +08:00
超级老白兔
527a76c480 feat(朋友圈): 添加评论功能及相关样式和接口
- 新增评论接口类型定义和状态管理
- 实现评论输入框和删除评论功能
- 调整评论区域样式,添加删除按钮和输入框样式
- 修改取消评论接口参数命名
2025-09-17 16:56:08 +08:00
wong
02c94a12d5 AI功能提交 2025-09-17 16:51:11 +08:00
wong
706be3efd1 兼容客服端密码登录 2025-09-17 16:49:11 +08:00
超级老白兔
3477b5d575 feat(朋友圈): 实现朋友圈点赞功能并优化组件结构
重构朋友圈组件结构,将核心逻辑拆分为独立组件。主要变更包括:
1. 新增点赞功能及相关API接口
2. 修改snsId类型从number到string以兼容接口
3. 在store中新增updateLikeMoment方法处理点赞状态
4. 提取FriendCard和MomentList为独立组件
5. 优化代码结构提升可维护性
2025-09-17 15:52:15 +08:00
超级老白兔
680c16c7da feat(朋友圈): 重构朋友圈功能,支持好友朋友圈展示和加载更多
- 删除无用的sendMessages.ts文件
- 修改FriendsCircleItem接口,将snsId类型改为number
- 重构weChat store,支持批量添加朋友圈数据
- 优化朋友圈样式,修复图片浮动问题
- 重构api.ts,简化请求参数处理
- 在msgManage.ts中添加朋友圈数据处理逻辑
- 完全重构FriendsCicle组件,支持好友朋友圈展示和加载更多功能
2025-09-17 14:57:58 +08:00
超级老白兔
c9eb19a064 refactor(朋友圈): 重构朋友圈数据管理为统一结构
移除原有的分类型朋友圈状态和方法,合并为统一的MomentCommon状态
更新相关组件以使用新的状态管理方式
2025-09-17 10:44:12 +08:00
超级老白兔
8b2c24d7a1 feat(wechat): 添加朋友圈功能支持
- 在微信状态管理中新增朋友圈相关状态和方法
- 实现朋友圈数据获取、展示和交互功能
- 添加朋友圈API接口和WebSocket消息处理
- 优化朋友圈UI展示和样式
2025-09-17 10:20:31 +08:00
超级老白兔
18b2735f80 feat(朋友圈): 添加朋友圈功能相关组件和状态管理
- 新增朋友圈数据类型定义和接口
- 在状态管理中添加朋友圈相关状态
- 实现朋友圈图片预览功能
- 优化朋友圈样式和交互体验
2025-09-16 18:42:51 +08:00
超级老白兔
d11ae4365c refactor: 移除流量池详情页的添加标签按钮并更新构建文件
移除流量池详情页中未使用的添加新标签按钮组件,同时更新构建生成的manifest.json和index.html文件中的资源引用
2025-09-16 18:04:39 +08:00
超级老白兔
a251697813 Merge branch 'yongpxu-dev' into yongpxu-dev2 2025-09-16 17:53:14 +08:00
超级老白兔
f9f798417b Merge branch 'yongpxu-dev' into yongxu-dev3 2025-09-16 17:53:05 +08:00
超级老白兔
4dc377c16e Merge branch 'yongpxu-dev' into yongpxu-dev4 2025-09-16 17:52:57 +08:00
超级老白兔
e528d8dc51 图标 2025-09-16 17:51:40 +08:00
超级老白兔
81e0f23075 chore: 更新构建产物和.gitignore文件
- 添加dist/*到.gitignore以避免提交构建产物
- 更新Vite构建生成的资源文件哈希值
2025-09-16 17:46:08 +08:00
超级老白兔
a7124c800e refactor: 移除触客宝相关代码及功能模块
feat: 为朋友圈功能添加点赞和评论交互区域样式

style: 优化朋友圈组件代码结构,增加类型定义
2025-09-16 17:40:02 +08:00
超级老白兔
93f0220a71 Merge branch 'yongpxu-dev' into yongpxu-dev2 2025-09-16 16:55:52 +08:00
超级老白兔
1d94368579 feat(朋友圈组件): 实现朋友圈列表分页加载和样式优化
添加分页加载功能,优化样式结构,使用折叠面板管理不同朋友圈类型
重构组件结构,添加加载状态和空状态显示
2025-09-16 16:31:56 +08:00
超级老白兔
21396f5a1d feat(weChat): 添加朋友圈功能组件及样式
- 新增FriendsCircle组件实现朋友圈展示功能
- 添加朋友圈样式文件包含布局和交互样式
- 修改SidebarMenu组件支持朋友圈选项卡
- 根据kfSelected状态控制朋友圈选项卡显示
2025-09-16 15:17:05 +08:00
超级老白兔
4d69c8e570 refactor(ckbox): 优化消息未读计数逻辑并调整导航栏布局
重构未读消息计数逻辑,使用chatSessions中的unreadCount替代原有的messageCount计算方式
调整导航栏中消息按钮和用户下拉菜单的位置顺序
2025-09-16 14:39:15 +08:00
超级老白兔
16e3ccada8 feat(ui): 优化多个组件的样式和功能
- 调整消息记录宽度和样式
- 更新导航栏算力图标和颜色
- 修改垂直用户列表布局和交互
- 移除侧边栏菜单图标
- 添加调试日志和错误处理
2025-09-16 11:47:36 +08:00
超级老白兔
a723b2801e Merge branch 'yongpxu-dev' into develop 2025-09-16 09:57:34 +08:00
wong
f577dbdd70 代码同步提交 2025-09-16 09:57:06 +08:00
超级老白兔
d84c11a459 fix(微信聊天窗口): 添加文件类型消息的消息类型处理
当文件类型为FileType.FILE时,设置消息类型为49以支持文件消息发送
2025-09-15 18:06:07 +08:00
超级老白兔
5c5059681d refactor(router): 统一登录组件文件名并移除无用路由
- 将login组件文件名从小写改为大写以保持命名一致性
- 移除mine模块中不再使用的ckbox路由
2025-09-15 18:04:18 +08:00
超级老白兔
c88431b564 refactor: 移除Cunkebao项目中未使用的微信聊天相关组件和代码
重构Touchkebao项目中的微信API调用逻辑,优化消息记录处理
2025-09-15 18:03:14 +08:00
超级老白兔
d802b9da1f feat(微信客服): 新增微信好友和群列表接口并优化初始化逻辑
- 添加获取微信好友列表和群列表的API接口
- 移除旧的初始化联系人列表逻辑,改用新接口
- 清理不再使用的会话过滤和排序代码
2025-09-15 15:42:05 +08:00
超级老白兔
c91e54370f refactor(websocket/wechat): 优化客服列表排序并简化初始化逻辑
- 在msgManage.ts中按在线状态排序客服列表
- 在main.ts中简化初始化逻辑,使用getAgentList和getChatroomList替代原有复杂逻辑
- 在api.ts中新增相关API接口并统一使用request2
2025-09-15 15:21:24 +08:00
超级老白兔
27f0532491 feat(sop-send): 实现SOP群发任务管理界面及功能
添加SOP任务管理界面,包括任务列表展示、统计卡片、任务增删改查及状态切换功能
实现响应式布局适配不同屏幕尺寸
2025-09-13 18:04:33 +08:00
超级老白兔
d95e07285c feat(精准群发): 实现三步表单流程及响应式设计
添加客户筛选、消息内容和发送设置三个步骤的表单功能
包含预估客户数计算、消息预览和发送摘要展示
优化样式并添加移动端响应式设计
2025-09-13 18:04:25 +08:00
wong
2b3c41ce36 Merge branch 'develop' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into develop 2025-09-13 17:20:57 +08:00
wong
410a43e6a1 触客宝部分功能提交 2025-09-13 17:20:34 +08:00
超级老白兔
a270b8ce3e chore: 更新构建生成的资源文件哈希值 2025-09-13 17:12:16 +08:00
超级老白兔
62e8039138 fix(微信账号详情): 将限制等级字段从字符串类型改为数字类型
修改微信账号详情页面的限制等级字段类型,从字符串类型改为数字类型以匹配后端数据格式。同时更新相关颜色和文本显示的判断逻辑。
2025-09-13 16:14:02 +08:00
超级老白兔
9f01ad0665 feat(微信账号详情): 添加风险评估标签页展示账号限制记录
新增风险评估标签页,用于展示微信账号的限制记录,包括限制原因、日期和风险等级。当没有限制记录时显示"暂无风险记录"。
2025-09-13 16:03:21 +08:00
超级老白兔
268afb7209 feat(traffic-pool): 重构流量池详情页数据结构和样式
- 更新API接口路径和数据结构以匹配新后端实现
- 重构用户详情类型定义和数据处理逻辑
- 优化页面样式和布局
- 实现基于RMM评分的动态标签显示
- 完善统计数据的展示逻辑
2025-09-13 15:47:57 +08:00
超级老白兔
fb362a56af refactor(mobile): 优化页面交互和移除未使用代码
移除未使用的导入和状态变量
将点击事件移至容器元素提升交互体验
减少好友列表每页显示数量为5条
2025-09-13 15:08:42 +08:00
超级老白兔
e5bf979682 Merge branch 'yongpxu-dev' into yongpxu-dev4 2025-09-13 11:57:00 +08:00
超级老白兔
cb05b5beb3 Merge branch 'yongpxu-dev' into develop 2025-09-13 11:56:18 +08:00
超级老白兔
7cf6f1b9fa Merge branch 'yongpxu-dev' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into yongpxu-dev 2025-09-13 11:55:03 +08:00
超级老白兔
5c42c8ad3c 1 2025-09-13 11:54:54 +08:00
超级老白兔
06c8b43950 Merge branch 'yongpxu-dev' into yongpxu-dev4 2025-09-13 11:54:36 +08:00
超级老白兔
7937fea5c3 Merge branch 'yongpxu-dev2' into yongpxu-dev
# Conflicts:
#	Touchkebao/src/pages/pc/ckbox/components/NavCommon/index.tsx   resolved by yongpxu-dev2 version
2025-09-13 11:53:54 +08:00
超级老白兔
4a48bec42d style(NavCommon): 移除headerRight和userInfo中的gap间距
简化样式代码,保持布局一致性
2025-09-13 11:52:52 +08:00
超级老白兔
575e0f2924 feat(功能中心): 新增功能中心相关页面和路由配置
添加SOP群发、AI模型训练、自动打招呼等9个功能页面的基础结构和样式
配置功能中心相关路由
调整消息通知按钮的Badge组件位置
2025-09-13 11:52:18 +08:00
超级老白兔
7749947138 refactor(powerCenter): 更新功能卡片路径从ckbox到powerCenter
统一功能卡片的路径前缀,将原ckbox路径改为powerCenter以保持路由一致性
2025-09-13 11:46:14 +08:00
超级老白兔
66ddb75c13 refactor(powerCenter): 更新功能卡片路径从ckbox到powerCenter
统一功能卡片的路径命名,将原ckbox路径改为powerCenter以保持路由一致性
2025-09-13 11:46:03 +08:00
超级老白兔
625705eaf0 Merge branch 'yongpxu-dev' into yongpxu-dev4 2025-09-13 11:42:03 +08:00
超级老白兔
287c2637ed style(NavCommon): 移除响应式设计和用户信息间隔样式
移除不再需要的移动端响应式设计代码和用户信息组件中的
2025-09-13 11:41:02 +08:00
超级老白兔
f640733276 FEAT => 本次更新项目为: 2025-09-13 11:37:42 +08:00
wong
cc432ba18f 代码提交同步 2025-09-13 10:45:32 +08:00
超级老白兔
fe03a4e9c1 Merge branch 'yongpxu-dev' into yongpxu-dev4 2025-09-13 10:39:34 +08:00
超级老白兔
4c3c32d5a4 Merge branch 'yongpxu-dev' into yongxu-dev3 2025-09-13 10:39:24 +08:00
超级老白兔
0be87ee2db Merge branch 'yongpxu-dev' into yongpxu-dev2 2025-09-13 10:38:58 +08:00
超级老白兔
7d3b5dbbe9 2025-09-13 10:38:36 +08:00
超级老白兔
2e3ac230ca refactor(login): 移除调试日志并修复响应数据解构
移除登录请求中的console.log调试语句
修复从响应数据中解构kefuData的方式,直接从res获取而非res.kefuData
2025-09-13 10:37:33 +08:00
超级老白兔
55286bdfe5 refactor(登录): 移除用户信息中的设备总数字段
简化登录逻辑,不再需要传递和处理设备总数信息
2025-09-13 10:00:03 +08:00
超级老白兔
8b64c1ab0d fix(登录): 更新登录API路径和验证码参数名称
将登录API路径从'/v1/auth/login'改为'/v1/kefu/login'
将验证码参数verifyCode改为verifySessionId以匹配后端接口
更新表单字段名称verificationCode为verifyCode保持一致性
2025-09-13 09:55:07 +08:00
超级老白兔
02b864d657 style(powerCenter): 移除多余边距并清理样式文件格式
清理了index.module.scss文件中的多余边距和空行,保持代码格式整洁统一
2025-09-12 18:10:04 +08:00
超级老白兔
ca1eefb906 feat(NavCommon): 添加关闭按钮并调整抽屉样式
- 在抽屉头部添加关闭按钮,提升用户体验
- 重构抽屉样式结构,分离头部和内容样式
- 调整图标大小和布局,保持视觉一致性
2025-09-12 18:05:18 +08:00
超级老白兔
f2fb543f93 feat(NavCommon): 重构导航组件并优化样式结构
- 新增图标组件并替换原有emoji图标
- 重构导航菜单数据结构并移除无用代码
- 实现菜单项激活状态高亮效果
- 完善用户退出登录功能
- 优化样式文件结构并添加详细注释
- 更新构建产物文件版本
2025-09-12 17:49:23 +08:00
超级老白兔
d3ee0bde5a feat(NavCommon): 重构导航栏样式并添加消息中心和用户菜单功能
- 重新设计用户信息区域样式,增加间距和悬停效果
- 添加消息中心抽屉组件,包含消息列表和操作按钮
- 实现用户下拉菜单,包含个人资料和退出登录选项
- 统一PC端和移动端的导航栏样式
2025-09-12 16:19:08 +08:00
超级老白兔
1ccdfa3e12 refactor(powerCenter): 将功能卡片和标签数据抽离到单独文件
重构功能中心页面,将功能卡片数据和标签数据抽离到独立的index.data.tsx文件中
使用useState和useMemo实现标签过滤功能
2025-09-12 15:47:27 +08:00
超级老白兔
9816d7ec18 feat(powerCenter): 新增功能中心页面及导航配置
添加功能中心页面,包含9个功能卡片展示和分类筛选
更新路由配置和导航菜单数据,移除无用代码和样式
2025-09-12 15:33:54 +08:00
超级老白兔
a2a0cb8461 FEAT => 本次更新项目为: 2025-09-12 10:30:33 +08:00
超级老白兔
76e5004830 Merge branch 'yongpxu-dev' into develop 2025-09-12 10:30:24 +08:00
超级老白兔
14d9790b5c Merge branch 'develop' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into develop 2025-09-12 10:30:15 +08:00
超级老白兔
2480f79a34 同步 2025-09-12 10:30:09 +08:00
wong
084dd23bc2 通讯录导入记录 2025-09-12 10:25:19 +08:00
wong
b989c19a8a 代码提交 2025-09-12 09:40:13 +08:00
超级老白兔
caa57b3e8b refactor(路由): 统一将路由路径从/ckbox更改为/pc
更新用户登录后跳转路径和导航菜单中的路由路径,从/ckbox/weChat改为/pc/weChat,/ckbox/dashboard改为/pc/dashboard,保持路由命名一致性
2025-09-11 18:02:30 +08:00
超级老白兔
f6b0e7b0d9 feat(router): 添加首页路由并调整PC端路由结构
添加新的首页路由组件,实现设备检测自动跳转功能
重构PC端路由路径,移除冗余子路由配置
2025-09-11 17:51:05 +08:00
超级老白兔
4d6b516662 refactor(db): 移除调试用的console.log语句
清理代码中用于调试的console.log输出,保持生产环境日志的整洁性
2025-09-11 17:35:20 +08:00
超级老白兔
1caf567f10 refactor: 移除调试日志和未使用的样式文件
清理数据库操作和WebSocket连接中的调试日志
删除未使用的index.module.scss文件和相关引用
移除已删除的main.ts文件
2025-09-11 17:27:23 +08:00
超级老白兔
1e34ecffc2 refactor: 移除测试相关代码及组件
fix(websocket): 禁用所有Toast提示以优化用户体验

删除开发环境下的测试路由、页面及组件,清理不再使用的代码。同时修改websocket模块,移除所有Toast提示以避免干扰用户操作。
2025-09-11 17:23:47 +08:00
超级老白兔
dd2f58dc78 refactor(profile): 重构用户设置页面为个人资料页面
将用户设置功能从/mine/setting迁移到/profile路径
删除不再使用的mine模块相关代码
更新路由配置以指向新的个人资料页面
2025-09-11 17:20:15 +08:00
超级老白兔
1977aa50c2 chore: 删除示例存储文件examples.ts 2025-09-11 17:15:47 +08:00
超级老白兔
60173a0efb refactor(router): 移除未使用的页面文件并添加用户设置路由
移除多个未使用的页面组件、样式和API文件,包括流量分发、自动建群、朋友圈同步等功能模块。同时添加新的用户设置路由配置到移动端路由模块中。这些变更旨在清理代码库并支持新的用户设置功能。
2025-09-11 17:11:30 +08:00
超级老白兔
fbfce10afb refactor(router): 合并路由模块并删除冗余配置文件
将auth.tsx和index.tsx中的路由配置合并到common.tsx中,并删除不再使用的config.ts文件
2025-09-11 16:48:35 +08:00
超级老白兔
2c539f4316 feat: 重构登录模块并添加验证码功能
- 将登录组件文件名从login.tsx改为Login.tsx
- 添加验证码图片显示和验证功能
- 修改登录后默认跳转路径为/ckbox/weChat
- 移除第三方登录功能
- 更新项目部署路径为tkb-wechat
- 清理无用路由模块
2025-09-11 16:44:35 +08:00
wong
db9e4eb004 Merge branch 'develop' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into develop 2025-09-11 15:16:50 +08:00
wong
bea5f44565 代码优化 2025-09-11 15:16:04 +08:00
超级老白兔
9b3181576f feat: 初始化项目基础架构与核心功能
添加项目基础文件结构、路由配置、API接口和核心组件
实现登录认证、权限控制、WebSocket通信等基础功能
引入antd-mobile UI组件库和Vite构建工具
配置TypeScript、ESLint、Prettier等开发环境
添加移动端适配方案和全局样式
完成首页、工作台、个人中心等基础页面框架
2025-09-11 15:00:57 +08:00
超级老白兔
648a61d09a fix(contact-import): 移除未使用的ContactImportTask导入
fix(traffic-pool): 添加tags存在性检查避免报错
feat(traffic-pool): 添加请求频率限制错误处理
refactor(traffic-pool): 使用防抖优化搜索功能
2025-09-11 14:50:05 +08:00
超级老白兔
18fbf79fa8 refactor(contact-import): 将task状态类型从ContactImportTask改为any
简化状态类型以兼容更多场景,避免类型限制导致的潜在问题
2025-09-11 14:42:00 +08:00
超级老白兔
ff97490a2b fix: 移除重复加载联系记录的副作用逻辑 2025-09-11 14:41:26 +08:00
超级老白兔
dc60dacb02 refactor(contact-import): 重构通讯录导入任务类型定义和样式
- 将ContactImportTask相关类型统一为Allocation类型
- 优化详情页样式和布局
- 移除冗余样式和代码
2025-09-11 14:36:49 +08:00
超级老白兔
b69ad40013 fix(contact-import): 修复联系人导入表单时间格式和设备组选项问题
- 将时间格式从HH:mm:ss简化为HH:mm
- 从config中获取设备组选项而不是手动构造
- 添加加载状态防止重复提交
2025-09-11 11:56:50 +08:00
超级老白兔
8d386d9bdf fix: 修正设备组相关变量名拼写错误
将多处代码中的变量名`deveiceGroups`和`deveiceGroupsOptions`修正为正确的拼写`deviceGroups`和`deviceGroupsOptions`,保持代码一致性
2025-09-11 11:46:36 +08:00
超级老白兔
32f50d676e feat(contact-import): 新增通讯录导入表单页面并优化列表页样式
refactor(contact-import): 重构API接口类型定义和数据结构

style(contact-import): 调整列表页和表单页的样式布局

fix(contact-import): 修复列表页数据加载和搜索功能的问题
2025-09-11 11:38:03 +08:00
超级老白兔
ecb5a741bf Merge branch 'yongpxu-dev' into develop 2025-09-11 10:11:50 +08:00
wong
19977cc536 Merge branch 'develop' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into develop 2025-09-11 10:10:02 +08:00
wong
51312a3a2a 通讯录导入前端 2025-09-11 10:08:26 +08:00
超级老白兔
919f0dc120 feat(表单): 添加采集内容类型选择功能
在表单页面新增采集内容类型选择功能,支持用户选择文本、图片和视频类型
2025-09-11 10:05:21 +08:00
超级老白兔
23c54af27d refactor(weChat): 移除ChatRecord组件中未使用的onSearch属性并重构搜索逻辑
将ChatRecord组件的搜索逻辑移至store管理,移除未使用的onSearch回调属性
更新构建产物文件路径
2025-09-10 18:21:42 +08:00
超级老白兔
9ed298bf3e feat(weChat): 添加清空当前联系人的功能
在weChat模块中添加clearCurrentContact方法用于清空当前联系人和消息,并在ckchat模块中调用该方法确保删除会话时同步清空联系人
2025-09-10 18:08:09 +08:00
超级老白兔
8507b640b2 fix(ckchat): 将deleteChatSession参数类型从string改为number
修改deleteChatSession方法的参数类型以匹配实际使用场景,同时在相关组件中直接使用store中的方法而非直接导入,保持
2025-09-10 17:55:17 +08:00
超级老白兔
3a66a3af3f Merge branch 'yongpxu-dev' into develop 2025-09-10 17:45:02 +08:00
超级老白兔
95303d2960 fix(MessageRecord): 修复消息记录中时间分隔和消息类型的显示问题
调整消息记录组件的时间分隔显示逻辑,将特定类型的消息内容直接显示为HTML,并过滤掉这些消息不进行常规渲染。同时优化消息时间的样式,添加链接颜色和间距设置。
2025-09-10 17:43:56 +08:00
超级老白兔
ad60e684fc feat(消息列表): 添加搜索功能并优化客服筛选逻辑
添加对消息列表的搜索功能,支持根据昵称和备注进行模糊匹配
优化客服筛选逻辑,将筛选和搜索功能合并处理
在转接和转回操作后增加删除聊天会话和本地数据的逻辑
2025-09-10 17:27:59 +08:00
wong
0f1edf3f9c 通讯录导入功能提交 2025-09-10 16:58:22 +08:00
超级老白兔
51b1918f72 feat(微信聊天): 添加聊天记录搜索和客户转接功能
- 在微信聊天界面新增聊天记录搜索组件,支持按时间和关键词搜索
- 添加客户转接功能组件,支持选择目标客服和添加附言
- 实现一键转回功能
- 添加相关API接口和状态管理
- 配置antd中文语言环境和dayjs本地化
2025-09-10 16:52:28 +08:00
超级老白兔
46d6641259 chore: 更新构建产物中的资源引用路径
更新manifest.json和index.html中引用的JS和CSS文件路径,以匹配最新的构建输出
2025-09-10 14:08:29 +08:00
超级老白兔
984b9af719 Merge branch 'yongpxu-dev' into yongpxu-dev4 2025-09-10 11:54:02 +08:00
超级老白兔
42e74a05f5 Merge branch 'yongpxu-dev' into yongxu-dev3 2025-09-10 11:53:46 +08:00
超级老白兔
4364546bc9 Merge branch 'develop' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into develop 2025-09-10 11:52:40 +08:00
超级老白兔
2bcaadbeb6 fix(音频消息): 优化音频URL检测逻辑避免CORS问题
修改音频URL检测逻辑,对于阿里云OSS等外部资源直接返回true,避免fetch HEAD请求触发CORS问题。同时调整crossOrigin设置策略,仅在需要访问音频数据时设置该属性。移除了冗余的备用播放方案,简化错误处理流程。
2025-09-10 11:52:37 +08:00
wong
4385995742 工作台 - 通讯录导入功能 2025-09-10 11:43:47 +08:00
wong
2c7d90e49d 去除队列冗余代码 2025-09-10 11:41:54 +08:00
超级老白兔
bc34346301 fix(MessageEnter): 修正音频消息内容处理逻辑
修复音频消息发送时内容处理不正确的问题,直接使用filePath而不是从中提取url
2025-09-10 11:37:14 +08:00
超级老白兔
5619d2b00e Merge branch 'yongpxu-dev' into yongpxu-dev2 2025-09-10 11:27:20 +08:00
超级老白兔
56a4711189 fix(微信聊天): 修复音频消息上传处理逻辑
修改音频上传回调参数类型为包含URL和时长的对象
优化音频格式检测逻辑,增加更多MP3格式支持
更新消息处理函数以正确处理音频数据
2025-09-10 11:26:49 +08:00
超级老白兔
4b84d5f013 feat(selection): 为所有选择弹窗添加当前页全选功能
- 在弹窗底部添加全选当前页的复选框
- 修改样式以适配新的全选功能
- 移除不再需要的总计数量显示
2025-09-10 11:23:50 +08:00
超级老白兔
c6304d75cf fix: 移除页码为1时的数据请求限制
统一修改多个选择弹窗组件,当页码变化时不再限制第一页的数据请求,确保数据加载逻辑一致
2025-09-10 11:01:13 +08:00
超级老白兔
8fb8e83632 fix(微信聊天): 修复音频消息上传处理逻辑
修改音频上传回调参数类型为包含URL和时长的对象
优化音频格式检
2025-09-10 10:51:21 +08:00
超级老白兔
390d88e0e9 refactor(ProfileCard): 移除未使用的图标和组件导入
清理未使用的antd图标和组件导入,减少代码冗余
2025-09-10 10:46:30 +08:00
超级老白兔
e08c290a66 refactor: 重构TwoColumnSelection组件并移动至新目录
将TwoColumnSelection组件从FriendSelection目录移动到新的TwoColumnSelection目录
优化组件代码格式和样式文件结构
更新相关引用路径
2025-09-10 10:46:02 +08:00
超级老白兔
f60bf294c1 feat(视频消息): 添加视频消息组件并优化消息记录处理
将视频消息处理逻辑从MessageRecord组件中抽离为独立组件VideoMessage
新增视频消息样式文件VideoMessage.module.scss
优化视频消息的加载状态处理和错误显示
2025-09-10 10:02:43 +08:00
超级老白兔
ae4fcbad67 feat(MessageRecord): 添加小程序消息组件并优化消息处理逻辑
将小程序消息处理逻辑抽离为独立组件SmallProgramMessage,优化代码结构
新增对多种小程序类型的样式支持,包括横向布局和垂直图片布局
增强文件消息处理,支持更多文件类型和图标显示
2025-09-09 19:01:24 +08:00
超级老白兔
543e274737 refactor(AudioMessage): 移除调试日志并优化音频播放逻辑
清理了多余的console日志输出,简化了音频播放的错误处理流程
2025-09-09 18:45:44 +08:00
超级老白兔
98a9aa7701 feat(音频消息): 增强音频消息组件功能并改进错误处理
- 支持JSON格式音频URL解析,可获取时长和文本信息
- 添加音频URL可用性检查机制
- 实现更完善的错误处理和重试逻辑
- 增加音频文本显示和错误提示样式
- 优化音频播放控制逻辑,确保跨域访问兼容性
- 将msgId类型改为string以避免潜在类型问题
2025-09-09 18:29:57 +08:00
超级老白兔
04589154ca Merge branch 'yongpxu-dev' into yongpxu-dev2 2025-09-09 18:18:56 +08:00
超级老白兔
03056186c6 feat(微信聊天): 添加语音消息功能支持
实现语音消息的录制、播放和发送功能,包括:
1. 新增AudioRecorder组件用于录音
2. 添加AudioMessage组件展示语音消息
3. 修改消息输入组件支持语音消息类型
4. 调整样式适配语音消息展示
2025-09-09 18:09:38 +08:00
超级老白兔
514b077da4 refactor(SimpleFileUpload): 移除未使用的导入并优化代码结构
清理未使用的React hooks和antd组件导入,保持代码简洁
2025-09-09 16:53:47 +08:00
超级老白兔
c4866e3865 refactor(Upload/MessageEnter): 重构文件上传组件和消息输入界面
- 简化 SimpleFileUpload 组件接口,移除 disabled 和 className 属性,改为通过 type 参数控制文件类型
- 添加 slot 属性支持自定义上传按钮
- 移除不必要的上传状态管理
- 优化 MessageEnter 界面,移除素材菜单和位置功能
- 添加图片和文件上传按钮
2025-09-09 16:53:11 +08:00
超级老白兔
d0953585a7 fix(Upload/MessageEnter): 移除调试日志并完善文件类型判断逻辑
移除SimpleFileUpload组件中上传成功后的console.log
在MessageEnter组件中添加文件类型判断功能,根据文件扩展名确定消息类型并发送相应消息
2025-09-09 16:40:20 +08:00
超级老白兔
6782f188f5 refactor(Upload): 移除调试日志并优化文件上传逻辑
- 移除SimpleFileUpload组件中的console调试日志
- 重构uploadFile方法,使用axios替代原有request方法
- 添加请求头认证和超时设置
- 改进错误处理,返回更具体的错误信息
2025-09-09 16:33:27 +08:00
超级老白兔
cc58e4420e feat(上传组件): 添加SimpleFileUpload组件并集成到聊天窗口
- 创建新的SimpleFileUpload组件实现文件上传功能
- 在聊天窗口替换原有上传按钮为新的组件
- 为上传API添加调试日志
- 移除聊天窗口重复的音频图标导入
2025-09-09 16:06:59 +08:00
超级老白兔
ef95bcb8bc style(MessageRecord): 调整消息记录图标样式以改善对齐
移除verticalAlign属性并添加lineHeight和float属性,使图标在消息记录中更准确地对齐
2025-09-09 15:31:50 +08:00
超级老白兔
a5064263ba fix(MessageEnter): 修正表情选择后直接发送的问题,改为插入输入框
将表情选择后的处理逻辑从直接发送改为插入到输入框末尾,让用户可以继续编辑消息
2025-09-09 15:28:44 +08:00
超级老白兔
7fcde76981 refactor(MessageEnter): 移除未使用的表情选择器状态及相关代码 2025-09-09 15:24:41 +08:00
超级老白兔
24c99c7b95 feat(MessageRecord): 添加微信表情符号解析功能
新增 parseEmojiText 方法用于解析文本中的表情符号格式[表情名称],并将其替换为对应的表情图片。当表情不存在时保持原文本显示。修改了文本消息的渲染逻辑以支持表情显示。
2025-09-09 15:22:29 +08:00
超级老白兔
575aa833b5 fix(EmojiSelection): 修正表情资源路径添加前导斜杠 2025-09-09 15:16:57 +08:00
超级老白兔
c9f9530d09 refactor(EmojiPicker): 优化表情选择器样式并移除未使用的代码
- 将默认触发器从 button 改为 span 以简化结构
- 调整触发器样式使其更紧凑
- 移除未使用的 getAllEmojis 导入
- 删除不再使用的 EmojiPickerDemo 组件
2025-09-09 15:07:23 +08:00
超级老白兔
e76e5629bd refactor(MessageRecord): 重构小程序消息解析逻辑
移除冗余的小程序消息解析代码,统一使用 parseWeappMsgStr 方法处理
简化缩略图获取逻辑,直接使用 parsedData.previewImage
2025-09-09 14:59:54 +08:00
超级老白兔
7853a3ff97 fix(utils): 修复解析小程序消息时URL清理逻辑
处理weappiconurl时,统一替换特殊字符和CDATA标记,确保thumburl正确生成
2025-09-09 14:45:16 +08:00
超级老白兔
983dbf0009 feat(聊天窗口): 添加表情选择器组件并集成到消息输入
refactor(聊天窗口): 重构聊天窗口组件结构,提取消息记录为独立组件

feat(消息解析): 添加微信小程序消息解析功能

style(表情选择器): 添加表情选择器样式文件

chore: 添加xmldom依赖用于XML解析
2025-09-09 14:44:02 +08:00
超级老白兔
f724e91421 feat(表情包): 添加微信表情资源及类型定义模块
新增微信表情图片资源文件及类型安全的TypeScript模块,包含表情分类、路径获取和搜索等功能
2025-09-09 11:23:23 +08:00
超级老白兔
f0bf8f737f build: 更新构建生成的资源文件哈希值
更新了Vite构建生成的JavaScript和CSS文件的哈希值,确保浏览器能正确加载最新版本的文件
2025-09-09 10:46:03 +08:00
超级老白兔
9a25812b81 refactor(微信聊天窗口): 移除无用代码并重构资料显示功能
- 删除注释掉的聊天工具栏代码
- 移除未使用的导入和聊天菜单组件
- 将资料显示控制逻辑移到组件内部
- 简化头部按钮,仅保留资料显示切换功能
2025-09-09 10:43:08 +08:00
超级老白兔
79ccb20135 fix(样式): 调整微信页面布局高度以避免溢出
将高度从100vh改为calc(100vh - 64px),防止内容被顶部导航栏遮挡
2025-09-09 10:00:10 +08:00
超级老白兔
fbc40bb4be Merge branch 'yongpxu-dev' into develop 2025-09-09 09:51:28 +08:00
超级老白兔
cb44735eec style: 统一图表卡片中的引号为单引号 2025-09-09 09:51:07 +08:00
wong
c5bc67771f 代码同步提交 2025-09-09 09:49:45 +08:00
超级老白兔
eb073b04ac refactor(ckbox): 重构导航组件并优化路由配置
将导航菜单数据抽离到独立文件,简化路由配置
移除未使用的NavCommon组件属性,优化微信管理页面结构
2025-09-08 18:52:06 +08:00
超级老白兔
2b48dd8722 refactor(PlaceholderPage): 移除未使用的showFooter属性和MeauMobile组件
style(dashboard): 统一图表组件中的引号为双引号
2025-09-08 18:21:14 +08:00
超级老白兔
9fa647e40e feat(ckbox): 重构监控页面为仪表盘并添加图表功能
将监控页面重命名为仪表盘,保留原有功能组件的同时新增多个图表展示模块
使用echarts实现消息趋势、功能分布等数据可视化
优化布局和样式,提升用户体验
2025-09-08 18:19:03 +08:00
超级老白兔
fe5e7b1633 refactor(wechat): 重构微信聊天界面组件结构,将相关文件移动到weChat子目录下
重构微信聊天界面的组件结构,将原有分散的组件文件整理到weChat子目录中,包括消息列表、联系人列表、垂直用户列表等组件。同时优化了样式文件和类型定义,保持代码结构清晰。修改路由配置以支持新的目录结构。
2025-09-08 18:07:12 +08:00
超级老白兔
6c6d0f328e chore: 删除触客宝模块测试页面 2025-09-08 17:54:41 +08:00
超级老白兔
9a8af03932 Merge branch 'yongpxu-dev' into develop 2025-09-08 17:26:11 +08:00
超级老白兔
6c8becb201 refactor(workspace): 将朋友圈同步任务详情页移动到列表目录下
重构朋友圈同步任务详情页的文件位置,从独立目录移动到列表目录下,保持相关功能文件的组织一致性
2025-09-08 17:25:38 +08:00
wong
cc180dcb65 群功能处理 2025-09-08 17:24:44 +08:00
超级老白兔
d98b056b57 feat(记录页面): 重构朋友圈同步记录页面功能
- 修改API端点从点赞记录变更为发表记录
- 更新日期格式化函数处理时间戳
- 移除记录卡片中不必要的操作者信息
- 调整样式移除最大宽度限制
- 更新页面标题和空状态提示文本
2025-09-08 17:05:30 +08:00
超级老白兔
527402425f feat(朋友圈同步): 新增朋友圈同步记录页面及功能
重构朋友圈同步模块结构,将原MomentsSync组件拆分为list和record两个子模块
添加朋友圈同步记录页面,包含搜索、分页和记录展示功能
优化样式文件组织,删除重复代码
新增api接口和数据模型定义
2025-09-08 16:41:16 +08:00
超级老白兔
dba6ae164c feat(MessageRecord): 添加视频消息预览和下载功能
新增视频消息的预览图显示、加载动画和下载按钮功能。优化视频消息的交互体验,包括点击预览图触发下载请求,显示加载状态,以及视频播放时的下载选项。同时添加了相关样式和动画效果。
2025-09-08 15:53:37 +08:00
超级老白兔
97cb2b072b style(MessageRecord): 统一消息气泡的圆角样式
将消息气泡的圆角从不对称样式(4px 18px 18px 18px)改为统一的10px圆角,提升视觉一致性
2025-09-08 15:27:57 +08:00
超级老白兔
f13d623d14 style(MessageRecord): 调整消息记录样式,优化图片边框和悬停效果
移除卡片悬停动画效果,调整图片尺寸并添加边框
2025-09-08 15:22:09 +08:00
超级老白兔
4e8c728457 feat(消息记录): 增加小程序类型2和文章链接消息样式及处理逻辑
添加对小程序类型2(垂直布局)的支持,包括样式和渲染逻辑
新增文章类型消息的样式和解析处理
增加链接类型消息的样式和解析处理
优化现有小程序消息的样式和布局
2025-09-08 15:19:29 +08:00
wong
e960c0863f 代码提交 2025-09-08 15:03:39 +08:00
超级老白兔
79c1a539bb style(MessageRecord): 优化小程序卡片样式和交互效果
- 调整卡片尺寸、间距和背景渐变效果
- 添加悬停动画和阴影效果
- 优化移动端适配样式
- 移除冗余的SVG图标代码
2025-09-08 14:21:52 +08:00
超级老白兔
bd6f1064fb feat(MessageRecord): 优化消息渲染逻辑并增强样式
重构消息内容解析逻辑,增加对多种消息类型的支持,包括文本、图片、视频、表情包、小程序和文件消息。改进错误处理和兼容性,同时优化UI样式和移动端适配。

- 新增消息类型检测工具函数
- 增强JSON解析和错误处理
- 优化小程序消息的XML解析和显示
- 改进文件消息的图标和文件名显示
- 添加移动端样式适配
- 统一错误消息渲染逻辑
2025-09-08 12:13:38 +08:00
超级老白兔
57ceae97a1 feat(MessageRecord): 新增消息类型样式并优化消息解析逻辑
- 新增图片、小程序和文件消息的样式组件
- 根据msgType字段重构消息解析逻辑,支持多种消息类型
- 添加错误处理和兼容旧版本消息格式
2025-09-08 11:08:00 +08:00
超级老白兔
4fa7834510 Merge branch 'yongpxu-dev' into develop 2025-09-08 10:44:10 +08:00
超级老白兔
8ac5413765 feat(ckchat): 添加根据客服筛选获取合同列表的方法 2025-09-08 10:44:00 +08:00
超级老白兔
524eef9a54 Merge branch 'develop' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into develop 2025-09-08 10:41:44 +08:00
超级老白兔
a4d19c8fc9 refactor(ckchat): 将getSomeContractList改为同步方法并添加类型注释
修改异步方法为同步方法,提高性能并添加类型注释以增强代码可读性
2025-09-08 10:40:42 +08:00
wong
d62701fa85 代码同步 2025-09-08 10:40:18 +08:00
超级老白兔
59da085676 feat(ckchat): 添加根据客服筛选合同列表的功能 2025-09-08 10:39:54 +08:00
超级老白兔
1305bfac59 fix(weChat): 移除消息加载状态的延迟设置
移除setTimeout延迟设置messagesLoading为false的逻辑,改为在try和finally块中直接设置,避免不必要的延迟
2025-09-08 10:32:00 +08:00
超级老白兔
b84a3255c6 fix(weChat): 修复消息加载顺序和加载状态显示问题
调整消息数组拼接顺序,确保新消息正确追加
添加加载状态图标并优化加载更多消息的逻辑
设置消息加载状态延迟更新以避免闪烁
2025-09-08 10:30:22 +08:00
超级老白兔
8682cdab51 Merge branch 'yongpxu-dev' into develop 2025-09-08 09:45:50 +08:00
超级老白兔
2033faff08 feat(weChat): 优化聊天消息加载逻辑并移除无用按钮
添加 isLoadingData 状态控制滚动行为
修改 loadChatMessages 方法支持分页加载
移除聊天窗口的语音和视频通话按钮
更新构建产物文件引用
2025-09-08 09:45:10 +08:00
wong
7f5daa0f85 群功能提交 2025-09-08 09:44:26 +08:00
超级老白兔
b2db8e8f5a Merge branch 'yongpxu-dev' into develop 2025-09-05 17:11:55 +08:00
wong
1c99eee96b 代码提交 2025-09-05 17:10:50 +08:00
wong
689e6d18df 群弹窗 2025-09-05 17:08:26 +08:00
超级老白兔
c4ba459b20 refactor(ckbox): 移除全局profile状态并移至ChatWindow组件
将profile显示状态从父组件移至ChatWindow组件内部管理,简化组件间通信
2025-09-05 17:04:34 +08:00
超级老白兔
ae1ef52113 FEAT => 本次更新项目为: 2025-09-05 16:57:30 +08:00
超级老白兔
03145afa4f feat(ckbox): 添加通用导航组件并优化聊天窗口布局
- 新增NavCommon组件作为通用导航栏
- 优化ChatWindow的flex布局和滚动行为
- 替换原Header为新的导航组件
- 更新构建产物文件
2025-09-05 16:54:18 +08:00
超级老白兔
b03b457e7e style(ckbox): 调整垂直用户列表样式和布局
- 修改侧边栏边框颜色为浅色
- 增加侧边栏宽度和头像尺寸
- 更新用户列表背景色和文字颜色
- 优化选中状态的视觉表现
2025-09-05 16:11:22 +08:00
超级老白兔
f31941425d refactor(聊天窗口): 优化消息列表和记录组件
移除未使用的导入和代码,添加加载更多提示
重构消息列表组件以支持客服筛选功能
2025-09-05 15:50:21 +08:00
超级老白兔
18ec2752ba 同步 2025-09-05 15:36:39 +08:00
超级老白兔
bbf0bee19b Merge branch 'yongpxu-dev' into develop 2025-09-05 15:25:13 +08:00
wong
e3bf844420 群成员功能优化 2025-09-05 15:24:09 +08:00
超级老白兔
afa58712cf fix(MessageList): 修复从store获取chatSessions的方式
使用getChatSessions方法替代直接访问chatSessions状态,确保获取的是最新数据
2025-09-05 15:22:26 +08:00
超级老白兔
f76029c2d9 fix: 添加群组列表到微信账号ID去重逻辑中 2025-09-05 15:14:36 +08:00
超级老白兔
25da77a3b1 refactor(ChatWindow): 使用Antd Divider替换自定义时间分隔线样式
移除MessageRecord.module.scss中自定义的时间分隔线样式,改为使用Antd的Divider组件
2025-09-05 15:08:52 +08:00
超级老白兔
70256b252c fix(chat): 修复新会话未读计数初始化问题
移除ckchat.ts中自动设置unreadCount为0的逻辑,改为在weChat.ts中添加会话时显式设置unreadCount为1,确保新消息有正确未读标记
2025-09-05 14:55:24 +08:00
超级老白兔
e7c109eab1 refactor(wechat): 优化消息接收处理和数据库结构
- 移除未使用的kfUserService导入
- 为weChatGroup和ContractData接口添加serverId字段
- 重构receivedMsg方法,根据消息类型从数据库获取会话信息
- 简化数据库表结构,移除冗余的WithServerId接口
2025-09-05 14:53:09 +08:00
超级老白兔
66241f32af feat(微信): 添加wechatChatroomId字段并优化消息处理逻辑
- 在weChatGroup接口中添加wechatChatroomId字段
- 移除调试用的console.log语句
- 重构消息处理逻辑,简化条件判断并新增会话初始化处理
2025-09-05 11:47:40 +08:00
超级老白兔
2e7f890218 Merge branch 'yongpxu-dev' into develop 2025-09-05 11:06:25 +08:00
超级老白兔
d31edeef65 refactor(weChat): 重构消息处理逻辑并优化组件结构
将消息滚动逻辑移至MessageRecord组件
统一处理群组和好友消息的ID判断
移除ChatWindow中不必要的props传递
2025-09-05 11:05:49 +08:00
wong
55ff880993 代码优化 2025-09-05 10:20:05 +08:00
超级老白兔
7c9ae9e339 refactor(ChatWindow): 提取消息记录组件并优化样式
将消息记录相关逻辑从ChatWindow组件中提取为独立的MessageRecord组件
新增MessageRecord.module.scss文件定义消息样式
简化ChatWindow组件逻辑,提高代码可维护性
2025-09-05 10:03:09 +08:00
超级老白兔
f1a2ee6170 refactor: 删除未使用的Person组件文件 2025-09-04 18:24:31 +08:00
超级老白兔
25a77db3c6 refactor(mine/content): 移除Collapse组件的默认激活状态
构建文件因代码更改而更新
2025-09-04 18:18:07 +08:00
超级老白兔
914538d2ed Merge branch 'yongpxu-dev' into develop 2025-09-04 18:14:01 +08:00
超级老白兔
9c9b982a56 refactor: 重构内容库相关页面和组件
删除不再使用的内容库相关页面、组件和API文件
重命名表单字段以更清晰地表达其用途
优化代码结构和组织方式
2025-09-04 18:13:39 +08:00
超级老白兔
0d18623473 feat(群聊): 实现群聊消息展示及成员信息获取功能
- 在WeChatState中新增currentGroupMembers字段存储群成员信息
- 添加getGroupMembers API接口获取群成员数据
- 重构消息类型定义,统一使用ChatRecord接口
- 修改消息处理逻辑,支持群聊消息展示
- 调整聊天窗口样式,区分群聊和私聊消息显示
- 实现群成员头像和昵称展示功能
2025-09-04 18:07:42 +08:00
wong
876b4e4a5d 代码提交 2025-09-04 17:34:49 +08:00
超级老白兔
a6134bb455 Merge branch 'yongpxu-dev' into develop
# Conflicts:
#	Cunkebao/src/pages/pc/ckbox/components/ChatWindow/components/ProfileCard/index.tsx   resolved by develop version
2025-09-04 16:33:40 +08:00
超级老白兔
711159aa2b FEAT => 本次更新项目为: 2025-09-04 16:33:03 +08:00
wong
451d737d90 群成员功能 2025-09-04 16:31:48 +08:00
超级老白兔
12d8c39ccf fix(weChat): 修正群聊ID赋值错误并优化初始化流程
- 将wechatChatroomId从contact.chatroomId改为contact.id以修复赋值错误
- 调整chatInitAPIdata中的初始化顺序,先获取群列表再处理唯一ID
- 修改getUniqueWechatAccountIds函数参数以支持群组数据
2025-09-04 15:00:29 +08:00
超级老白兔
54464efdcd fix(ChatWindow): 增加对消息对象的空值检查以防止运行时错误
- 在hasVideoStateChange函数中优先检查消息对象和内容是否存在
- 在groupMessagesByTime函数中过滤掉null和undefined的消息
- 在renderMessage函数中添加null检查并为缺失id的消息生成临时key
2025-09-04 14:51:23 +08:00
超级老白兔
923f0e99b9 fix(ChatWindow): 处理消息内容为null或undefined的情况
添加对消息内容为null或undefined的检查,防止解析时出错
2025-09-04 11:58:36 +08:00
超级老白兔
2d78c2a37a refactor(ChatWindow): 移除调试日志并优化头像显示逻辑
删除无用的console.log调试信息,避免生产环境输出敏感数据
头像显示逻辑改为优先使用contract.avatar,不存在时使用contract.chatroomAvatar作为备选
2025-09-04 11:25:23 +08:00
超级老白兔
37da3e8350 refactor(ProfileCard): 优化图标导入并删除未使用的图标
移除未使用的图标导入并重新组织剩余图标的导入顺序,提高代码整洁度
2025-09-04 11:19:20 +08:00
超级老白兔
890e3c338b fix(ProfileCard): 修复群聊信息编辑时JSON字符串格式问题
修复群名称和群公告编辑时JSON字符串格式错误,将单引号替换为双引号以确保正确解析
2025-09-04 11:07:44 +08:00
超级老白兔
8d9d069267 Merge branch 'yongpxu-dev' into develop
# Conflicts:
#	Cunkebao/src/pages/pc/ckbox/components/ChatWindow/components/ProfileCard/index.tsx   resolved by develop version
2025-09-04 10:52:55 +08:00
wong
3c68a603af 代码提交 2025-09-04 10:49:22 +08:00
超级老白兔
1f0ef3c64d refactor(chat): 重命名Person组件为ProfileCard并优化代码
修复微信聊天消息可能为undefined的问题
添加调试日志检查消息状态
确保wechatTime字段安全访问
2025-09-04 10:47:57 +08:00
超级老白兔
df0bbddbd5 feat(weChat): 添加联系人存在检查逻辑并优化消息处理
在setCurrentContact方法中添加isExist参数,用于区分新增联系人和已存在联系人的处理逻辑
优化消息处理流程,确保未读消息计数正确更新
2025-09-03 18:33:05 +08:00
超级老白兔
7bd7bd3564 fix(weChat/ckchat): 修复切换联系人时未重置未读计数的问题
在切换联系人时,确保会话的未读计数被正确重置为0。将重置逻辑统一移至addChatSession方法中处理,避免遗漏。
2025-09-03 18:20:24 +08:00
超级老白兔
30cafc5619 refactor(weChat/ckchat): 优化会话更新逻辑并移除冗余代码
- 修复未读消息计数时可能出现的类型问题
- 直接使用chatSessions状态而非getChatSessions方法
- 简化会话更新逻辑,移除不必要的缓存处理
- 使用更简洁的路径引用deepCopy工具
2025-09-03 18:04:39 +08:00
超级老白兔
7e5617bd80 refactor(ckbox): 移除SidebarMenu的currentContract属性并优化状态管理
- 移除不再使用的currentContract属性和相关props传递
- 将chatSessions状态管理移至MessageList组件内部
- 添加CmdFriendInfoChanged消息处理器
- 添加调试日志用于会话更新
2025-09-03 17:55:25 +08:00
超级老白兔
533c16be3f feat(weChat): 添加receivedMsg方法处理接收消息逻辑
新增receivedMsg方法用于处理微信消息接收逻辑,区分当前会话消息和未读消息更新
优化updateChatSession实现,使用深拷贝避免直接修改状态
调整ckchat.data.ts中方法顺序,保持代码整洁
2025-09-03 17:47:43 +08:00
超级老白兔
ff96312d53 feat(websocket): 添加消息处理逻辑并清理无用代码
在websocket消息处理器中添加addMessage调用以处理新消息
移除ChatWindow组件中无用的样式和注释代码
2025-09-03 17:18:19 +08:00
超级老白兔
0bddc4dc5b fix: 修复消息发送后输入框未清空及自动点赞状态切换问题
修复消息发送后输入框未清空的问题,优化自动点赞任务状态切换逻辑
更新消息处理逻辑,修正构建文件引用路径
2025-09-03 17:05:53 +08:00
超级老白兔
9cdfe552e0 fix: 移除currentContract持久化并清理调试日志和WebSocket状态
移除weChat模块中currentContract的持久化配置,避免登录和刷新时数据残留
清理ChatWindow组件中的调试日志
在登录时清空WebSocket连接状态
2025-09-03 16:49:45 +08:00
超级老白兔
c27642bc12 feat(websocket): 添加清空连接状态方法用于退出登录
新增clearConnectionState方法,用于在用户退出登录时清空WebSocket连接状态。该方法会关闭现有连接、停止所有定时器并重置所有相关状态变量,确保用户登出后不会保留之前的连接信息。
2025-09-03 16:36:10 +08:00
超级老白兔
a3ba45626d feat(微信/websocket): 新增消息处理逻辑并优化websocket连接
- 在WeChatState接口中添加addMessage方法用于接收新消息
- 在websocket消息处理器中调用addMessage存储接收到的消息
- 优化websocket连接逻辑,断开时自动尝试重连
- 改进聊天窗口视频状态检测逻辑,减少不必要的滚动
2025-09-03 16:33:52 +08:00
超级老白兔
ef853d2736 feat(weChat): 重构视频消息处理逻辑并优化加载状态管理
- 移除旧的待处理视频请求队列及相关方法
- 新增setVideoLoading和setVideoUrl方法简化视频状态管理
- 优化ChatWindow组件中的视频加载状态检测和滚动行为
- 添加CmdDownloadVideoResult消息处理器自动更新视频URL
2025-09-03 16:06:12 +08:00
超级老白兔
8b1387a8ed feat(weChat): 添加视频请求处理和WebSocket监听功能
- 在weChat store中新增pendingVideoRequests状态和相关操作方法
- 实现WebSocket监听处理视频下载响应
- 重构ChatWindow组件,将视频处理逻辑移至store
- 优化消息分组和渲染逻辑
2025-09-03 15:08:29 +08:00
超级老白兔
647e2a5f7e refactor(weChat): 重构微信聊天模块状态管理
将微信聊天相关状态从组件中提取到独立的zustand store
移除冗余的props传递,使用store管理当前联系人和消息
优化消息加载逻辑,统一处理消息状态
2025-09-03 14:52:32 +08:00
wong
d3ae45a360 群推消息推送优化 2025-09-03 14:34:26 +08:00
超级老白兔
48880bed0d feat(wechat): 实现微信聊天状态管理及消息处理功能
添加微信聊天状态管理store,包含联系人管理、消息发送/接收、未读消息计数等功能
修复聊天窗口参数传递问题,统一使用contract.id作为标识
调整消息加载数量从10条减少到5条
2025-09-03 11:25:10 +08:00
超级老白兔
c6da2062f2 FEAT => 本次更新项目为: 2025-09-03 10:45:19 +08:00
超级老白兔
414660a0a5 refactor(ChatWindow): 移除调试用的console.log语句
清理无用代码,避免生产环境输出不必要的信息
2025-09-03 10:01:26 +08:00
超级老白兔
2995755cda refactor(websocket): 将硬编码的5000毫秒改为5 * 1000以提高可读性 2025-09-03 09:54:40 +08:00
超级老白兔
0d6ac88dea refactor(websocket): 将客服状态查询定时器逻辑移至websocket store
将原本在组件中的客服状态查询定时器逻辑重构到websocket store中,统一管理定时器的启动和停止。同时在连接成功时自动启动定时器,断开连接时自动停止,避免内存泄漏。
2025-09-03 09:52:58 +08:00
超级老白兔
eb63dc1d8d refactor(websocket): 移除消息处理器中的空行 2025-09-03 09:35:09 +08:00
超级老白兔
22560a5ce2 fix(SidebarMenu): 修改搜索框占位文本为"搜索客户..."
原占位文本"搜索联系人、群组"不符合当前业务场景,更新为更准确的"搜索客户..."
2025-09-02 17:58:19 +08:00
超级老白兔
4c5e049c16 feat(ckbox): 添加更新微信好友配置的API和调用
在聊天会话初始化时调用updateConfig API更新好友配置,标记为可聊天状态
2025-09-02 17:51:37 +08:00
超级老白兔
92e9b69348 feat(WechatFriends): 添加搜索功能并优化联系人列表展示
- 新增搜索联系人及群组功能,支持本地数据库查询
- 添加无搜索结果时的提示样式
- 优化联系人列表渲染逻辑,区分搜索模式和分组模式
- 统一联系人项展示样式,支持群组标识
2025-09-02 17:40:11 +08:00
超级老白兔
b08086e3f5 feat 2025-09-02 17:36:53 +08:00
超级老白兔
70877c8c96 feat(ckchat): 添加搜索关键词状态及相关方法
在CkChatState接口中添加searchKeyword字段用于存储搜索关键词,并新增setSearchKeyword和clearSearchKeyword方法用于管理搜索状态
2025-09-02 16:32:25 +08:00
超级老白兔
e35403eaf4 fix(websocket): 处理被踢出通知时跳转到登录页面
当收到"Kicked out"通知时,直接重定向到登录页面以强制用户重新登录
2025-09-02 15:52:44 +08:00
超级老白兔
8d8068f5d6 fix: 将聊天记录请求数量从100减少到10以降低负载 2025-09-02 15:39:27 +08:00
超级老白兔
fd82dfc5e0 fix(ChatWindow): 修复聊天窗口消息请求参数错误
调整了消息请求的参数逻辑,将时间戳改为固定值并修正了群聊和私聊的参数判断条件
2025-09-02 15:27:55 +08:00
超级老白兔
d5e609aa37 feat(聊天窗口): 重构消息输入组件并添加微信风格样式
将消息输入功能从ChatWindow组件中拆分为独立的MessageEnter组件
添加微信风格的样式和交互效果
新增消息处理逻辑和素材选择功能
重命名getMessages为getChatMessages以保持命名一致性
2025-09-02 15:21:54 +08:00
超级老白兔
b3f6d4f6e7 fix(websocket): 移除重复的seq字段并统一在命令中添加
在websocket命令构造中统一添加seq字段,避免在调用处重复设置。移除ckbox页面中重复的seq设置,保持代码一致性。
2025-09-02 14:26:44 +08:00
超级老白兔
4fd8c1f5bf docs(ckbox): 更新注释说明为查询客服用户激活状态 2025-09-02 14:23:36 +08:00
超级老白兔
45c496313d refactor(Skeleton): 重构骨架屏组件结构和样式
- 将原有单一骨架屏拆分为头部、侧边栏、聊天区域和右侧面板多个模块
- 优化骨架屏的样式细节,使其更接近真实UI
- 添加加载状态提示和交互效果
2025-09-02 14:20:03 +08:00
超级老白兔
97bb1c1fa9 refactor(ckbox): 调整样式和清理无用代码
- 删除未使用的MessageEnter组件
- 修复样式文件中缩进不一致问题
- 移除ChatWindow中未使用的store引用
- 调整消息输入框的行数设置
2025-09-02 12:00:31 +08:00
超级老白兔
316a237297 fix(ckchat): 修复聊天窗口输入框事件处理和类型定义
修复输入框的onKeyPress事件为onKeyDown以更好处理键盘事件
更新Person组件props类型定义以支持weChatGroup类型
将getkfUserList改为异步函数以备后续实现
2025-09-02 11:49:26 +08:00
超级老白兔
efa34a1ac6 Merge branch 'develop' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into develop 2025-09-02 11:28:46 +08:00
wong
c146796987 京东联盟 转链 2025-09-02 11:24:23 +08:00
超级老白兔
a67ca442a0 FEAT => 本次更新项目为: 2025-09-02 11:23:18 +08:00
超级老白兔
e7b795f744 refactor(websocket): 优化websocket消息处理及状态检查逻辑
移除调试日志输出并优化微信账号状态检查逻辑
添加深拷贝工具函数并应用于客服列表处理
将状态检查改为间隔10秒的轮询方式
2025-09-02 10:18:25 +08:00
超级老白兔
20658c3ca5 refactor(websocket): 重构websocket模块并添加消息管理器
- 将websocket模块拆分为多个文件,提高代码可维护性
- 新增msgManage.ts处理不同类型的websocket消息
- 优化消息处理逻辑,减少重复代码
- 更新相关文件引用路径
2025-09-02 09:52:38 +08:00
超级老白兔
cfa8182789 refactor(websocket): 移除获取微信账号状态的冗余命令
移除在WebSocket连接成功后发送的获取微信账号状态的命令,该命令在当前场景下不再需要
2025-09-01 17:36:03 +08:00
超级老白兔
a867f25481 fix: 修复FilterModal中用户状态选择类型转换问题
将用户状态选择的值从直接赋值改为使用Number()进行类型转换,确保类型一致性
2025-09-01 17:34:40 +08:00
超级老白兔
9906f14446 FEAT => 本次更新项目为: 2025-09-01 17:33:52 +08:00
超级老白兔
cca999a18d FEAT => 本次更新项目为: 2025-09-01 17:33:47 +08:00
超级老白兔
3198959cb7 feat(群推任务): 添加获取群推任务详情的API接口
feat(客服聊天): 实现搜索功能并优化联系人筛选逻辑

refactor(WebSocket): 重构连接逻辑,增加状态检查和调试信息

fix(WebSocket): 修复页面刷新后重连逻辑,避免重复连接
2025-09-01 17:28:33 +08:00
超级老白兔
832be374b5 refactor(ckchat): 重构联系人列表获取逻辑并添加缓存机制
- 将联系人列表获取逻辑从直接调用改为使用useEffect异步获取
- 为getNewContractList添加缓存机制避免重复计算
- 在相关状态变更时自动清除缓存
- 新增asyncNewContractList方法用于设置联系人列表
2025-09-01 14:58:15 +08:00
超级老白兔
aec0bad35f feat(ckchat): 添加联系人列表缓存功能并重构状态管理
- 新增getContractList方法实现联系人列表缓存
- 重构asyncKfSelected方法以触发多个缓存更新
- 移除asyncNewContractList方法,改为使用createContractList API
- 修复多处拼写错误和代码格式问题
- 优化缓存更新逻辑,避免不必要的重新计算
2025-09-01 14:51:11 +08:00
超级老白兔
f77e8709a8 refactor(ckchat): 重构联系人列表获取逻辑并优化状态管理
- 将联系人列表获取逻辑从组件移至store
- 新增getNewContractList方法替代直接访问状态
- 移除不再使用的getContractList方法
- 优化缓存处理逻辑
- 修复部分语法错误和格式问题
2025-09-01 14:44:46 +08:00
超级老白兔
f05efe464a feat(ckchat): 重构联系人列表逻辑并添加缓存功能
- 将联系人列表构建逻辑提取到独立api文件
- 添加getContractList缓存机制避免重复计算
- 优化kfSelected变更时的缓存清除逻辑
- 移除main.ts中冗余的联系人分组逻辑
2025-09-01 11:40:01 +08:00
超级老白兔
3cb10e217b perf(ckchat): 优化getChatSessions缓存机制避免无限循环
添加缓存机制来避免getChatSessions方法的重复计算,通过检查kfSelected和chatSessions的变化来决定是否重新计算缓存。同时在相关操作后主动清除缓存以确保数据一致性。
2025-09-01 10:43:09 +08:00
超级老白兔
52430d6466 refactor(db): 移除测试相关代码并优化消息列表数据结构
移除数据库测试页面和示例代码,清理测试路由配置
新增MessageListData接口支持微信群组和联系人两种数据类型
优化数据库表结构和服务导出
2025-09-01 10:36:16 +08:00
超级老白兔
64c75772bb feat(数据库): 添加消息列表数据接口和表
refactor(聊天会话): 根据选中客服过滤会话列表

fix(聊天窗口): 移除重复的未读消息清除逻辑

refactor(侧边栏): 统一联系人点击处理逻辑

chore: 删除无用的数据库测试文件
2025-09-01 10:24:15 +08:00
超级老白兔
5437a47e37 feat(聊天窗口): 支持群聊消息获取功能
修改api接口参数和组件逻辑,使聊天窗口能够处理群聊消息
2025-08-30 17:37:55 +08:00
超级老白兔
1605b96173 chore: 更新应用名称并统一logo图片
更新aiApp的应用名称从"Ai数智员工"为"AI数智员工",同时更新了aiApp和ckApp的logo图片
2025-08-30 17:30:49 +08:00
超级老白兔
09e78277b5 feat(ckchat): 添加获取客服用户信息的接口方法 2025-08-30 17:17:09 +08:00
超级老白兔
58ad5b3254 Merge branch 'develop' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into develop 2025-08-30 17:15:50 +08:00
超级老白兔
14813013a7 feat(ckchat): 添加获取客服用户信息的方法并更新相关引用
添加getKfUserInfo方法用于根据微信账号ID获取客服用户信息
更新Person组件中使用新方法替代原有的kfSelectedUser调用
2025-08-30 17:15:22 +08:00
wong
343c142d87 门店端优化 2025-08-30 17:14:57 +08:00
超级老白兔
25b983a9ae Merge branch 'develop' into yongpxu-dev
# Conflicts:
#	Cunkebao/src/pages/pc/ckbox/components/ChatWindow/components/Person/index.tsx   resolved by develop version
#	Cunkebao/src/pages/pc/ckbox/components/ChatWindow/index.tsx   resolved by yongpxu-dev version
#	Cunkebao/src/store/module/ckchat/ckchat.data.ts   resolved by yongpxu-dev version
#	Cunkebao/src/store/module/ckchat/ckchat.ts   resolved by yongpxu-dev version
2025-08-30 17:10:30 +08:00
超级老白兔
8e16067cf3 fix(SidebarMenu/WechatFriends): 修复头像显示逻辑,优先展示chatroomAvatar
当contact.avatar不存在时,现在会尝试使用contact.chatroomAvatar作为头像来源
2025-08-30 17:08:06 +08:00
wong
b9d88160a2 触客宝右边栏提交 2025-08-30 17:07:53 +08:00
超级老白兔
b780a4db58 fix(ckchat): 修正获取选中客服信息的方法名拼写错误 2025-08-30 17:07:08 +08:00
超级老白兔
0975995486 feat(ckbox): 重构微信联系人分组逻辑并优化数据库操作
- 在ContactGroupByLabel和weChatGroup接口中添加count和labels字段
- 将weChatGroup重命名为weChatGroupServerId以更准确描述用途
- 修改数据库操作,使用service直接处理数据存储
- 重构createContractList函数,根据groupType查询不同服务获取数据
- 移除VerticalUserList中不必要的异步获取逻辑,直接使用store数据
2025-08-30 17:02:31 +08:00
超级老白兔
14f0a6d7f3 fix: 修正数据库清理中微信群的表名拼写错误 2025-08-30 15:55:54 +08:00
超级老白兔
136e0f6225 refactor(ckbox): 统一接口命名将wechatGroup改为weChatGroup
重构微信相关接口命名,将wechatGroup统一改为weChatGroup以保持命名一致性
更新相关组件、store和数据库服务以适配新接口名称
2025-08-30 15:55:15 +08:00
超级老白兔
8581432bf4 refactor(数据库): 重命名GroupData为wechatGroup并优化数据库初始化
重构GroupData接口为wechatGroup以更准确描述微信群组数据结构
在数据库初始化时添加调试模式清理数据功能
更新所有相关引用和数据库服务实例名称
2025-08-30 15:36:03 +08:00
超级老白兔
5bdd299dad refactor(db): 重构数据库架构使用serverId作为主键
- 将数据库主键从自增id改为直接使用serverId,避免ID冲突
- 简化数据存储和查询逻辑,提高性能
- 添加重复数据检测和去重功能
- 更新相关组件以适配新的数据库接口
- 在应用启动时初始化数据库连接
2025-08-30 15:00:26 +08:00
超级老白兔
d4336ed447 refactor(store): 移除未使用的ckchat模块及相关代码
清理不再使用的ckchat store模块及其相关导入,简化代码结构
2025-08-30 14:23:12 +08:00
超级老白兔
fa1b2b329f Merge branch 'yongpxu-dev' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into yongpxu-dev 2025-08-30 11:52:55 +08:00
超级老白兔
13cb684abd refactor(store): 重构ckchat模块为子目录结构
feat(test): 添加数据库测试页面和工具

将ckchat相关代码移动到store/module/ckchat子目录,包含数据定义和实现文件
添加数据库测试页面和工具类,支持服务器ID与本地ID映射
移除不再使用的initSafeArea函数
2025-08-30 11:52:52 +08:00
wong
f6837f7819 代码提交 2025-08-30 10:58:34 +08:00
超级老白兔
bf2e017ca0 Merge branch 'yongpxu-dev' into yongpxu-dev4 2025-08-29 17:20:25 +08:00
超级老白兔
1defb30632 Merge branch 'yongpxu-dev' into yongxu-dev3 2025-08-29 17:20:19 +08:00
超级老白兔
b3aa52cd91 FEAT => 本次更新项目为: 2025-08-29 17:19:23 +08:00
超级老白兔
06e0ce5106 refactor: 移除测试页面并优化主页面功能
- 删除未使用的测试页面及相关路由配置
- 注释掉主页面中暂时不需要的初始化函数调用
- 添加页面备份文件以备后续参考
2025-08-29 17:14:23 +08:00
超级老白兔
46c31ac653 feat(更新服务): 添加应用自动更新功能
- 在首页添加应用版本检查和更新功能
- 新增updateService.js实现版本比较、下载安装和更新提示
- 支持Android和iOS平台的更新处理
2025-08-29 17:11:27 +08:00
超级老白兔
778f1a3a11 feat(update): 添加应用自动更新功能
- 新增updateService模块实现版本检查、下载和安装功能
- 在首页集成更新检查逻辑
- 支持Android和iOS平台的更新处理
- 添加版本比较和更新提示对话框功能
2025-08-29 17:09:47 +08:00
wong
fb10e43055 代码优化 2025-08-29 17:04:11 +08:00
wong
2deb80fdbf app更新优化 2025-08-29 16:56:50 +08:00
wong
1d731c0006 app更新接口提交 2025-08-29 16:46:47 +08:00
超级老白兔
3dba61f9d9 chore: 更新manifest.json中的appid 2025-08-29 16:03:05 +08:00
超级老白兔
2ba9616f49 docs: 更新应用名称为"Ai数智员工"
修改manifest.json文件中的应用名称,从"Ai智能客服"变更为"Ai数智员工"以反映产品定位更新
2025-08-29 16:00:20 +08:00
超级老白兔
27aa23179f refactor: 更新应用名称和API基础URL
将应用名称从"存客宝"更改为"Ai智能客服"以更准确反映产品功能
更新baseUrl为新的API域名"kr-phone.quwanzhi.com"
2025-08-29 15:59:53 +08:00
超级老白兔
5a23174e8b Merge branch 'yongpxu-dev' into yongpxu-dev4 2025-08-29 15:57:54 +08:00
超级老白兔
e80a31905e Merge branch 'yongpxu-dev' into yongxu-dev3 2025-08-29 15:57:46 +08:00
超级老白兔
c8d63bf93a Merge branch 'yongpxu-dev' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into yongpxu-dev 2025-08-29 15:56:02 +08:00
超级老白兔
02b394f31b feat(聊天窗口): 添加右侧联系人资料卡片组件
将联系人资料卡片从主聊天窗口组件中拆分出来,创建独立的Person组件
实现资料卡片的样式和功能,包括基本信息展示、备注编辑和操作按钮
添加响应式设计支持移动端显示
2025-08-29 15:55:03 +08:00
超级老白兔
a5dcb64a10 feat: 初始化AI应用项目结构并添加基础功能
添加项目基础文件结构包括静态资源、配置文件、页面组件和工具函数
实现web-view通信功能,支持配置传递和消息处理
添加安全区域高度计算工具和全局样式配置
2025-08-29 15:48:59 +08:00
超级老白兔
db4bc8651d feat(客服聊天): 添加获取当前选中客服用户的功能
在CkChatState接口中添加kfSelectedUser方法用于获取当前选中的客服用户信息,并在聊天窗口组件中显示该信息
2025-08-29 15:40:46 +08:00
超级老白兔
8e177534f4 FEAT => 本次更新项目为: 2025-08-29 15:29:48 +08:00
超级老白兔
49a94318ac Merge branch 'develop' into yongpxu-dev
# Conflicts:
#	Cunkebao/src/pages/pc/ckbox/components/ChatWindow/index.tsx   resolved by yongpxu-dev version
2025-08-29 15:27:07 +08:00
wong
9fc2dee5d7 触客宝右侧功能提交 2025-08-29 15:16:59 +08:00
wong
d89682027e 门店端优化 2025-08-29 15:16:17 +08:00
超级老白兔
bc7cc6810d feat(db): 添加Dexie数据库支持并重构数据存储结构
添加Dexie作为IndexedDB封装库,实现本地数据存储功能
重构数据接口定义和存储模块结构,优化类型定义
统一数据接口文件位置,增强代码可维护性
2025-08-29 15:13:31 +08:00
超级老白兔
bdc94d853d refactor(组件): 优化微信好友列表和聊天窗口菜单代码结构
重构微信好友列表组件中的getCollapseItems方法,简化代码格式
将聊天窗口的菜单从JSX改为items数组配置方式,提高可维护性
2025-08-29 10:49:13 +08:00
超级老白兔
190f2df15e feat(store): 添加asyncKfSelected方法用于更新选中客服
添加asyncKfSelected方法到ckchat store,用于异步更新选中的客服ID。同时移除未使用的代码和console.log
2025-08-29 10:41:19 +08:00
超级老白兔
7a4831e200 feat(ckchat): 添加客服在线状态显示和选择功能
- 在KfUserListData接口中添加isOnline字段表示客服在线状态
- 在CkChatState中添加kfSelected字段存储当前选中的客服ID
- 重构VerticalUserList组件,使用zustand管理选中状态
- 添加在线状态指示器样式,区分在线和离线状态
- 优化persistUtils工具,添加分片存储功能处理大数据
2025-08-29 10:36:37 +08:00
wong
db2133a4b0 Merge branch 'develop' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into develop 2025-08-29 09:51:56 +08:00
wong
26e519bec0 群创建 代码优化 2025-08-29 09:51:00 +08:00
超级老白兔
bcc2022826 style(SidebarMenu): 调整侧边栏菜单的内边距和移除多余样式
移除搜索框的全局样式和标签栏底部内边距,优化头部容器的内边距
2025-08-29 09:45:24 +08:00
超级老白兔
faefefe186 refactor(ckbox): 优化侧边栏菜单组件和联系人列表
- 将群组图标和文字替换为朋友圈
- 移除未使用的response变量
- 重构联系人列表组件,使用Collapse的items属性替代Panel组件
- 添加CollapseProps类型导入
2025-08-29 09:43:39 +08:00
超级老白兔
519f66f46d Merge branch 'develop' into yongpxu-dev 2025-08-29 09:27:32 +08:00
超级老白兔
bc6d85acca feat(消息列表): 添加未读消息计数和最近一天消息提示
- 在消息列表项中添加未读消息计数气泡显示
- 默认不展开微信好友分组
- 在消息列表底部添加"最近一天的消息"提示栏
2025-08-28 18:30:11 +08:00
超级老白兔
d878a1fcaa feat(WechatFriends): 实现联系人列表分页加载功能
添加react-window依赖并实现分组联系人列表的分页加载功能,优化大数据量下的性能表现
- 每组初始加载20条数据,滚动到底部可点击加载更多
- 添加加载状态提示和"没有更多了"的结束提示
- 优化样式添加加载更多按钮的容器样式
2025-08-28 18:24:05 +08:00
超级老白兔
b4eb2919b1 feat(联系人列表): 实现分组展示功能并重构组件结构
添加新的联系人分组功能,支持按分组展示联系人列表
重构联系人列表组件结构,将原有组件拆分为更清晰的模块
新增状态管理逻辑用于存储和获取分组联系人数据
移除不再使用的旧样式文件和组件
2025-08-28 18:17:40 +08:00
超级老白兔
64b5518309 fix(api): 处理401错误时跳转到登录页面并显示提示
添加对401错误的处理逻辑,当用户未登录或登录过期时,显示提示并跳转到登录页面。同时保留当前路径以便登录后跳回。
2025-08-28 18:01:36 +08:00
超级老白兔
e2ff3dd7c5 feat(ContentSelection): 添加搜索功能并优化分页逻辑
- 在PopupHeader组件中添加onSearch回调支持
- 将Input组件替换为Input.Search以支持搜索按钮
- 重构selectionPopup组件,移除useCallback并优化搜索和分页处理
- 减少每页显示数量从20改为10
- 简化空状态显示逻辑
2025-08-28 17:56:12 +08:00
超级老白兔
7430f4deb8 Merge branch 'yongpxu-dev' into yongpxu-dev2
# Conflicts:
#	Cunkebao/dist/.vite/manifest.json
#	Cunkebao/dist/index.html
2025-08-28 17:39:40 +08:00
超级老白兔
b89860bc93 refactor(ContentSelection): 将弹窗组件抽离为独立文件并优化逻辑
将内容选择弹窗组件抽离为独立的selectionPopup.tsx文件,优化代码结构
添加加载状态处理,改进搜索和分页逻辑,增强组件复用性
2025-08-28 17:38:35 +08:00
超级老白兔
87a1002aa5 fix(workspace/moments-sync): 修复群组选择key冲突并更新内容库显示逻辑
修复测试页面中群组选择tab的key冲突问题,将'groups'改为'groups2'
更新MomentsSync页面内容库显示逻辑,使用contentGroupsOptions中的name字段替代contentLibraryNames
2025-08-28 17:19:23 +08:00
超级老白兔
ca44dab358 fix(selection): 使用临时状态管理选中项避免直接修改props
在多个选择弹窗组件中引入临时状态变量tempSelectedOptions来管理选中项,避免直接修改props中的selectedOptions。当用户确认选择时才更新实际选中的选项,提供更一致的用户体验。
2025-08-28 17:14:50 +08:00
超级老白兔
53a78e6744 feat(ContentSelection): 添加临时选中选项以优化选择交互
在内容选择组件中引入临时选中选项(tempSelectedOptions),避免直接修改选中状态。用户确认时才更新实际选中选项,提供更流畅的选择体验并防止误操作。
2025-08-28 17:04:54 +08:00
wong
e050da41e5 验证修改优化 2025-08-28 16:35:10 +08:00
超级老白兔
0a6f892ba8 FEAT => 本次更新项目为:contentLibraries 2025-08-28 16:26:14 +08:00
超级老白兔
f7b28d876d fix(AccountListModal): 修改状态2的显示文本为"请求已发送待通过"
构建产物已更新,反映最新的代码变更
2025-08-28 16:09:58 +08:00
超级老白兔
b0496e309e FEAT => 本次更新项目为: 2025-08-28 16:06:39 +08:00
超级老白兔
31d75be68e fix(AccountListModal): 更新账号状态显示逻辑和颜色标识
修改账号状态显示逻辑,将字符串状态改为数字类型,并更新对应的颜色标识和状态文本。同时更新构建产物的文件引用路径。
2025-08-28 16:06:16 +08:00
超级老白兔
1053d4125f fix: 修正设备组字段名拼写错误及状态值错误
修复接口字段名拼写错误,将`devices`改为`deveiceGroups`以保持前后端一致
同时修正状态值映射错误,将启用状态对应的值从2改为0
2025-08-28 15:58:50 +08:00
超级老白兔
fdc6c15d88 feat(ckchat): 添加联系人分组功能并实现骨架屏优化
添加新的联系人分组状态 newContractList 和对应的异步设置方法 asyncNewContractList
实现页面加载时的骨架屏效果,优化用户体验
重构 SidebarMenu 组件样式,分离骨架屏逻辑
新增 PageSkeleton 组件用于统一管理骨架屏
2025-08-28 15:51:32 +08:00
超级老白兔
ee5d7fef31 Merge branch 'yongpxu-dev' into yongpxu-dev2
# Conflicts:
#	Cunkebao/src/pages/pc/ckbox/main.ts   resolved by yongpxu-dev version
2025-08-28 15:41:51 +08:00
超级老白兔
640daf2431 refactor(ckbox): 重构客服列表和联系人管理逻辑
- 将ctrlUserList重命名为kfUserList并优化相关接口
- 新增异步更新客服列表、联系人列表和会话列表的方法
- 重构联系人分组逻辑,支持按标签分组
- 优化会话列表排序规则,按最后更新时间降序排列
- 移除无用代码并简化组件逻辑
2025-08-28 15:18:18 +08:00
超级老白兔
703656d3c4 Merge branch 'yongpxu-dev' into yongpxu-dev2 2025-08-27 17:51:38 +08:00
超级老白兔
3c1337b213 FEAT => 本次更新项目为: 2025-08-27 17:51:24 +08:00
超级老白兔
57f59b8827 Merge branch 'yongpxu-dev2' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into yongpxu-dev2 2025-08-27 17:48:18 +08:00
超级老白兔
3bf91cedc9 refactor(ui): 移除手动添加选项并重命名控制终端列表变量
- 删除两个页面中的"手动添加"标签页选项
- 将controlTerminalList重命名为kfUserList以提高可读性
- 更新构建文件引用路径
2025-08-27 17:48:15 +08:00
超级老白兔
93f4f1dc5a Merge branch 'yongpxu-dev' into yongpxu-dev2
# Conflicts:
#	Cunkebao/dist/.vite/manifest.json
#	Cunkebao/dist/index.html
2025-08-27 17:26:54 +08:00
超级老白兔
35c5cf60d4 refactor(群推任务): 统一API接口参数和响应处理
重构群推任务相关API接口,将参数改为对象形式并统一响应处理
更新任务状态切换接口,添加type参数区分任务类型
修改字段名maxPushPerDay为maxPerDay保持一致性
使用Toast组件替代window.alert进行提示
2025-08-27 17:26:00 +08:00
超级老白兔
0d5e34cfdd refactor(群推表单): 重构表单数据结构并整合京东联盟功能
- 将布尔类型字段改为数字枚举类型以增强可读性
- 移除独立的京东联盟组件,将其功能整合到基础设置中
- 简化表单步骤,从4步减少到3步
- 优化表单字段命名使其更语义化
2025-08-27 17:04:39 +08:00
超级老白兔
29e6bf8582 feat(群推任务): 添加更新群推任务接口并修改创建接口路径
修改创建群推任务的接口路径为/v1/workbench/create,并添加type参数
新增更新群推任务的接口/v1/workbench/update
2025-08-27 15:35:58 +08:00
超级老白兔
79ccd8580e refactor(流量池): 优化批量加入分组弹窗组件并清理无用代码
将Modal组件替换为Popup组件以改善移动端用户体验,移除调试日志和未使用的类型导入
2025-08-27 14:30:20 +08:00
超级老白兔
968480669e refactor(ckbox): 重构侧边栏组件结构并优化代码组织
feat(ckbox): 添加垂直用户列表组件用于终端用户展示
feat(ckbox): 实现控制终端用户数据管理功能

fix(ckbox): 修复联系人列表样式问题
fix(ckbox): 解决消息列表数据同步问题

style(ckbox): 调整侧边栏样式和布局
style(ckbox): 优化组件样式文件结构

chore(ckbox): 移除未使用的客户相关组件和样式
2025-08-27 14:29:37 +08:00
超级老白兔
1334942fc0 feat(聊天窗口): 优化消息时间显示格式并调整样式
重构消息时间格式化逻辑,提取为公共工具函数 formatWechatTime
移除聊天窗口中的分隔线样式,调整消息间距
更新构建产物文件引用路径
2025-08-27 10:22:51 +08:00
超级老白兔
08dc74cb67 feat(聊天窗口): 优化消息时间显示样式和格式化逻辑
- 在消息时间前后添加分割线并调整间距
- 根据消息时间范围显示不同格式的时间(当天、昨天、一周内、超过一周)
- 使用微信时间或创建时间作为消息时间基准
- 当相邻消息时间差超过5分钟时创建新时间组
2025-08-26 16:34:17 +08:00
超级老白兔
3645075473 fix(websocket): 修复WebSocket连接和视频消息处理问题
- 显式指定WebSocket URL确保连接到正确服务器
- 添加本地地址连接拦截逻辑防止错误连接
- 优化视频消息处理逻辑,包括加载状态管理和下载响应处理
- 使用时间戳作为唯一序列号避免重复
- 修复消息订阅逻辑,仅在有待处理视频请求时监听
2025-08-26 16:18:37 +08:00
超级老白兔
a26b465ff6 refactor(ckbox): 统一将contact重命名为contract
将代码中所有的contact变量和类名统一改为contract,包括API路径、组件属性、CSS类名等
更新相关路由配置和文档中的API接口说明
2025-08-26 14:19:19 +08:00
超级老白兔
c7b15896ac fix: 修复下载视频时friendMessageId的错误赋值逻辑 2025-08-26 11:50:26 +08:00
超级老白兔
f7a27c7c63 feat(ckbox): 实现聊天会话管理和多媒体消息支持
- 在ckchat store中添加聊天会话管理功能
- 支持多种类型消息渲染(图片、视频、音频、文件等)
- 优化聊天界面样式和时间分组显示
- 修复联系人数据结构命名问题
- 添加群聊列表获取功能
2025-08-26 11:48:10 +08:00
超级老白兔
c12633b2b1 refactor(ckbox): 重构聊天模块接口和类型定义
- 将HTTP方法从PUT改为GET以符合REST规范
- 移除测试用的硬编码凭证
- 新增ChatRecord接口并替换原有ChatSession
- 合并重复的样式文件并重命名
- 优化联系人点击处理逻辑
2025-08-25 14:05:32 +08:00
超级老白兔
83ae92b2b6 FEAT => 本次更新项目为: 2025-08-22 17:55:04 +08:00
超级老白兔
465c63ed1c feat(ckbox): 添加消息清除未读和获取功能
- 在api.ts中添加clearUnreadCount和getMessages接口
- 实现联系人点击时清除未读并获取消息
- 优化websocket重连逻辑,添加认证失败处理
- 修改登录凭证为karuo账户
- 添加递归获取所有联系人列表功能
2025-08-22 16:54:24 +08:00
超级老白兔
812cb97713 refactor(ckbox): 统一联系人数据结构并简化聊天会话处理
- 将ContactData接口添加索引签名以支持动态属性
- 移除ChatSession接口,直接使用ContactData作为聊天会话类型
- 简化组件间数据传递和状态管理
- 更新相关组件props类型定义
2025-08-22 15:17:47 +08:00
超级老白兔
f099bb5420 chore: 更新构建生成的资源文件引用路径
自动构建后更新manifest.json和index.html中的资源文件引用路径
2025-08-22 14:47:52 +08:00
超级老白兔
0b1872cc02 fix: 修复设备ID类型错误并优化选项处理
- 将设备ID从string类型改为number类型以匹配后端接口
- 为packageOptions添加默认空数组防止undefined错误
- 优化选项获取逻辑,正确处理API返回的数据结构
- 修复自动点赞任务创建时的friendsGroups校验条件
2025-08-22 14:47:39 +08:00
超级老白兔
b3cf0243dd 1 2025-08-22 14:24:52 +08:00
超级老白兔
b32e6cac0c Merge branch 'yongpxu-dev' into yongpxu-dev2 2025-08-22 14:24:30 +08:00
超级老白兔
32ea075e90 FEAT => 本次更新项目为: 2025-08-22 14:21:35 +08:00
wong
5ce77e0adc 内容库兼容性优化 2025-08-22 11:32:01 +08:00
超级老白兔
647a053ccc fix(workspace): 修正自动点赞任务中设备组字段名称错误
修复自动点赞任务创建页面中设备组字段名称拼写错误,将`deveicegroups`统一改为`deveiceGroups`,并更新相关逻辑判断和组件属性传递
2025-08-22 10:36:33 +08:00
wong
d726be7d66 代码提交 2025-08-22 10:23:05 +08:00
超级老白兔
d0bd7d4cd7 feat(websocket): 重构WebSocket连接逻辑并添加初始化命令
- 重构WebSocket连接逻辑,使用新的URL参数构建方式
- 添加初始化连接时的CmdSignIn和CmdRequestWechatAccountsAliveStatus命令
- 修改WebSocket消息类型定义,简化消息结构
- 从CkChatStore获取accountId用于连接参数
- 移除Login页面中与WebSocket相关的冗余代码
2025-08-21 17:44:47 +08:00
超级老白兔
eadb7a8f3e refactor(auto-group): 将内容库选择器替换为流量池选择器
将原有的内容库选择组件(ContentSelector)替换为流量池选择组件(PoolSelector),并更新相关类型定义和表单逻辑
2025-08-21 16:58:12 +08:00
超级老白兔
cfb752509a refactor(PoolSelection): 重命名组件及相关接口从Group到Pool
将组件及相关接口从GroupSelection重命名为PoolSelection以更准确反映其用途
更新相关引用和类型定义
调整流量池选择弹窗的样式和交互
2025-08-21 16:47:55 +08:00
超级老白兔
8e89c5ba73 feat(ckbox): 实现聊天界面功能并集成WebSocket
添加联系人列表、聊天会话和消息窗口组件
集成WebSocket连接实现实时聊天功能
重构API调用以获取聊天记录和联系人信息
添加样式文件美化聊天界面
2025-08-21 10:51:23 +08:00
超级老白兔
61e1ffc6c4 style(组件): 优化流量池选择组件头像显示样式
将PoolSelection组件中的头像显示从Avatar组件改为显示名称首字母的div,提升视觉一致性
2025-08-20 18:44:54 +08:00
超级老白兔
ad5fc0bb52 feat(ckbox): 重构联系人列表获取逻辑并优化登录流程
- 将联系人列表从模拟数据改为从API获取
- 优化登录处理流程,分离存客宝和触客宝的token获取
- 添加messageApi统一处理消息提示
- 修复路径引用问题并移除未使用的导入
2025-08-20 17:38:59 +08:00
wong
0681c69d67 自动建群群提交 + 自动点赞数据优化 2025-08-20 17:35:34 +08:00
超级老白兔
3f4101a87d FEAT => 本次更新项目为: 2025-08-20 17:33:28 +08:00
超级老白兔
87aea20056 feat(流量池选择): 新增流量池包选择功能并保留原接口兼容
- 添加流量池包相关接口和类型定义
- 修改选择弹窗组件以支持流量池包选择
- 保留原有流量池接口和类型以兼容现有代码
- 更新UI展示以适应流量池包数据结构
2025-08-20 17:31:22 +08:00
超级老白兔
3d944770f1 feat(流量池选择): 新增流量池选择组件及相关API和类型定义
添加流量池选择组件,包含以下功能:
- 流量池列表获取API
- 流量池项和组件属性类型定义
- 选择弹窗组件实现
- 样式文件和测试页面集成
- 支持搜索、分页和多选功能
2025-08-20 16:08:49 +08:00
超级老白兔
1d93368eb0 feat(自动建群表单): 优化表单加载状态和输入组件样式
- 添加数据加载状态控制,编辑模式显示加载中提示
- 重构数字输入组件样式,使用antd的InputNumber组件
- 将StepIndicator移动到header区域优化布局
- 重命名defaultValues为initialValues以更准确表达用途
2025-08-20 15:45:55 +08:00
超级老白兔
fcc4805220 feat(自动建群): 添加内容库选择功能并重构表单为分步式
添加内容库选择组件及相关类型定义
重构自动建群表单为分步式操作流程
新增基础设置、设备选择和内容选择三个步骤组件
完善表单验证逻辑和步骤导航功能
2025-08-20 15:07:17 +08:00
超级老白兔
d93165bfac feat(自动建群): 添加删除自动建群任务功能
新增删除自动建群任务的API接口及前端交互逻辑,使用自定义确认弹窗替代原生confirm,提供更好的用户体验和错误处理
2025-08-20 11:19:53 +08:00
超级老白兔
640f6fca02 Merge branch 'yongpxu-dev' into yongpxu-dev4 2025-08-20 09:41:25 +08:00
超级老白兔
82c2300496 Merge branch 'yongpxu-dev' into yongxu-dev3 2025-08-20 09:41:20 +08:00
超级老白兔
d2560784a2 feat(test): 添加更新通知组件测试页面
添加用于
2025-08-19 15:20:00 +08:00
超级老白兔
16fae82c17 FEAT => 本次更新项目为: 2025-08-19 15:07:36 +08:00
超级老白兔
f9be0fad2d feat(UpdateNotification): 优化更新提示组件样式和功能
- 添加 forceShow 和 onClose 属性支持强制显示和关闭回调
- 重新设计 UI 样式为顶部通知栏布局
- 新增"稍后"按钮支持延迟更新
- 优化动画效果和交互体验
2025-08-19 14:57:25 +08:00
超级老白兔
50db041021 FEAT => 本次更新项目为: 2025-08-19 12:12:50 +08:00
超级老白兔
a6945d1dc9 FEAT => 本次更新项目为: 2025-08-19 11:58:01 +08:00
超级老白兔
9c2f275534 調整自動建群列表頁腳樣式,將原有的內聯樣式替換為 CSS 類名以提升可維護性。 2025-08-19 11:50:11 +08:00
超级老白兔
bd317d8fc0 FEAT => 本次更新项目为: 2025-08-19 11:02:35 +08:00
超级老白兔
eda7f00453 更新自動建群 API,調整獲取任務列表的路徑,並新增複製自動建群任務的功能,優化任務複製邏輯以提升用戶體驗。 2025-08-19 11:01:19 +08:00
超级老白兔
b6cef907f9 調整自動建群表單,移除群名稱模板的預設值,並優化表單項目以支持動態數據顯示。 2025-08-19 10:54:31 +08:00
超级老白兔
0a792a5406 更新自動建群表單,新增獲取群組詳情的 API 調用以回填表單數據,並調整表單結構以支持動態數據顯示。 2025-08-19 10:35:25 +08:00
超级老白兔
0468531655 FEAT => 本次更新项目为: 2025-08-18 18:21:31 +08:00
超级老白兔
dac3d51f88 更新自動建群功能,調整 API 接口以支持朋友圈同步任務,優化表單結構及樣式,並整合導航組件以提升用戶體驗。更新資源引用以確保正確加載。 2025-08-18 18:01:59 +08:00
超级老白兔
273ba8073c FEAT => 本次更新项目为: 2025-08-18 11:33:56 +08:00
超级老白兔
96e22b14aa Merge branch 'yongpxu-dev' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into yongpxu-dev 2025-08-18 11:32:57 +08:00
超级老白兔
1b1bd7536d 新增 VITE_API_WS_URL 環境變數,更新主程式以引入嚴格模式包裝器,並在登錄頁面中整合觸客寶用戶信息獲取功能,調整請求模組以動態獲取 token2。 2025-08-18 11:30:56 +08:00
超级老白兔
60e5a682bd FEAT => 本次更新项目为: 2025-08-16 17:59:36 +08:00
超级老白兔
8af3ad3549 新增流量分發記錄功能,更新樣式以改善搜索條和分發統計彈窗的顯示效果,並在列表中整合相應的功能邏輯。 2025-08-16 17:34:36 +08:00
超级老白兔
7dd20b0a9b 新增 VITE_API_BASE_URL2 環境變數,更新請求模組以移除 token2 支持,並在登錄頁面中整合新的 token 登錄功能,調整狀態管理以支持多個 token 的存儲。 2025-08-16 16:31:02 +08:00
超级老白兔
85f4ca9744 FEAT => 本次更新项目为:更新 index.html 和 manifest.json 中的資源引用,新增 token2 支持於請求模組,並調整 ChatWindow 組件的樣式以改善顯示效果。 2025-08-16 11:24:07 +08:00
超级老白兔
c7e90fc917 新增用戶信息統計功能,更新主頁面以顯示用戶相關數據,並調整狀態管理邏輯以提升性能。 2025-08-15 19:15:56 +08:00
wong
639d7d3cb6 1 2025-08-15 18:30:03 +08:00
超级老白兔
504220f630 新增用戶信息統計功能,更新主頁面以顯示用戶相關數據,並調整相應的狀態管理邏輯。 2025-08-15 17:59:22 +08:00
超级老白兔
94196b1fe3 头部信息 2025-08-15 17:53:42 +08:00
超级老白兔
9cd285223b 新增一條綠色平滑線圖數據,並調整相應的樣式屬性以提升可視化效果。 2025-08-15 17:42:52 +08:00
wong
25ae2458f0 流量池添加及场景获客统计数据 2025-08-15 15:37:00 +08:00
超级老白兔
a66f9b01eb 移除按鈕的上邊距樣式,以改善整體佈局。 2025-08-15 14:15:03 +08:00
超级老白兔
695ccdd177 FEAT => 本次更新项目为: 2025-08-14 18:13:35 +08:00
超级老白兔
d17ed6e5c3 FEAT => 本次更新项目为: 2025-08-14 18:12:03 +08:00
超级老白兔
5f58a1a2c4 FEAT => 本次更新项目为: 2025-08-14 17:05:36 +08:00
超级老白兔
7be8ff2e94 刪除帳號和設備列表彈窗組件,新增流量池列表彈窗組件,並更新樣式以支持新的彈窗功能,優化流量分配列表的顯示邏輯。 2025-08-14 16:53:16 +08:00
超级老白兔
27b9ef910c 更新流量分配列表,新增帳號和設備列表彈窗功能,調整樣式以提升用戶體驗,並優化設備選擇組件的顯示邏輯。 2025-08-14 15:13:29 +08:00
超级老白兔
10c78470b3 Merge branch 'yongpxu-dev' into yongpxu-dev2 2025-08-14 15:04:27 +08:00
超级老白兔
566ca54fcf FEAT => 本次更新项目为: 2025-08-14 15:04:03 +08:00
超级老白兔
db4e2f9d43 FEAT => 本次更新项目为: 2025-08-14 10:46:22 +08:00
超级老白兔
0e71a6701d Merge branch 'yongpxu-dev' into yongpxu-dev2 2025-08-14 10:13:24 +08:00
超级老白兔
b4384c4329 FEAT => 本次更新项目为: 2025-08-14 10:11:07 +08:00
超级老白兔
3c71a2be96 更新流量池列表相關邏輯,替換獲客場景和包選項的獲取方式,調整篩選條件的狀態管理,並優化篩選模態框的數據加載。 2025-08-13 17:34:38 +08:00
超级老白兔
907451df48 FEAT => 本次更新项目为: 2025-08-13 17:27:54 +08:00
超级老白兔
94df1469c0 更新流量池列表相關邏輯,替換獲客場景接口,調整用戶價值和狀態的篩選邏輯,並優化篩選模態框的狀態管理。 2025-08-13 17:07:51 +08:00
wong
e53f31487e 门店端优化 2025-08-13 17:03:25 +08:00
wong
f5dd5e8191 电话获客 2025-08-13 17:02:36 +08:00
超级老白兔
2c509d5aa1 更新設備選擇組件,新增獲客場景選項,調整篩選邏輯以支持多種篩選條件,並修正路由以符合新結構。 2025-08-13 16:16:05 +08:00
wong
5ef40510ce 设备管理新增删除及头像 2025-08-13 14:30:22 +08:00
超级老白兔
140c0ed7e0 FEAT => 本次更新项目为: 2025-08-13 14:28:21 +08:00
超级老白兔
e2dfd44874 更新設備選擇組件,新增設備頭像和好友數據顯示,調整樣式以提升用戶體驗,並更新相關數據結構以支持新屬性。 2025-08-13 12:18:43 +08:00
超级老白兔
f10af2741e Merge branch 'yongpxu-dev' into yongpxu-dev2
# Conflicts:
#	nkebao/postcss.config.js   resolved by yongpxu-dev version
2025-08-13 11:32:56 +08:00
超级老白兔
720686fb88 Merge branch 'yongpxu-dev' into yongxu-dev3
# Conflicts:
#	nkebao/postcss.config.js   resolved by yongpxu-dev version
2025-08-13 11:32:48 +08:00
超级老白兔
f0e06e4197 Merge branch 'yongpxu-dev' into yongpxu-dev4
# Conflicts:
#	nkebao/postcss.config.js   resolved by yongpxu-dev version
2025-08-13 11:32:40 +08:00
超级老白兔
22cc5755fa FEAT => 本次更新项目为: 2025-08-13 11:32:17 +08:00
超级老白兔
4a70635ae4 FEAT => 本次更新项目为: 2025-08-13 11:32:05 +08:00
超级老白兔
6380b8752b FEAT => 本次更新项目为: 2025-08-13 11:31:54 +08:00
wong
46ce2f7e8d 代码提交 2025-08-13 10:18:13 +08:00
wong
13577c302d 代码同步 2025-08-13 09:43:41 +08:00
超级老白兔
4e78eb6c5e 更新 index.html 和 manifest.json 中的資源引用版本,刪除不再使用的資源檔案,並調整設備詳情頁面的導航邏輯以使用 navigate 函數。 2025-08-12 18:28:19 +08:00
超级老白兔
628d940a3e FEAT => 本次更新项目为: 2025-08-12 18:26:08 +08:00
超级老白兔
949930f2cf FEAT => 本次更新项目为: 2025-08-12 17:07:42 +08:00
超级老白兔
aa583e6748 FEAT => 本次更新项目为: 2025-08-12 17:03:12 +08:00
超级老白兔
be9e07cfea 刪除 package-lock.json 和 yarn.lock 檔案,新增 antd-mobile-icons 依賴,並更新 package.json 中的腳本命令以使用 pnpm 進行構建和開發,調整 Vite 配置以允許從所有主機訪問。 2025-08-12 16:58:28 +08:00
wong
c847eff9fc 通话记录数据清洗 2025-08-12 16:58:00 +08:00
超级老白兔
746d3af943 FEAT => 本次更新项目为: 2025-08-12 16:15:55 +08:00
超级老白兔
2693e573f6 新增自定義標籤功能,更新表單數據結構以支持自定義標籤選項,並優化相關邏輯以提升用戶體驗。 2025-08-12 16:12:37 +08:00
超级老白兔
9170857d8a 優化好友備註區塊的樣式,調整提示框位置及外觀,並改善交互效果。更新好友備註選擇區的結構,提升可讀性與使用體驗。 2025-08-12 15:36:44 +08:00
超级老白兔
240c749806 更新 index.html 和 manifest.json 中的資源引用版本,將 index-PKCtfAad.js 更改為 index-C7IEJLdM.js,以保持一致性。 2025-08-12 15:32:43 +08:00
超级老白兔
88a007de7c 更新 index.html 和 manifest.json 中的資源引用版本,並在新計劃頁面中調整海報模板的屬性名稱,將 preview 改為 url,以統一資料結構。 2025-08-12 15:31:27 +08:00
wong
14c882ff08 获取电话底层优化 2025-08-12 15:02:30 +08:00
wong
67fac4b2f2 场景获客优化 2025-08-12 15:02:00 +08:00
超级老白兔
0baf472473 FEAT => 本次更新项目为: 2025-08-12 12:00:57 +08:00
超级老白兔
faf8a6e234 更新環境變數,將 API 基礎 URL 更改為 http://www.yishi.com,並調整前端資源引用的版本號。同時在新計劃頁面中新增自定義標籤功能,並優化相關邏輯 2025-08-12 11:33:55 +08:00
wong
f6b620383c Merge branch 'develop' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into develop 2025-08-12 10:05:41 +08:00
wong
d40710de3c 代码提交 2025-08-12 10:04:53 +08:00
超级老白兔
1750dc13eb Merge branch 'develop' into yongpxu-dev
# Conflicts:
#	nkebao/postcss.config.js   resolved by develop version
#	nkebao/技术栈.md   resolved by develop version
2025-08-12 09:33:39 +08:00
超级老白兔
19bce0bfa1 FEAT => 本次更新项目为: 2025-08-12 09:33:15 +08:00
超级老白兔
05333b4345 Merge branch 'develop' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into develop 2025-08-12 09:32:52 +08:00
超级老白兔
c62c06a072 FEAT => 本次更新项目为: 2025-08-12 09:32:45 +08:00
wong
1b8f64b4fb Merge branch 'develop' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into develop 2025-08-12 09:29:57 +08:00
wong
863a4fd31f 电话获客 2025-08-12 09:29:27 +08:00
超级老白兔
1b7f8bae6c Merge branch 'yongpxu-dev' into develop 2025-08-12 09:29:00 +08:00
wong
239e518676 工作台及场景获客字段同步 2025-08-12 09:28:57 +08:00
超级老白兔
60465774d4 FEAT => 本次更新项目为:
同步
2025-08-12 09:28:41 +08:00
超级老白兔
9c3bc5200a 同步代码 2025-08-12 09:27:50 +08:00
超级老白兔
dd4446fd8c FEAT => 本次更新项目为: 2025-08-12 09:24:26 +08:00
超级老白兔
ea4e36d759 FEAT => 本次更新项目为:重构上传组件的使用说明文档,统一代码风格,增加聊天文件上传组件的功能描述,并删除不再使用的样式和组件,以提升代码的可维护性和用户体验。 2025-08-11 18:06:27 +08:00
超级老白兔
4a5f9579b4 FEAT => 本次更新项目为:在个人中心页面新增“触客宝”功能模块,并在路由中添加相应的路径,以提升用户体验和功能完整性。 2025-08-11 15:26:20 +08:00
超级老白兔
69e2acd156 FEAT => 本次更新项目为:重构 PostCreateAddFriendPlanV1Controller 控制器,继承自 BaseController,修正设备参数名称为 'deveiceGroups',并优化用户信息获取逻辑,以提升代码的可读性和维护性。同时,更新开发环境变量配置。 2025-08-11 14:11:11 +08:00
超级老白兔
cdd5d88e2d Merge branch 'develop' into yongpxu-dev
# Conflicts:
#	nkebao/.env.development   resolved by yongpxu-dev version
2025-08-11 12:20:24 +08:00
超级老白兔
d8effe2dcb FEAT => 本次更新项目为:重构计划相关的 API 接口,更新计划的接口路径并移除不再使用的函数和类型定义,以简化代码结构并提升可维护性。同时,调整新建计划的逻辑以适应新的接口。 2025-08-11 12:18:22 +08:00
超级老白兔
bea245ced9 FEAT => 本次更新项目为:统一内容管理的导航路径,将所有相关路径前缀修改为 "/mine/content",以提升路由结构的一致性和用户体验。 2025-08-11 11:27:49 +08:00
超级老白兔
90f29da343 FEAT => 本次更新项目为:将 FriendSelection 组件的 selectedOptions 属性改为可选,并在相关组件中进行相应调整,以提升代码的灵活性和可读性。同时,更新导航路径以统一路由结构。 2025-08-11 11:18:02 +08:00
超级老白兔
1d5441b84a FEAT => 本次更新项目为:删除消费记录相关的 API、数据定义、样式和组件,以简化代码结构并移除不再使用的功能。 2025-08-11 11:11:13 +08:00
超级老白兔
8c9a660afd FEAT => 本次更新项目为:统一组件接口,将属性名称从 selectedGroups 更改为 selectedOptions,以提升代码一致性和可读性,并对相关组件进行了相应调整。 2025-08-11 10:49:02 +08:00
超级老白兔
0af7969fcc FEAT => 本次更新项目为: 2025-08-08 18:32:25 +08:00
超级老白兔
dc296336e0 FEAT => 本次更新项目为:新增获取京东社交媒体和推广站点列表的接口,并优化相关组件的状态管理与数据处理 2025-08-08 18:20:32 +08:00
超级老白兔
82a8c8b374 FEAT => 本次更新项目为: 2025-08-08 17:24:50 +08:00
超级老白兔
2432f7817c FEAT => 本次更新项目为:优化流量分配选项的文本格式,移除多余的空格以提升代码整洁性 2025-08-08 17:24:37 +08:00
wong
14b1230f72 场景获客及时获取群好友 2025-08-08 17:04:47 +08:00
超级老白兔
e0c0c59e73 FEAT => 本次更新项目为:将设备管理路径从 "/devices" 修改为 "/mine/devices",以统一路由结构并提升用户体验 2025-08-08 16:25:50 +08:00
超级老白兔
18c57904bb Merge branch 'yongpxu-dev2' into yongpxu-dev 2025-08-08 15:53:26 +08:00
超级老白兔
c0982905dd FEAT => 本次更新项目为: 2025-08-08 15:50:09 +08:00
超级老白兔
227ddbb776 FEAT => 本次更新项目为:新增帳號選擇組件,將選擇狀態類型從數字陣列更改為帳號項目陣列,以提升代碼的可讀性和一致性 2025-08-08 15:47:41 +08:00
超级老白兔
cef477dfee FEAT => 本次更新项目为:统一组件接口,将属性名称从 selectedContent 和 selectedGroups 更改为 selectedOptions,以提升代码一致性和可读性 2025-08-08 15:47:07 +08:00
超级老白兔
ee82732880 FEAT => 本次更新项目为: 2025-08-08 15:46:11 +08:00
超级老白兔
9dbd2d2a0c Merge branch 'yongpxu-dev' into yongpxu-dev2
# Conflicts:
#	nkebao/src/pages/mobile/test/select.tsx   resolved by yongpxu-dev version
2025-08-08 15:04:39 +08:00
超级老白兔
0abddfbfb3 FEAT => 本次更新项目为: 2025-08-08 15:03:45 +08:00
超级老白兔
8749a59957 FEAT => 本次更新项目为:重构帳號選擇組件,簡化狀態管理,並更新測試頁面以使用新接口 2025-08-08 14:59:59 +08:00
超级老白兔
b7d94b56f0 FEAT => 本次更新项目为:
设备选择构建完成
2025-08-08 14:58:26 +08:00
超级老白兔
d785f11aff FEAT => 本次更新项目为:
好友选择构建完成
2025-08-08 13:56:34 +08:00
超级老白兔
a06e691420 Merge branch 'yongpxu-dev' into yongpxu-dev2 2025-08-08 11:36:33 +08:00
超级老白兔
98b3d0dff7 FEAT => 本次更新项目为:将设备选择组件中的属性名称从 selectedDevices 更改为 selectedOptions,以统一命名规范并提升可读性 2025-08-08 11:36:05 +08:00
超级老白兔
08d851ec81 FEAT => 本次更新项目为: 2025-08-08 10:37:43 +08:00
超级老白兔
a339dd898b FEAT => 本次更新项目为:移除選擇測試組件,更新環境變數,優化內容表單中的好友和群組選擇邏輯 2025-08-08 10:10:28 +08:00
超级老白兔
b06a0e16b0 FEAT => 本次更新项目为:
内容选择构建完成
2025-08-07 18:27:37 +08:00
超级老白兔
bb06d3e4f8 FEAT => 本次更新项目为:
内容库处理完成
2025-08-07 18:21:35 +08:00
超级老白兔
504e8ff9b6 FEAT => 本次更新项目为:
选择社群构建完成
2025-08-07 17:43:20 +08:00
超级老白兔
67c76d8b04 FEAT => 本次更新项目为:
存个版本
2025-08-07 16:15:45 +08:00
超级老白兔
662a192b81 FEAT => 本次更新项目为:
群组选择构建完成
2025-08-07 14:52:06 +08:00
wong
b33231b3b4 代码提交 2025-08-07 11:56:04 +08:00
超级老白兔
f592784c11 Merge branch 'develop' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into develop 2025-08-07 09:41:25 +08:00
超级老白兔
ab32093caf Merge branch 'develop' into yongpxu-dev 2025-08-07 09:41:06 +08:00
wong
f78cac645c 群推送代码提交 2025-08-07 09:22:39 +08:00
超级老白兔
cd88e44464 FEAT => 本次更新项目为:
同步
2025-08-06 18:29:12 +08:00
wong
94c484dbe4 工作台-消息群发 2025-08-06 18:02:03 +08:00
wong
7a2553940c 代码提交 2025-08-06 18:00:50 +08:00
wong
d4c10de30a 群同步 2025-08-06 17:57:24 +08:00
超级老白兔
7ebece0491 FEAT => 本次更新项目为:優化基本設置頁面,新增文件上傳組件,調整樣式及顯示邏輯 2025-08-06 17:54:41 +08:00
超级老白兔
f59ce8809d FEAT => 本次更新项目为:
优化了代码
2025-08-06 17:36:15 +08:00
超级老白兔
b53929cb22 FEAT => 本次更新项目为:
充值记录完成
2025-08-06 17:22:01 +08:00
超级老白兔
070d6b70d6 sj 2025-08-06 11:01:54 +08:00
超级老白兔
2deddf6fd4 FEAT => 本次更新项目为:检查更新 2025-08-05 18:12:32 +08:00
超级老白兔
a1ae5e9364 同步 2025-08-05 18:06:57 +08:00
超级老白兔
ed99243890 FEAT => 本次更新项目为:
版本更新问题去掉
2025-08-05 13:55:04 +08:00
超级老白兔
302670ed99 FEAT => 本次更新项目为:
用户信息保存
2025-08-05 13:42:31 +08:00
超级老白兔
ff801d2169 FEAT => 本次更新项目为:
改为正常版本
2025-08-05 12:02:05 +08:00
超级老白兔
dca72fac8c FEAT => 本次更新项目为:
新版本
2025-08-05 12:01:22 +08:00
超级老白兔
57a32e252d FEAT => 本次更新项目为:
更新模块完成
2025-08-05 11:59:18 +08:00
wong
982b2c024b 同步群列表 2025-08-05 10:28:28 +08:00
wong
ebff15fbed 编辑用户信息及修改密码 2025-08-05 10:26:55 +08:00
超级老白兔
9b1cfb6e03 Merge branch 'yongpxu-dev' into yongpxu-dev2 2025-08-04 17:12:14 +08:00
超级老白兔
e63441c254 修正應用程式圖標路徑,將"/public/logo.png"更改為"/logo.png"以確保正確顯示。 2025-08-04 17:11:48 +08:00
超级老白兔
192c8c3c0a FEAT => 本次更新项目为:
样式同步了
2025-08-04 16:27:45 +08:00
超级老白兔
2ef2aff18f FEAT => 本次更新项目为:
上传封面主图构建完成
2025-08-04 16:03:39 +08:00
超级老白兔
a4be3d534f FEAT => 本次更新项目为:完善上传组件使用说明,增加数据回显功能示例,优化代码结构,移除冗余代码 2025-08-04 15:11:27 +08:00
超级老白兔
7621b91f15 FEAT => 本次更新项目为:移除上传组件相关文件,整合上传功能至主图上传组件,优化代码结构及样式 2025-08-04 14:11:36 +08:00
超级老白兔
38f5fcf360 FEAT => 本次更新项目为:
基础组件构建完成
2025-08-04 11:43:08 +08:00
超级老白兔
f2a10e249f FEAT => 本次更新项目为:
样式修正
2025-08-04 11:22:28 +08:00
超级老白兔
e36f602e6a FEAT => 本次更新项目为:
组件基础完成
2025-08-04 11:16:29 +08:00
超级老白兔
d838108025 Merge branch 'yongpxu-dev' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into yongpxu-dev 2025-08-04 10:38:09 +08:00
超级老白兔
02a42dd4b2 FEAT => 本次更新项目为:更新环境变量及标题为“存客宝”,新增应用模式标识,优化iOS设备安全区域高度计算 2025-08-04 10:35:35 +08:00
超级老白兔
6ed19f7a84 FEAT => 本次更新项目为:
store持久化
2025-08-04 10:34:59 +08:00
超级老白兔
7f5da492ee Merge branch 'yongpxu-dev' into yongpxu-dev4
# Conflicts:
#	nkebao/AI_ICON_GUIDE.md   resolved by yongpxu-dev version
#	nkebao/ICON_DETAILED_MAPPING.md   resolved by yongpxu-dev version
#	nkebao/ICON_MAPPING_GUIDE.md   resolved by yongpxu-dev version
#	nkebao/ICON_QUICK_REFERENCE.md   resolved by yongpxu-dev version
#	nkebao/index.html   resolved by yongpxu-dev version
2025-08-04 10:04:41 +08:00
超级老白兔
eedd687e47 1 2025-08-04 10:04:29 +08:00
超级老白兔
73407ceb8d Merge branch 'yongpxu-dev' into yongxu-dev3
# Conflicts:
#	nkebao/AI_ICON_GUIDE.md   resolved by yongpxu-dev version
#	nkebao/ICON_DETAILED_MAPPING.md   resolved by yongpxu-dev version
#	nkebao/ICON_MAPPING_GUIDE.md   resolved by yongpxu-dev version
#	nkebao/ICON_QUICK_REFERENCE.md   resolved by yongpxu-dev version
#	nkebao/index.html   resolved by yongpxu-dev version
2025-08-04 10:04:17 +08:00
超级老白兔
fe62708aa3 1 2025-08-04 10:04:01 +08:00
超级老白兔
9ef72679b3 Merge branch 'yongpxu-dev' into yongpxu-dev2 2025-08-04 10:02:26 +08:00
超级老白兔
05783db2b1 FEAT => 本次更新项目为:
存了
2025-08-02 20:41:02 +08:00
超级老白兔
65f80c55b0 FEAT => 本次更新项目为:
基础配置传递过去了
2025-08-02 19:58:49 +08:00
超级老白兔
947f5c0f6b FEAT => 本次更新项目为:
联通测试完成
2025-08-02 19:52:12 +08:00
超级老白兔
4967f31791 store 恢复 2025-08-02 18:42:43 +08:00
超级老白兔
ae4cbd46dc FEAT => 本次更新项目为:
初始化状态链接功能
2025-08-02 17:10:41 +08:00
超级老白兔
56c9c24937 FEAT => 本次更新项目为: 2025-08-02 16:33:53 +08:00
超级老白兔
688e3faacd FEAT => 本次更新项目为:
App与H5交互构建完成
2025-08-02 16:31:59 +08:00
超级老白兔
91ddc42667 FEAT => 本次更新项目为:
交互完成,开始封装
2025-08-02 15:01:54 +08:00
超级老白兔
fca202fd76 FEAT => 本次更新项目为:
精简初步完成
2025-08-02 14:43:08 +08:00
超级老白兔
2e01757519 FEAT => 本次更新项目为:
定版本app通信
2025-08-02 11:32:04 +08:00
超级老白兔
fb543f99ba Merge branch 'yongpxu-dev' into yongpxu-dev2 2025-08-01 16:45:03 +08:00
超级老白兔
de0f8fafda 同步 2025-08-01 16:44:35 +08:00
超级老白兔
fddda27ca8 FEAT => 本次更新项目为:
基础通信搞定了
2025-08-01 16:29:34 +08:00
超级老白兔
325d53cad6 FEAT => 本次更新项目为:
新封装技术栈
2025-08-01 14:30:51 +08:00
超级老白兔
b59ddea3b6 FEAT => 本次更新项目为:
可以构建app了
2025-08-01 11:36:29 +08:00
超级老白兔
3cc48d33e6 FEAT => 本次更新项目为:提交 2025-08-01 11:14:33 +08:00
超级老白兔
165349172b FEAT => 本次更新项目为:
更新
2025-08-01 11:14:26 +08:00
超级老白兔
fa36c21672 FEAT => 本次更新项目为:
构建安卓app
2025-08-01 10:57:48 +08:00
超级老白兔
efec6d6857 FEAT => 更新测试页面URL,移除不再使用的postMessage测试组件,优化项目配置,添加Capacitor命令到package.json。 2025-07-31 18:44:45 +08:00
超级老白兔
ecddbf2226 FEAT => 本次更新项目为: 2025-07-31 18:26:23 +08:00
超级老白兔
031558c483 FEAT => 添加iframe返回键处理功能,优化返回键事件管理,更新样式以改善用户体验。 2025-07-31 18:25:26 +08:00
超级老白兔
02d0031079 FEAT => 本次更新项目为:
存一半
2025-07-31 18:18:01 +08:00
超级老白兔
101676cef3 REFactor => 移除安全区域相关功能,优化web-view组件样式,更新导航组件结构,简化代码逻辑。 2025-07-31 17:58:25 +08:00
超级老白兔
9193bda39f FEAT => 本次更新项目为:
初始化appbuild
2025-07-31 17:41:43 +08:00
超级老白兔
c5d4e80e7c REFactor => 移除安全区域相关功能和测试页面,简化导航组件,优化主入口文件结构。 2025-07-31 16:38:35 +08:00
超级老白兔
599d67141f FEAT => 更新项目配置和组件,添加安全区域支持,优化导航栏,移除不必要的组件测试页面。 2025-07-31 16:30:34 +08:00
超级老白兔
529e5d3b83 Merge branch 'yongpxu-dev' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into yongpxu-dev 2025-07-30 17:36:18 +08:00
超级老白兔
68fe9946d2 FEAT => 更新场景列表页面,添加分页功能并优化卡片点击事件处理,移除不必要的加载更多按钮。 2025-07-30 17:36:15 +08:00
超级老白兔
f4df55b9e1 Merge branch 'yongpxu-dev' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into yongpxu-dev 2025-07-30 17:31:58 +08:00
超级老白兔
3c4d0fcb5f FEAT => 本次更新项目为:
用户详情搞定
2025-07-30 17:29:15 +08:00
超级老白兔
1c154c6f48 FEAT => 本次更新项目为:设置中心构建完成 2025-07-30 17:08:31 +08:00
超级老白兔
c4b41daf6a FEAT => 本次更新项目为:
设置的构建完成
2025-07-30 17:01:21 +08:00
超级老白兔
2577fd81eb FEAT => 本次更新项目为:
设置页面构建完成
2025-07-30 16:58:29 +08:00
超级老白兔
75987baef8 FEAT => 本次更新项目为:
废弃流量池不需要的接口
2025-07-30 16:36:21 +08:00
超级老白兔
e3ccf61fd2 FEAT => 本次更新项目为:
bu修复
2025-07-30 15:37:13 +08:00
超级老白兔
f430718e5f Merge branch 'yongpxu-dev' into yongpxu-dev2
# Conflicts:
#	nkebao/src/pages/mobile/mine/devices/DeviceDetail.tsx   resolved by yongpxu-dev2 version
2025-07-30 15:29:22 +08:00
超级老白兔
9815134536 FEAT => 本次更新项目为:
存一下
2025-07-30 15:19:15 +08:00
超级老白兔
78e2105a62 FEAT => 更新设备绑定引导页逻辑,新增设备列表接口调用以优化设备数量获取,提升用户体验。 2025-07-30 15:19:02 +08:00
超级老白兔
c78134f05c FEAT => 更新设备绑定引导页逻辑,优化设备数量获取方式,使用用户状态中的设备总数替代API调用,提升性能和用户体验。 2025-07-30 14:57:03 +08:00
超级老白兔
0693f5de74 FEAT => 本次更新项目为:
存了
2025-07-30 14:42:22 +08:00
超级老白兔
f78af9e77c FEAT => 本次更新项目为:
设备绑定指引
2025-07-30 12:52:58 +08:00
超级老白兔
6638e24901 FEAT => 本次更新项目为:
-设备管理-设备详情-关联账户-微信号详情(微信号管理的详情)✔
2025-07-30 11:02:44 +08:00
超级老白兔
4a4e9a611f FEAT => 本次更新项目为:
存客宝设备绑定引导页
2025-07-30 10:40:15 +08:00
超级老白兔
51495a93ff Merge branch 'yongpxu-dev' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into yongpxu-dev
# Conflicts:
#	nkebao/src/pages/mobile/mine/devices/index.tsx   resolved by origin/yongpxu-dev(远端) version
2025-07-30 09:32:33 +08:00
超级老白兔
0059c3ba3b fix: Add missing commas in various TypeScript files to ensure proper syntax and prevent potential runtime errors. 2025-07-30 09:29:32 +08:00
超级老白兔
035c0602b5 FEAT => 本次更新项目为:设备类别构建完成 2025-07-29 19:51:56 +08:00
超级老白兔
e4b1cf4a15 FEAT => 本次更新项目为:
-设备扫描二维码弹窗优化✔
2025-07-29 19:49:09 +08:00
超级老白兔
0941124ab6 Merge branch 'yongpxu-dev' into yongpxu-dev4
# Conflicts:
#	nkebao/vite.config.ts   resolved by yongpxu-dev version
2025-07-29 19:31:35 +08:00
超级老白兔
89a7c12fa0 feat: 本次更新项目为: 2025-07-29 19:31:23 +08:00
超级老白兔
2da76dfcff Merge branch 'yongpxu-dev' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into yongpxu-dev 2025-07-29 19:29:28 +08:00
超级老白兔
62ceca1d34 Merge branch 'yongpxu-dev' into yongxu-dev3
# Conflicts:
#	nkebao/vite.config.ts   resolved by yongpxu-dev version
2025-07-29 19:29:20 +08:00
超级老白兔
dd2db73e9d FEAT => 本次更新项目为:
2025-07-29 19:29:07 +08:00
超级老白兔
2824e6582c Merge branch 'yongpxu-dev2' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into yongpxu-dev2
# Conflicts:
#	nkebao/vite.config.ts   resolved by origin/yongpxu-dev2(远端) version
2025-07-29 19:28:00 +08:00
超级老白兔
d2d9e53655 FEAT => 本次更新项目为:
村里
2025-07-29 19:27:48 +08:00
超级老白兔
54b84f8bf6 FEAT => 本次更新项目为:
存了
2025-07-29 19:27:24 +08:00
超级老白兔
e45344a1c3 Revert " feat: 本次更新项目为:"
This reverts commit 3995ef55e1.
2025-07-29 19:26:39 +08:00
超级老白兔
2b978997c7 Merge branch 'yongpxu-dev2' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into yongpxu-dev2
# Conflicts:
#	nkebao/.env.development   resolved by yongpxu-dev2 version
#	nkebao/src/pages/mobile/mine/traffic-pool/detail/data.ts   resolved by yongpxu-dev2 version
2025-07-29 19:25:12 +08:00
超级老白兔
834ccea786 Merge branch 'yongpxu-dev' into yongpxu-dev2
# Conflicts:
#	nkebao/src/pages/mobile/mine/traffic-pool/detail/api.ts   resolved by yongpxu-dev version
#	nkebao/src/pages/mobile/mine/traffic-pool/detail/data.ts   resolved by yongpxu-dev version
#	nkebao/src/pages/mobile/mine/traffic-pool/detail/index.tsx   resolved by yongpxu-dev version
2025-07-29 19:24:44 +08:00
超级老白兔
13a940b8c2 Merge branch 'yongpxu-dev' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into yongpxu-dev 2025-07-29 19:23:03 +08:00
超级老白兔
a4f63f0d70 Merge branch 'yongpxu-dev' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into yongpxu-dev 2025-07-29 19:22:55 +08:00
超级老白兔
3995ef55e1 feat: 本次更新项目为:
同步
2025-07-29 19:22:49 +08:00
超级老白兔
92fa2975c2 FEAT => 本次更新项目为:
同步
2025-07-29 19:22:42 +08:00
超级老白兔
ea2336fe1e FEAT => 本次更新项目为:
同步
2025-07-29 19:22:32 +08:00
超级老白兔
d9f2e134b1 存了 2025-07-29 19:20:45 +08:00
超级老白兔
922d1357fa FEAT => 本次更新项目为:
临时存了
2025-07-29 19:19:28 +08:00
超级老白兔
c1cc74c2f3 FEAT => 本次更新项目为: 2025-07-29 19:14:56 +08:00
超级老白兔
dce6910371 FEAT => 本次更新项目为:
用户详情
2025-07-29 19:08:50 +08:00
超级老白兔
10dd9869d4 feat: 添加设备绑定引导页面及相关逻辑,更新路由配置 2025-07-29 18:42:04 +08:00
超级老白兔
600e2a52ad feat: 更新构建脚本,添加类型检查命令并优化Vite配置,调整chunk大小限制和文件命名格式 2025-07-29 17:29:39 +08:00
超级老白兔
dcb1c95215 FEAT => 本次更新项目为:语法校验即可 2025-07-29 17:06:18 +08:00
超级老白兔
1c1062b235 FEAT => 本次更新项目为:
素材列表、编辑、新增全部完成
2025-07-29 16:38:48 +08:00
超级老白兔
d1d8391e1d feat: 添加素材列表卡片标题显示 2025-07-29 16:13:12 +08:00
超级老白兔
63df76bf01 feat: 更新素材表单组件,优化状态管理和数据获取逻辑,移除不必要的状态,使用useCallback提升性能 2025-07-29 16:11:17 +08:00
超级老白兔
d277cd6518 feat: 本次更新项目为:
上传组件封装完成
2025-07-29 16:06:37 +08:00
超级老白兔
8a06e6504d feat: 本次更新项目为:
样式做的很好
2025-07-29 14:59:10 +08:00
超级老白兔
f6beb38502 feat: 本次更新项目为:
扫码获取二维码添加设备
2025-07-29 14:26:52 +08:00
超级老白兔
da11868d48 2025-07-29 11:40:47 +08:00
超级老白兔
7e9b8e2341 Merge branch 'yongpxu-dev' into yongpxu-dev2
# Conflicts:
#	nkebao/src/pages/mobile/mine/traffic-pool/detail/api.ts   resolved by yongpxu-dev2 version
#	nkebao/src/pages/mobile/mine/traffic-pool/detail/data.ts   resolved by yongpxu-dev2 version
#	nkebao/src/pages/mobile/mine/traffic-pool/detail/index.tsx   resolved by yongpxu-dev2 version
2025-07-29 11:40:31 +08:00
超级老白兔
8d2dcad9ca Merge branch 'yongpxu-dev' into yongxu-dev3
# Conflicts:
#	nkebao/src/pages/mobile/mine/wechat-accounts/list/api.ts   resolved by yongxu-dev3 version
2025-07-29 11:40:23 +08:00
超级老白兔
6d768f3a97 feat: 本次更新项目为:
语法格式化
2025-07-29 11:35:04 +08:00
笔记本里的永平
3a444a29b9 存进度 2025-07-29 10:07:09 +08:00
笔记本里的永平
232d4834be feat: 本次提交更新内容如下
存储进度
2025-07-29 10:06:40 +08:00
笔记本里的永平
e1ed0e5dff feat: 本次提交更新内容如下
eslint规则校验
2025-07-28 17:18:03 +08:00
笔记本里的永平
a9306bb8ba feat: 本次提交更新内容如下
格式更新一下
2025-07-28 16:53:18 +08:00
笔记本里的永平
9facfe2ff8 feat: 本次提交更新内容如下
接口对接成功
2025-07-28 14:43:49 +08:00
笔记本里的永平
c8742de888 feat: 本次提交更新内容如下
-流量分发新建\编辑✔
-内容库新建\编辑✔
-隐藏Ai策略优化✔
-隐藏Ai销售预测✔
2025-07-28 11:42:54 +08:00
笔记本里的永平
14e397ab26 feat: 本次提交更新内容如下
1、在线微信号传参构建完成
2025-07-28 11:13:57 +08:00
笔记本里的永平
cbc8c4a501 feat: 本次提交更新内容如下
项目分包优化
2025-07-25 18:08:16 +08:00
笔记本里的永平
ed5ff02b91 feat: 本次提交更新内容如下 2025-07-25 18:04:45 +08:00
笔记本里的永平
4608e23b60 feat: 本次提交更新内容如下
自动化部署脚本构建完成
2025-07-25 18:04:40 +08:00
笔记本里的永平
0cee80e6d7 feat: 本次提交更新内容如下
优化存一版
2025-07-25 18:03:00 +08:00
笔记本里的永平
2234fdf172 feat: 本次提交更新内容如下
脚本构建完成了
2025-07-25 16:57:19 +08:00
笔记本里的永平
a243e66746 feat: 本次提交更新内容如下
layout兼容问题
2025-07-25 16:15:52 +08:00
cea4a01a4a Initial Commit 2025-04-14 16:40:39 +08:00
3617 changed files with 491330 additions and 104207 deletions

16
.codegraph/.gitignore vendored Normal file
View File

@@ -0,0 +1,16 @@
# CodeGraph data files
# These are local to each machine and should not be committed
# Database
*.db
*.db-wal
*.db-shm
# Cache
cache/
# Logs
*.log
# Hook markers
.dirty

6
.codegraph/daemon.pid Normal file
View File

@@ -0,0 +1,6 @@
{
"pid": 74205,
"version": "0.9.9",
"socketPath": "/Users/karuo/Documents/开发/2、私域银行/cunkebao_v3/.codegraph/daemon.sock",
"startedAt": 1780473089935
}

View File

@@ -0,0 +1,21 @@
---
description: CodeGraph F21a — 经卡若AI 全局 MCP 解析代码,不依赖本仓科室配置
alwaysApply: true
---
<!-- CODEGRAPH_START · 卡若AI F21a 引用 -->
## CodeGraph全局 · 卡若AI F21a
结构读/写代码 **只走卡若AI F21a**MCP 已在 `~/.cursor/mcp.json` 由 `codegraph_mcp_serve.sh` 启动。
**真源**`/Users/karuo/Documents/个人/卡若AI/04_卡火/火种_知识模型/CodeGraph_MCP语义代码图谱/SKILL.md`
| 场景 | 工具 |
|:---|:---|
| 任务上下文 | `codegraph_context` → `codegraph_explore` |
| 找符号 | `codegraph_search` |
| 调用链 | `codegraph_callers` / `codegraph_callees` |
| 改 API 影响 | `codegraph_impact` |
无 `.codegraph/``bash …/CodeGraph_MCP语义代码图谱/脚本/codegraph_init_repo.sh "$(pwd)"`
**勿**在本仓新增 `.cursor/mcp.json` 的 codegraph 块。
<!-- CODEGRAPH_END -->

View File

@@ -0,0 +1,40 @@
---
description: 存客宝 v3 部署——Agent 自主执行、自主修错、验收至首页可访问(覆盖「部署失败再问用户」)
alwaysApply: true
---
# 存客宝 v3 · 部署自主处理
> **生效**2026-05-26。用户说「部署」时**不得**只跑脚本报成功就结束;必须验收到**首页有内容**。
## 强制流程
1. **执行**`bash 开发文档/8、部署/scripts/deploy_local_docker.sh --build`(改前端/首次/用户抱怨空白页时必须 `--build`)。
2. **脚本失败时 Agent 自行排查修复**,不要停下来问用户,常见顺序:
- Docker 未响应 → `open -a Docker`,等就绪后重试
- 全量 `--build` 中 `server` 镜像失败composer/php 拉取)→ 改为 `docker compose build cunkebao-web touchkebao-web superadmin-web && docker compose up -d`
- `vendor` 缺失 → 重建 `server` 或 `docker compose up -d --build server`
- MySQL 未 healthy → `COMPOSE_PROFILES=embedded-mysql docker compose up -d mysql`,确认 3308
- 3100 HTTP 200 但首页空白 → 查 `pageerror`(如 `homeIcons` 缺 import、`PermissionRoute` hydration、index.html 缓存;修代码后 **必须 rebuild cunkebao-web**
3. **验收(全绿才算部署成功)**
- HTTP3100 / 3101 = 200
- API登录 code 200经 `/api` 与 8082 任一)
- **首页 smoke**`node 开发文档/8、部署/scripts/verify_home_smoke.mjs` → 页面含「设备数量」「场景获客」,`pageerror` 为空
- `index.html` 响应头含 `Cache-Control: no-cache`
4. **失败则循环**:修 → rebuild 前端 → 再 deploy → 再 smoke直到通过或明确环境级阻塞仅此时向用户说明
## 禁止
- 仅 `curl` 首页 200 就宣称部署成功
- 部署失败后只给用户命令让用户自己跑
- 未 rebuild 就声称「已更新前端」
## 脚本与文档
- 本地一键:`开发文档/8、部署/scripts/deploy_local_docker.sh`
- 首页 smoke`开发文档/8、部署/scripts/verify_home_smoke.mjs`
- 腾讯云:`开发文档/8、部署/scripts/deploy_tencent_baota.sh`(用户明确要求线上时)
## 与「仅本地不 push」关系
部署修错可改本地代码与 `开发文档/`**不自动 git push**(见 `cunkebao-local-only-no-github.mdc`),除非用户本轮明确说提交/推送。

View File

@@ -0,0 +1,28 @@
---
description: 四端只 HTTP 对接、不串仓硬性铁律。改触客宝/AI数智员工/存客宝/超管任意一端时强制遵守。
globs:
- "**/*"
alwaysApply: true
---
# 四端对接铁律 · 只 HTTP · 不串仓
> 真源:`开发文档/2、架构/四端对接铁律_只HTTP不串仓.md`
## 强制
1. **各端各自仓库、各自职责** — 存客宝(3100) · 触客宝(3101) · AI数智员工(3104) · SuperAdmin(3103) **不互相改业务代码**。
2. **协作只走 HTTP API** — JWT `/v1/*` · Open `X-API-KEY` · 禁止跨项目 import 源码、禁止直连 MySQL/Mongo。
3. **数据范围** — 请求必须带当前项目 `companyId`;禁止跨项目读写。
4. **新能力** — 先更 `开发文档/5、接口/` 索引,再改 `route.php`,最后写 UI。
5. **工作手机/神射手** — 只经存客宝 BFF 或 documented HTTPAI数智员工 **禁止** `/v1/kefu/*`。
## 禁止
- 在触客宝/AI数智员工仓修改 `Server/application/cunkebao`(除非用户本轮明确「改存客宝 Server」
- copy 兄弟项目 React 业务组件进本仓(设计 token 可对齐)
- 触客宝直连 `traffic_pool` 表
## 接口索引
`开发文档/5、接口/SuperAdmin_四端对接接口索引.md` · `02-存客宝对接/触客宝PC接口对接索引.md`

View File

@@ -0,0 +1,89 @@
---
description: 存客宝 v3 · 卡若AI 对话强制规则(复盘五块 + 本轮文档可打开路径)
alwaysApply: true
---
# 存客宝 v3 · 卡若AI 对话强制规则
> **生效**2026-05-31 · 优先级:与本仓 `cunkebao-v3-devdoc-first.mdc`、`cunkebao-local-only-no-github.mdc` 并列。
## 一、身份与启动(每轮)
1. **读卡若AI**`/Users/karuo/Documents/个人/卡若AI/BOOTSTRAP.md` → `SKILL_REGISTRY.md`(热技能命中则读对应 `SKILL.md`)。
2. **回廊洗字**`运营中枢/参考资料/卡若闽南口音_ASR纠错库.json`(卡路/卡洛/卡罗拉→**卡若**)。
3. **执行前公示**(默认):正文最前 **理解 ≤200 字** + **本次要做** 有序列表;用户说「直接做」可跳过列表,**复盘仍必须**。
4. **存客宝开发**:叠加 `开发文档/开发铁律_先读文档再编码.md` Phase 0。
## 二、对话结束 · 强制复盘(卡若 v5/v6
**每条回复的最后一块**必须是完整 **[卡若复盘]YYYY-MM-DD HH:mm**,真源:
`卡若AI/运营中枢/参考资料/卡若复盘格式_固定规则.md` · 速查 `04_卡火/火炬_全栈消息/卡若复盘格式/SKILL.md`F01d
| 顺序 | 块 |
|:---:|:---|
| 1 | **🎯 目标·结果·达成率**(单行 ≤50 字,含 **0100%** |
| 2 | **📌 过程**1、2、3 分点,可验收数据) |
| 3 | **💡 反思**13 点) |
| 4 | **📝 总结** |
| 5 | **▶ 下一步执行** |
复盘块内**禁止表格**;禁止省略复盘或写「见上文」。
## 三、复盘之后 · 本轮文档Cursor 可点 · 强制)
复盘五块写完后、回复结束前,追加 **📎 本轮文档****只列本轮对话新建/修改的文件**,通常 13 个;**禁止**贴历史轮次、索引 README、无关专文
### 3.1 Cursor 聊天内(默认 · 必用)
**禁止**在 Cursor 复盘末尾使用下列形式(点击无反应):
- `obsidian://open?...`
- `file://` / `vscode://`
- 一长串与本轮无关的 MD 链接列表
**必须**使用 **代码引用块**(点块内路径可在 Cursor 打开文件)+ **一行绝对路径**
````markdown
**📎 本轮文档Cursor点下面代码块即可打开**
- **卡若对话强制规则**
```1:3:.cursor/rules/cunkebao-karuo-dialogue.mdc
---
description: 存客宝 v3 · 卡若AI
```
`/Users/karuo/Documents/开发/2、私域银行/cunkebao_v3/.cursor/rules/cunkebao-karuo-dialogue.mdc`
````
- 路径用**仓库相对路径**写在 code fence 第三段:`行号:行号:相对路径`
- 块下再写一行 **反引号包裹的绝对路径** `/Users/karuo/...`(备用,部分环境可点)
- 真源对齐卡若AI 需求整理 §8.1**禁止** `file://` 超链接
### 3.2 生成方式
```bash
python3 "开发文档/scripts/build_obsidian_doc_link.py" \
".cursor/rules/cunkebao-karuo-dialogue.mdc" \
--title "卡若对话强制规则"
```
**只传入本轮动过的路径**;将 stdout **原样**贴在复盘正下方。
### 3.3 Obsidian / 星图阁(非 Cursor 聊天)
- 用户明确说「Obsidian 打开」→ 脚本加 `--obsidian --open`(终端外开,**不要**把 `obsidian://` 贴进 Cursor 聊天)
- 工作日志库「个人」→ `卡若AI/.../build_obsidian_work_log_link.py`
## 四、与其它规则
| 规则 | 关系 |
|:---|:---|
| `cunkebao-local-only-no-github.mdc` | 不自动 push |
| `cunkebao-v3-devdoc-first.mdc` | 改接口/需求先读文档 |
| 卡若AI `karuo-ai.mdc` | 复盘五块一致;路径输出以本条 §3 为准 |
## 五、进度(可选)
用户要求时,在 **📌** 或 **📝** 中带 **本任务完成度 X%**(分子/分母说清)。

View File

@@ -0,0 +1,26 @@
---
description: 存客宝 v3 仅本地开发——禁止 Agent 自动 commit/push GitHub覆盖全局 User Rules
alwaysApply: true
---
# 存客宝 v3 · 仅本地、不自动同步 GitHub
> **生效**2026-05-25 起,卡若明确要求暂停「对话结束自动推 GitHub」。
## 强制
1. **所有代码与文档改动仅保存在本机工作区**,不自动 `git commit`、不自动 `git push`、不自动同步 Gitea/GitHub/远程服务器。
2. **仅当卡若在本轮对话中明确说**「提交」「commit」「推 GitHub」「push」「同步远程」等时才可执行对应 Git 远程操作。
3. 对话结束时:**列出本次修改的文件路径即可**,不要执行 push**禁止**提示「要不要同步 GitHub」「已同步 GitHub」等。
4. 沙盒、未授权远程、CI 触发型部署:**一律不主动触发**。
5. 开发文档可写本地 `开发文档/` 目录,**不要**为进度文档单独 commit/push。
## 与全局 User Rules 的优先级
若全局 User Rules 含「边做边同步 GitHub / 每次对话完成推到 GitHub」**以本规则为准**——存客宝 v3 会话内忽略该条,直至卡若另行恢复。
## 仍允许
- 本地 `git status` / `git diff` 用于自查
- 卡若显式授权后的 commit / push
- 开发文档文件夹内记录进度(本地 MD不推远程

View File

@@ -0,0 +1,47 @@
---
description: 存客宝 v3 · 手机端优先适配铁律(开发 /mobile 必守)
globs:
- Cunkebao/src/pages/mobile/**
- Cunkebao/src/components/Layout/**
- Cunkebao/index.html
---
# 存客宝 · 手机端优先Mobile First
> **产品定位**:存客宝 **以手机端界面为主**PC 为同套 `Layout frame=mobile` 全屏,不是桌面专属布局。
> **壳层参照**`Cunkebao/src/components/Layout/` · `Cunkebao/index.html` · 触客宝 `.cursor/skills/触客宝手机端前端壳/SKILL.md`(键盘/100dvh 同源)
## 一、结构(强制)
| 层级 | 规则 |
|:---|:---|
| 页面壳 | 用 `Layout``header` 顶 · `main` **唯一纵向滚动** · `footer` 底 |
| 多步表单 | **`embedded`**:底栏内嵌在 flex 底,**禁止**只靠 Portal 让用户上拉找「下一步」 |
| 内容区 | **禁止** `min-height: 100vh` / `padding-bottom: 100px` 撑高;滚动只发生在 `Layout.main` |
## 二、选项与排版(禁止挤压)
| 场景 | 做法 |
|:---|:---|
| ≤3 个短选项 | `radioGroupSegment` 等分横排 |
| ≥4 个或文案较长 | `radioGroupWrap` **两列换行**,禁止 `radioGroupHorizontal` 塞 5 项导致**竖排单字** |
| 长说明 | 副文案单独一行(`radioDesc`),不挤在 Radio 同一窄列 |
| 触控 | 可点区域高度 **≥ 44px**;字号 **≥ 14px**(输入 **≥ 16px** 防 iOS 放大) |
## 三、底栏按钮(下一步 / 提交)
- 固定在视口**最下**`embedded` 的 `inlineFooter` 或 `TabBarPortal`
- 主按钮 **block / flex:1**,与「上一步」并排时 `footer-btn-group`
- 主体 `main` 预留 `padding-bottom` ≥ 底栏高 + safe-area`Layout` 已处理 `embedded` 时勿重复加大留白)
## 四、新页 / 改页 Checklist
- [ ] 已读本条 + Layout 源码
- [ ] 无 `100vh` 撑高 body
- [ ] 多选项未竖排挤字
- [ ] 底栏无需上拉即可点「下一步」
- [ ] 真机或 375px 模拟器目视
## 五、需求落盘
手机适配类需求写入 `开发文档/1、需求/修改/存客宝_进行中_{YYYYMMDD}.md`REQ-CKB-11x验收**375px 宽无挤字、底栏固定可见**。

View File

@@ -0,0 +1,43 @@
---
description: 存客宝 v3 · 读需求表必先看图(强制)
globs:
- "开发文档/1、需求/**/*.md"
alwaysApply: false
---
# 存客宝 v3 · 读需求表必先看图
> **生效**2026-05-26 起。卡若明确要求:每次读 `开发文档/1、需求/修改/存-*.md` 或类似需求 MD 时,**必须**确认能看到 MD 引用的所有图片,再开始开发。
## 强制流程(开发前 Phase 0
1. **先读需求 MD**`Read` 工具读完整文件)。
2. **列出所有 `![](images/xxx.png)` 引用**(用 `Grep` 模式 `../../10、项目管理/images/[^)]+\.png`)。
3. **`ls images/`** 确认本地文件均存在;若缺图必须在对话里**明确报告缺失清单**,不要假装能看到。
4. **逐张 `Read` 关键截图**(至少所有 P0/P1 模块对应的截图与「参考样式」「标注」类图片。Read 工具支持 PNG/JPG/GIF/WebP会作为图像加载到上下文。
5. **复述**截图中看到的元素(按钮文字、颜色、布局、标注红框),与 MD 文字描述对照,若有冲突以**截图为准**并在回复中标注。
6. **图片缺失或读取失败时**:先用 `GenerateImage` 不可、改用 `WebFetch` 也不可。立刻向用户报告,**不**继续编码。
## 禁止
- 仅凭 MD 文字描述就开始编码,跳过截图。
- 用 `cat`/`head` 读 PNG无效
- 复述 MD 时把截图当作文字一并描述但实际未 Read伪装看图
## 适用范围
- `开发文档/1、需求/修改/*.md`
- `开发文档/1、需求/草稿/*.md`
- 任何外部传入的 PDF 需求(先 `Read` PDF再 `Read` 拆出的 PNG 页)
## 复盘要求
每次按本规则开发后,在复盘里说明:
- 本轮 Read 了哪些 PNG路径
- 截图中验证/纠正了哪些 MD 文字描述
- 是否有图片缺失或读取失败
## 与其他规则关系
- 与 `cunkebao-v3-devdoc-first.mdc` 协同:先读 1、需求图 → 再读 5、接口/2、架构 → 再编码。
- 与 `cunkebao-local-only-no-github.mdc` 不冲突:仍只本地,不自动推。

View File

@@ -0,0 +1,54 @@
---
description: 存客宝 v3 开发铁律——先读开发文档再编码,迭代结束回写文档(含 5、接口
alwaysApply: true
---
# 存客宝 v3 · 开发文档先行
本项目代码变更**必须**遵循 `开发文档/开发铁律_先读文档再编码.md`。
## 动手前Phase 0
1. 读 `开发文档/开发铁律_先读文档再编码.md` 的 Phase 0 表,按任务类型读完对应 MD
2. **目录/需求维护** 必读 `开发文档/开发文档目录结构铁律.md`(十大目录 · modify 收口 · 已完成进 10、项目管理
2. **接口/BFF/对接** 必读:
- `开发文档/5、接口/README.md`
- `开发文档/5、接口/07-接口分类总览Obsidian配色.md`
- `开发文档/5、接口/存客宝API全量索引.md`
- 涉及 workphone 时再读 `5、接口/02-存客宝与工作手机对接/` 下 05/06/03
3. **架构/新模块** 必读 `开发文档/2、架构/README.md` → `系统架构.md`
4. 对话中先列出「本次已读文档路径」≤5 条),再改代码
## 开发中Phase 1
- 路由真源:`Server/application/*/config/route.php`
- 不改原有业务 URL设备写操作走 `/v1/workphone/*`
- 对照 `5、接口/02-存客宝与工作手机对接/06-业务接口与工作手机一对一映射总表.md`
- **边开发边标注**:只改 `开发文档/1、需求/修改/{端}_进行中_{YYYYMMDD}.md`(⬜→🟡→✅);**禁止**同日另开 `{端}_{主题}_{date}.md`;关单节迁入 `开发文档/10、项目管理/已完成/`
- **需求落盘 Skill**`.cursor/skills/需求协调与归档/SKILL.md` §九(一项目一文件)
### ⛳ 强制打勾铁律(卡若 2026-05-31 · 最高优先)
> **每完成一项,立即在开发文档对应行打 ✅** —— 不攒批、不等收尾、不口头代替。
1. **触发即更新**:任一需求/子项验收通过的**当下**,立刻把进行中 MD 对应行 `⬜/🟡 → ✅`,并在验收列补**可验收证据**HTTP 码 / 条数 / 脚本 exit / 截图路径)。
2. **粒度到子项**:表格每行、清单每条 `- [ ] → - [x]`;一个功能含多子项的,完成几项打几个勾。
3. **顺序固定**`改代码 → 验证 → 立即打勾 ✅ + 证据 → 再继续下一项`;严禁"全部做完再统一打勾"。
4. **复盘对齐**:复盘 📌 引用的完成项,必须与 MD 中已 ✅ 的行一致;不一致以 MD 为准并补勾。
5. **跨文档同步**:接口变更同步打勾 `开发进度_接口文档.md`;其它相关文档同样"完成一项打一勾"。
6. **未完成保留**:⬜/🟡/🔒 原样留下,不删行;整节全 ✅ 才迁 `10、项目管理/已完成/` 并留索引行。
## 收尾Phase 2
- 路由变更 → 同步 `5、接口/存客宝API全量索引.md`
- BFF/SDK 变更 → 同步 02-对接目录 + `开发文档/开发进度_接口文档.md`
- 新增 MD → 运行 `开发文档/scripts/generate_doc_header_banners.py`
- 复盘须写:读了哪些文档、更新了哪些文档
## Skill
| Skill | 路径 |
|:---|:---|
| 卡若AI 开发文档先行 | `01_卡资/金盾_数据安全/存客宝/开发文档先行/SKILL.md` |
| 需求整理 W05b | `.cursor/skills/开发需求文档整理/SKILL.md` |
| 需求协调 W05c | `.cursor/skills/需求协调与归档/SKILL.md` |

View File

@@ -0,0 +1,122 @@
---
name: cunkebao-architecture-five-diagrams
description: >-
存客宝 v3 项目架构五图:对话内 GenerateImage 生成高级架构/流程图,写入
开发文档/2、架构/images/architecture-overview/,并维护 08-项目架构五图读懂指南.md。
触发:架构五图、五图读懂、项目架构图、生成架构图、一图读懂存客宝、
PM架构图、不用Python生成图片、架构 infographic。禁止用 Pillow/Python 画架构总览图。
---
# 存客宝 · 架构五图(对话内 AI 出图)
> **铁律**:架构总览 / 业务流程 / 板块关系图 → **只用 Cursor `GenerateImage`** 在对话里生成;**禁止**用 `generate_doc_header_banners.py` 或 Pillow 替代。
> **文档说明小头图**(单篇 MD 顶栏)仍走 F09a「开发文档说明头图」Skill。
---
## 一、何时触发
- 用户要「几张图看懂整个项目」「给 PM 的架构图」「五图读懂」
- 存客宝大版本架构变更后需更新总览图
- 用户明确说「不要用 Python 生成图片」
---
## 二、五图标准套装(固定 5 张)
| 序号 | 文件名 | 标题(中文) | 内容要点 |
|:----:|--------|-------------|----------|
| 1 | `01-系统四层架构总览.png` | 存客宝 v3 · 系统四层架构总览 | 客户端层 → Nginx → Server/Moncter/WebSocket → MongoDB/MySQL/Redis + 工作手机 SDK |
| 2 | `02-核心业务数据流.png` | 存客宝 · 核心业务数据流 | 工作手机 ↔ SDK ↔ ThinkPHP ↔ 三库WebSocket ↔ React 前端 |
| 3 | `03-六大业务板块关系.png` | 存客宝 · 六大业务板块 | 场景获客/工作台/设备/微信号/流量池/内容库 → 中心 BFFroute.php 真源 |
| 4 | `04-场景获客与好友添加流程.png` | 场景获客 + 好友添加 · 完整流程 | 建计划→task_customer→Workerman→健康分→SDK→状态0~5→Webhook |
| 5 | `05-定时任务与自动化调度.png` | 存客宝 · 定时任务与自动化调度 | task_scheduler 高/中/低频任务Command→Queue→Job |
**输出目录**(项目内):
```
开发文档/2、架构/images/architecture-overview/
```
**配套文档**(必须同步更新或新建):
```
开发文档/2、架构/08-项目架构五图读懂指南.md
```
---
## 三、GenerateImage 提示词规范
### 视觉风格(统一)
- 比例:**16:9 横版**
- 风格:**dark glassmorphism**,深蓝/紫渐变底,毛玻璃卡片,细线箭头
- 字体:**中文为主**大号标题PM 可读
- 质量Keynote / 企业 SaaS 发布会级别,**不要**代码截图、不要 ASCII
### 每张图调用模板
```
Professional enterprise architecture infographic, 16:9 landscape,
premium dark glassmorphism, subtle blue-purple gradient.
Chinese title: "{标题}".
{具体内容 bullet英文描述布局即可}
Clean sans-serif Chinese typography, Apple keynote quality, footer: CKB v3
```
### 并行生成
5 张图 **同一轮对话并行** 调用 5 次 `GenerateImage`,不要串行等待。
### 落盘
GenerateImage 默认写到 Cursor assets**必须 cp 到**
```bash
开发文档/2、架构/images/architecture-overview/
```
(用 Shell 复制,不要用 Python 画图。)
---
## 四、文档维护 checklist
生成图片后按序执行:
1. [ ] 5 张 PNG 已在 `architecture-overview/`
2. [ ] `08-项目架构五图读懂指南.md` 内 5 处 `![...](images/architecture-overview/...)`
3. [ ] `2、架构/README.md` 阅读顺序增加「08-五图读懂」
4. [ ] `5、接口/开发进度_接口文档.md` 或架构变更记录加一行
5. [ ] **不**运行 `generate_doc_header_banners.py` 为这五张图生成 doc-header
---
## 五、内容真源(生成前必读)
| 主题 | 文档 / 代码 |
|------|-------------|
| 四层架构 | `开发文档/2、架构/系统架构.md` |
| 数据流 | `开发文档/2、架构/核心业务链路.md` |
| 六板块 | `开发文档/5、接口/03-业务板块接口/README.md` |
| 获客加友 | `开发文档/2、架构/07-业务板块核心算法.md` |
| 定时任务 | `开发文档/2、架构/自动化工作流.md` · `Server/config/task_scheduler.php` |
---
## 六、与 F09a 头图 Skill 的分工
| 类型 | 工具 | Skill |
|------|------|-------|
| 单篇 MD 顶栏小 banner | GenerateImage首选 | F09a 开发文档说明头图 |
| **项目级架构五图** | GenerateImage强制 | **本 Skill** |
| 离线无 AI 的小色条 | Pillow fallback | F09a 仅 fallback不用于五图 |
---
## 七、变更记录
| 版本 | 日期 | 说明 |
|------|------|------|
| 1.0 | 2026-05-25 | 首版;替代 Python 批量画架构总览 |

View File

@@ -0,0 +1,193 @@
---
name: 存客宝官网开发
description: 存客宝对外官网(/官网/需求、SEO/GEO、产品矩阵截图、留资单接口、超管接口文档第9类。触发存客宝官网、官网开发、官网SEO、产品矩阵、官网留资、对外接口、官网需求、GEO、私域官网。
triggers: 存客宝官网,官网开发,官网SEO,产品矩阵,官网留资,对外接口,GEO,私域官网,触客宝官网
owner: 火炬
group: 火
version: "1.0"
updated: "2026-05-31"
---
# 存客宝官网开发 SkillF01e · 项目内)
> **代码**`/Users/karuo/Documents/开发/2、私域银行/cunkebao_v3/官网/`(静态站 · 零构建)
> **当日需求真源(唯一)**`开发文档/1、需求/修改/官网_进行中_{YYYYMMDD}.md` — **新需求只追加此文件章节**,禁止再开 `官网_{主题}_*.md` 于 `修改/`
> **鉴定/索引**`开发文档/1、需求/官网/0013` 为已整理专文,**非**当日追加口(见 [需求协调与归档](../需求协调与归档/SKILL.md) §九)
> **对话规则**`.cursor/rules/cunkebao-karuo-dialogue.mdc`(卡若复盘 + 本轮文档代码块)
---
## 一、何时启用
| 触发 | 动作 |
|:---|:---|
| 改官网页面/样式/留资 | 读 **`官网_进行中_{date}.md`**REQ/E 序)· 专文仅作参考 → 改 `官网/`**回勾进行中(⬜→🟡→✅)**`03-研发迭代日志` |
| 运营后台/访客/Webhook | 读 `_进行中` **§ REQ-WEB-60** → `scripts/analytics-store.mjs` + `admin/` → 子项打勾 |
| **AI 客服对外(新)** | **先读 14 专文 §十一** · **勿抢先写代码** · Server `official-ai/chat` → 再官网挂件 |
| 留资/对接 API | 只读 [07-官网统一留资接口](../../开发文档/1、需求/官网/03-接口与对接/07-官网统一留资接口_20260531.md)**禁止再造第二 URL** |
| SEO/关键词 | 读 [09](../../开发文档/1、需求/官网/04-SEO与增长/09-官网SEO与GEO全站优化_20260531.md);要做后台读 [12](../../开发文档/1、需求/官网/04-SEO与增长/12-官网SEO运营后台与自动挂链_20260531.md) |
| 产品矩阵配图 | 读 [08-产品矩阵界面与截图](../../开发文档/1、需求/官网/02-页面与视觉/08-产品矩阵界面与截图_20260531.md) |
| 超管接口汇总 | 同步 `SuperAdmin/lib/api-docs-index.ts` + `5、接口/SuperAdmin_四端对接接口索引.md` |
---
## 二、文档地图(按编号)
| 编号 | 文件 | 用途 |
|:---|:---|:---|
| **进行中** | `修改/官网_进行中_20260531.md` | **REQ-WEB 总表 · 待改文件 · E1E7** |
| 00 | 00-官网需求执行总表_20260531.md | 进度 % · 速查 |
| 01 | 01-需求与验收_v2.md | IA、价格、验收 smoke |
| 06 | 06-首页Hero三版_20260531.md | Hero 配色/真截图 |
| 07 | 07-官网统一留资接口_20260531.md | **鉴定版** POST /v1/api/scenarios |
| 08 | 08-产品矩阵界面与截图_20260531.md | 三端截图规范 |
| 09 | 09-官网SEO与GEO全站优化_20260531.md | 关键词矩阵 + Schema + 工具 |
| 10 | 10-官网对外接口文档_20260531.md | 改造官网索引 |
| 11 | 11-超管统一接口文档中心_20260531.md | 超管 9 类汇总 |
| 12 | 12-官网SEO运营后台与自动挂链_20260531.md | **⬜** SEO 运营中心需求(挂链/发帖/收录) |
| 13 | 13-官网AI数智员工单设备硬件专题_20260531.md | 单手机 mockup · 流程图 · `../../10、项目管理/images/官网_20260531/` |
| **14** | **14-官网AI客服获客场景_20260531.md** | **P0 · 仅文档 · 开发按 §十一Server→官网** |
| **15** | **15-官网后台用户旅程与Webhook推送_20260531.md** | **P1 · 有手机优先 · 一键推 Webhook** |
---
## 三、常用命令
```bash
# 本地预览 + smoke
bash 开发文档/8、部署/scripts/deploy_official_site.sh --smoke
# → http://127.0.0.1:8090/
# 复盘末尾生成本轮文档链接Cursor 可点)
python3 开发文档/scripts/build_obsidian_doc_link.py \
"开发文档/1、需求/官网/02-页面与视觉/08-产品矩阵界面与截图_20260531.md" \
--title "产品矩阵规范"
```
---
## 四、留资铁律(踩坑合集)
| 坑 | 正确做法 |
|:---|:---|
| 再造 `/v1/open/*` 或第二个留资 URL | **唯一** `POST /v1/api/scenarios` + apiKey/sign |
| 只传 `portrait.tags` | 必须传顶层 **`tags` + `siteTags`** 逗号串(`lead.js` 已补) |
| `portrait` 参与签名 | 签名时 **删除** portrait、apiKey、sign |
| 页脚明文微信/电话 | 只留 **data-lead** 弹窗 |
| planId 写 URL | 用 **apiKey** 绑 plan **779** |
**配置**`官网/assets/js/site-config.js` · **提交**`lead.js` · **轨迹**`track.js`
### 4.1 访客追踪 + WebhookREQ-WEB-60
| 项 | 说明 |
|:---|:---|
| 追踪 API | `POST /api/track`(公开)· 数据 `data/analytics.json` |
| 留资推送 | `POST /api/lead-local`(有手机号才推飞书)· **勿**浏览器直连飞书 |
| 飞书格式 | `{ msg_type:"text", content:{ text:"…" } }` · 成功 `code===0` |
| 合并键 | `phone` > `fingerprint`canvas+UA非真 IMEI/MAC> `visitorId` |
| 后台 | 概览/获客/旅程 · 右上 ⏰ `GET /admin/api/alerts` |
| 边做边勾 | 完成子项即改 `_进行中` REQ-WEB-60 / **REQ-WEB-61** 表状态 ✅ |
| 开发顺序 | **REQ-CKB-66 阶段1Server→ 阶段2计划UI→ REQ-WEB-61 阶段3官网** |
---
## 五、SEO / GEO 要点2026
1. **SEO 地基优先**76% Google AI 摘要 URL 在自然 Top10 — 先 meta、sitemap、Schema、内链。
2. **五类词**:核心词 / 场景词连锁·AI客服/ 长尾 FAQ / 蒸馏词 / 品牌词 → 见 09 §三。
3. **Schema**index 已有 SoftwareApplication + ItemList(产品矩阵)pricing FAQPage。
4. **工具**Screaming Frog 全站爬、Google Rich Results Test、百度搜索资源平台。
5. **GEO**E-E-A-T + 真实案例数字 + 站外知乎/百家号同实体 NAP。
6. **勿迷信单独 GEO 外包**:与 SEO 同一套内容工程。
---
## 六、产品矩阵 UI
| 端 | 截图路径 | 替换方式 |
|:---|:---|:---|
| 存客宝 | `官网/assets/img/matrix-cunkebao.png` | 3100 真机截图覆盖 |
| 触客宝 | `官网/assets/img/matrix-touchkebao.png` | 3101 真机截图覆盖 |
| AI数智员工 | `官网/assets/img/matrix-aistaff.png` | 3104 真机截图覆盖 |
- HTML`index.html#matrix` · class `matrix-shot`
- 标题:**三端入口** + **存客宝产品矩阵**(对齐设计稿)
---
## 七、超管「接口文档」同步(第 9 类)
```
改留资接口说明
→ 07/10 官网 MD
→ SuperAdmin_四端对接接口索引.md §九
→ SuperAdmin/lib/api-docs-index.ts id: official-site
→ 超管 /dashboard/ai-center?tab=docs 自测
```
**注意**Tab 挂在 AI 中心下,**内容是全平台 9 类**,文案勿写「仅 AI 接口」。
---
## 八、复盘与链接Cursor 专用 · 必记)
| 错误 | 正确 |
|:---|:---|
| 复盘贴 `obsidian://` | **点不开**;用 **代码引用块** ` ```1:3:相对路径 ` + 绝对路径一行 |
| 贴 6 个历史 MD 链接 | **只列本轮**新建/修改 13 个文件 |
| 用 `file://` 超链接 | 卡若需求整理 §8.1 **禁止** |
脚本:`开发文档/scripts/build_obsidian_doc_link.py`(默认 Cursor 块)
---
## 九、与兄弟 Skill 关系
| Skill | 关系 |
|:---|:---|
| [开发需求文档整理](../开发需求文档整理/SKILL.md) | 四端需求 MD官网专文走 **本 Skill** |
| [需求协调与归档](../需求协调与归档/SKILL.md) | 跨端 COORD |
| [存客宝宝塔部署](../存客宝宝塔部署/SKILL.md) | 公网部署官网时 |
| 卡若AI F01d 复盘格式 | 每轮收尾五块 |
---
## 十、验收清单(每轮)
- [ ] `node 官网/smoke.mjs` 全绿
- [ ] 矩阵三图不裂、alt 有意义
- [ ] 留资弹窗可提交(本地需 apiKey
- [ ] 文档 03 迭代日志 + 相关专文变更记录
- [ ] 若动接口:超管 api-docs-index 已同步
---
## 十一、SEO 运营后台(需求 · 12 号文档)
| 要点 | 说明 |
|:---|:---|
| 放哪 | **SuperAdmin 平级「SEO 运营」**,不要塞 AI 中心 |
| 自动挂链 | **站内**内链脚本 + **矩阵站**互链表;**站外**发稿任务单(知乎等多为草稿+人工) |
| 申请 | P1 接百度站长、GSC、IndexNow API |
| 禁止 | 小旋风类黑帽站群、泛目录、买链轮链 |
| 开源参考 | GitHub `SEO-Interlinking-Tool``schema-sentry` |
| 本轮 | **只写需求**,不改 `官网/` |
---
## 十二、经验沉淀evolution
| 日期 | 经验 |
|:---|:---|
| 2026-05-31 | Cursor 聊天内 obsidian:// 无效 → 复盘用代码引用块 |
| 2026-05-31 | 官网留资已有单接口,文档 07 鉴定即可 |
| 2026-05-31 | 超管接口文档 = 9 类全平台,官网为第 9 类 |
| 2026-05-31 | 产品矩阵需 UI 截图,非纯文字卡 |
| 2026-05-31 | SEO+GEO关键词矩阵在 09ItemList Schema 上 index |
| 2026-05-31 | SEO 后台要自建;站群 SaaS 黑帽不做;发帖 API 稀缺→任务单 |
| 2026-05-31 | 本机素材:`9、手册/使用手册/截图/AI数智员工-登录页.png`;海报参考在 `个人/4、工作日志/会议纪要/参考/` |
| 2026-05-31 | 单设备叙事≠海报获客;硬件专题见 13 号 REQ-WEB-5054 |
| 2026-05-31 | **当日官网需求只写 `官网_进行中`**`官网/0x` 专文=鉴定索引,勿在 `modify/` 再开主题 MD |
| 2026-05-31 | 官网 AI systemPrompt**Server 七层合并**(存客宝 §6· 默认循序渐进留资见 REQ-WEB-63 |
| 2026-05-31 | REQ-WEB-60访客 analytics + 飞书 Webhook + 后台 Karuo UI开发完须在 `_进行中` 打勾 |

View File

@@ -0,0 +1,120 @@
---
name: 存客宝宝塔部署
description: 存客宝 v3 部署到腾讯云宝塔 42.194.245.239 的标准流程、验收与踩坑防治。触发词存客宝部署、宝塔部署、kr-op部署、ckbapi部署、腾讯云部署、部署踩坑、Query.php、场景获客失败、工作台500、二维码不显示。
---
# 存客宝宝塔部署 Skill
> 生产kr-op / kr-kf / ckbapi · 服务器 42.194.245.239:22022
> 详细踩坑:`开发文档/8、部署/宝塔腾讯云部署踩坑清单.md`
## 一、部署前必读(防治清单)
| 序号 | 风险 | 防治 |
|------|------|------|
| 1 | 登录 405 | 构建 `VITE_API_BASE_URL=https://ckbapi.quwanzhi.com` + kr-op `/api` 反代 |
| 2 | 登录 10501 / where 全挂 | **禁止**覆盖 `thinkphp/library/think/db/Query.php` 为 TP5.1 精简版;脚本 2b 强制同步仓库版 |
| 3 | JWT 500 | 控制器用 `JwtAuthTrait::authUser()`,勿读 `$request->userInfo` |
| 4 | 工作台 500 | `setAttr('config')` 勿用 `$item->config` / `$item->data[]` |
| 5 | 流量池分页 1 条 | count 用 `(clone $query)->count()` |
| 6 | 场景设置保存 500 | 先跑 `20260525_acquisition_global_settings.sql` |
| 7 | 场景列表空白 / 401 | 前端 token 每次请求从 store 读401 跳登录 |
| 8 | **海报二维码 img 404** | URL **勿**带 `.png` 后缀Nginx 当静态文件 404`/v1/frontend/poster/qrcode/{id}` |
| 9 | **海报弹窗误显 H5 码** | 主二维码 = **小程序码**`poster_qrcode_mode=miniprogram`H5 表单仅下方链接区,两者隔离 |
| 10 | **小程序码进表单/错 AppId** | 落地页 **`pages/poster/index2`**(非 `input2`AppId **`wx789850448e26c91d`**(存客宝);`.env` 勿重复 `[weChat]` 段 |
| 11 | **授权手机号后无入池** | `decryptphone` 勿用 EasyWeChat `phone_number`;用 `MiniProgramQrCodeService::getUserPhoneNumber` curl 直连微信 |
| 12 | rsync 勿删 `.env` / `vendor` / `runtime` | 脚本已 exclude |
## 二、标准命令(项目根 cunkebao_v3
```bash
# 1. 数据库迁移(有 migrations 时先跑)
bash 开发文档/8、部署/scripts/run_db_migrations_tencent.sh
# 2. 全量部署
bash 开发文档/8、部署/scripts/deploy_tencent_baota.sh
# 3. 仅前端
bash 开发文档/8、部署/scripts/deploy_tencent_baota.sh --skip-server
# 4. 验收(必须 17/17扩展含 AI/支付/海报;线上全链路)
bash 开发文档/8、部署/scripts/acceptance_tencent_prod.sh
bash 开发文档/8、部署/scripts/acceptance_tencent_extended.sh
bash 开发文档/8、部署/scripts/acceptance_tencent_online_full.sh
# 5. 仅同步支付 overlay + 证书
bash 开发文档/8、部署/scripts/sync_payment_certs_tencent.sh
```
## 三、上线顺序
**迁移 SQL → rsync 后端(含 Query.php 2b→ 构建前端 → 发布 dist → 清 cache → 验收**
## 四、快速诊断
```bash
# 登录
curl -X POST https://ckbapi.quwanzhi.com/v1/auth/login \
-H 'Content-Type: application/json' \
-d '{"account":"karuo","password":"***","typeId":1}'
# 场景(需 Bearer
curl -H "Authorization: Bearer $TOKEN" \
'https://ckbapi.quwanzhi.com/v1/plan/scenes?page=1&limit=5'
# 海报二维码(应 200 image/png勿测 .png 后缀)
curl -I 'https://ckbapi.quwanzhi.com/v1/frontend/poster/qrcode/709'
# Query.php 版本(应为 375f1093… 一类newQuery 须复制 name/table
ssh -p 22022 root@42.194.245.239 \
"md5sum /www/wwwroot/ckbapi.quwanzhi.com/thinkphp/library/think/db/Query.php"
```
## 五、路径速查
| 组件 | 路径 |
|------|------|
| API | `/www/wwwroot/ckbapi.quwanzhi.com` |
| 存客宝 dist | `/www/wwwroot/auto-devlop/ckb-operation/dist` |
| 触客宝 dist | `/www/wwwroot/auto-devlop/tkb-wechat/dist` |
| monorepo | `/www/wwwroot/mckb_quwanzhi_com` |
| MySQL | 10.0.0.4:3306 / cunkebao_v3 / ck_ |
## 六、复盘归档
每次部署后更新:`开发文档/8、部署/04-部署复盘/`
---
## 七、超管 SuperAdmin本地 Docker vs 宝塔)
| 项 | 本地 Docker | 宝塔生产 |
|----|-------------|----------|
| 访问 | http://localhost:**3103** | **kr-admin.quwanzhi.com**Node/PM2 单独部署,未进 ckb dist |
| API 反代 | Next `rewrites``cunkebao-server``/api/v1/admin` | 需 Nginx 反代到 **ckbapi.quwanzhi.com/v1/admin** 或同域 `/api` |
| 构建 | `docker compose build superadmin-web`build-arg `SUPERADMIN_API_PROXY_TARGET=http://cunkebao-server` | `npm run build` + `next start``NEXT_PUBLIC_API_BASE_URL=/api/v1/admin` |
| 设备二维码 | 依赖 `api.guid` + `api.deviceSocketHost``.env.docker` | 同左,生产 `.env` 必须配置;缺则添加设备报「环境配置不完整」 |
| S2 同步设备 | 需本机/内网能访问 **rpc.API_BASE_URL**(工作手机 SDK | 宝塔 server 需能连 S2本地 Docker 常连 `workphone-sdk:8899` 或线上 kf |
| 客户池列表 | 37 万+ 数据,首屏约 **35s**V2 表);勿用旧 `traffic_source_v1` JOIN | 同架构;生产库更大时需加索引/缓存 |
| 端口冲突 | 登记 **3103**(勿与 website 3102 混用) | 宝塔单独 Node 项目,不占 3100/3101 |
### 超管常见报错
| 现象 | 原因 | 处理 |
|------|------|------|
| 添加设备网络错误 | 前端打到错误路径 `/v1/api/device/add` | 用 `POST /v1/admin/devices/qrcode` |
| 二维码环境不完整 | 缺 guid / deviceSocketHost | 补 `Server/.env` `[api]``config/device_bind.php` |
| 客户池一直 loading | 旧 trafficPool 全表 JOIN 超时 | 已改 V2确认部署含新 `GetPoolListController` |
| 转移设备失败 | 目标项目无 s2_accountId | 项目编辑页确认触客宝账号已创建 |
| 本地 3105/3103 混用 | 多个 next dev 实例 | 统一 Docker **3103** 或登记端口 |
### 超管验收(本地)
```bash
bash 开发文档/8、部署/scripts/acceptance_superadmin_docker.sh
# 扩展overview + devices
TOKEN=$(curl -s -X POST http://localhost:8082/v1/admin/auth/login -H 'Content-Type: application/json' \
-d '{"account":"admin","password":"e10adc3949ba59abbe56e057f20f883e"}' | python3 -c "import sys,json;print(json.load(sys.stdin)['data']['token'])")
curl -s -H "Authorization: Bearer $TOKEN" 'http://localhost:8082/v1/admin/dashboard/overview?limit=5' | python3 -m json.tool | head -30
curl -s -H "Authorization: Bearer $TOKEN" 'http://localhost:8082/v1/admin/devices/list?limit=5' | python3 -m json.tool | head -20
```

View File

@@ -0,0 +1,180 @@
---
name: 开发需求文档整理
description: 将录屏转写、标注截图、口述草稿合并为存客宝标准需求 MD。命名 项目_功能主题_日期modify 扁平无子目录;四端分文件。触发词:需求文档、录屏需求、截图需求、需求拆解、整理需求、开发需求文档、存客宝需求、触客宝需求、超管需求。
---
# 开发需求文档整理 Skill存客宝 v3 · W05b 项目内)
> **卡若AI 母 Skill**`/Users/karuo/Documents/个人/卡若AI/02_卡人/水泉_规划拆解/需求整理/SKILL.md`(通用)
> **本 Skill**:存客宝 **录屏全量包** + **模块拆解**;落盘纪律以本文为准。
> **协调归档**:配合 [需求协调与归档](../需求协调与归档/SKILL.md)W05c 项目内)
---
## 一、目录与命名(强制 · **2026-05-31 修订**
> **当日进行中 = 一项目一文件**。主题需求写在文件 **内章节**,不另开 `{项目}_{主题}.md`。
> 纪律真源:[需求协调与归档/SKILL.md](../需求协调与归档/SKILL.md) §二、§九
```
开发文档/1、需求/
├── 索引.md
├── 修改/
│ ├── YYYYMMDD_需求总览.md ← 唯一横表(待办+协同+审计)
│ ├── 存客宝_进行中_{YYYYMMDD}.md ← 存客宝当日唯一真源(多节)
│ ├── 触客宝_进行中_{YYYYMMDD}.md
│ ├── 官网_进行中_{YYYYMMDD}.md
│ ├── AI数智员工_进行中_{YYYYMMDD}.md
│ ├── images/
│ └── (无 images/ · 无 已完成/
开发文档/10、项目管理/
├── images/ ← 需求配图
└── 已完成/ ← 关单批次
```
| 规则 | 说明 |
|:---|:---|
| **进行中文件名** | **仅** `{端}_进行中_{YYYYMMDD}.md` |
| **禁止** | 根目录 `存客宝_设置与我的页_*``触客宝_手机_*``SuperAdmin_*_{主题}_*` 等与 `_进行中` 并存 |
| **超管/协同** | SuperAdmin、触客宝登录/BFF 等 **写入 `存客宝_进行中_{YYYYMMDD}.md` 新 §**,不另开 `SuperAdmin_*.md` |
| **文内结构** | `## §X · {功能主题}`:问题 / 根因 / 规则 / 接口 / REQ / 验收 |
| **端名称** | **触客宝**、**存客宝**、**SuperAdmin**、**AI数智员工** |
| **禁止误称** | 不写「初客宝 / 初刻宝 / 纯客宝」 |
**当日示例20260531**
| 端 | 唯一文件 | 节示例 |
|:---|:---|:---|
| 存客宝 | `存客宝_进行中_20260531.md` | §三 设置/我的 · §一 总表 dedupe |
| 触客宝 | `触客宝_进行中_20260531.md` | 功能中心二版 |
| 官网 | `官网_进行中_20260531.md` | REQ-WEB · E1E9 |
---
## 二、完成目标优先
**标题下第一句**必须是:
```markdown
完成目标:【一句话:交付什么、谁受益、如何验收】。
```
再写来源、时间轴、模块、排期。禁止先堆口述原文。
---
## 三、何时启用
| 素材 | 动作 |
|:---|:---|
| 录屏 TXT + 截图 + 草稿 | **追加**对应端 `{项目}_进行中_{日期}.md` 新 §,不新建主题 MD |
| 口述「整理需求」 | 读本文 + 项目经验 `卡若AI/.../项目经验/存客宝.md` |
| 跨端需求 | 拆到四端各一篇 + 总表COORD 写入各端「跨项目协调」节 |
---
## 四、执行流程
```
素材收集 → 完成目标 → 识别端(四端之一) → 图片入 10、项目管理/images/ → 模块拆解 → 落盘 → 更新索引
```
### Step 1 · 确定端与主题
| 端 | 端口 | 主题示例 |
|:---|:---|:---|
| 存客宝 | 3100 H5 | 微信号、场景获客、迁移、设备 |
| 触客宝 | 3101 PC | AI获客、工作台、Webhook |
| SuperAdmin | 3103 | 超管后台、客户池、项目 |
| AI数智员工 | 3104 | 扫码、飞书、协同对接 |
### Step 2 · 图片
- 进行中:`![](images/xxx.png)`(相对 `modify/*.md`
- 命名建议:`YYYYMMDD-模块-序号.png`
- Obsidian`attachmentFolderPath` = `./images`
### Step 3 · 模块拆解(每端 MD 内)
| 块 | 内容 |
|:---|:---|
| 需求总表 | 优先级 + 功能块 + 状态 |
| 分模块章节 | 说明 / 表 / 验收 / 代码路径 |
| **跨项目协调(本端 · W05c** | 见 [需求协调与归档](../需求协调与归档/SKILL.md) |
### Step 4 · 录屏全量包(可选)
大录屏可另存 `10、项目管理/已完成/` 或保留详细节;**当日进行中**仍只维护该端 **一篇** 主题 MD。
---
## 五、标准章节
见 [template.md](template.md)。必含:完成目标、需求总表、模块章节、开发计划、验收清单、变更记录。
---
## 六、与卡若AI / 项目规范
| 环节 | 动作 |
|:---|:---|
| W05b 通用 | 卡若AI `需求整理/SKILL.md`;存客宝以 **本节目录纪律** 为准 |
| W05c 协调 | 共享 `/Users/karuo/Documents/开发/_共享/跨项目协调/索引.md` |
| COORD 分配 | 001/005/006→存客宝001/003→触客宝001/002/003→SuperAdmin001/002/004→AI数智员工 |
| 开发前 | `开发文档/开发铁律_先读文档再编码.md` Phase 0 |
| Git | `cunkebao-local-only-no-github.mdc`,不自动 push |
---
## 七、质量门禁
- [ ] 当日需求已写入 `{端}_进行中_{日期}.md`(无第二份同端 MD
- [ ] 文内含 `完成目标` 或 § 内问题/根因/验收表
- [ ] 第一句 `完成目标:...`
- [ ] 无「初刻宝」等误称
- [ ] 图片 `../../10、项目管理/images/` 存在
- [ ] 本端 COORD 表已写入(有则写,无则注「当前无」)
- [ ] `1、需求/索引.md` 与当日总表已更新
---
## 八、验收后归档
1. 迁入 `10、项目管理/已完成/{项目}_{功能主题}_{日期}/` + `../../10、项目管理/images/`
2. 运行 `python3 开发文档/1、需求/scripts/flatten_requirements.py`(可选)
3. 更新 `YYYYMMDD_需求总览.md`
---
## 九、存客宝官网(独立 Skill
对外品牌站 **不走四端 `{项目}_{主题}_{日期}.md`**,走专题目录:
| 项 | 路径 |
|:---|:---|
| Skill | [.cursor/skills/存客宝官网开发/SKILL.md](../存客宝官网开发/SKILL.md) |
| **进行中真源** | [`修改/官网_进行中_20260531.md`](../修改/官网_进行中_20260531.md) |
| 文档 | `开发文档/1、需求/官网/`0012 编号专文) |
| 代码 | `官网/` 静态站 |
触发词官网需求、官网SEO、产品矩阵、官网留资 → **先读官网 Skill**,再落盘 `官网/``1、需求/官网/*.md`
**复盘链接**:官网任务同样遵守 `cunkebao-karuo-dialogue.mdc`(代码块路径,禁止 obsidian:// 贴聊天)。
---
## 十、经验沉淀
| 日期 | 说明 |
|:---|:---|
| 2026-05-31 | §一 修订:**进行中仅 `{端}_进行中_{date}.md`**;与 W05c 需求协调 Skill 对齐 |
---
## 十一、延伸阅读
- [template.md](template.md) · [examples.md](examples.md)
- [需求协调与归档/SKILL.md](../需求协调与归档/SKILL.md)
- [存客宝官网开发/SKILL.md](../存客宝官网开发/SKILL.md)
- 卡若AI`02_卡人/水泉_规划拆解/需求整理/references/项目经验/存客宝.md`

View File

@@ -0,0 +1,37 @@
# 标杆示例 · 2026-05-26 全量需求
## 文档路径
`开发文档/1、需求/修改/存-20260526_超级后台设备客服与流量池全量需求.md`
## 素材来源对照
| 类型 | 原始路径 | 处理方式 |
|------|----------|----------|
| 录屏 | `/Users/karuo/Downloads/存客宝开发 20260526.txt` | → 第一章时间轴 14 行 |
| 截图夹 | `/Users/karuo/Downloads/20260526/*.png` | → 复制为 `../../10、项目管理/images/20260526-*.png` |
| 草稿 | `修改/存-20260526.md` | → 并入模块 D微信号/流量池) |
## 结构亮点(可复制)
1. **时间轴先行**:开发先懂「口述顺序」,再按端看章节。
2. **mermaid 产品关系**:多系统(超管/存客宝/触客宝/工作手机)必读。
3. **每节固定块**:需求 + 图 + 表 + 验收 + 代码路径。
4. **P0 扫码绑 IMEI**:步骤表 + 链到 20260525 设备管理文档。
5. **无接口原则**:设备列表「无接口不展示」写进表。
6. **Phase 0 六条**:可直接开 sprint。
7. **验收 20+ checkbox**:测试无需再问产品。
## 图片命名对照(节选)
| 标准名 | 原文件名 |
|--------|----------|
| `20260526-superadmin-01.png` | 超级管理后台标注_20260526204146.png |
| `20260526-device-02.png` | 存客宝-我的-设备管理标注_20260526205229.png |
| `20260526-kefu-module-02.png` | 存客宝-我的-新增客户版块标注_20260526210031.png |
## 触发本 Skill 的用户话术示例
- 「把录屏和截图整理成需求文档,放修改目录」
- 「按上次 0526 的格式再做一份需求」
- 「需求要能直接在 Obsidian 看图,开发能照着做」

View File

@@ -0,0 +1,185 @@
# 需求文档标准模板(复制后替换占位符)
> 进行中文件名:`{项目名称}_{功能主题}_{YYYYMMDD}.md`(例 `存客宝_微信号场景迁移与设备_20260529.md`
> 位置:`开发文档/1、需求/修改/`(扁平,无子目录)
> 图片:`开发文档/10、项目管理/images/` · 已完成:`10、项目管理/已完成/{项目}_{主题}_{日期}/images/`
---
```markdown
# {项目名称}_{功能主题}_{YYYYMMDD}
完成目标:【一句话写清本轮最终交付、边界和验收结果。例:把某账号/项目/功能链路整理到可开发、可测试、可验收的稳定状态。】
> **来源**:录屏口述 `【录屏文件名】.txt`(【时长】)+ 标注截图 `【文件夹或说明】` + 草稿 `【草稿文件名,无则删】`
> **日期**YYYY-MM-DD
> **状态**:待开发
> **适用端**:【例:超级管理后台 3103 · 存客宝 H5 3100 · 触客宝】
---
## 一、录屏时间轴(与口述一一对应)
| 时间点 | 模块 | 口述要点 |
|--------|------|----------|
| MM:SS | 【模块名】 | 【一句话需求,**加粗**关键动作】 |
| MM:SSMM:SS | 【模块名】 | 【跨段合并要点】 |
| — | 草稿补充 | 【仅来自草稿、录屏未提的项】 |
---
## 二、目标拆解(先定目标,再拆需求)
| 目标层级 | 完成目标 | 验收标准 |
|----------|----------|----------|
| 总目标 | 【一句话总目标】 | 【最终验收标准】 |
| 子目标 1 | 【模块/数据/页面目标】 | 【可测试结果】 |
| 子目标 2 | 【模块/数据/页面目标】 | 【可测试结果】 |
---
## 三、产品关系(开发必读)
```mermaid
flowchart TB
subgraph A["【系统A】"]
A1[模块]
end
subgraph B["【系统B】"]
B1[模块]
end
A1 --> B1
```
- **【产品甲】**:【与产品乙的关系一句】
- **【关键链路】**:【例:扫码 → IMEI → 入库 → 超管可见】
---
## 四、模块 A · 【端名称 · 如超级管理后台】
### A1. 【功能名】P0/P1
**完成目标**:【本小节完成后达到什么状态】
**需求**:【一句话】
![【图说】](images/YYYYMMDD-模块-01.png)
| 项 | 说明 |
|----|------|
| 业务规则 | 【规则】 |
| 验收 | 【可测试句子】 |
| 建议改动 | 【组件/文件,无则写待勘察】 |
| 接口 | 【有则链 5、接口无则「无接口不展示」】 |
---
### A2. 【功能名】P0
【重复 A1 结构:说明 + 图 + 表 + 验收 + 代码入口】
---
## 五、模块 B · 【端名称】
### B1. 【功能名】P0
**完成目标**:【本小节完成后达到什么状态】
![【图说】](images/YYYYMMDD-module-02.png)
| 功能点 | 详细说明 | 优先级 |
|--------|----------|--------|
| 【点1】 | 【说明】 | P0 |
**代码入口**`【仓库相对路径】`
---
## 六、模块 C · 【可选】
【无则写:本期录屏未涉及,略。】
---
## 七、开发计划(建议排期)
### Phase 0 · 本周必做
| 编号 | 任务 | 端 | 估时 |
|------|------|-----|------|
| P0-1 | 【任务】 | 【SuperAdmin/Cunkebao/Server】 | 【0.5d】 |
### Phase 1 · 下周
| 编号 | 任务 | 端 |
|------|------|-----|
| P1-1 | 【任务】 | 【端】 |
### Phase 2 · 迭代
| 编号 | 任务 |
|------|------|
| P2-1 | 【任务】 |
---
## 八、验收清单(测试可直接勾选)
### 【端名称】
- [ ] 【验收项1】
- [ ] 【验收项2】
---
## 九、代码与文档索引(开发定位)
| 模块 | 路径 |
|------|------|
| 【模块】 | `【文件路径】` |
| 接口真源 | `开发文档/5、接口/存客宝API全量索引.md` |
---
## 十、素材清单(本目录 images
| 文件名 | 用途 |
|--------|------|
| `YYYYMMDD-xxx-01.png` | 【对应章节】 |
> **Obsidian**`![](images/xxx.png)` 与本文同级 `../../10、项目管理/images/` 目录。
---
## 十一、进度
| 维度 | 状态 |
|------|------|
| 需求拆解 | ✅ 已完成 |
| UI 素材归档 | ✅ / ⏳ |
| 开发 | ⏳ 待排期 |
| 接口文档回写 | ⏳ 开发后 |
**维护**:变更写在下方表。
| 日期 | 变更 |
|------|------|
| YYYY-MM-DD | 初版:录屏 + 截图 + 草稿合并 |
```
---
## 模块章节编号约定
| 章 | 内容 |
|----|------|
| 二 | 目标拆解(总目标与子目标) |
| 三 | 产品关系 |
| 四 | 模块 A通常超管 |
| 五 | 模块 B通常存客宝主功能 |
| 六 | 模块 C我的/客服等) |
| 七~十一 | 固定:计划、验收、索引、素材、进度 |
模块超过四个时继续「六、模块 E」**不要**打乱七~十一的固定编号。

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

@@ -0,0 +1,177 @@
---
name: 触客宝手机端前端壳
description: 触客宝 Touchkebao 手机 H5 壳层开发铁律:顶底固定、禁缩放、键盘不乱动、仅中间滚动。对齐存客宝 index.html+Layout 与 AI数智员工 mobile-terminal。触发词触客宝手机端、mobile shell、viewport、键盘、顶栏固定、底栏Tab、user-scalable、visualViewport、100dvh、乱动、壳固定。
---
# 触客宝 · 手机端前端壳 Skill
> **需求真源**[触客宝_进行中 §98 / TKB-M30](../../开发文档/1、需求/修改/触客宝_进行中_20260602.md)(§十五~§十九 见 [0530归档](../../开发文档/10、项目管理/已完成/触客宝_0530进行中全文归档_20260530/)
> **参照实现**
> - 存客宝 `Cunkebao/index.html` · `Cunkebao/src/components/Layout/`
> - AI数智员工 `AI数智员工/app/layout.tsx` · `globals.css` · `mobile-app-shell.tsx`
> **路由范围**`/mobile/**` · 组件根 `Touchkebao/src/pages/mobile/`
---
## 一、何时启用
| 场景 | 必须读本 Skill |
|:---|:---|
| 新建/改 `/mobile/` 任意页面 | ✅ |
| 改 `Layout.tsx` · TabBar · 顶栏 | ✅ |
| 改聊天输入区 · 键盘交互 · 发送/AI 不遮挡 | ✅ §十八 |
| 改顶栏 · 同步态 · 算力 | ✅ §十六 |
| 改进房预加载 · Dexie 缓存 | ✅ §十七 · **PC+手机双端同一套** |
| 改 ErrorBoundary / 登录跳转 | ✅ §十九 |
| 改 `Touchkebao/index.html` | ✅ |
| 仅改 PC `/pc/` | ❌ 不必 |
---
## 二、壳三层(固定结构)
```
html.tkb-mobile锁滚
└─ #root
└─ .shellfixed · 100dvh · overflow hidden · max-width 420px
├─ .topBar ← flex-shrink:0 · z-50 · safe-area-top
├─ .body ← flex:1 · min-height:0 · 唯一纵向滚动
└─ .tabBar ← flex-shrink:0 · z-50 · safe-area-bottom
```
**全屏子页**(聊天室):`.room` 覆盖 Tab · 结构 `topBar + record(scroll) + enter(fixed bottom)`
---
## 三、index.html 清单(强制)
```html
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover, shrink-to-fit=no" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="format-detection" content="telephone=no" />
```
**内联 `--real-vh` 脚本**(与存客宝一致):
```javascript
function syncVh() {
var vv = window.visualViewport;
var h = (vv && vv.height) || window.innerHeight || document.documentElement.clientHeight;
document.documentElement.style.setProperty("--real-vh", h * 0.01 + "px");
}
syncVh();
window.addEventListener("resize", syncVh);
window.addEventListener("orientationchange", syncVh);
if (window.visualViewport) {
window.visualViewport.addEventListener("resize", syncVh);
}
```
**触控锁滚**(存客宝同款):
```css
@media (hover: none) and (pointer: coarse) {
html, body { position: fixed; width: 100%; height: 100%; overflow: hidden; touch-action: manipulation; }
#root { width: 100%; height: 100%; overflow: hidden; }
}
```
---
## 四、CSS 变量与高度(强制)
```scss
.shell {
position: fixed;
inset: 0;
max-width: 420px;
width: 100%;
margin: 0 auto;
display: flex;
flex-direction: column;
overflow: hidden;
height: 100dvh;
height: calc(var(--real-vh, 1vh) * 100);
max-height: calc(var(--real-vh, 1vh) * 100);
}
.body {
flex: 1;
min-height: 0;
overflow-y: auto;
overflow-x: hidden;
overscroll-behavior-y: contain;
-webkit-overflow-scrolling: touch;
touch-action: pan-y;
}
```
---
## 五、键盘 / 输入(强制)
| 规则 | 说明 |
|:---|:---|
| 输入字号 **≥ 16px** | 防 iOS focus 自动 zoom |
| **不**滚 `body` | 只滚 `.body``.record` |
| `visualViewport` 只更新 `--real-vh` | 禁止改 body top 造成跳变 |
| 输入区 `touch-action: auto` | 壳层 `touch-action: manipulation` |
| 获焦不 unmount 父 Layout | 避免 Tab 栏闪烁 |
---
## 六、禁止清单
-`user-scalable=yes` 或缺少 `maximum-scale=1`
- ❌ 整页 `html/body { overflow-y: auto }`
- ❌ 只用 `100vh` 不用 `--real-vh` / `100dvh`
- ❌ 顶栏 `position: sticky` 代替 flex 壳
- ❌ 多个并列 `position:fixed` 全屏滚动区
- ❌ 键盘弹出时隐藏 TabBar 再显示(闪屏)
---
## 七、新页面开发 Checklist
开发任意 `/mobile/` 页面前 **逐项打勾**
- [ ] 内容在 `.body` 内 · 不在 shell 外再包一层可滚 `min-h-screen`
- [ ] 未新增 `100vh` 撑高 body
- [ ] 弹层 Drawer/Modal 用 `embedded` 或 Portal · 不破坏 shell overflow
- [ ] 输入框字号 ≥ 16px
- [ ] 长列表在 `.body` 内滚 · 不绑 `window` scroll
- [ ] iPhone 真机或 390 smoke捏合不缩放 · 键盘不整页乱跳 · **发送+AI 可见**(§十八)
- [ ] 顶栏:**圆形头像** · 同步时头像闪 · **「· 聊天」保留**(§十六)
- [ ] 需求变更已写入 `触客宝_进行中_20260530.md`(一项目一文件)
---
## 八、验收命令
```bash
node 开发文档/8、部署/scripts/verify_touchkebao_mobile.mjs
# 扩展后应含viewport user-scalable=no · sessionRows · 无横向溢出
```
---
## 九、与需求协调 Skill 关系
| Skill | 职责 |
|:---|:---|
| [需求协调与归档](../需求协调与归档/SKILL.md) | 需求落盘 · 一项目一 `_进行中` |
| **本文** | 手机 H5 **壳层与键盘** 编码铁律 |
| [开发需求文档整理](../开发需求文档整理/SKILL.md) | 录屏→需求 MD |
---
## 十、参照文件速查
| 项目 | 文件 |
|:---|:---|
| 存客宝 viewport | `cunkebao_v3/Cunkebao/index.html` |
| 存客宝 Layout | `Cunkebao/src/components/Layout/Layout.tsx` · `layout.module.scss` |
| AI 终端 globals | `AI数智员工/app/globals.css``.mobile-terminal` · `.mobile-app-frame` |
| AI Shell 组件 | `AI数智员工/app/components/mobile-app-shell.tsx` |
| 触客宝工作台 | `Touchkebao/src/pages/mobile/workbench/Layout.module.scss` |
| 触客宝聊天室 | `Touchkebao/src/pages/mobile/workbench/ChatRoom/index.module.scss` |

View File

@@ -0,0 +1,197 @@
---
name: 需求协调与归档
description: 存客宝四端需求维护与文档收敛一项目一进行中MD、已完成只进10、项目管理/已完成/、关单分拣、COORD、0530维护经验。触发词需求协调、需求归档、四端汇总、已完成、进行中、修改目录整理、一项目一文件、关单、需求维护、项目管理。
---
# 需求协调与归档 Skill存客宝 v3 · 0602 维护版)
> **🚫 不再写需求总览(卡若 0602 定)**:需求**按项目、按当天**直接写进 `{项目}_进行中_{YYYYMMDD}.md`,谁的子项目就写谁的文件,简单记录;**禁止**再建/维护 `YYYYMMDD_需求总览.md` 横表(旧文件留作历史索引)。
> **🚫 不再写未完成项审计(卡若 0603 定)**:禁止 `YYYYMMDD_未完成项审计*.md`**完成度表 + §待卡若验收 + §P0 开发顺序** 写在各端当日 `_进行中`。非当天未完 **迁入当天文件** 后 **删除** 旧 `_进行中``modify/` 只留当天,详文备份在 `10、项目管理/已完成/`)。
> **端真源(唯一)**`开发文档/1、需求/修改/{项目}_进行中_{YYYYMMDD}.md`**每端最多 1 个**
> **已完成总汇**`开发文档/10、项目管理/已完成/YYYYMMDD_四端已完成与全量检测总汇/`**不在根目录、不在 modify/**
> **跨端协同**:写在**发起方**项目 `_进行中`「跨项目协调」节(标 `协同 XXX`),不再单列总览。
> **术语铁律**:统一「知识库」「流量池」;**无「流量词」概念**ASR 误识,纠错库 `卡若AI/运营中枢/参考资料/卡若闽南口音_ASR纠错库.json` 已收 流量词→流量池)。
> **卡若AI 母 Skill**`/Users/karuo/Documents/个人/卡若AI/02_卡人/水泉_规划拆解/需求协调/SKILL.md`
> **单篇整理**[开发需求文档整理/SKILL.md](../开发需求文档整理/SKILL.md)
---
## 一、何时启用
| 场景 | 动作 |
|:---|:---|
| 新 P0/P1 需求(**当日/本轮** | **只追加** `修改/{端}_进行中_{YYYYMMDD}.md` 新 § 节 · **禁止**根目录另开 `{端}_{主题}_{date}.md` |
| 需求写完仅文档 | 在 `_进行中` 内写 **固定规则+验收** · 状态标 ⬜ |
| **官网边开发边勾** | 子项完成即改 `官网_进行中` **⬜→🟡→✅**REQ-WEB-60/61**AI 客服**按 [14 专文 §十一](../../开发文档/1、需求/官网/05-AI与硬件/14-官网AI客服获客场景_20260531.md) 阶段打勾 |
| **存客宝 AI 客服** | 同步 `存客宝_进行中` **REQ-CKB-66** · Server 先于官网 |
| 验收通过 | 迁入 `10、项目管理/已完成/{项目}_{主题}_{date}/` · 更新 **已完成总汇** §索引 |
| 端 100% 关单 | **删除** 根目录 `{端}_进行中` · 总汇保留链接 |
| 日终 / 分拣 | 各端 `_进行中` 内更新状态 · 已完成项 **移出** 根目录(**不维护总览** |
| 跨端依赖 | COORD 写入 **各端 `_进行中`**「跨项目协调」小节 |
---
## 二、目录纪律2026-06-02 · 已完成迁入项目管理)
```
开发文档/1、需求/修改/
├── README.md
├── 存客宝_进行中_YYYYMMDD.md ← 需求只写各端进行中(不写总览)
├── 触客宝_进行中_YYYYMMDD.md
├── 官网_进行中_YYYYMMDD.md
└── AI数智员工_进行中_YYYYMMDD.md (有未完才建)
# YYYYMMDD_需求总览.md ← 已停用 · 仅历史索引,勿再维护
开发文档/10、项目管理/
├── README.md
├── images/ ← 需求截图(禁止 modify/images
├── 已完成/ ← 关单批次唯一落点
│ ├── README.md
│ └── {项目}_{功能主题}_{YYYYMMDD}/
├── 开发进度_*.md
└── scripts/
```
### 禁止(本轮维护教训)
| 禁止 | 正确做法 |
|:---|:---|
| `modify/已完成/` · `modify/images/` | `10、项目管理/已完成/` · `10、项目管理/images/` |
| 写「需求总览/横表」 | **不写总览**;需求按项目当天写进 `{项目}_进行中_{YYYYMMDD}.md` |
| 文档里写「流量词」 | 统一「**流量池**」ASR 误识,无流量词概念) |
| 根目录 `四端已完成*.md` | 只放 `10、项目管理/已完成/…/` |
| 新建 `10、使用手册/` | 只写 `9、手册/使用手册/…` |
| 同项目两个 MD`_进行中` + 专文) | P0 全文 **并入** `_进行中` 新章节 · 删/归档专文 |
| 根目录 `SuperAdmin_{主题}_{date}.md` | 写入 **`存客宝_进行中_{date}.md` §** |
| 文件名 初刻宝/初客宝/触刻版 | 统一 **触客宝** |
| COORD 只写横表 | **必须**写入各端 `_进行中` |
---
## 三、0530 维护期经验(固定写法)
### 3.1 需求文档结构P0 块)
每个 P0 在 `_进行中` 内必须含:
1. **问题表**(卡若原话 / 截图路径)
2. **根因**(代码文件 · 现状 vs 期望)
3. **固定规则**(归一化、合并键、禁止项 · **不可写抽象**
4. **接口清单**(不变 URL
5. **代码锚点**(待建/已有路径)
6. **验收表**(可数字 · V1Vn
### 3.2 只写文档不开发
- 状态标 **「P0 · 仅文档 · 待开发」**
- 同步 `开发文档/5、接口/开发进度_接口文档.md` 顶部一节
- **不**为专文单独占根目录文件名
### 3.3 已完成 vs 进行中边界
| 状态 | 放哪 |
|:---|:---|
| 代码 ✅ · 待目视 🟡 | 进行中留一行 · 细节进总汇或 `10、项目管理/已完成/` 批次 |
| 代码 ✅ · 验收 ✅ | 移入 `10、项目管理/已完成/` · 从 `_进行中` **删**该行 |
| 运营 P2签字/Key 轮换) | 写横表 · **不**占 P0 开发 slot |
| 全端 100% | 无 `_进行中` · 链总汇 §二 |
### 3.4 截图与 images
- 进行中:`10、项目管理/images/{项目}_{现象}_{YYYYMMDD}.png`
- 关单迁 `10、项目管理/已完成/{批次}/images/`**改相对路径**
---
## 四、COORD 分配(写入各端 `_进行中`
| COORD | 简述 | 写入文档 |
|:---|:---|:---|
| 001 | SuperAdmin 开放 API | 存客宝、SuperAdmin、触客宝、AI数智员工 |
| 006 | 设备/微信项目同源 | **存客宝、触客宝** |
(其余见历史表 · 各端「跨项目协调」小节)
---
## 五、关单流程(逐步)
```
1. 开发/文档完成 → 更新 {端}_进行中 状态 ✅
2. 全文批次 → 10、项目管理/已完成/{项目}_{主题}_{date}/同名.md
3. 更新 已完成/…/四端已完成总汇.md §索引
4. 从 _进行中 删除已完成行;端无未完 → 删除 _进行中 文件
5. 更新 YYYYMMDD_需求总览.md
6. 更新 5、接口/开发进度_接口文档.md
7. 更新 10、项目管理/已完成/README.md 表格一行
8. 禁止 git push除非卡若本轮明确说提交
```
### 脚本(可选)
```bash
python3 开发文档/1、需求/scripts/flatten_requirements.py
python3 开发文档/1、需求/scripts/reorganize_requirement_docs.py
```
---
## 六、开发前检查
1. 读待开发横表 + **本端唯一** `_进行中`
2.**跨项目协调**
3. 对话列出:已读文档 ≤5 条
4. 确认 **没有** 第二份同端 MD
5. 关单目标路径为 **`10、项目管理/已完成/`**
---
## 七、质量门禁
- [ ] 根目录无 `*已完成*` MD总汇只在 `10、项目管理/已完成/`
- [ ] 每端 **≤1** 个 `_进行中``modify/`
- [ ] **禁止**`10、项目管理/已完成/` 新建批次(仅跳转 README
- [ ] P0 块含:问题 / 根因 / 固定规则 / 验收
- [ ] 已完成批次在 `10、项目管理/已完成/{项目}_{主题}_{date}/` 且图片不断链
- [ ] `10、项目管理/README.md``已完成/README.md` 已更新
---
## 八、与卡若AI 分工
| Skill | 职责 |
|:---|:---|
| **本文** | 一项目一文件 · **已完成进 10、项目管理** · 关单分拣 |
| 开发需求文档整理 | 录屏→全量 MD · 落盘纪律以本文为准 |
---
## 九、当日需求落盘Agent 必背)
```
卡若提新需求
→ 打开 modify/{端}_进行中_{YYYYMMDD}.md 新 §
→ 更新 待开发清单 一行
→ 截图 → 10、项目管理/images/
→ 禁止 新建 modify/{端}_{主题}_{YYYYMMDD}.md
关单后
→ 迁入 10、项目管理/已完成/{项目}_{主题}_{date}/
```
---
## 十、经验沉淀
| 日期 | 教训 |
|:---|:---|
| 2026-06-02 | 十大目录收口:已完成+配图→`10、项目管理` · 三表→`需求总览` · `10、使用手册``9、手册/使用手册` |
| 2026-06-02 | CKB-90流量分发多子账号轮询 + 客服选择 UI 与好友分配一致 |
---
## 十一、延伸阅读
- [修改/README.md](../../开发文档/1、需求/修改/README.md)
- [10、项目管理/README.md](../../开发文档/10、项目管理/README.md)
- [已完成/README.md](../../开发文档/10、项目管理/已完成/README.md)
- [四端对接铁律](../../开发文档/2、架构/四端对接铁律_只HTTP不串仓.md)

20
.gitignore vendored
View File

@@ -1,12 +1,20 @@
Store_vue/unpackage/
*.js
Store_vue/node_modules/
Server/.specstory/
Cunkebao/.next/
Cunkebao/.specstory/
.idea/
Cunkebao/.next/
Store_vue/node_modules/
*.zip
Cunkebao/.specstory/
*.cursorindexingignore
Server/.specstory/
Server/thinkphp/
Store_vue/.specstory/
Store_vue/unpackage/
Store_vue/.vscode/
SuperAdmin/.specstory/
Cunkebao/dist
Touchkebao/.specstory/
Serverruntime/
Moncter/提示词/
*.log
*.code-workspace
项目整体分析报告.md
Server/docs/traffic_pool_design.md

13
.obsidian/app.json vendored Normal file
View File

@@ -0,0 +1,13 @@
{
"pdfExportSettings": {
"pageSize": "Letter",
"landscape": false,
"margin": "0",
"downscalePercent": 100
},
"promptDelete": false,
"attachmentFolderPath": "./images",
"useMarkdownLinks": true,
"newLinkFormat": "relative",
"alwaysUpdateLinks": true
}

5
.obsidian/appearance.json vendored Normal file
View File

@@ -0,0 +1,5 @@
{
"enabledCssSnippets": [
"cunkebao-devdoc"
]
}

33
.obsidian/core-plugins.json vendored Normal file
View File

@@ -0,0 +1,33 @@
{
"file-explorer": true,
"global-search": true,
"switcher": true,
"graph": true,
"backlink": true,
"canvas": true,
"outgoing-link": true,
"tag-pane": true,
"footnotes": false,
"properties": true,
"page-preview": true,
"daily-notes": true,
"templates": true,
"note-composer": true,
"command-palette": true,
"slash-command": false,
"editor-status": true,
"bookmarks": true,
"markdown-importer": false,
"zk-prefixer": false,
"random-note": false,
"outline": true,
"word-count": true,
"slides": false,
"audio-recorder": false,
"workspaces": false,
"file-recovery": true,
"publish": false,
"sync": true,
"bases": true,
"webviewer": false
}

93
.obsidian/graph.json vendored Normal file
View File

@@ -0,0 +1,93 @@
{
"collapse-filter": false,
"search": "path:开发文档",
"showTags": true,
"showAttachments": false,
"hideUnresolved": false,
"showOrphans": false,
"collapse-color-groups": false,
"colorGroups": [
{
"query": "path:开发文档/2、架构",
"color": {
"a": 1,
"rgb": 14010688
}
},
{
"query": "path:开发文档/1、需求",
"color": {
"a": 1,
"rgb": 6178001
}
},
{
"query": "path:开发文档/3、原型",
"color": {
"a": 1,
"rgb": 6178001
}
},
{
"query": "path:开发文档/4、前端",
"color": {
"a": 1,
"rgb": 162529
}
},
{
"query": "path:开发文档/5、接口",
"color": {
"a": 1,
"rgb": 162529
}
},
{
"query": "path:开发文档/6、后端",
"color": {
"a": 1,
"rgb": 162529
}
},
{
"query": "path:开发文档/7、数据库",
"color": {
"a": 1,
"rgb": 5606192
}
},
{
"query": "path:开发文档/8、部署",
"color": {
"a": 1,
"rgb": 5606192
}
},
{
"query": "path:开发文档/9、手册",
"color": {
"a": 1,
"rgb": 14010688
}
},
{
"query": "path:开发文档/10、使用手册",
"color": {
"a": 1,
"rgb": 12976168
}
}
],
"collapse-display": true,
"showArrow": true,
"textFadeMultiplier": 0,
"nodeSizeMultiplier": 1,
"lineSizeMultiplier": 1,
"collapse-forces": true,
"centerStrength": 0.5,
"repelStrength": 10,
"linkStrength": 1,
"linkDistance": 200,
"scale": 0.17544920373570672,
"close": true
}

124
.obsidian/snippets/cunkebao-devdoc.css vendored Normal file
View File

@@ -0,0 +1,124 @@
/* 存客宝 v3 · 开发文档 Obsidian 目录配色
* 启用Settings → Appearance → CSS snippets → cunkebao-devdoc
* 依赖Obsidian 文件资源管理器 nav-folder-title data-path 属性
* 规范:与工作手机 workphone-devdoc.css 四类分类色对齐
*/
/* ── 一、需求与架构 ── */
.nav-folder-title[data-path="开发文档/1、需求"] > .nav-folder-title-content {
color: #5E35B1 !important;
font-weight: 600;
}
.nav-folder-title[data-path="开发文档/2、架构"] > .nav-folder-title-content {
color: #1565C0 !important;
font-weight: 600;
}
.nav-folder-title[data-path="开发文档/3、原型"] > .nav-folder-title-content {
color: #5E35B1 !important;
font-weight: 600;
}
/* ── 二、开发与接口 ── */
.nav-folder-title[data-path="开发文档/4、前端"] > .nav-folder-title-content {
color: #0277BD !important;
font-weight: 600;
}
.nav-folder-title[data-path="开发文档/4、前端/UI"] > .nav-folder-title-content {
color: #0288D1 !important;
}
.nav-folder-title[data-path="开发文档/5、接口"] > .nav-folder-title-content {
color: #0277BD !important;
font-weight: 600;
}
.nav-folder-title[data-path^="开发文档/5、接口/0"] > .nav-folder-title-content {
color: #0288D1 !important;
}
.nav-folder-title[data-path="开发文档/5、接口/images"] > .nav-folder-title-content {
color: #78909C !important;
}
.nav-folder-title[data-path="开发文档/5、接口/02-存客宝与工作手机对接"] > .nav-folder-title-content {
color: #FFB300 !important;
font-weight: 600;
}
.nav-folder-title[data-path^="开发文档/5、接口/02-存客宝与工作手机对接/04-CodeGraph"] > .nav-folder-title-content {
color: #78909C !important;
}
.nav-folder-title[data-path="开发文档/6、后端"] > .nav-folder-title-content {
color: #0277BD !important;
font-weight: 600;
}
/* ── 三、部署与数据 ── */
.nav-folder-title[data-path="开发文档/7、数据库"] > .nav-folder-title-content {
color: #558B2F !important;
font-weight: 600;
}
.nav-folder-title[data-path="开发文档/8、部署"] > .nav-folder-title-content {
color: #558B2F !important;
font-weight: 600;
}
.nav-folder-title[data-path="开发文档/8、部署/scripts"] > .nav-folder-title-content {
color: #689F38 !important;
}
.nav-folder-title[data-path="开发文档/8、部署/01-本地环境"] > .nav-folder-title-content {
color: #689F38 !important;
}
.nav-folder-title[data-path="开发文档/8、部署/02-数据库同步"] > .nav-folder-title-content {
color: #558B2F !important;
}
.nav-folder-title[data-path="开发文档/8、部署/03-运维与CI"] > .nav-folder-title-content {
color: #558B2F !important;
}
.nav-folder-title[data-path="开发文档/8、部署/04-部署复盘"] > .nav-folder-title-content {
color: #689F38 !important;
}
.nav-folder-title[data-path="开发文档/8、部署/05-测试验收"] > .nav-folder-title-content {
color: #F9A825 !important;
font-weight: 600;
}
.nav-folder-title[data-path^="开发文档/8、部署/05-测试验收/"] > .nav-folder-title-content {
color: #FFB300 !important;
}
/* ── 四、手册与使用 ── */
.nav-folder-title[data-path="开发文档/9、手册"] > .nav-folder-title-content {
color: #1565C0 !important;
font-weight: 600;
}
.nav-folder-title[data-path="开发文档/9、手册/提示词"] > .nav-folder-title-content {
color: #0288D1 !important;
}
.nav-folder-title[data-path="开发文档/10、使用手册"] > .nav-folder-title-content {
color: #C62828 !important;
font-weight: 600;
}
.nav-folder-title[data-path="开发文档/10、使用手册/存客宝"] > .nav-folder-title-content {
color: #E65100 !important;
font-weight: 600;
}
.nav-folder-title[data-path="开发文档/10、使用手册/存客宝/工作台"] > .nav-folder-title-content {
color: #FF6F00 !important;
}
.nav-folder-title[data-path="开发文档/10、使用手册/截图"] > .nav-folder-title-content {
color: #78909C !important;
}
/* ── 辅助目录 ── */
.nav-folder-title[data-path="开发文档/工作手机对接"] > .nav-folder-title-content {
color: #90A4AE !important;
}
.nav-folder-title[data-path="开发文档/scripts"] > .nav-folder-title-content {
color: #546E7A !important;
}
/* 文档说明头图 */
.markdown-preview-view img[alt="文档说明"],
.markdown-source-view img[alt="文档说明"] {
display: block;
width: 100%;
max-width: 920px;
margin: 0.5em 0 1.2em;
border-radius: 10px;
box-shadow: 0 2px 12px rgba(15, 23, 42, 0.08);
border: 1px solid rgba(148, 163, 184, 0.35);
}

235
.obsidian/workspace.json vendored Normal file
View File

@@ -0,0 +1,235 @@
{
"main": {
"id": "413f86c90d0909cc",
"type": "split",
"children": [
{
"id": "984914435f6a9181",
"type": "tabs",
"children": [
{
"id": "4301052b31068085",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "开发文档/1、需求/修改/存客宝_进行中_20260603.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "存客宝_进行中_20260603"
}
}
]
}
],
"direction": "vertical"
},
"left": {
"id": "28b5f5be79ea5491",
"type": "split",
"children": [
{
"id": "03d49e20527f98d9",
"type": "tabs",
"children": [
{
"id": "b4bd2ff5d3f2ec66",
"type": "leaf",
"state": {
"type": "file-explorer",
"state": {
"sortOrder": "alphabetical",
"autoReveal": false
},
"icon": "lucide-folder-closed",
"title": "文件列表"
}
},
{
"id": "a8ab05904e453c81",
"type": "leaf",
"state": {
"type": "search",
"state": {
"query": "tag:#存客宝",
"matchingCase": false,
"explainSearch": false,
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical"
},
"icon": "lucide-search",
"title": "搜索"
}
},
{
"id": "1b4c70b94399d9a5",
"type": "leaf",
"state": {
"type": "bookmarks",
"state": {},
"icon": "lucide-bookmark",
"title": "书签"
}
}
]
}
],
"direction": "horizontal",
"width": 276.5004348754883
},
"right": {
"id": "213cf3c58fffb77e",
"type": "split",
"children": [
{
"id": "b9b3f94b382e2801",
"type": "tabs",
"children": [
{
"id": "7fb9573cc08dd33f",
"type": "leaf",
"state": {
"type": "backlink",
"state": {
"file": "开发文档/1、需求/修改/20260530_四端已完成与全量检测总汇.md",
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical",
"showSearch": false,
"searchQuery": "",
"backlinkCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-coming-in",
"title": "20260530_四端已完成与全量检测总汇 的反向链接列表"
}
},
{
"id": "6e4f013221e7c63d",
"type": "leaf",
"state": {
"type": "outgoing-link",
"state": {
"file": "开发文档/项目文档生成器_核心提示词.md",
"linksCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-going-out",
"title": "项目文档生成器_核心提示词 的出链列表"
}
},
{
"id": "7b4a28550b01a9ca",
"type": "leaf",
"state": {
"type": "tag",
"state": {
"sortOrder": "frequency",
"useHierarchy": true,
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-tags",
"title": "标签"
}
},
{
"id": "b9587677fcf19822",
"type": "leaf",
"state": {
"type": "all-properties",
"state": {
"sortOrder": "frequency",
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-archive",
"title": "添加笔记属性"
}
},
{
"id": "9a63f6e4237e033b",
"type": "leaf",
"state": {
"type": "outline",
"state": {
"file": "开发文档/项目文档生成器_核心提示词.md",
"followCursor": false,
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-list",
"title": "项目文档生成器_核心提示词 的大纲"
}
}
]
}
],
"direction": "horizontal",
"width": 300,
"collapsed": true
},
"left-ribbon": {
"hiddenItems": {
"switcher:打开快速切换": false,
"graph:查看关系图谱": false,
"canvas:新建白板": false,
"daily-notes:打开/创建今天的日记": false,
"templates:插入模板": false,
"command-palette:打开命令面板": false,
"bases:新建数据库": false
}
},
"active": "4301052b31068085",
"lastOpenFiles": [
"Touchkebao/dist/xiaobao-ai.png",
"Touchkebao/dist/websdk.js",
"Touchkebao/dist/manifest.json",
"Touchkebao/dist/logo.png",
"Touchkebao/dist/index.html",
"Touchkebao/dist/assets/vendor-fZy-8e4I.js",
"Touchkebao/dist/assets/utils-Bc0vVQOI.js",
"Touchkebao/dist/assets/ui-DsBy32W5.js",
"Touchkebao/dist/assets/ui-DmZQDU-f.css",
"Touchkebao/dist/assets/other/wither.png",
"Touchkebao/dist/assets/other/sun.png",
"Touchkebao/dist/assets/other/rose.png",
"Touchkebao/dist/assets/other/poop.png",
"Touchkebao/dist/assets/other/moon.png",
"Touchkebao/dist/assets/other/lips.png",
"Touchkebao/dist/assets/other/knife.png",
"Touchkebao/dist/assets/other/heart.png",
"Touchkebao/dist/assets/other/coffee.png",
"Touchkebao/dist/assets/other",
"Touchkebao/dist/assets/index-DfxITDxP.css",
"Touchkebao/dist/assets/index-DHDH-NpT.js",
"开发文档/8、部署/开发进度_五端全量验收_20260603.md",
"开发文档/1、需求/修改/官网_进行中_20260603.md",
"开发文档/1、需求/修改/未完成项与跨仓验收汇总.md",
"开发文档/10、项目管理/已完成/触客宝_0603日终复盘_20260603.md",
"Server/public/uploads/knowledge/914/ingest/20260603_203119_10_转化话术C_3.md",
"Server/public/uploads/knowledge/914/ingest/20260603_203119_10_引流玩法B_2.md",
"Server/public/uploads/knowledge/914/ingest/20260603_203119_10_测试套餐A_1.md",
"开发文档/6、后端/核心算法清单.md",
"开发文档/6、后端/核心算法图解手册.md",
"开发文档/10、项目管理/账号密码与登录环境一览.md",
"开发文档/10、项目管理/开发进度.md",
"Server/public/uploads/knowledge/914/ingest/20260603_184809_10_转化话术C_3.md",
"Server/public/uploads/knowledge/914/ingest/20260603_184809_10_引流玩法B_2.md",
"Server/public/uploads/knowledge/914/ingest/20260603_184809_10_测试套餐A_1.md",
"Server/public/uploads/knowledge/914/ingest/20260603_184041_10_转化话术C_3.md",
"Server/public/uploads/knowledge/914/ingest/20260603_184041_10_引流玩法B_2.md",
"Server/public/uploads/knowledge/914/ingest/20260603_184041_10_测试套餐A_1.md",
"开发文档/1、需求/修改/AI数智员工_进行中_20260603.md",
"Server/public/uploads/knowledge/914/ingest/20260603_183530_10_转化话术C_3.md",
"Server/public/uploads/knowledge/914/ingest/20260603_183530_10_引流玩法B_2.md",
"Server/public/uploads/knowledge/914/ingest/20260603_183530_10_测试套餐A_1.md",
"开发文档/1、需求/修改/存客宝_进行中_20260603.md",
"开发文档/1、需求/修改/触客宝_进行中_20260603.md",
"Server/public/uploads/knowledge/914/ingest/20260603_172928_13_转化话术C_3.md",
"Server/public/uploads/knowledge/914/ingest/20260603_172928_13_测试套餐A_1.md"
]
}

9
Cunkebao/.dockerignore Normal file
View File

@@ -0,0 +1,9 @@
node_modules
dist
.git
.env
.env.*
*.log
.DS_Store
coverage
.vite

12
Cunkebao/.env.development Normal file
View File

@@ -0,0 +1,12 @@
# 开发环境直接使用线上 API腾讯云数据库
# 如需使用本地后端,改为 VITE_API_BASE_URL=/api 并确保 vite.config.ts 代理配置正确
VITE_API_BASE_URL=https://ckbapi.quwanzhi.com
VITE_API_BASE_URL2=https://kf.quwanzhi.com:9991
VITE_API_WS_URL=wss://kf.quwanzhi.com:9993
VITE_APP_TITLE=存客宝
# 开发环境自动登录配置(仅开发环境使用,生产环境禁止使用)
# WARNING: 此配置仅用于开发调试,正式环境部署时必须删除或禁用
VITE_DEV_AUTO_LOGIN=true
VITE_DEV_ACCOUNT=admin
VITE_DEV_PASSWORD=k123456

1
Cunkebao/.env.local Normal file
View File

@@ -0,0 +1 @@
NEXT_PUBLIC_API_BASE_URL= http://yishi.com

6
Cunkebao/.env.production Normal file
View File

@@ -0,0 +1,6 @@
# 基础环境变量示例
VITE_API_BASE_URL=https://ckbapi.quwanzhi.com
VITE_API_BASE_URL2=https://kf.quwanzhi.com:9991
VITE_API_WS_URL=wss://kf.quwanzhi.com:9993
# VITE_API_BASE_URL=http://www.yishi.com
VITE_APP_TITLE=存客宝

64
Cunkebao/.eslintrc.js Normal file
View File

@@ -0,0 +1,64 @@
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
node: true,
},
extends: [
"eslint:recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended", // 这个配置会自动处理大部分冲突
],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 12,
sourceType: "module",
},
plugins: ["react", "react-hooks", "@typescript-eslint", "prettier"],
rules: {
"prettier/prettier": "error",
"react/react-in-jsx-scope": "off",
"@typescript-eslint/no-unused-vars": "warn",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unnecessary-type-constraint": "warn",
"react/prop-types": "off",
"linebreak-style": "off",
"eol-last": "off",
"no-empty": "warn",
"prefer-const": "warn",
// 确保与 Prettier 完全兼容
"comma-dangle": "off",
"comma-spacing": "off",
"comma-style": "off",
"object-curly-spacing": "off",
"array-bracket-spacing": "off",
indent: "off",
quotes: "off",
semi: "off",
"arrow-parens": "off",
"no-multiple-empty-lines": "off",
"max-len": "off",
"space-before-function-paren": "off",
"space-before-blocks": "off",
"keyword-spacing": "off",
"space-infix-ops": "off",
"space-in-parens": "off",
"space-in-brackets": "off",
"object-property-newline": "off",
"array-element-newline": "off",
"function-paren-newline": "off",
"object-curly-newline": "off",
"array-bracket-newline": "off",
},
settings: {
react: {
version: "detect",
},
},
};

27
Cunkebao/.gitattributes vendored Normal file
View File

@@ -0,0 +1,27 @@
# 设置默认行为如果core.autocrlf没有设置Git会自动处理行尾符
* text=auto
# 明确指定文本文件使用LF
*.js text eol=lf
*.jsx text eol=lf
*.ts text eol=lf
*.tsx text eol=lf
*.json text eol=lf
*.css text eol=lf
*.scss text eol=lf
*.html text eol=lf
*.md text eol=lf
*.yml text eol=lf
*.yaml text eol=lf
# 二进制文件
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.svg binary
*.woff binary
*.woff2 binary
*.ttf binary
*.eot binary

32
Cunkebao/.gitignore vendored
View File

@@ -1,23 +1,11 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
node_modules/
dist/
build/
yarn.lock
.env
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
dist/*
.cursorindexingignore
*.zip
.idea/
.next/

13
Cunkebao/.prettierrc Normal file
View File

@@ -0,0 +1,13 @@
{
"semi": true,
"trailingComma": "all",
"singleQuote": false,
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"endOfLine": "lf",
"bracketSpacing": true,
"arrowParens": "avoid",
"jsxSingleQuote": false,
"quoteProps": "as-needed"
}

11
Cunkebao/.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,11 @@
{
"recommendations": [
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"bradlc.vscode-tailwindcss",
"ms-vscode.vscode-typescript-next",
"formulahendry.auto-rename-tag",
"christian-kohler.path-intellisense",
"ms-vscode.vscode-json"
]
}

45
Cunkebao/.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,45 @@
{
"files.eol": "\n",
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true,
"files.trimTrailingWhitespace": true,
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.organizeImports": "never"
},
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
],
"eslint.format.enable": false,
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[scss]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"typescript.preferences.importModuleSpecifier": "relative",
"typescript.suggest.autoImports": true,
"editor.tabSize": 2,
"editor.insertSpaces": true,
"editor.detectIndentation": false
}

23
Cunkebao/Dockerfile Normal file
View File

@@ -0,0 +1,23 @@
# 存客宝前端 - React + Vite
FROM node:20-alpine AS builder
WORKDIR /app
RUN npm install -g pnpm
ARG VITE_API_BASE_URL=
ENV VITE_API_BASE_URL=$VITE_API_BASE_URL
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
COPY . .
RUN pnpm build
FROM nginx:alpine
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

View File

@@ -1,266 +0,0 @@
# 内客宝 - 智能获客管理平台
## 📋 项目简介
内客宝是一个专业的微信获客和流量管理平台,基于 React 技术栈构建。平台提供智能化的客户获取、管理和运营解决方案,集成了多种自动化工具,帮助企业高效管理微信营销活动。
## 🚀 技术栈详解
### 核心框架
- **React 18.2.0** - 现代化的用户界面库
- **TypeScript 4.9.5** - 类型安全的 JavaScript 超集
- **Create React App (CRA) 5.0.1** - React 应用脚手架
- **React Router DOM 6.20.0** - 客户端路由管理
### 构建工具
- **CRACO 7.1.0** - Create React App Configuration Override
- 支持自定义 webpack 配置
- 路径别名配置
- 构建优化
### UI 组件库
- **Radix UI** - 无样式的可访问组件库
- 完整的组件生态系统30+ 组件)
- 优秀的无障碍访问支持
- 高度可定制
- **Tailwind CSS 3.4.17** - 实用优先的 CSS 框架
- 响应式设计支持
- 自定义主题配置
- 原子化 CSS 类
### 图标和样式
- **Lucide React 0.454.0** - 精美的图标库
- **Tailwind CSS Animate** - CSS 动画库
- **Class Variance Authority** - 组件变体管理
- **Tailwind Merge** - Tailwind 类名合并工具
### 状态管理和表单
- **React Hook Form 7.54.1** - 高性能表单库
- **Zod 3.24.1** - TypeScript 优先的模式验证
- **@hookform/resolvers 3.9.1** - 表单验证解析器
### 数据可视化
- **Recharts** - 基于 React 的图表库
- **Chart.js 4.5.0** - 灵活的图表库
- **@ant-design/plots** - Ant Design 图表组件
### HTTP 请求和数据处理
- **Axios 1.6.0** - HTTP 客户端
- **Crypto-js 4.2.0** - 加密库
- **Date-fns** - 日期处理库
- **XLSX 0.18.5** - Excel 文件处理
### 通知和反馈
- **React Hot Toast 2.5.2** - 轻量级通知库
- **Sonner 1.7.4** - 现代化 Toast 组件
### 高级组件
- **@tanstack/react-table** - 功能强大的表格组件
- **Embla Carousel React 8.5.1** - 轮播组件
- **React Resizable Panels 2.1.7** - 可调整大小的面板
- **Vaul 0.9.6** - 抽屉组件
- **Input OTP 1.4.1** - OTP 输入组件
- **React Day Picker** - 日期选择器
### 开发工具
- **PostCSS 8** - CSS 后处理器
- **Autoprefixer 10.4.20** - CSS 前缀自动添加
- **ESLint** - 代码质量检查
- **Jest** - 单元测试框架
- **Testing Library** - React 测试工具
## 📁 项目结构
```
nkebao/
├── public/ # 静态资源
├── src/ # 源代码
│ ├── api/ # API 接口封装
│ ├── components/ # 全局组件
│ │ ├── ui/ # UI 基础组件
│ │ └── icons/ # 图标组件
│ ├── config/ # 配置文件
│ ├── contexts/ # React Context
│ ├── hooks/ # 自定义 Hooks
│ ├── pages/ # 页面组件
│ │ ├── workspace/ # 工作台模块
│ │ │ ├── auto-like/ # 自动点赞
│ │ │ ├── auto-group/ # 自动建群
│ │ │ ├── group-push/ # 群消息推送
│ │ │ ├── moments-sync/ # 朋友圈同步
│ │ │ ├── ai-assistant/ # AI 对话助手
│ │ │ └── traffic-distribution/ # 流量分发
│ │ ├── devices/ # 设备管理
│ │ ├── scenarios/ # 场景管理
│ │ ├── content/ # 内容管理
│ │ └── ...
│ ├── types/ # TypeScript 类型定义
│ ├── utils/ # 工具函数
│ ├── App.tsx # 应用根组件
│ └── index.tsx # 应用入口
├── craco.config.js # CRACO 配置
├── tailwind.config.js # Tailwind CSS 配置
├── tsconfig.json # TypeScript 配置
└── package.json # 项目依赖
```
## 🎯 核心功能模块
### 工作台 (Workspace)
- **自动点赞** - 智能点赞管理和配置
- **自动建群** - 群组自动化创建和管理
- **群消息推送** - 群组消息批量发送
- **朋友圈同步** - 内容同步和发布
- **AI 对话助手** - 智能客服和对话管理
- **流量分发** - 流量分配和策略管理
### 设备管理 (Devices)
- 设备状态监控和配置
- 设备性能分析
- 设备权限管理
### 场景管理 (Scenarios)
- 营销场景配置
- 自动化流程设计
- 场景效果分析
### 内容管理 (Content)
- 内容创建与编辑
- 内容模板管理
- 内容发布调度
### 其他模块
- 用户管理 (Users)
- 订单管理 (Orders)
- 流量池管理 (Traffic Pool)
- 联系人导入 (Contact Import)
## 🛠️ 开发指南
### 环境要求
- **Node.js** 16+
- **npm** 或 **yarn**
### 安装依赖
```bash
# 使用 npm
npm install
# 使用 yarn
yarn install
```
### 开发环境启动
```bash
# 使用 npm
npm start
# 使用 yarn
yarn start
```
### 构建生产版本
```bash
# 使用 npm
npm run build
# 使用 yarn
yarn build
```
### 运行测试
```bash
# 使用 npm
npm test
# 使用 yarn
yarn test
```
## 🔧 配置说明
### 路径别名配置
项目使用 CRACO 配置了路径别名:
```javascript
'@': path.resolve(__dirname, 'src'),
'@/components': path.resolve(__dirname, 'src/components'),
'@/api': path.resolve(__dirname, 'src/api'),
'@/types': path.resolve(__dirname, 'src/types'),
'@/hooks': path.resolve(__dirname, 'src/hooks'),
'@/utils': path.resolve(__dirname, 'src/utils'),
'@/styles': path.resolve(__dirname, 'src/styles'),
'@/pages': path.resolve(__dirname, 'src/pages'),
```
### Tailwind CSS 配置
- 自定义字体大小和间距
- 响应式断点配置
- 主题颜色系统
### TypeScript 配置
- 严格模式启用
- 路径映射配置
- JSX 支持
## 📱 响应式设计
项目采用移动优先的响应式设计:
- 支持桌面端、平板端、移动端
- 自适应布局组件
- 触摸友好的交互设计
## 🎨 UI 设计系统
### 设计原则
- 简洁现代的设计风格
- 一致的用户体验
- 无障碍访问支持
### 组件库特点
- 基于 Radix UI 的高质量组件
- 完整的表单组件系统
- 数据展示组件
- 导航和布局组件
## 🔒 安全特性
- 身份验证和授权
- API 请求拦截
- 数据验证和清理
- 加密功能支持
## 📊 性能优化
- 代码分割和懒加载
- 组件优化
- 缓存策略
- 包大小优化
## 🧪 测试策略
- 单元测试 (Jest + Testing Library)
- 组件测试
- 集成测试支持
## 🤝 贡献指南
1. Fork 项目
2. 创建功能分支 (`git checkout -b feature/AmazingFeature`)
3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
4. 推送到分支 (`git push origin feature/AmazingFeature`)
5. 创建 Pull Request
## 📄 许可证
本项目采用 MIT 许可证。
## 📞 联系方式
如有问题或建议,请联系开发团队。
---
**项目名称**: 内客宝 (nkebao2)
**版本**: 0.1.0
**技术栈**: React + TypeScript + CRA + Tailwind CSS
**最后更新**: 2024年12月

View File

@@ -1,16 +0,0 @@
const path = require('path');
module.exports = {
webpack: {
alias: {
'@': path.resolve(__dirname, 'src'),
'@/components': path.resolve(__dirname, 'src/components'),
'@/api': path.resolve(__dirname, 'src/api'),
'@/types': path.resolve(__dirname, 'src/types'),
'@/hooks': path.resolve(__dirname, 'src/hooks'),
'@/utils': path.resolve(__dirname, 'src/utils'),
'@/styles': path.resolve(__dirname, 'src/styles'),
'@/pages': path.resolve(__dirname, 'src/pages'),
},
},
};

95
Cunkebao/devlop.py Normal file
View File

@@ -0,0 +1,95 @@
import os
import zipfile
import paramiko
# 配置
local_dir = './dist' # 本地要打包的目录
zip_name = 'dist.zip'
# 上传到服务器的 zip 路径
remote_path = '/www/wwwroot/auto-devlop/ckb-operation/dist.zip' # 服务器上的临时zip路径
server_ip = '42.194.245.239'
server_port = 6523
server_user = 'yongpxu'
server_pwd = 'Aa123456789.'
# 服务器 dist 相关目录
remote_base_dir = '/www/wwwroot/auto-devlop/ckb-operation'
dist_dir = f'{remote_base_dir}/dist'
dist1_dir = f'{remote_base_dir}/dist1'
dist2_dir = f'{remote_base_dir}/dist2'
# 美化输出用的函数
from datetime import datetime
def info(msg):
print(f"\033[36m[INFO {datetime.now().strftime('%H:%M:%S')}] {msg}\033[0m")
def success(msg):
print(f"\033[32m[SUCCESS] {msg}\033[0m")
def error(msg):
print(f"\033[31m[ERROR] {msg}\033[0m")
def step(msg):
print(f"\n\033[35m==== {msg} ====" + "\033[0m")
# 1. 先运行 pnpm build
step('Step 1: 构建项目 (pnpm build)')
info('开始执行 pnpm build...')
ret = os.system('pnpm build')
if ret != 0:
error('pnpm build 失败,终止部署!')
exit(1)
success('pnpm build 完成')
# 2. 打包
step('Step 2: 打包 dist 目录为 zip')
info('开始打包 dist 目录...')
with zipfile.ZipFile(zip_name, 'w', zipfile.ZIP_DEFLATED) as zipf:
for root, dirs, files in os.walk(local_dir):
for file in files:
filepath = os.path.join(root, file)
arcname = os.path.relpath(filepath, local_dir)
zipf.write(filepath, arcname)
success('本地打包完成')
# 3. 上传
step('Step 3: 上传 zip 包到服务器')
info('开始上传 zip 包...')
transport = paramiko.Transport((server_ip, server_port))
transport.connect(username=server_user, password=server_pwd)
sftp = paramiko.SFTPClient.from_transport(transport)
sftp.put(zip_name, remote_path)
sftp.close()
transport.close()
success('上传到服务器完成')
# 删除本地 dist.zip
try:
os.remove(zip_name)
success('本地 dist.zip 已删除')
except Exception as e:
error(f'本地 dist.zip 删除失败: {e}')
# 4. 远程解压并覆盖
step('Step 4: 服务器端解压、切换目录')
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(server_ip, server_port, server_user, server_pwd)
commands = [
f'unzip -oq {remote_path} -d {dist2_dir}', # 静默解压
f'rm {remote_path}',
f'if [ -d {dist_dir} ]; then mv {dist_dir} {dist1_dir}; fi',
f'mv {dist2_dir} {dist_dir}',
f'rm -rf {dist1_dir}'
]
for i, cmd in enumerate(commands, 1):
info(f'执行第{i}步: {cmd}')
stdin, stdout, stderr = ssh.exec_command(cmd)
out, err = stdout.read().decode(), stderr.read().decode()
# 只打印非 unzip 命令的输出
if i != 1 and out.strip():
print(out.strip())
if err.strip():
error(err.strip())
ssh.close()
success('服务器解压并覆盖完成,部署成功!')

View File

@@ -0,0 +1,48 @@
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
client_max_body_size 200M;
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied any;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml application/javascript application/json;
gzip_comp_level 6;
location / {
try_files $uri $uri/ /index.html;
}
location = /index.html {
add_header Cache-Control "no-cache, no-store, must-revalidate" always;
add_header Pragma "no-cache" always;
add_header Expires "0" always;
}
location = /.vite/manifest.json {
add_header Cache-Control "no-cache, no-store, must-revalidate" always;
}
location /api/ {
proxy_pass http://cunkebao-server/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 60s;
proxy_read_timeout 300s;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
}

View File

@@ -0,0 +1,48 @@
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
client_max_body_size 200M;
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied any;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml application/javascript application/json;
gzip_comp_level 6;
location / {
try_files $uri $uri/ /index.html;
}
location = /index.html {
add_header Cache-Control "no-cache, no-store, must-revalidate" always;
add_header Pragma "no-cache" always;
add_header Expires "0" always;
}
location = /.vite/manifest.json {
add_header Cache-Control "no-cache, no-store, must-revalidate" always;
}
location /api/ {
proxy_pass http://cunkebao-server/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 60s;
proxy_read_timeout 300s;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
}

View File

@@ -0,0 +1,196 @@
# 存客宝 · 自动点赞扩展「自动评论」开发说明
## 1. 文档目的
在现有「工作台 · 自动点赞」能力上,增加**自动评论**子能力。评论方式分为两种:
| 模式 | 说明 |
|------|------|
| **固定评论** | 用户预先配置**多条**文案;执行时**随机选取一条**发出。 |
| **AI 评论** | 根据朋友圈正文 / 可见描述等上下文,由大模型生成短评论后再发出。 |
本文档供前后端与设备协议联调使用,并约定配置字段、接口与任务执行顺序。
---
## 2. 需求摘要
### 2.1 产品硬性约定(本次补充)
1. **自动评论总开关(必选)**
- 每个自动点赞任务必须提供**独立的「自动评论」开关**(开 / 关)。
- **关**:不发起任何自动评论逻辑,行为与当前线上「仅自动点赞」一致。
- **开**:再根据下方「评论模式」走固定评论或 AI 评论。
- 对应配置字段:`enableAutoComment`0=关1=开);前后端表单、列表展示均需体现该开关状态。
2. **固定评论:多条配置、随机一条**
- 固定评论模式下,用户可配置**多条**文案(数组,至少 1 条)。
- 每次对某条朋友圈执行自动评论时,从 `fixedComments` 中**随机抽取一条**作为本次评论内容(均匀随机即可;不要求去重轮播,除非后续产品另定)。
- 仅 1 条配置时,行为等价于「每次都用该条」。
### 2.2 其他需求说明
- 自动评论依附于**现有自动点赞工作台**`type = 1`),在同一任务配置中通过上述**总开关** + **评论模式**管理。
- **固定评论**:除「多条 + 随机一条」外,仍需校验每条长度(建议与微信单条评论上限对齐,具体以客户端协议为准)。
- **AI 评论**:用户可编辑「补充提示词」;**默认提示词**(新建任务时表单默认值、后端缺省回填)为:
```
1、模仿好友自然语气简洁走心贴合朋友圈内容口语化不生硬适配日常互动
2、轻松接地气简短真诚不浮夸适配风景 / 日常 / 自拍等多类朋友圈
3、可适当在句末加一个微信内置表情客户端识别的方括号写法例如[微笑]、[666]、[强]、[玫瑰]、[愉快],与语气相符即可,最多一个,勿堆砌;不要用一串 Unicode 小黄脸代替
```
- 业务上需明确:**仅评论**、**先赞后评**、**仅赞不评** 的组合策略(见第 5 节建议默认)。
---
## 3. 现状与代码入口(便于对接)
### 3.1 存客宝(`F:\karuo\yi-shi\Cunkebao`
- 路由:`/workspace/auto-like``/workspace/auto-like/new``/workspace/auto-like/edit/:id``/workspace/auto-like/record/:id`
- 列表 / 详情 API 封装:`src/pages/mobile/workspace/auto-like/list/api.ts``/v1/workbench/list``/v1/workbench/detail``/v1/workbench/create``/v1/workbench/update` 等,`type: 1`
- 任务与表单类型:`src/pages/mobile/workspace/auto-like/new/data.ts` 等处的 `LikeTask``CreateLikeTaskData`
### 3.2 服务端(`F:\karuo\yi-shi\Server`
- 配置表:`ck_workbench_auto_like`(模型 `app\cunkebao\model\WorkbenchAutoLike`
- 执行记录:`ck_workbench_auto_like_item`
- 创建 / 更新配置:`application\cunkebao\controller\workbench\WorkbenchController.php``TYPE_AUTO_LIKE` 分支
- 校验:`application\cunkebao\validate\Workbench.php``type = 1` 相关规则
- 定时 / 队列任务:`application\job\WorkbenchAutoLikeJob.php`,点赞调用 `WebSocketController::momentInteract()`
- 当前 `momentInteract` 仅下发 `momentInteractType => 1`(点赞),**评论能力需在设备指令层扩展**(见第 6 节)
---
## 4. 配置项设计(建议字段)
`workbench_auto_like` 上扩展存储(**新增列**或 **`json` 扩展字段**二选一,推荐新增列便于查询与默认值):
| 字段(示例命名) | 类型 | 说明 |
|------------------|------|------|
| `enableAutoComment` | tinyint(1) | **自动评论总开关**0 关 / 1 开(关则完全不评论) |
| `commentMode` | tinyint(1) | 仅当 `enableAutoComment=1` 时有效1=固定评论2=AI 评论 |
| `fixedComments` | json / text | 固定评论文案**数组**≥1 条);执行时**随机取一条**评论,如 `["真好","赞"]` |
| `aiCommentPrompt` | varchar(2000) 或 text | 用户自定义 AI 提示词;**空则使用产品默认拼接** |
| `commentAfterLike` | tinyint(1) | 可选1=先赞后评0=仅评论不强制点赞(与 `enableAutoComment`、原点赞开关组合) |
**默认行为建议:**
- `enableAutoComment = 0`**自动评论总开关关闭**,与线上一致,只点赞、不评论。
- `enableAutoComment = 1`:必须带有效 `commentMode`;固定模式下 `fixedComments` 至少 1 条,执行时随机一条。
- `commentMode = 2``aiCommentPrompt` 为空:服务端保存/返回时回填为第 2 节中的两段默认文案(可存库,也可仅前端默认 + 后端生成时用常量)。
---
## 5. 任务执行逻辑(`WorkbenchAutoLikeJob`
建议流程(可在 PRD 确认后微调):
1. 沿用现有:时间窗、`maxLikes`、内容类型、好友分页、点赞间隔等。
2. 对「目标朋友圈」在点赞成功后:
- **仅当 `enableAutoComment = 1`(总开关开)** 且当日已成功评论次数(按 `commentTime` 统计、与点赞同一时段窗口)**未达到 `maxLikes` 所允许的条数**时,才进入评论逻辑(评论与点赞**各自计数****上限数值均取配置中的 `maxLikes`**);总开关为关则跳过整段评论。
- `commentMode = 1`(固定评论):从 `fixedComments` 数组中 **随机选取一条** 作为本次评论文案并下发。
- `commentMode = 2`AI 评论):拉取朋友圈文本上下文 → 调用 AI 服务 → 得到短句 → 截断与敏感词过滤(如有)→ 下发评论指令。
3. 评论与点赞的间隔:建议在 `interval` 之外增加**独立评论间隔**字段 `commentInterval`(秒),避免操作过快触发风控(可选,产品定)。
**去重:** 若同一条朋友圈既要赞又要评,`workbench_auto_like_item` 需能区分「已赞」「已评」或增加评论记录表,避免重复评论(见第 7 节)。
---
## 6. 设备 / WebSocket 协议(必排期)
当前 `application\api\controller\WebSocketController.php``momentInteract` 固定为点赞类型。需与**终端 / 协议文档**确认:
- 朋友圈评论是否仍使用 `CmdMomentInteract`,通过不同 `momentInteractType` 或附加 `commentContent` 等字段区分;
- 或独立命令如 `CmdMomentComment`(以实际协议为准)。
**后端交付物:** 新增或扩展方法(例如 `momentComment($snsId, $wechatAccountId, $wechatFriendId, $content)`),由 `WorkbenchAutoLikeJob` 在生成文案后调用。
---
## 7. 数据与统计
### 7.1 记录表扩展
任选一种:
- **方案 A**:在 `ck_workbench_auto_like_item` 增加 `commentContent``commentTime``commentStatus` 等;同一条动态赞+评可同一行更新或两行(需唯一约束说明)。
- **方案 B**:新建 `ck_workbench_auto_comment_item`,与 `momentsId` / `snsId` / `workbenchId` 关联,结构更清晰。
列表页若需展示「评论内容 / 是否 AI」需同步扩展 `WorkbenchAutoLikeController` / `WorkbenchController` 的 records 接口字段。
### 7.2 统计
与现有 `todayLikeCount``totalLikeCount` 并列,可增加 `todayCommentCount``totalCommentCount`(在 `WorkbenchController` 组装 `config` 时查询)。
---
## 8. 接口与校验(`WorkbenchController` + `Workbench` 校验器)
- `create` / `update``type = 1`)增加对上述字段的读写。
- 校验规则示例:
- **`enableAutoComment`**:必填布尔或 0/1为 1 时下列规则生效。
- `enableAutoComment = 1` 时:`commentMode` 必填1 或 2
- `commentMode = 1``fixedComments` 为**非空数组**(至少一条文案),每条长度 ≤ 限制;服务端/Job 执行时**随机取一条**。
- `commentMode = 2``aiCommentPrompt` 可为空(空则用默认常量);若限制长度建议 ≥ 500 字以容纳用户扩展。
存客宝侧:`CreateLikeTaskData` / `LikeTask` 增加对应 TS 字段;新建/编辑页增加表单项(**自动评论总开关**、模式单选、**固定评论多条录入 + 说明「随机一条」**、AI 提示词多行文本默认值)。
---
## 9. AI 评论实现建议(服务端)
- 复用项目内已有 AI 调用模式(例如内容库 `ContentLibraryController::aiRewrite``application\ai\controller\OpenAi.php` 所走通道),封装 **`generateMomentComment(context, userPrompt)`**
- **System / 前置说明**:强调输出**一条**短评论、无引号包裹、无多余解释。
- **User 内容**:拼接「朋友圈正文/摘要」+ 默认两段提示 + 用户自定义 `aiCommentPrompt`
- 失败策略:记录日志;可选降级为「不发评论」或「随机一条固定兜底文案」(产品定)。
---
## 10. 存客宝前端交互要点
- 在「新建/编辑自动点赞」页增加区块:**自动评论**,顶部为**总开关**(关则隐藏或禁用下方模式与文案配置,提交时 `enableAutoComment=0`)。
- 总开关**开**时展示子选项:
- **固定评论**:支持录入**多条**文案(列表、多标签或换行拆分等交互任选);文案旁或区块说明:**「每次评论随机抽取其中一条」**。
- **AI 评论**:多行 `TextArea`,占位符或默认值展示第 2 节两段文案。
- 列表 / 记录页:如需区分展示,可增加「评论数」或记录列(依赖接口)。
---
## 11. 测试清单(提测用)
- [ ] 仅点赞:老数据无新字段或**自动评论总开关关**时,行为与线上一致。
- [ ] **总开关**:关不评论;开才评论。
- [ ] 固定评论:**多条配置**、多次执行观察为**随机一条**、单条边界长度、仅文字朋友圈 / 带图朋友圈。
- [ ] AI 评论默认提示词、自定义提示词、AI 超时 / 失败。
- [ ] 当日评论次数达到 `maxLikes` 后不再发评论(与点赞各自计数、上限数值均为 `maxLikes`);点赞是否仍执行(按产品设计)。
- [ ] 先赞后评顺序与间隔;重复调度不产生重复评论。
- [ ] 多端设备协议联调通过。
---
## 12. 交付物清单
| 层级 | 交付物 |
|------|--------|
| DB | `workbench_auto_like`(及可选新表)迁移 SQL |
| Server | `WorkbenchController``WorkbenchValidate``WorkbenchAutoLikeJob``WebSocketController`或新评论方法、AI 封装 |
| Cunkebao | `auto-like` 表单/类型/API 字段、文案与校验提示 |
| 联调 | 设备侧评论指令说明与抓包用例 |
---
## 13. 附录:默认 AI 提示词(常量)
以下为产品约定默认值,建议定义为后端常量 + 前端表单初始值,保持完全一致:
```
1、模仿好友自然语气简洁走心贴合朋友圈内容口语化不生硬适配日常互动
2、轻松接地气简短真诚不浮夸适配风景 / 日常 / 自拍等多类朋友圈
3、可适当在句末加一个微信内置表情客户端识别的方括号写法例如[微笑]、[666]、[强]、[玫瑰]、[愉快],与语气相符即可,最多一个,勿堆砌;不要用一串 Unicode 小黄脸代替
```
---
*文档版本v1.2 · 与仓库路径 `Cunkebao`、`Server` 当前结构对应,实施时以当时代码为准微调字段命名与表结构。*

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

66
Cunkebao/index.html Normal file
View File

@@ -0,0 +1,66 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover, shrink-to-fit=no"
/>
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
<meta name="format-detection" content="telephone=no" />
<title>存客宝</title>
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16.png" />
<link rel="apple-touch-icon" href="/logo-192.png" />
<link rel="manifest" href="/manifest.json" />
<meta name="theme-color" content="#F5A623" />
<style>
html {
font-size: 16px;
}
html,
body {
margin: 0;
overscroll-behavior: none;
-webkit-overflow-scrolling: auto;
}
@media (hover: none) and (pointer: coarse) {
html,
body {
position: fixed;
width: 100%;
height: 100%;
overflow: hidden;
touch-action: manipulation;
}
#root {
width: 100%;
height: 100%;
overflow: hidden;
}
}
</style>
<script>
(function () {
function syncVh() {
var vv = window.visualViewport;
var h = (vv && vv.height) || window.innerHeight || document.documentElement.clientHeight;
document.documentElement.style.setProperty("--real-vh", h * 0.01 + "px");
}
syncVh();
window.addEventListener("resize", syncVh);
window.addEventListener("orientationchange", syncVh);
if (window.visualViewport) {
window.visualViewport.addEventListener("resize", syncVh);
}
})();
</script>
<!-- 引入 uni-app web-view SDK必须 -->
<script type="text/javascript" src="/websdk.js"></script>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

View File

@@ -1,6 +0,0 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference types="next/navigation-types/compat/navigation" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

21347
Cunkebao/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,106 +1,56 @@
{
"name": "nkebao2",
"version": "0.1.0",
"name": "cunkebao",
"version": "3.0.0",
"license": "MIT",
"private": true,
"dependencies": {
"@ant-design/plots": "latest",
"@hookform/resolvers": "^3.9.1",
"@radix-ui/react-accordion": "latest",
"@radix-ui/react-alert-dialog": "^1.1.4",
"@radix-ui/react-aspect-ratio": "^1.1.1",
"@radix-ui/react-avatar": "latest",
"@radix-ui/react-checkbox": "latest",
"@radix-ui/react-collapsible": "latest",
"@radix-ui/react-context-menu": "^2.2.4",
"@radix-ui/react-dialog": "latest",
"@radix-ui/react-dropdown-menu": "latest",
"@radix-ui/react-hover-card": "^1.1.4",
"@radix-ui/react-icons": "latest",
"@radix-ui/react-label": "latest",
"@radix-ui/react-menubar": "^1.1.4",
"@radix-ui/react-navigation-menu": "^1.2.3",
"@radix-ui/react-popover": "latest",
"@radix-ui/react-progress": "latest",
"@radix-ui/react-radio-group": "latest",
"@radix-ui/react-scroll-area": "latest",
"@radix-ui/react-select": "latest",
"@radix-ui/react-separator": "^1.1.1",
"@radix-ui/react-slider": "^1.3.5",
"@radix-ui/react-slot": "^1.1.1",
"@radix-ui/react-switch": "latest",
"@radix-ui/react-tabs": "latest",
"@radix-ui/react-toast": "latest",
"@radix-ui/react-toggle": "^1.1.1",
"@radix-ui/react-toggle-group": "^1.1.1",
"@radix-ui/react-tooltip": "latest",
"@tanstack/react-table": "latest",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/crypto-js": "^4.2.2",
"@types/jest": "^27.5.2",
"@types/node": "^18.19.34",
"@types/react": "^18.2.43",
"@types/react-dom": "^18.2.17",
"autoprefixer": "^10.4.20",
"axios": "^1.6.0",
"chart.js": "^4.5.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "1.0.4",
"@ant-design/icons": "^5.6.1",
"antd": "^5.13.1",
"antd-mobile": "^5.39.1",
"antd-mobile-icons": "^0.3.0",
"axios": "^1.6.7",
"crypto-js": "^4.2.0",
"date-fns": "^4.1.0",
"embla-carousel-react": "8.5.1",
"input-otp": "1.4.1",
"lucide-react": "^0.525.0",
"dayjs": "^1.11.13",
"echarts": "^5.6.0",
"echarts-for-react": "^3.0.2",
"qrcode": "^1.5.4",
"react": "^18.2.0",
"react-day-picker": "latest",
"react-dom": "^18.2.0",
"react-hook-form": "^7.54.1",
"react-hot-toast": "^2.5.2",
"react-resizable-panels": "^2.1.7",
"react-router-dom": "^6.20.0",
"react-scripts": "5.0.1",
"recharts": "latest",
"regenerator-runtime": "latest",
"sonner": "^1.7.4",
"tailwind-merge": "^2.6.0",
"tailwindcss-animate": "^1.0.7",
"tdesign-mobile-react": "^0.16.0",
"vaul": "^0.9.6",
"web-vitals": "^2.1.4",
"xlsx": "^0.18.5",
"zod": "^3.24.1"
"react-window": "^1.8.11",
"vconsole": "^3.15.1",
"xmldom": "^0.6.0",
"zustand": "^5.0.6"
},
"devDependencies": {
"@craco/craco": "^7.1.0",
"postcss": "^8",
"tailwindcss": "^3.4.17",
"typescript": "^4.9.5"
"@types/crypto-js": "^4.2.2",
"@types/node": "^24.0.14",
"@types/qrcode": "^1.5.6",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"@typescript-eslint/eslint-plugin": "^7.7.0",
"@typescript-eslint/parser": "^7.7.0",
"@vitejs/plugin-react": "^4.6.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-react": "^7.34.1",
"eslint-plugin-react-hooks": "^5.2.0",
"postcss": "^8.4.38",
"postcss-pxtorem": "^6.0.0",
"prettier": "^3.2.5",
"sass": "^1.75.0",
"typescript": "^5.4.5",
"vite": "^7.0.5"
},
"scripts": {
"dev": "craco start",
"build": "craco build",
"test": "craco test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
"dev": "pnpm vite",
"build": "pnpm vite build",
"build:check": "tsc && pnpm vite build",
"preview": "pnpm vite preview",
"lint": "eslint src --ext .js,.jsx,.ts,.tsx --fix",
"format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,json,scss,css}\"",
"lint:check": "eslint src --ext .js,.jsx,.ts,.tsx",
"format:check": "prettier --check \"src/**/*.{js,jsx,ts,tsx,json,scss,css}\""
}
}

5261
Cunkebao/pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
allowBuilds:
'@parcel/watcher': set this to true or false
core-js: set this to true or false
esbuild: set this to true or false

View File

@@ -1,6 +1,8 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
plugins: {
'postcss-pxtorem': {
rootValue: 16,
propList: ['*'],
},
},
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -1,43 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

BIN
Cunkebao/public/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

View File

@@ -1,6 +1,13 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"name": "存客宝",
"short_name": "存客宝",
"description": "存客宝私域管理系统",
"theme_color": "#F5A623",
"background_color": "#ffffff",
"display": "standalone",
"orientation": "portrait",
"scope": "/",
"start_url": "/",
"icons": [
{
"src": "favicon.ico",
@@ -8,18 +15,16 @@
"type": "image/x-icon"
},
{
"src": "logo192.png",
"src": "logo-192.png",
"sizes": "192x192",
"type": "image/png",
"sizes": "192x192"
"purpose": "any maskable"
},
{
"src": "logo512.png",
"src": "logo-512.png",
"sizes": "512x512",
"type": "image/png",
"sizes": "512x512"
"purpose": "any maskable"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
]
}

View File

@@ -1,3 +0,0 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

308
Cunkebao/public/websdk.js Normal file
View File

@@ -0,0 +1,308 @@
!(function (e, n) {
"object" == typeof exports && "undefined" != typeof module
? (module.exports = n())
: "function" == typeof define && define.amd
? define(n)
: ((e = e || self).uni = n());
})(this, function () {
"use strict";
try {
var e = {};
(Object.defineProperty(e, "passive", {
get: function () {
!0;
},
}),
window.addEventListener("test-passive", null, e));
} catch (e) {}
var n = Object.prototype.hasOwnProperty;
function i(e, i) {
return n.call(e, i);
}
var t = [];
function o() {
return window.__dcloud_weex_postMessage || window.__dcloud_weex_;
}
function a() {
return window.__uniapp_x_postMessage || window.__uniapp_x_;
}
var r = function (e, n) {
var i = { options: { timestamp: +new Date() }, name: e, arg: n };
if (a()) {
if ("postMessage" === e) {
var r = { data: n };
return window.__uniapp_x_postMessage
? window.__uniapp_x_postMessage(r)
: window.__uniapp_x_.postMessage(JSON.stringify(r));
}
var d = {
type: "WEB_INVOKE_APPSERVICE",
args: { data: i, webviewIds: t },
};
window.__uniapp_x_postMessage
? window.__uniapp_x_postMessageToService(d)
: window.__uniapp_x_.postMessageToService(JSON.stringify(d));
} else if (o()) {
if ("postMessage" === e) {
var s = { data: [n] };
return window.__dcloud_weex_postMessage
? window.__dcloud_weex_postMessage(s)
: window.__dcloud_weex_.postMessage(JSON.stringify(s));
}
var w = {
type: "WEB_INVOKE_APPSERVICE",
args: { data: i, webviewIds: t },
};
window.__dcloud_weex_postMessage
? window.__dcloud_weex_postMessageToService(w)
: window.__dcloud_weex_.postMessageToService(JSON.stringify(w));
} else {
if (!window.plus)
return window.parent.postMessage(
{ type: "WEB_INVOKE_APPSERVICE", data: i, pageId: "" },
"*",
);
if (0 === t.length) {
var u = plus.webview.currentWebview();
if (!u) throw new Error("plus.webview.currentWebview() is undefined");
var g = u.parent(),
v = "";
((v = g ? g.id : u.id), t.push(v));
}
if (plus.webview.getWebviewById("__uniapp__service"))
plus.webview.postMessageToUniNView(
{ type: "WEB_INVOKE_APPSERVICE", args: { data: i, webviewIds: t } },
"__uniapp__service",
);
else {
var c = JSON.stringify(i);
plus.webview
.getLaunchWebview()
.evalJS(
'UniPlusBridge.subscribeHandler("'
.concat("WEB_INVOKE_APPSERVICE", '",')
.concat(c, ",")
.concat(JSON.stringify(t), ");"),
);
}
}
},
d = {
navigateTo: function () {
var e =
arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
n = e.url;
r("navigateTo", { url: encodeURI(n) });
},
navigateBack: function () {
var e =
arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
n = e.delta;
r("navigateBack", { delta: parseInt(n) || 1 });
},
switchTab: function () {
var e =
arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
n = e.url;
r("switchTab", { url: encodeURI(n) });
},
reLaunch: function () {
var e =
arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
n = e.url;
r("reLaunch", { url: encodeURI(n) });
},
redirectTo: function () {
var e =
arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
n = e.url;
r("redirectTo", { url: encodeURI(n) });
},
getEnv: function (e) {
a()
? e({ uvue: !0 })
: o()
? e({ nvue: !0 })
: window.plus
? e({ plus: !0 })
: e({ h5: !0 });
},
postMessage: function () {
var e =
arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
r("postMessage", e.data || {});
},
},
s = /uni-app/i.test(navigator.userAgent),
w = /Html5Plus/i.test(navigator.userAgent),
u = /complete|loaded|interactive/;
var g =
window.my &&
navigator.userAgent.indexOf(
["t", "n", "e", "i", "l", "C", "y", "a", "p", "i", "l", "A"]
.reverse()
.join(""),
) > -1;
var v =
window.swan && window.swan.webView && /swan/i.test(navigator.userAgent);
var c =
window.qq &&
window.qq.miniProgram &&
/QQ/i.test(navigator.userAgent) &&
/miniProgram/i.test(navigator.userAgent);
var p =
window.tt &&
window.tt.miniProgram &&
/toutiaomicroapp/i.test(navigator.userAgent);
var _ =
window.wx &&
window.wx.miniProgram &&
/micromessenger/i.test(navigator.userAgent) &&
/miniProgram/i.test(navigator.userAgent);
var m = window.qa && /quickapp/i.test(navigator.userAgent);
var f =
window.ks &&
window.ks.miniProgram &&
/micromessenger/i.test(navigator.userAgent) &&
/miniProgram/i.test(navigator.userAgent);
var l =
window.tt &&
window.tt.miniProgram &&
/Lark|Feishu/i.test(navigator.userAgent);
var E =
window.jd && window.jd.miniProgram && /jdmp/i.test(navigator.userAgent);
var x =
window.xhs &&
window.xhs.miniProgram &&
/xhsminiapp/i.test(navigator.userAgent);
for (
var S,
h = function () {
((window.UniAppJSBridge = !0),
document.dispatchEvent(
new CustomEvent("UniAppJSBridgeReady", {
bubbles: !0,
cancelable: !0,
}),
));
},
y = [
function (e) {
if (s || w)
return (
window.__uniapp_x_postMessage ||
window.__uniapp_x_ ||
window.__dcloud_weex_postMessage ||
window.__dcloud_weex_
? document.addEventListener("DOMContentLoaded", e)
: window.plus && u.test(document.readyState)
? setTimeout(e, 0)
: document.addEventListener("plusready", e),
d
);
},
function (e) {
if (_)
return (
window.WeixinJSBridge && window.WeixinJSBridge.invoke
? setTimeout(e, 0)
: document.addEventListener("WeixinJSBridgeReady", e),
window.wx.miniProgram
);
},
function (e) {
if (c)
return (
window.QQJSBridge && window.QQJSBridge.invoke
? setTimeout(e, 0)
: document.addEventListener("QQJSBridgeReady", e),
window.qq.miniProgram
);
},
function (e) {
if (g) {
document.addEventListener("DOMContentLoaded", e);
var n = window.my;
return {
navigateTo: n.navigateTo,
navigateBack: n.navigateBack,
switchTab: n.switchTab,
reLaunch: n.reLaunch,
redirectTo: n.redirectTo,
postMessage: n.postMessage,
getEnv: n.getEnv,
};
}
},
function (e) {
if (v)
return (
document.addEventListener("DOMContentLoaded", e),
window.swan.webView
);
},
function (e) {
if (p)
return (
document.addEventListener("DOMContentLoaded", e),
window.tt.miniProgram
);
},
function (e) {
if (m) {
window.QaJSBridge && window.QaJSBridge.invoke
? setTimeout(e, 0)
: document.addEventListener("QaJSBridgeReady", e);
var n = window.qa;
return {
navigateTo: n.navigateTo,
navigateBack: n.navigateBack,
switchTab: n.switchTab,
reLaunch: n.reLaunch,
redirectTo: n.redirectTo,
postMessage: n.postMessage,
getEnv: n.getEnv,
};
}
},
function (e) {
if (f)
return (
window.WeixinJSBridge && window.WeixinJSBridge.invoke
? setTimeout(e, 0)
: document.addEventListener("WeixinJSBridgeReady", e),
window.ks.miniProgram
);
},
function (e) {
if (l)
return (
document.addEventListener("DOMContentLoaded", e),
window.tt.miniProgram
);
},
function (e) {
if (E)
return (
window.JDJSBridgeReady && window.JDJSBridgeReady.invoke
? setTimeout(e, 0)
: document.addEventListener("JDJSBridgeReady", e),
window.jd.miniProgram
);
},
function (e) {
if (x) return window.xhs.miniProgram;
},
function (e) {
return (document.addEventListener("DOMContentLoaded", e), d);
},
],
M = 0;
M < y.length && !(S = y[M](h));
M++
);
S || (S = {});
var P = "undefined" != typeof uni ? uni : {};
if (!P.navigateTo) for (var b in S) i(S, b) && (P[b] = S[b]);
return ((P.webView = S), P);
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

View File

@@ -1,38 +0,0 @@
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

View File

@@ -1,9 +0,0 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});

View File

@@ -1,190 +1,48 @@
import React, { useEffect } from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { AuthProvider } from "./contexts/AuthContext";
import { WechatAccountProvider } from "./contexts/WechatAccountContext";
import ProtectedRoute from "./components/ProtectedRoute";
import LayoutWrapper from "./components/LayoutWrapper";
import { initInterceptors } from "./api";
import Home from "./pages/Home";
import Login from "./pages/login/Login";
import Devices from "./pages/devices/Devices";
import DeviceDetail from "./pages/devices/DeviceDetail";
import WechatAccounts from "./pages/wechat-accounts/WechatAccounts";
import WechatAccountDetail from "./pages/wechat-accounts/WechatAccountDetail";
import Workspace from "./pages/workspace/Workspace";
import AutoLike from "./pages/workspace/auto-like/AutoLike";
import NewAutoLike from "./pages/workspace/auto-like/NewAutoLike";
import AutoLikeDetail from "./pages/workspace/auto-like/AutoLikeDetail";
import NewDistribution from "./pages/workspace/traffic-distribution/NewDistribution";
import AutoGroup from "./pages/workspace/auto-group/AutoGroup";
import AutoGroupDetail from "./pages/workspace/auto-group/Detail";
import GroupPush from "./pages/workspace/group-push/GroupPush";
import MomentsSync from "./pages/workspace/moments-sync/MomentsSync";
import MomentsSyncDetail from "./pages/workspace/moments-sync/Detail";
import NewMomentsSync from "./pages/workspace/moments-sync/new";
import AIAssistant from "./pages/workspace/ai-assistant/AIAssistant";
import TrafficDistribution from "./pages/workspace/traffic-distribution/TrafficDistribution";
import TrafficDistributionDetail from "./pages/workspace/traffic-distribution/Detail";
import Scenarios from "./pages/scenarios/Scenarios";
import NewPlan from "./pages/scenarios/new/page";
import ScenarioList from "./pages/scenarios/ScenarioList";
import Profile from "./pages/profile/Profile";
import Plans from "./pages/plans/Plans";
import PlanDetail from "./pages/plans/PlanDetail";
import Orders from "./pages/orders/Orders";
import TrafficPool from "./pages/traffic-pool/TrafficPool";
import ContactImport from "./pages/contact-import/ContactImport";
import Content from "./pages/content/Content";
import TrafficPoolDetail from "./pages/traffic-pool/TrafficPoolDetail";
import NewContent from "./pages/content/NewContent";
import Materials from "./pages/content/materials/List";
import MaterialsNew from "./pages/content/materials/New";
import NewGroupPush from './pages/workspace/group-push/new';
// 占位导入(如未实现可后续补充)
// import GroupPushDetail from './pages/workspace/group-push/GroupPushDetail';
// import EditGroupPush from './pages/workspace/group-push/EditGroupPush';
// import NewAutoGroup from './pages/workspace/auto-group/NewAutoGroup';
// import EditAutoGroup from './pages/workspace/auto-group/EditAutoGroup';
import React from "react";
import AppRouter from "@/router";
import UpdateNotification from "@/components/UpdateNotification";
import { prefetchHomeOverview } from "@/store/module/homeOverview";
import { useUserStore } from "@/store/module/user";
function App() {
// 初始化HTTP拦截器
useEffect(() => {
const cleanup = initInterceptors();
return cleanup;
React.useEffect(() => {
const syncViewport = () => {
const h = window.visualViewport?.height ?? window.innerHeight;
document.documentElement.style.setProperty("--real-vh", `${h * 0.01}px`);
};
syncViewport();
window.addEventListener("resize", syncViewport);
window.visualViewport?.addEventListener("resize", syncViewport);
window.visualViewport?.addEventListener("scroll", syncViewport);
return () => {
window.removeEventListener("resize", syncViewport);
window.visualViewport?.removeEventListener("resize", syncViewport);
window.visualViewport?.removeEventListener("scroll", syncViewport);
};
}, []);
React.useEffect(() => {
const token = localStorage.getItem("token");
if (token) {
prefetchHomeOverview();
}
return useUserStore.subscribe((state, prev) => {
if (state.isLoggedIn && !prev.isLoggedIn) {
prefetchHomeOverview();
}
if (!state.isLoggedIn && prev.isLoggedIn) {
import("@/store/module/homeOverview").then(m =>
m.useHomeOverviewStore.getState().clear(),
);
}
});
}, []);
return (
<BrowserRouter
future={{ v7_startTransition: true, v7_relativeSplatPath: true }}
>
<AuthProvider>
<WechatAccountProvider>
<ProtectedRoute>
<LayoutWrapper>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="/devices" element={<Devices />} />
<Route path="/devices/:id" element={<DeviceDetail />} />
<Route path="/wechat-accounts" element={<WechatAccounts />} />
<Route
path="/wechat-accounts/:id"
element={<WechatAccountDetail />}
/>
<Route path="/workspace" element={<Workspace />} />
<Route path="/workspace/auto-like" element={<AutoLike />} />
<Route
path="/workspace/auto-like/new"
element={<NewAutoLike />}
/>
<Route
path="/workspace/auto-like/:id"
element={<AutoLikeDetail />}
/>
<Route
path="/workspace/auto-like/:id/edit"
element={<NewAutoLike />}
/>
<Route
path="/workspace/traffic-distribution"
element={<TrafficDistribution />}
/>
<Route
path="/workspace/traffic-distribution/new"
element={<NewDistribution />}
/>
<Route
path="/workspace/traffic-distribution/edit/:id"
element={<NewDistribution />}
/>
<Route path="/workspace/auto-group" element={<AutoGroup />} />
<Route
path="/workspace/auto-group/:id"
element={<AutoGroupDetail />}
/>
<Route path="/workspace/group-push" element={<GroupPush />} />
<Route
path="/workspace/group-push/new"
element={<NewGroupPush />}
/>
<Route
path="/workspace/group-push/:id"
element={<div>GroupPushDetail组件</div>}
/>
<Route
path="/workspace/group-push/:id/edit"
element={<div>EditGroupPush组件</div>}
/>
<Route
path="/workspace/moments-sync"
element={<MomentsSync />}
/>
<Route
path="/workspace/moments-sync/new"
element={<NewMomentsSync />}
/>
<Route
path="/workspace/moments-sync/:id"
element={<MomentsSyncDetail />}
/>
<Route
path="/workspace/moments-sync/edit/:id"
element={<NewMomentsSync />}
/>
<Route
path="/workspace/ai-assistant"
element={<AIAssistant />}
/>
<Route
path="/workspace/traffic-distribution"
element={<TrafficDistribution />}
/>
<Route
path="/workspace/traffic-distribution/:id"
element={<TrafficDistributionDetail />}
/>
{/* 场景计划开始 */}
<Route path="/scenarios" element={<Scenarios />} />
<Route path="/scenarios/new" element={<NewPlan />} />
<Route
path="/scenarios/new/:scenarioId"
element={<NewPlan />}
/>
<Route path="/scenarios/edit/:planId" element={<NewPlan />} />
<Route
path="/scenarios/list/:scenarioId/:scenarioName"
element={<ScenarioList />}
/>
{/* 场景计划结束 */}
<Route path="/profile" element={<Profile />} />
<Route path="/plans" element={<Plans />} />
<Route path="/plans/:planId" element={<PlanDetail />} />
<Route path="/orders" element={<Orders />} />
<Route path="/traffic-pool" element={<TrafficPool />} />
<Route
path="/traffic-pool/:id"
element={<TrafficPoolDetail />}
/>
<Route path="/contact-import" element={<ContactImport />} />
<Route path="/content" element={<Content />} />
<Route path="/content/new" element={<NewContent />} />
<Route path="/content/edit/:id" element={<NewContent />} />
<Route path="/content/materials/:id" element={<Materials />} />
<Route
path="/content/materials/new/:id"
element={<MaterialsNew />}
/>
<Route
path="/content/materials/edit/:id/:materialId"
element={<MaterialsNew />}
/>
{/* 你可以继续添加更多路由 */}
</Routes>
</LayoutWrapper>
</ProtectedRoute>
</WechatAccountProvider>
</AuthProvider>
</BrowserRouter>
<>
<AppRouter />
<UpdateNotification position="top" autoReload={false} showToast={true} />
</>
);
}

View File

@@ -0,0 +1,350 @@
// Android 专用 polyfill - 解决Android 7等低版本系统的兼容性问题
// 检测是否为Android设备
const isAndroid = () => {
return /Android/i.test(navigator.userAgent);
};
// 检测Android版本
const getAndroidVersion = () => {
const match = navigator.userAgent.match(/Android\s+(\d+)/);
return match ? parseInt(match[1]) : 0;
};
// 检测是否为低版本Android
const isLowVersionAndroid = () => {
const version = getAndroidVersion();
return version <= 7; // Android 7及以下版本
};
// 只在Android设备上执行polyfill
if (isAndroid() && isLowVersionAndroid()) {
console.log("检测到低版本Android系统启用兼容性polyfill");
// 修复Array.prototype.includes在Android WebView中的问题
if (!Array.prototype.includes) {
Array.prototype.includes = function (searchElement, fromIndex) {
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
var o = Object(this);
var len = o.length >>> 0;
if (len === 0) {
return false;
}
var n = fromIndex | 0;
var k = Math.max(n >= 0 ? n : len + n, 0);
while (k < len) {
if (o[k] === searchElement) {
return true;
}
k++;
}
return false;
};
}
// 修复String.prototype.includes在Android WebView中的问题
if (!String.prototype.includes) {
String.prototype.includes = function (search, start) {
if (typeof start !== "number") {
start = 0;
}
if (start + search.length > this.length) {
return false;
} else {
return this.indexOf(search, start) !== -1;
}
};
}
// 修复String.prototype.startsWith在Android WebView中的问题
if (!String.prototype.startsWith) {
String.prototype.startsWith = function (searchString, position) {
position = position || 0;
return this.substr(position, searchString.length) === searchString;
};
}
// 修复String.prototype.endsWith在Android WebView中的问题
if (!String.prototype.endsWith) {
String.prototype.endsWith = function (searchString, length) {
if (length === undefined || length > this.length) {
length = this.length;
}
return (
this.substring(length - searchString.length, length) === searchString
);
};
}
// 修复Array.prototype.find在Android WebView中的问题
if (!Array.prototype.find) {
Array.prototype.find = function (predicate) {
if (this == null) {
throw new TypeError("Array.prototype.find called on null or undefined");
}
if (typeof predicate !== "function") {
throw new TypeError("predicate must be a function");
}
var list = Object(this);
var length = parseInt(list.length) || 0;
var thisArg = arguments[1];
for (var i = 0; i < length; i++) {
var element = list[i];
if (predicate.call(thisArg, element, i, list)) {
return element;
}
}
return undefined;
};
}
// 修复Array.prototype.findIndex在Android WebView中的问题
if (!Array.prototype.findIndex) {
Array.prototype.findIndex = function (predicate) {
if (this == null) {
throw new TypeError(
"Array.prototype.findIndex called on null or undefined",
);
}
if (typeof predicate !== "function") {
throw new TypeError("predicate must be a function");
}
var list = Object(this);
var length = parseInt(list.length) || 0;
var thisArg = arguments[1];
for (var i = 0; i < length; i++) {
var element = list[i];
if (predicate.call(thisArg, element, i, list)) {
return i;
}
}
return -1;
};
}
// 修复Object.assign在Android WebView中的问题
if (typeof Object.assign !== "function") {
Object.assign = function (target) {
if (target == null) {
throw new TypeError("Cannot convert undefined or null to object");
}
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if (nextSource != null) {
for (var nextKey in nextSource) {
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
};
}
// 修复Array.from在Android WebView中的问题
if (!Array.from) {
Array.from = (function () {
var toStr = Object.prototype.toString;
var isCallable = function (fn) {
return (
typeof fn === "function" || toStr.call(fn) === "[object Function]"
);
};
var toInteger = function (value) {
var number = Number(value);
if (isNaN(number)) {
return 0;
}
if (number === 0 || !isFinite(number)) {
return number;
}
return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
};
var maxSafeInteger = Math.pow(2, 53) - 1;
var toLength = function (value) {
var len = toInteger(value);
return Math.min(Math.max(len, 0), maxSafeInteger);
};
return function from(arrayLike) {
var C = this;
var items = Object(arrayLike);
if (arrayLike == null) {
throw new TypeError(
"Array.from requires an array-like object - not null or undefined",
);
}
var mapFunction = arguments.length > 1 ? arguments[1] : void undefined;
var T;
if (typeof mapFunction !== "undefined") {
if (typeof mapFunction !== "function") {
throw new TypeError(
"Array.from: when provided, the second argument must be a function",
);
}
if (arguments.length > 2) {
T = arguments[2];
}
}
var len = toLength(items.length);
var A = isCallable(C) ? Object(new C(len)) : new Array(len);
var k = 0;
var kValue;
while (k < len) {
kValue = items[k];
if (mapFunction) {
A[k] =
typeof T === "undefined"
? mapFunction(kValue, k)
: mapFunction.call(T, kValue, k);
} else {
A[k] = kValue;
}
k += 1;
}
A.length = len;
return A;
};
})();
}
// 修复requestAnimationFrame在Android WebView中的问题
if (!window.requestAnimationFrame) {
window.requestAnimationFrame = function (callback) {
return setTimeout(function () {
callback(Date.now());
}, 1000 / 60);
} as unknown as typeof window.requestAnimationFrame;
}
if (!window.cancelAnimationFrame) {
window.cancelAnimationFrame = function (id) {
clearTimeout(id);
};
}
// 修复IntersectionObserver在Android WebView中的问题
if (!window.IntersectionObserver) {
window.IntersectionObserver = function (callback, options) {
this.callback = callback;
this.options = options || {};
this.observers = [];
this.observe = function (element) {
this.observers.push(element);
// 简单的实现,实际项目中可能需要更复杂的逻辑
setTimeout(() => {
this.callback([
{
target: element,
isIntersecting: true,
intersectionRatio: 1,
},
]);
}, 100);
};
this.unobserve = function (element) {
var index = this.observers.indexOf(element);
if (index > -1) {
this.observers.splice(index, 1);
}
};
this.disconnect = function () {
this.observers = [];
};
} as unknown as typeof window.IntersectionObserver;
}
// 修复ResizeObserver在Android WebView中的问题
if (!window.ResizeObserver) {
window.ResizeObserver = function (callback) {
this.callback = callback;
this.observers = [];
this.observe = function (element) {
this.observers.push(element);
};
this.unobserve = function (element) {
var index = this.observers.indexOf(element);
if (index > -1) {
this.observers.splice(index, 1);
}
};
this.disconnect = function () {
this.observers = [];
};
} as unknown as typeof window.ResizeObserver;
}
// 修复URLSearchParams在Android WebView中的问题
if (!window.URLSearchParams) {
window.URLSearchParams = function (init) {
this.params = {};
if (init) {
if (typeof init === "string") {
if (init.charAt(0) === "?") {
init = init.slice(1);
}
var pairs = init.split("&");
for (var i = 0; i < pairs.length; i++) {
var pair = pairs[i].split("=");
var key = decodeURIComponent(pair[0]);
var value = decodeURIComponent(pair[1] || "");
this.append(key, value);
}
}
}
this.append = function (name, value) {
if (!this.params[name]) {
this.params[name] = [];
}
this.params[name].push(value);
};
this.get = function (name) {
return this.params[name] ? this.params[name][0] : null;
};
this.getAll = function (name) {
return this.params[name] || [];
};
this.has = function (name) {
return !!this.params[name];
};
this.set = function (name, value) {
this.params[name] = [value];
};
this.delete = function (name) {
delete this.params[name];
};
this.toString = function () {
var pairs = [];
for (var key in this.params) {
if (this.params.hasOwnProperty(key)) {
for (var i = 0; i < this.params[key].length; i++) {
pairs.push(
encodeURIComponent(key) +
"=" +
encodeURIComponent(this.params[key][i]),
);
}
}
}
return pairs.join("&");
};
} as unknown as typeof window.URLSearchParams;
}
}

View File

@@ -1,82 +0,0 @@
import { request } from './request';
import type { ApiResponse } from '@/types/common';
// 登录响应数据类型
export interface LoginResponse {
token: string;
token_expired: string;
member: {
id: number;
username: string;
account: string;
avatar?: string;
s2_accountId: string;
};
}
// 验证码响应类型
export interface VerificationCodeResponse {
code: string;
expire_time: string;
}
// 认证相关API
export const authApi = {
// 账号密码登录
login: async (account: string, password: string) => {
const response = await request.post<ApiResponse<LoginResponse>>('/v1/auth/login', {
account,
password,
typeId: 1 // 默认使用用户类型1
});
return response as unknown as ApiResponse<LoginResponse>;
},
// 验证码登录
loginWithCode: async (account: string, code: string) => {
const response = await request.post<ApiResponse<LoginResponse>>('/v1/auth/login/code', {
account,
code,
typeId: 1
});
return response as unknown as ApiResponse<LoginResponse>;
},
// 发送验证码
sendVerificationCode: async (account: string) => {
const response = await request.post<ApiResponse<VerificationCodeResponse>>('/v1/auth/send-code', {
account,
type: 'login' // 登录验证码
});
return response as unknown as ApiResponse<VerificationCodeResponse>;
},
// 获取用户信息
getUserInfo: async () => {
const response = await request.get<ApiResponse<any>>('/v1/auth/info');
return response as unknown as ApiResponse<any>;
},
// 刷新Token
refreshToken: async () => {
const response = await request.post<ApiResponse<{ token: string; token_expired: string }>>('/v1/auth/refresh', {});
return response as unknown as ApiResponse<{ token: string; token_expired: string }>;
},
// 微信登录
wechatLogin: async (code: string) => {
const response = await request.post<ApiResponse<LoginResponse>>('/v1/auth/wechat', {
code
});
return response as unknown as ApiResponse<LoginResponse>;
},
// Apple登录
appleLogin: async (identityToken: string, authorizationCode: string) => {
const response = await request.post<ApiResponse<LoginResponse>>('/v1/auth/apple', {
identity_token: identityToken,
authorization_code: authorizationCode
});
return response as unknown as ApiResponse<LoginResponse>;
},
};

View File

@@ -1,119 +0,0 @@
import { get, post, del } from './request';
import {
LikeTask,
CreateLikeTaskData,
UpdateLikeTaskData,
LikeRecord,
ApiResponse,
PaginatedResponse
} from '@/types/auto-like';
// 获取自动点赞任务列表
export async function fetchAutoLikeTasks(): Promise<LikeTask[]> {
try {
const res = await get<ApiResponse<PaginatedResponse<LikeTask>>>('/v1/workbench/list?type=1&page=1&limit=100');
if (res.code === 200 && res.data) {
return res.data.list || [];
}
return [];
} catch (error) {
console.error('获取自动点赞任务失败:', error);
return [];
}
}
// 获取单个任务详情
export async function fetchAutoLikeTaskDetail(id: string): Promise<LikeTask | null> {
try {
console.log(`Fetching task detail for id: ${id}`);
// 使用any类型来处理可能的不同响应结构
const res = await get<any>(`/v1/workbench/detail?id=${id}`);
console.log('Task detail API response:', res);
if (res.code === 200) {
// 检查响应中的data字段
if (res.data) {
// 如果data是对象直接返回
if (typeof res.data === 'object') {
return res.data;
} else {
console.error('Task detail API response data is not an object:', res.data);
return null;
}
} else {
console.error('Task detail API response missing data field:', res);
return null;
}
}
console.error('Task detail API error:', res.msg || 'Unknown error');
return null;
} catch (error) {
console.error('获取任务详情失败:', error);
return null;
}
}
// 创建自动点赞任务
export async function createAutoLikeTask(data: CreateLikeTaskData): Promise<ApiResponse> {
return post('/v1/workbench/create', {
...data,
type: 1 // 自动点赞类型
});
}
// 更新自动点赞任务
export async function updateAutoLikeTask(data: UpdateLikeTaskData): Promise<ApiResponse> {
return post('/v1/workbench/update', {
...data,
type: 1 // 自动点赞类型
});
}
// 删除自动点赞任务
export async function deleteAutoLikeTask(id: string): Promise<ApiResponse> {
return del('/v1/workbench/delete', { params: { id } });
}
// 切换任务状态
export async function toggleAutoLikeTask(id: string, status: string): Promise<ApiResponse> {
return post('/v1/workbench/update-status', { id, status });
}
// 复制自动点赞任务
export async function copyAutoLikeTask(id: string): Promise<ApiResponse> {
return post('/v1/workbench/copy', { id });
}
// 获取点赞记录
export async function fetchLikeRecords(
workbenchId: string,
page: number = 1,
limit: number = 20,
keyword?: string
): Promise<PaginatedResponse<LikeRecord>> {
try {
const params = new URLSearchParams({
workbenchId,
page: page.toString(),
limit: limit.toString()
});
if (keyword) {
params.append('keyword', keyword);
}
const res = await get<ApiResponse<PaginatedResponse<LikeRecord>>>(`/v1/workbench/like-records?${params.toString()}`);
if (res.code === 200 && res.data) {
return res.data;
}
return { list: [], total: 0, page, limit };
} catch (error) {
console.error('获取点赞记录失败:', error);
return { list: [], total: 0, page, limit };
}
}
export type { LikeTask, LikeRecord, CreateLikeTaskData };

View File

@@ -0,0 +1,30 @@
import request from "@/api/request";
/**
* 通用文件上传(走统一 request 拦截器401 跳转登录、code/msg 解析)
*/
export async function uploadFile(
file: File,
uploadUrl: string = "/v1/attachment/upload",
): Promise<string> {
const formData = new FormData();
formData.append("file", file);
const data = await request(
uploadUrl,
formData,
"POST",
{
skipErrorToast: true,
timeout: 30000,
} as Parameters<typeof request>[3],
0,
);
if (typeof data === "string" && data) return data;
const url = data?.url || data?.source || "";
if (!url) {
throw new Error("上传失败:未返回文件地址");
}
return url;
}

View File

@@ -1,69 +0,0 @@
import { get, post, put, del } from './request';
import type { ApiResponse, PaginatedResponse } from '@/types/common';
// 内容库类型定义
export interface ContentLibrary {
id: string;
name: string;
sourceType: number;
creatorName: string;
updateTime: string;
status: number;
}
// 内容库列表响应
export interface ContentLibraryListResponse {
code: number;
msg: string;
data: {
list: ContentLibrary[];
total: number;
page: number;
limit: number;
};
}
// 获取内容库列表
export const fetchContentLibraryList = async (
page: number = 1,
limit: number = 100,
keyword?: string
): Promise<ContentLibraryListResponse> => {
const params = new URLSearchParams();
params.append('page', page.toString());
params.append('limit', limit.toString());
if (keyword) {
params.append('keyword', keyword);
}
return get<ContentLibraryListResponse>(`/v1/content/library/list?${params.toString()}`);
};
// 内容库API对象
export const contentLibraryApi = {
// 获取内容库列表
async getList(page: number = 1, limit: number = 100, keyword?: string): Promise<ContentLibraryListResponse> {
return fetchContentLibraryList(page, limit, keyword);
},
// 创建内容库
async create(params: { name: string; sourceType: number }): Promise<ApiResponse<ContentLibrary>> {
return post<ApiResponse<ContentLibrary>>('/v1/content/library', params);
},
// 更新内容库
async update(id: string, params: Partial<ContentLibrary>): Promise<ApiResponse<ContentLibrary>> {
return put<ApiResponse<ContentLibrary>>(`/v1/content/library/${id}`, params);
},
// 删除内容库
async delete(id: string): Promise<ApiResponse<void>> {
return del<ApiResponse<void>>(`/v1/content/library/${id}`);
},
// 获取内容库详情
async getById(id: string): Promise<ApiResponse<ContentLibrary>> {
return get<ApiResponse<ContentLibrary>>(`/v1/content/library/${id}`);
},
};

View File

@@ -1,200 +0,0 @@
import { get, post, put, del } from './request';
import type { ApiResponse, PaginatedResponse } from '@/types/common';
import type {
Device,
DeviceStats,
DeviceTaskRecord,
QueryDeviceParams,
CreateDeviceParams,
UpdateDeviceParams,
DeviceStatus,
ServerDevicesResponse
} from '@/types/device';
const API_BASE = "/devices";
// 获取设备列表 - 连接到服务器/v1/devices接口
export const fetchDeviceList = async (page: number = 1, limit: number = 20, keyword?: string): Promise<ServerDevicesResponse> => {
const params = new URLSearchParams();
params.append('page', page.toString());
params.append('limit', limit.toString());
if (keyword) {
params.append('keyword', keyword);
}
return get<ServerDevicesResponse>(`/v1/devices?${params.toString()}`);
};
// 获取设备详情 - 连接到服务器/v1/devices/:id接口
export const fetchDeviceDetail = async (id: string | number): Promise<ApiResponse<any>> => {
return get<ApiResponse<any>>(`/v1/devices/${id}`);
};
// 获取设备关联的微信账号
export const fetchDeviceRelatedAccounts = async (id: string | number): Promise<ApiResponse<any>> => {
return get<ApiResponse<any>>(`/v1/wechats/related-device/${id}`);
};
// 获取设备操作记录
export const fetchDeviceHandleLogs = async (id: string | number, page: number = 1, limit: number = 10): Promise<ApiResponse<any>> => {
return get<ApiResponse<any>>(`/v1/devices/${id}/handle-logs?page=${page}&limit=${limit}`);
};
// 更新设备任务配置
export const updateDeviceTaskConfig = async (
config: {
deviceId: string | number;
autoAddFriend?: boolean;
autoReply?: boolean;
momentsSync?: boolean;
aiChat?: boolean;
}
): Promise<ApiResponse<any>> => {
return post<ApiResponse<any>>(`/v1/devices/task-config`, config);
};
// 删除设备
export const deleteDevice = async (id: number): Promise<ApiResponse<any>> => {
return del<ApiResponse<any>>(`/v1/devices/${id}`);
};
// 设备管理API
export const devicesApi = {
// 获取设备列表
async getList(page: number = 1, limit: number = 20, keyword?: string): Promise<ServerDevicesResponse> {
const params = new URLSearchParams();
params.append('page', page.toString());
params.append('limit', limit.toString());
if (keyword) {
params.append('keyword', keyword);
}
return get<ServerDevicesResponse>(`/v1/devices?${params.toString()}`);
},
// 获取设备二维码
async getQRCode(accountId: string): Promise<ApiResponse<{ qrCode: string }>> {
return post<ApiResponse<{ qrCode: string }>>('/v1/api/device/add', { accountId });
},
// 通过IMEI添加设备
async addByImei(imei: string, name: string): Promise<ApiResponse<any>> {
return post<ApiResponse<any>>('/v1/api/device/add-by-imei', { imei, name });
},
// 创建设备
async create(params: CreateDeviceParams): Promise<ApiResponse<Device>> {
return post<ApiResponse<Device>>(`${API_BASE}`, params);
},
// 更新设备
async update(params: UpdateDeviceParams): Promise<ApiResponse<Device>> {
return put<ApiResponse<Device>>(`${API_BASE}/${params.id}`, params);
},
// 获取设备详情
async getById(id: string): Promise<ApiResponse<Device>> {
return get<ApiResponse<Device>>(`${API_BASE}/${id}`);
},
// 查询设备列表
async query(params: QueryDeviceParams): Promise<ApiResponse<PaginatedResponse<Device>>> {
// 创建一个新对象用于构建URLSearchParams
const queryParams: Record<string, string> = {};
// 按需将params中的属性添加到queryParams
if (params.keyword) queryParams.keyword = params.keyword;
if (params.status) queryParams.status = params.status;
if (params.type) queryParams.type = params.type;
if (params.page) queryParams.page = params.page.toString();
if (params.pageSize) queryParams.pageSize = params.pageSize.toString();
// 特殊处理需要JSON序列化的属性
if (params.tags) queryParams.tags = JSON.stringify(params.tags);
if (params.dateRange) queryParams.dateRange = JSON.stringify(params.dateRange);
// 构建查询字符串
const queryString = new URLSearchParams(queryParams).toString();
return get<ApiResponse<PaginatedResponse<Device>>>(`${API_BASE}?${queryString}`);
},
// 删除设备(旧版本)
async deleteById(id: string): Promise<ApiResponse<void>> {
return del<ApiResponse<void>>(`${API_BASE}/${id}`);
},
// 删除设备(新版本)
async delete(id: number): Promise<ApiResponse<any>> {
return del<ApiResponse<any>>(`/v1/devices/${id}`);
},
// 重启设备
async restart(id: string): Promise<ApiResponse<void>> {
return post<ApiResponse<void>>(`${API_BASE}/${id}/restart`);
},
// 解绑设备
async unbind(id: string): Promise<ApiResponse<void>> {
return post<ApiResponse<void>>(`${API_BASE}/${id}/unbind`);
},
// 获取设备统计数据
async getStats(id: string): Promise<ApiResponse<DeviceStats>> {
return get<ApiResponse<DeviceStats>>(`${API_BASE}/${id}/stats`);
},
// 获取设备任务记录
async getTaskRecords(id: string, page = 1, pageSize = 20): Promise<ApiResponse<PaginatedResponse<DeviceTaskRecord>>> {
return get<ApiResponse<PaginatedResponse<DeviceTaskRecord>>>(`${API_BASE}/${id}/tasks?page=${page}&pageSize=${pageSize}`);
},
// 批量更新设备标签
async updateTags(ids: string[], tags: string[]): Promise<ApiResponse<void>> {
return post<ApiResponse<void>>(`${API_BASE}/tags`, { deviceIds: ids, tags });
},
// 批量导出设备数据
async exportDevices(ids: string[]): Promise<Blob> {
const response = await fetch(`${process.env.REACT_APP_API_BASE || 'http://localhost:3000/api'}${API_BASE}/export`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ deviceIds: ids }),
});
return response.blob();
},
// 检查设备在线状态
async checkStatus(ids: string[]): Promise<ApiResponse<Record<string, DeviceStatus>>> {
return post<ApiResponse<Record<string, DeviceStatus>>>(`${API_BASE}/status`, { deviceIds: ids });
},
// 获取设备关联的微信账号
async getRelatedAccounts(id: string | number): Promise<ApiResponse<any>> {
return get<ApiResponse<any>>(`/v1/wechats/related-device/${id}`);
},
// 获取设备操作记录
async getHandleLogs(id: string | number, page: number = 1, limit: number = 10): Promise<ApiResponse<any>> {
return get<ApiResponse<any>>(`/v1/devices/${id}/handle-logs?page=${page}&limit=${limit}`);
},
// 更新设备任务配置
async updateTaskConfig(config: {
deviceId: string | number;
autoAddFriend?: boolean;
autoReply?: boolean;
momentsSync?: boolean;
aiChat?: boolean;
}): Promise<ApiResponse<any>> {
return post<ApiResponse<any>>(`/v1/devices/task-config`, config);
},
// 获取设备任务配置
async getTaskConfig(id: string | number): Promise<ApiResponse<any>> {
return get<ApiResponse<any>>(`/v1/devices/${id}/task-config`);
},
};

View File

@@ -1,201 +0,0 @@
import { get, post, put, del } from './request';
// 群发推送任务类型定义
export interface GroupPushTask {
id: string;
name: string;
status: number; // 1: 运行中, 2: 已暂停
deviceCount: number;
targetGroups: string[];
pushCount: number;
successCount: number;
lastPushTime: string;
createTime: string;
creator: string;
pushInterval: number;
maxPushPerDay: number;
timeRange: { start: string; end: string };
messageType: 'text' | 'image' | 'video' | 'link';
messageContent: string;
targetTags: string[];
pushMode: 'immediate' | 'scheduled';
scheduledTime?: string;
}
// API响应类型
interface ApiResponse<T = any> {
code: number;
message: string;
data: T;
}
/**
* 获取群发推送任务列表
*/
export async function fetchGroupPushTasks(): Promise<GroupPushTask[]> {
try {
const response = await get<ApiResponse<GroupPushTask[]>>('/v1/workspace/group-push/tasks');
if (response.code === 200 && Array.isArray(response.data)) {
return response.data;
}
// 如果API不可用返回模拟数据
return getMockGroupPushTasks();
} catch (error) {
console.error('获取群发推送任务失败:', error);
// 返回模拟数据作为降级方案
return getMockGroupPushTasks();
}
}
/**
* 删除群发推送任务
*/
export async function deleteGroupPushTask(id: string): Promise<ApiResponse> {
try {
const response = await del<ApiResponse>(`/v1/workspace/group-push/tasks/${id}`);
return response;
} catch (error) {
console.error('删除群发推送任务失败:', error);
throw error;
}
}
/**
* 切换群发推送任务状态
*/
export async function toggleGroupPushTask(id: string, status: string): Promise<ApiResponse> {
try {
const response = await post<ApiResponse>(`/v1/workspace/group-push/tasks/${id}/toggle`, {
status
});
return response;
} catch (error) {
console.error('切换群发推送任务状态失败:', error);
throw error;
}
}
/**
* 复制群发推送任务
*/
export async function copyGroupPushTask(id: string): Promise<ApiResponse> {
try {
const response = await post<ApiResponse>(`/v1/workspace/group-push/tasks/${id}/copy`);
return response;
} catch (error) {
console.error('复制群发推送任务失败:', error);
throw error;
}
}
/**
* 创建群发推送任务
*/
export async function createGroupPushTask(taskData: Partial<GroupPushTask>): Promise<ApiResponse> {
try {
const response = await post<ApiResponse>('/v1/workspace/group-push/tasks', taskData);
return response;
} catch (error) {
console.error('创建群发推送任务失败:', error);
throw error;
}
}
/**
* 更新群发推送任务
*/
export async function updateGroupPushTask(id: string, taskData: Partial<GroupPushTask>): Promise<ApiResponse> {
try {
const response = await put<ApiResponse>(`/v1/workspace/group-push/tasks/${id}`, taskData);
return response;
} catch (error) {
console.error('更新群发推送任务失败:', error);
throw error;
}
}
/**
* 获取群发推送任务详情
*/
export async function getGroupPushTaskDetail(id: string): Promise<GroupPushTask> {
try {
const response = await get<ApiResponse<GroupPushTask>>(`/v1/workspace/group-push/tasks/${id}`);
if (response.code === 200 && response.data) {
return response.data;
}
throw new Error(response.message || '获取任务详情失败');
} catch (error) {
console.error('获取群发推送任务详情失败:', error);
throw error;
}
}
/**
* 模拟数据 - 当API不可用时使用
*/
function getMockGroupPushTasks(): GroupPushTask[] {
return [
{
id: '1',
name: '产品推广群发',
deviceCount: 2,
targetGroups: ['VIP客户群', '潜在客户群'],
pushCount: 156,
successCount: 142,
lastPushTime: '2025-02-06 13:12:35',
createTime: '2024-11-20 19:04:14',
creator: 'admin',
status: 1, // 运行中
pushInterval: 60,
maxPushPerDay: 200,
timeRange: { start: '09:00', end: '21:00' },
messageType: 'text',
messageContent: '新品上市,限时优惠!点击查看详情...',
targetTags: ['VIP客户', '高意向'],
pushMode: 'immediate',
},
{
id: '2',
name: '活动通知推送',
deviceCount: 1,
targetGroups: ['活动群', '推广群'],
pushCount: 89,
successCount: 78,
lastPushTime: '2024-03-04 14:09:35',
createTime: '2024-03-04 14:29:04',
creator: 'manager',
status: 2, // 已暂停
pushInterval: 120,
maxPushPerDay: 100,
timeRange: { start: '10:00', end: '20:00' },
messageType: 'image',
messageContent: '活动海报.jpg',
targetTags: ['活跃用户', '中意向'],
pushMode: 'scheduled',
scheduledTime: '2024-03-05 10:00:00',
},
{
id: '3',
name: '新客户欢迎消息',
deviceCount: 3,
targetGroups: ['新客户群', '体验群'],
pushCount: 234,
successCount: 218,
lastPushTime: '2025-02-06 15:30:22',
createTime: '2024-12-01 09:15:30',
creator: 'admin',
status: 1, // 运行中
pushInterval: 30,
maxPushPerDay: 300,
timeRange: { start: '08:00', end: '22:00' },
messageType: 'text',
messageContent: '欢迎加入我们的大家庭!这里有最新的产品信息和优惠活动...',
targetTags: ['新客户', '欢迎'],
pushMode: 'immediate',
},
];
}

View File

@@ -1,14 +0,0 @@
// 导出所有API相关的内容
export * from './auth';
export * from './utils';
export * from './interceptors';
export * from './request';
// 导出现有的API模块
export * from './devices';
export * from './scenarios';
export * from './wechat-accounts';
export * from './trafficDistribution';
// 默认导出request实例
export { default as request } from './request';

View File

@@ -1,152 +0,0 @@
import { refreshAuthToken, isTokenExpiringSoon, clearToken } from './utils';
// Token过期处理
export const handleTokenExpired = () => {
if (typeof window !== 'undefined') {
// 清除本地存储
clearToken();
// 跳转到登录页面
setTimeout(() => {
window.location.href = '/login';
}, 0);
}
};
// 显示API错误但不会重定向
export const showApiError = (error: any, defaultMessage: string = '请求失败') => {
if (typeof window === 'undefined') return; // 服务端不处理
let errorMessage = defaultMessage;
// 尝试从各种可能的错误格式中获取消息
if (error) {
if (typeof error === 'string') {
errorMessage = error;
} else if (error instanceof Error) {
errorMessage = error.message || defaultMessage;
} else if (typeof error === 'object') {
// 尝试从API响应中获取错误消息
errorMessage = error.msg || error.message || error.error || defaultMessage;
}
}
// 显示错误消息
console.error('API错误:', errorMessage);
// 这里可以集成toast系统
// 由于toast context在组件层级这里暂时用console
// 实际项目中可以通过事件系统或其他方式集成
};
// 请求拦截器 - 检查token是否需要刷新
export const requestInterceptor = async (): Promise<boolean> => {
if (typeof window === 'undefined') {
return true;
}
// 检查token是否即将过期
if (isTokenExpiringSoon()) {
try {
console.log('Token即将过期尝试刷新...');
const success = await refreshAuthToken();
if (!success) {
console.log('Token刷新失败需要重新登录');
handleTokenExpired();
return false;
}
console.log('Token刷新成功');
} catch (error) {
console.error('Token刷新过程中出错:', error);
handleTokenExpired();
return false;
}
}
return true;
};
// 响应拦截器 - 处理常见错误
export const responseInterceptor = (response: any, result: any) => {
// 处理401未授权
if (response?.status === 401 || (result && result.code === 401)) {
handleTokenExpired();
throw new Error('登录已过期,请重新登录');
}
// 处理403禁止访问
if (response?.status === 403 || (result && result.code === 403)) {
throw new Error('没有权限访问此资源');
}
// 处理404未找到
if (response?.status === 404 || (result && result.code === 404)) {
throw new Error('请求的资源不存在');
}
// 处理500服务器错误
if (response?.status >= 500 || (result && result.code >= 500)) {
throw new Error('服务器内部错误,请稍后重试');
}
return result;
};
// 错误拦截器 - 统一错误处理
export const errorInterceptor = (error: any) => {
console.error('API请求错误:', error);
let errorMessage = '网络请求失败,请稍后重试';
if (error) {
if (typeof error === 'string') {
errorMessage = error;
} else if (error instanceof Error) {
errorMessage = error.message;
} else if (error.name === 'TypeError' && error.message.includes('fetch')) {
errorMessage = '网络连接失败,请检查网络设置';
} else if (error.name === 'AbortError') {
errorMessage = '请求已取消';
}
}
showApiError(error, errorMessage);
throw new Error(errorMessage);
};
// 网络状态监听
export const setupNetworkListener = () => {
if (typeof window === 'undefined') return;
const handleOnline = () => {
console.log('网络已连接');
// 可以在这里添加网络恢复后的处理逻辑
};
const handleOffline = () => {
console.log('网络已断开');
showApiError(null, '网络连接已断开,请检查网络设置');
};
window.addEventListener('online', handleOnline);
window.addEventListener('offline', handleOffline);
// 返回清理函数
return () => {
window.removeEventListener('online', handleOnline);
window.removeEventListener('offline', handleOffline);
};
};
// 初始化拦截器
export const initInterceptors = () => {
// 设置网络监听
const cleanupNetwork = setupNetworkListener();
// 返回清理函数
return () => {
if (cleanupNetwork) {
cleanupNetwork();
}
};
};

View File

@@ -1,111 +0,0 @@
import { get, post, del } from './request';
import {
MomentsSyncTask,
CreateMomentsSyncData,
UpdateMomentsSyncData,
SyncRecord,
ApiResponse,
PaginatedResponse
} from '@/types/moments-sync';
// 获取朋友圈同步任务列表
export async function fetchMomentsSyncTasks(): Promise<MomentsSyncTask[]> {
try {
const res = await get<ApiResponse<PaginatedResponse<MomentsSyncTask>>>('/v1/workbench/list?type=2&page=1&limit=100');
if (res.code === 200 && res.data) {
return res.data.list || [];
}
return [];
} catch (error) {
console.error('获取朋友圈同步任务失败:', error);
return [];
}
}
// 获取单个任务详情
export async function fetchMomentsSyncTaskDetail(id: string): Promise<MomentsSyncTask | null> {
try {
const res = await get<ApiResponse<MomentsSyncTask>>(`/v1/workbench/detail?id=${id}`);
if (res.code === 200 && res.data) {
return res.data;
}
return null;
} catch (error) {
console.error('获取任务详情失败:', error);
return null;
}
}
// 创建朋友圈同步任务
export async function createMomentsSyncTask(data: CreateMomentsSyncData): Promise<ApiResponse> {
return post('/v1/workbench/create', {
...data,
type: 2 // 朋友圈同步类型
});
}
// 更新朋友圈同步任务
export async function updateMomentsSyncTask(data: UpdateMomentsSyncData): Promise<ApiResponse> {
return post('/v1/workbench/update', {
...data,
type: 2 // 朋友圈同步类型
});
}
// 删除朋友圈同步任务
export async function deleteMomentsSyncTask(id: string): Promise<ApiResponse> {
return del('/v1/workbench/delete', { params: { id } });
}
// 切换任务状态
export async function toggleMomentsSyncTask(id: string, status: string): Promise<ApiResponse> {
return post('/v1/workbench/update-status', { id, status });
}
// 复制朋友圈同步任务
export async function copyMomentsSyncTask(id: string): Promise<ApiResponse> {
return post('/v1/workbench/copy', { id });
}
// 获取同步记录
export async function fetchSyncRecords(
workbenchId: string,
page: number = 1,
limit: number = 20,
keyword?: string
): Promise<PaginatedResponse<SyncRecord>> {
try {
const params = new URLSearchParams({
workbenchId,
page: page.toString(),
limit: limit.toString()
});
if (keyword) {
params.append('keyword', keyword);
}
const res = await get<ApiResponse<PaginatedResponse<SyncRecord>>>(`/v1/workbench/sync-records?${params.toString()}`);
if (res.code === 200 && res.data) {
return res.data;
}
return { list: [], total: 0, page, limit };
} catch (error) {
console.error('获取同步记录失败:', error);
return { list: [], total: 0, page, limit };
}
}
// 手动同步
export async function syncMoments(id: string): Promise<ApiResponse> {
return post('/v1/workbench/sync', { id });
}
// 同步所有任务
export async function syncAllMoments(): Promise<ApiResponse> {
return post('/v1/workbench/sync-all', { type: 2 });
}
export type { MomentsSyncTask, SyncRecord, CreateMomentsSyncData };

View File

@@ -1,73 +1,107 @@
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
import { requestInterceptor, responseInterceptor, errorInterceptor } from './interceptors';
import axios, {
AxiosInstance,
AxiosRequestConfig,
Method,
AxiosResponse,
} from "axios";
import { Toast } from "antd-mobile";
import { useUserStore } from "@/store/module/user";
const DEFAULT_DEBOUNCE_GAP = 1000;
const debounceMap = new Map<string, number>();
// 创建axios实例
const request: AxiosInstance = axios.create({
baseURL: process.env.REACT_APP_API_BASE_URL || 'https://ckbapi.quwanzhi.com',
const instance: AxiosInstance = axios.create({
baseURL: (import.meta as any).env?.VITE_API_BASE_URL || "/api",
timeout: 20000,
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
});
// 请求拦截器
request.interceptors.request.use(
async (config) => {
// 检查token是否需要刷新
if (config.headers.Authorization) {
const shouldContinue = await requestInterceptor();
if (!shouldContinue) {
throw new Error('请求被拦截,需要重新登录');
instance.interceptors.request.use((config: any) => {
const token =
useUserStore.getState().token ||
localStorage.getItem("token") ||
"";
if (token) {
config.headers = config.headers || {};
config.headers["Authorization"] = `Bearer ${token}`;
}
return config;
});
instance.interceptors.response.use(
(res: AxiosResponse) => {
const { code, success, msg } = res.data || {};
if (code === 200 || success) {
return res.data.data ?? res.data;
}
if (code === 401) {
localStorage.removeItem("token");
useUserStore.getState().logout?.();
const currentPath = window.location.pathname + window.location.search;
if (currentPath === "/login") {
window.location.href = "/login";
} else {
window.location.href = `/login?returnUrl=${encodeURIComponent(currentPath)}`;
}
return Promise.reject(msg || "未授权,请重新登录");
}
// 添加token到请求头
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
if (code === 402) {
const payload = { code: 402, msg, data: res.data?.data };
if (!(res.config as any)?.skipErrorToast) {
Toast.show({ content: msg || "算力不足", position: "top" });
}
return Promise.reject(payload);
}
return config;
if (!(res.config as any)?.skipErrorToast) {
Toast.show({ content: msg || "接口错误", position: "top" });
}
return Promise.reject(msg || "接口错误");
},
err => {
// 网络错误静默处理,不弹出 Toast根据用户需求
// 如需恢复错误提示,取消下面一行注释:
// Toast.show({ content: err.message || "网络异常", position: "top" });
console.warn("[v0] Network error (silent):", err.message);
return Promise.reject(err);
},
(error) => {
return Promise.reject(error);
}
);
// 响应拦截器
request.interceptors.response.use(
(response: AxiosResponse) => {
// 处理响应数据
const result = response.data;
const processedResult = responseInterceptor(response, result);
return processedResult;
},
(error) => {
// 统一错误处理
return errorInterceptor(error);
export function request(
url: string,
data?: any,
method: Method = "GET",
config?: AxiosRequestConfig & { skipErrorToast?: boolean },
debounceGap?: number,
): Promise<any> {
const gap =
typeof debounceGap === "number" ? debounceGap : DEFAULT_DEBOUNCE_GAP;
const key = `${method}_${url}_${JSON.stringify(data)}`;
const now = Date.now();
const last = debounceMap.get(key) || 0;
if (gap > 0 && now - last < gap) {
// Toast.show({ content: '请求过于频繁,请稍后再试', position: 'top' });
return Promise.reject("请求过于频繁,请稍后再试");
}
);
debounceMap.set(key, now);
// 封装GET请求
export const get = <T = any>(url: string, config?: AxiosRequestConfig): Promise<T> => {
return request.get(url, config);
};
const axiosConfig: AxiosRequestConfig = {
url,
method,
...config,
} as AxiosRequestConfig & { skipErrorToast?: boolean };
// 封装POST请求
export const post = <T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> => {
return request.post(url, data, config);
};
// 如果是FormData不设置Content-Type让浏览器自动设置
if (data instanceof FormData) {
delete axiosConfig.headers?.["Content-Type"];
}
// 封装PUT请求
export const put = <T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> => {
return request.put(url, data, config);
};
if (method.toUpperCase() === "GET") {
axiosConfig.params = data;
} else {
axiosConfig.data = data;
}
return instance(axiosConfig);
}
// 封装DELETE请求
export const del = <T = any>(url: string, config?: AxiosRequestConfig): Promise<T> => {
return request.delete(url, config);
};
// 导出request实例
export { request };
export default request;
export default request;

View File

@@ -0,0 +1,89 @@
import axios, {
AxiosInstance,
AxiosRequestConfig,
Method,
AxiosResponse,
} from "axios";
import { Toast } from "antd-mobile";
import { useUserStore } from "@/store/module/user";
const DEFAULT_DEBOUNCE_GAP = 1000;
const debounceMap = new Map<string, number>();
interface RequestConfig extends AxiosRequestConfig {
headers: {
Client?: string;
"Content-Type"?: string;
};
}
const instance: AxiosInstance = axios.create({
baseURL: (import.meta as any).env?.VITE_API_BASE_URL2 || "/api",
timeout: 20000,
headers: {
"Content-Type": "application/json",
Client: "kefu-client",
},
});
instance.interceptors.request.use((config: any) => {
// 在每次请求时动态获取最新的 token2
const { token2 } = useUserStore.getState();
if (token2) {
config.headers = config.headers || {};
config.headers["Authorization"] = `bearer ${token2}`;
}
return config;
});
instance.interceptors.response.use(
(res: AxiosResponse) => {
return res.data;
},
err => {
// 处理401错误跳转到登录页面
if (err.response && err.response.status === 401) {
Toast.show({ content: "登录已过期,请重新登录", position: "top" });
// 获取当前路径,用于登录后跳回
const currentPath = window.location.pathname + window.location.search;
window.location.href = `/login?returnUrl=${encodeURIComponent(currentPath)}`;
return Promise.reject(err);
}
Toast.show({ content: err.message || "网络异常", position: "top" });
return Promise.reject(err);
},
);
export function request(
url: string,
data?: any,
method: Method = "GET",
config?: RequestConfig,
debounceGap?: number,
): Promise<any> {
const gap =
typeof debounceGap === "number" ? debounceGap : DEFAULT_DEBOUNCE_GAP;
const key = `${method}_${url}_${JSON.stringify(data)}`;
const now = Date.now();
const last = debounceMap.get(key) || 0;
if (gap > 0 && now - last < gap) {
// Toast.show({ content: '请求过于频繁,请稍后再试', position: 'top' });
return Promise.reject("请求过于频繁,请稍后再试");
}
debounceMap.set(key, now);
const axiosConfig: RequestConfig = {
url,
method,
...config,
};
if (method.toUpperCase() === "GET") {
axiosConfig.params = data;
} else {
axiosConfig.data = data;
}
return instance(axiosConfig);
}
export default request;

View File

@@ -1,327 +0,0 @@
import { get, del, post,put } from './request';
import type { ApiResponse } from '@/types/common';
// 服务器返回的场景数据类型
export interface SceneItem {
id: number;
name: string;
image: string;
status: number;
createTime: number;
updateTime: number | null;
deleteTime: number | null;
}
// 前端使用的场景数据类型
export interface Channel {
id: string;
name: string;
icon: string;
stats: {
daily: number;
growth: number;
};
link?: string;
plans?: Plan[];
}
// 计划类型
export interface Plan {
id: string;
name: string;
isNew?: boolean;
status: "active" | "paused" | "completed";
acquisitionCount: number;
}
// 任务类型
export interface Task {
id: string;
name: string;
status: number;
stats: {
devices: number;
acquired: number;
added: number;
};
lastUpdated: string;
executionTime: string;
nextExecutionTime: string;
trend: { date: string; customers: number }[];
}
// 消息内容类型
export interface MessageContent {
id: string;
type: string; // "text" | "image" | "video" | "file" | "miniprogram" | "link" | "group" 等
content?: string;
intervalUnit?: "seconds" | "minutes";
sendInterval?: number;
// 其他可选字段
[key: string]: any;
}
// 每天的消息计划
export interface MessagePlan {
day: number;
messages: MessageContent[];
}
// 海报类型
export interface Poster {
id: string;
name: string;
type: string;
preview: string;
}
// 标签类型
export interface Tag {
id: string;
name: string;
[key: string]: any;
}
// textUrl类型
export interface TextUrl {
apiKey: string;
originalString?: string;
sign?: string;
fullUrl: string;
}
// 计划详情类型
export interface PlanDetail {
id: number;
name: string;
scenario: number;
scenarioTags: Tag[];
customTags: Tag[];
posters: Poster[];
device: string[];
enabled: boolean;
addInterval: number;
remarkFormat: string;
endTime: string;
greeting: string;
startTime: string;
remarkType: string;
addFriendInterval: number;
messagePlans: MessagePlan[];
sceneId: number | string;
userId: number;
companyId: number;
status: number;
apiKey: string;
wxMinAppSrc?: any;
textUrl: TextUrl;
[key: string]: any;
}
/**
* 获取获客场景列表
*
* @param params 查询参数
* @returns 获客场景列表
*/
export const fetchScenes = async (params: {
page?: number;
limit?: number;
keyword?: string;
} = {}): Promise<ApiResponse<SceneItem[]>> => {
const { page = 1, limit = 10, keyword = "" } = params;
const queryParams = new URLSearchParams();
queryParams.append("page", String(page));
queryParams.append("limit", String(limit));
if (keyword) {
queryParams.append("keyword", keyword);
}
try {
return await get<ApiResponse<SceneItem[]>>(`/v1/plan/scenes?${queryParams.toString()}`);
} catch (error) {
console.error("Error fetching scenes:", error);
// 返回一个错误响应
return {
code: 500,
msg: "获取场景列表失败",
data: []
};
}
};
/**
* 获取场景详情
*
* @param id 场景ID
* @returns 场景详情
*/
export const fetchSceneDetail = async (id: string | number): Promise<ApiResponse<SceneItem>> => {
try {
return await get<ApiResponse<SceneItem>>(`/v1/plan/scenes/${id}`);
} catch (error) {
console.error("Error fetching scene detail:", error);
return {
code: 500,
msg: "获取场景详情失败",
data: null
};
}
};
/**
* 获取场景名称
*
* @param channel 场景标识
* @returns 场景名称
*/
export const fetchSceneName = async (channel: string): Promise<ApiResponse<{ name: string }>> => {
try {
return await get<ApiResponse<{ name: string }>>(`/v1/plan/scenes-detail?id=${channel}`);
} catch (error) {
console.error("Error fetching scene name:", error);
return {
code: 500,
msg: "获取场景名称失败",
data: { name: channel }
};
}
};
/**
* 获取计划列表
*
* @param channel 场景标识
* @param page 页码
* @param pageSize 每页数量
* @returns 计划列表
*/
export const fetchPlanList = async (
channel: string,
page: number = 1,
pageSize: number = 10
): Promise<ApiResponse<{ list: Task[]; total: number }>> => {
try {
return await get<ApiResponse<{ list: Task[]; total: number }>>(
`/v1/plan/list?sceneId=${channel}&page=${page}&pageSize=${pageSize}`
);
} catch (error) {
console.error("Error fetching plan list:", error);
return {
code: 500,
msg: "获取计划列表失败",
data: { list: [], total: 0 }
};
}
};
/**
* 复制计划
*
* @param planId 计划ID
* @returns 复制结果
*/
export const copyPlan = async (planId: string): Promise<ApiResponse<any>> => {
try {
return await get<ApiResponse<any>>(`/v1/plan/copy?planId=${planId}`);
} catch (error) {
console.error("Error copying plan:", error);
return {
code: 500,
msg: "复制计划失败",
data: null
};
}
};
/**
* 删除计划
*
* @param planId 计划ID
* @returns 删除结果
*/
export const deletePlan = async (planId: string): Promise<ApiResponse<any>> => {
try {
return await del<ApiResponse<any>>(`/v1/plan/delete?planId=${planId}`);
} catch (error) {
console.error("Error deleting plan:", error);
return {
code: 500,
msg: "删除计划失败",
data: null
};
}
};
/**
* 获取计划详情
*
* @param planId 计划ID
* @returns 计划详情
*/
export const fetchPlanDetail = async (planId: string): Promise<ApiResponse<PlanDetail>> => {
try {
return await get<ApiResponse<PlanDetail>>(`/v1/plan/detail?planId=${planId}`);
} catch (error) {
console.error("Error fetching plan detail:", error);
return {
code: 500,
msg: "获取计划详情失败",
data: null
};
}
};
/**
* 将服务器返回的场景数据转换为前端展示需要的格式
*
* @param item 服务器返回的场景数据
* @returns 前端展示的场景数据
*/
export const transformSceneItem = (item: SceneItem): Channel => {
// 为每个场景生成随机的"今日"数据和"增长百分比"
const dailyCount = Math.floor(Math.random() * 100);
const growthPercent = Math.floor(Math.random() * 40) - 10; // -10% 到 30% 的随机值
// 默认图标(如果服务器没有返回)
const defaultIcon = "/assets/icons/poster-icon.svg";
return {
id: String(item.id),
name: item.name,
icon: item.image || defaultIcon,
stats: {
daily: dailyCount,
growth: growthPercent
}
};
};
export const getPlanScenes = () => get<any>('/v1/plan/scenes');
export async function createScenarioPlan(data: any) {
return post('/v1/plan/create', data);
}
// 编辑计划
export async function updateScenarioPlan(planId: number | string, data: any) {
return await put(`/v1/plan/update?planId=${planId}`, data);
}
/**
* 获取计划小程序二维码
* @param taskid 任务ID
* @returns base64二维码
*/
export const getWxMinAppCode = async (taskId: string): Promise<{ code: number; data?: string; msg?: string }> => {
try {
return await get<{ code: number; data?: string; msg?: string }>(
`/v1/plan/getWxMinAppCode?taskId=${ taskId }`,
);
} catch (error) {
return { code: 500, msg: '获取小程序二维码失败' };
}
};

View File

@@ -1,227 +0,0 @@
import { get, post, put, del } from './request';
import type { ApiResponse } from '@/types/common';
// 工作台任务类型
export enum WorkbenchTaskType {
MOMENTS_SYNC = 1, // 朋友圈同步
GROUP_PUSH = 2, // 社群推送
AUTO_LIKE = 3, // 自动点赞
AUTO_GROUP = 4, // 自动建群
TRAFFIC_DISTRIBUTION = 5, // 流量分发
}
// 工作台任务状态
export enum WorkbenchTaskStatus {
PENDING = 0, // 待处理
RUNNING = 1, // 运行中
PAUSED = 2, // 已暂停
COMPLETED = 3, // 已完成
FAILED = 4, // 失败
}
// 账号类型
export interface Account {
id: string;
userName: string;
realName: string;
nickname: string;
memo: string;
}
// 账号列表响应类型
export interface AccountListResponse {
list: Account[];
total: number;
page: number;
limit: number;
}
// 流量池类型
export interface TrafficPool {
id: string;
name: string;
count: number;
description?: string;
deviceIds: string[];
createTime?: string;
updateTime?: string;
}
// 流量池列表响应类型
export interface TrafficPoolListResponse {
list: TrafficPool[];
total: number;
page: number;
pageSize: number;
}
// 流量分发规则类型
export interface DistributionRule {
id: number;
name: string;
type: number;
status: number;
autoStart: number;
createTime: string;
updateTime: string;
companyId: number;
config?: {
id: number;
workbenchId: number;
distributeType: number; // 1-均分配, 2-优先级分配, 3-比例分配
maxPerDay: number; // 每日最大分配量
timeType: number; // 1-全天, 2-自定义时间段
startTime: string; // 开始时间
endTime: string; // 结束时间
account: string[]; // 账号列表
devices: string[]; // 设备列表
pools: string[]; // 流量池列表
createTime: string;
updateTime: string;
lastUpdated: string;
total: {
dailyAverage: number; // 日均分发量
totalAccounts: number; // 分发账户总数
deviceCount: number; // 分发设备数量
poolCount: number; // 流量池数量
totalUsers: number; // 总用户数
};
};
auto_like?: any;
moments_sync?: any;
group_push?: any;
}
// 流量分发列表响应类型
export interface TrafficDistributionListResponse {
list: DistributionRule[];
total: number;
page: number;
limit: number;
}
/**
* 获取账号列表
* @param params 查询参数
* @returns 账号列表
*/
export const fetchAccountList = async (params: {
page?: number; // 页码
limit?: number; // 每页数量
keyword?: string; // 搜索关键词
} = {}): Promise<ApiResponse<AccountListResponse>> => {
const { page = 1, limit = 10, keyword = "" } = params;
const queryParams = new URLSearchParams();
queryParams.append('page', page.toString());
queryParams.append('limit', limit.toString());
if (keyword) {
queryParams.append('keyword', keyword);
}
return get<ApiResponse<AccountListResponse>>(`/v1/workbench/account-list?${queryParams.toString()}`);
};
/**
* 获取设备标签(流量池)列表
* @param params 查询参数
* @returns 流量池列表
*/
export const fetchDeviceLabels = async (params: {
deviceIds: string[]; // 设备ID列表
page?: number; // 页码
pageSize?: number; // 每页数量
keyword?: string; // 搜索关键词
}): Promise<ApiResponse<TrafficPoolListResponse>> => {
const { deviceIds, page = 1, pageSize = 10, keyword = "" } = params;
const queryParams = new URLSearchParams();
queryParams.append('deviceIds', deviceIds.join(','));
queryParams.append('page', page.toString());
queryParams.append('pageSize', pageSize.toString());
if (keyword) {
queryParams.append('keyword', keyword);
}
return get<ApiResponse<TrafficPoolListResponse>>(`/v1/workbench/device-labels?${queryParams.toString()}`);
};
/**
* 获取流量分发规则列表
* @param params 查询参数
* @returns 流量分发规则列表
*/
export const fetchDistributionRules = async (params: {
page?: number;
limit?: number;
keyword?: string;
} = {}): Promise<ApiResponse<TrafficDistributionListResponse>> => {
const { page = 1, limit = 10, keyword = "" } = params;
const queryParams = new URLSearchParams();
queryParams.append('type', WorkbenchTaskType.TRAFFIC_DISTRIBUTION.toString());
queryParams.append('page', page.toString());
queryParams.append('limit', limit.toString());
if (keyword) {
queryParams.append('keyword', keyword);
}
return get<ApiResponse<TrafficDistributionListResponse>>(`/v1/workbench/list?${queryParams.toString()}`);
};
/**
* 获取流量分发规则详情
* @param id 规则ID
* @returns 流量分发规则详情
*/
export const fetchDistributionRuleDetail = async (id: string): Promise<ApiResponse<DistributionRule>> => {
return get<ApiResponse<DistributionRule>>(`/v1/workbench/detail?id=${id}`);
};
/**
* 创建流量分发规则
* @param params 创建参数
* @returns 创建结果
*/
export const createDistributionRule = async (params: any): Promise<ApiResponse<{ id: string }>> => {
return post<ApiResponse<{ id: string }>>('/v1/workbench/create', {
...params,
type: WorkbenchTaskType.TRAFFIC_DISTRIBUTION
});
};
/**
* 更新流量分发规则
* @param id 规则ID
* @param params 更新参数
* @returns 更新结果
*/
export const updateDistributionRule = async (id : string, params: any): Promise<ApiResponse<any>> => {
return post<ApiResponse<any>>(`/v1/workbench/update`, {
id: id,
...params,
type: WorkbenchTaskType.TRAFFIC_DISTRIBUTION
});
};
/**
* 删除流量分发规则
* @param id 规则ID
* @returns 删除结果
*/
export const deleteDistributionRule = async (id: string): Promise<ApiResponse<any>> => {
return del<ApiResponse<any>>(`/v1/workbench/delete?id=${id}`);
};
/**
* 启动/暂停流量分发规则
* @param id 规则ID
* @param status 状态1-启动0-暂停
* @returns 操作结果
*/
export const toggleDistributionRuleStatus = async (id: string, status: 0 | 1): Promise<ApiResponse<any>> => {
return post<ApiResponse<any>>('/v1/workbench/update-status', { id, status });
};

View File

@@ -1,18 +0,0 @@
import { request } from './request';
import type { AxiosResponse } from 'axios';
// 上传图片,返回图片地址
export async function uploadImage(file: File): Promise<string> {
const formData = new FormData();
formData.append('file', file);
const response: AxiosResponse<any> = await request.post('/v1/attachment/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
const res = response.data || response;
if (res?.url) {
return res.url;
}
throw new Error(res?.msg || '图片上传失败');
}

View File

@@ -1,195 +0,0 @@
import { authApi } from './auth';
import { get, post, put, del } from './request';
import type { ApiResponse, PaginatedResponse } from '@/types/common';
// 设置token到localStorage
export const setToken = (token: string) => {
if (typeof window !== 'undefined') {
localStorage.setItem('token', token);
}
};
// 获取token
export const getToken = (): string | null => {
if (typeof window !== 'undefined') {
return localStorage.getItem('token');
}
return null;
};
// 清除token
export const clearToken = () => {
if (typeof window !== 'undefined') {
localStorage.removeItem('token');
localStorage.removeItem('userInfo');
localStorage.removeItem('token_expired');
localStorage.removeItem('s2_accountId');
}
};
// 验证token是否有效
export const validateToken = async (): Promise<boolean> => {
try {
const response = await authApi.getUserInfo();
return response.code === 200;
} catch (error) {
console.error('Token验证失败:', error);
return false;
}
};
// 刷新令牌
export const refreshAuthToken = async (): Promise<boolean> => {
if (typeof window === 'undefined') {
return false;
}
try {
const response = await authApi.refreshToken();
if (response.code === 200 && response.data?.token) {
setToken(response.data.token);
// 更新过期时间
if (response.data.token_expired) {
localStorage.setItem('token_expired', response.data.token_expired);
}
return true;
}
return false;
} catch (error) {
console.error('刷新Token失败:', error);
return false;
}
};
// 检查token是否即将过期
export const isTokenExpiringSoon = (): boolean => {
if (typeof window === 'undefined') {
return false;
}
const tokenExpired = localStorage.getItem('token_expired');
if (!tokenExpired) return true;
try {
const expiredTime = new Date(tokenExpired).getTime();
const currentTime = new Date().getTime();
// 提前10分钟认为即将过期
return currentTime >= (expiredTime - 10 * 60 * 1000);
} catch (error) {
console.error('解析token过期时间失败:', error);
return true;
}
};
// 检查token是否已过期
export const isTokenExpired = (): boolean => {
if (typeof window === 'undefined') {
return false;
}
const tokenExpired = localStorage.getItem('token_expired');
if (!tokenExpired) return true;
try {
const expiredTime = new Date(tokenExpired).getTime();
const currentTime = new Date().getTime();
// 提前5分钟认为过期给刷新留出时间
return currentTime >= (expiredTime - 5 * 60 * 1000);
} catch (error) {
console.error('解析token过期时间失败:', error);
return true;
}
};
// 请求去重器
class RequestDeduplicator {
private pendingRequests = new Map<string, Promise<any>>();
async deduplicate<T>(key: string, requestFn: () => Promise<T>): Promise<T> {
if (this.pendingRequests.has(key)) {
return this.pendingRequests.get(key)!;
}
const promise = requestFn();
this.pendingRequests.set(key, promise);
try {
const result = await promise;
return result;
} finally {
this.pendingRequests.delete(key);
}
}
getPendingCount(): number {
return this.pendingRequests.size;
}
clear(): void {
this.pendingRequests.clear();
}
}
// 请求取消管理器
class RequestCancelManager {
private abortControllers = new Map<string, AbortController>();
createController(key: string): AbortController {
// 取消之前的请求
this.cancelRequest(key);
const controller = new AbortController();
this.abortControllers.set(key, controller);
return controller;
}
cancelRequest(key: string): void {
const controller = this.abortControllers.get(key);
if (controller) {
controller.abort();
this.abortControllers.delete(key);
}
}
cancelAllRequests(): void {
this.abortControllers.forEach(controller => controller.abort());
this.abortControllers.clear();
}
getController(key: string): AbortController | undefined {
return this.abortControllers.get(key);
}
}
// 导出单例实例
export const requestDeduplicator = new RequestDeduplicator();
export const requestCancelManager = new RequestCancelManager();
/**
* 通用文件上传方法(支持图片、文件)
* @param {File} file - 要上传的文件对象
* @param {string} [uploadUrl='/v1/attachment/upload'] - 上传接口地址
* @returns {Promise<string>} - 上传成功后返回文件url
*/
export async function uploadFile(file: File, uploadUrl: string = '/v1/attachment/upload'): Promise<string> {
try {
// 创建 FormData 对象用于文件上传
const formData = new FormData();
formData.append('file', file);
// 使用 post 方法上传文件,设置正确的 Content-Type
const res = await post(uploadUrl, formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
// 检查响应结果
if (res?.code === 200 && res?.data?.url) {
return res.data.url;
} else {
throw new Error(res?.msg || '文件上传失败');
}
} catch (e: any) {
throw new Error(e?.message || '文件上传失败');
}
}

View File

@@ -1,207 +0,0 @@
import { get, post, put } from './request';
import type { ApiResponse } from '@/types/common';
// 添加接口返回数据类型定义
interface WechatAccountSummary {
accountAge: string;
activityLevel: {
allTimes: number;
dayTimes: number;
};
accountWeight: {
scope: number;
ageWeight: number;
activityWeigth: number;
restrictWeight: number;
realNameWeight: number;
};
statistics: {
todayAdded: number;
addLimit: number;
};
restrictions: {
id: number;
level: string;
reason: string;
date: string;
}[];
}
interface QueryWechatAccountParams {
page?: number;
limit?: number;
keyword?: string;
sort?: string;
order?: string;
}
/**
* 获取微信账号列表
* @param params 查询参数
* @returns 微信账号列表响应
*/
export const fetchWechatAccountList = async (params: QueryWechatAccountParams = {}): Promise<ApiResponse<{
list: any[];
total: number;
page: number;
limit: number;
}>> => {
const queryParams = new URLSearchParams();
// 添加查询参数
if (params.page) queryParams.append('page', params.page.toString());
if (params.limit) queryParams.append('limit', params.limit.toString());
if (params.keyword) queryParams.append('nickname', params.keyword); // 使用nickname作为关键词搜索参数
if (params.sort) queryParams.append('sort', params.sort);
if (params.order) queryParams.append('order', params.order);
// 发起API请求
return get<ApiResponse<{
list: any[];
total: number;
page: number;
limit: number;
}>>(`/v1/wechats?${queryParams.toString()}`);
};
/**
* 刷新微信账号状态
* @returns 刷新结果
*/
export const refreshWechatAccounts = async (): Promise<ApiResponse<any>> => {
return put<ApiResponse<any>>('/v1/wechats/refresh', {});
};
/**
* 执行微信好友转移
* @param sourceId 源微信账号ID
* @param targetId 目标微信账号ID
* @returns 转移结果
*/
export const transferWechatFriends = async (sourceId: string | number, targetId: string | number): Promise<ApiResponse<any>> => {
return post<ApiResponse<any>>('/v1/wechats/transfer-friends', {
source_id: sourceId,
target_id: targetId
});
};
/**
* 将服务器返回的微信账号数据转换为前端使用的格式
* @param serverAccount 服务器返回的微信账号数据
* @returns 前端使用的微信账号数据
*/
export const transformWechatAccount = (serverAccount: any): any => {
// 从deviceInfo中提取设备信息
let deviceName = '';
if (serverAccount.deviceInfo) {
// 尝试解析设备信息字符串
const deviceInfo = serverAccount.deviceInfo.split(' ');
if (deviceInfo.length > 0) {
// 提取设备名称
if (deviceInfo.length > 1) {
deviceName = deviceInfo[1] ? deviceInfo[1].replace(/[()]/g, '').trim() : '';
}
}
}
// 如果没有设备名称,使用备用名称
if (!deviceName) {
deviceName = serverAccount.deviceMemo || '未命名设备';
}
// 假设每天最多可添加20个好友
const maxDailyAdds = 20;
const todayAdded = serverAccount.todayNewFriendCount || 0;
return {
id: serverAccount.id.toString(),
avatar: serverAccount.avatar || '',
nickname: serverAccount.nickname || serverAccount.accountNickname || '未命名',
wechatId: serverAccount.wechatId || '',
deviceId: serverAccount.deviceId || '',
deviceName,
friendCount: serverAccount.totalFriend || 0,
todayAdded,
remainingAdds: serverAccount.canAddFriendCount || (maxDailyAdds - todayAdded),
maxDailyAdds,
status: serverAccount.wechatStatus === 1 ? "normal" : "abnormal" as "normal" | "abnormal",
lastActive: new Date().toLocaleString() // 服务端未提供,使用当前时间
};
};
/**
* 获取微信好友列表
* @param wechatId 微信账号ID
* @param page 页码
* @param pageSize 每页数量
* @param searchQuery 搜索关键词
* @returns 好友列表数据
*/
export const fetchWechatFriends = async (wechatId: string, page: number = 1, pageSize: number = 20, searchQuery: string = ''): Promise<ApiResponse<{
list: any[];
total: number;
page: number;
limit: number;
}>> => {
try {
const queryParams = new URLSearchParams();
queryParams.append('page', page.toString());
queryParams.append('limit', pageSize.toString());
if (searchQuery) {
queryParams.append('search', searchQuery);
}
return get<ApiResponse<{
list: any[];
total: number;
page: number;
limit: number;
}>>(`/v1/wechats/${wechatId}/friends?${queryParams.toString()}`);
} catch (error) {
console.error("获取好友列表失败:", error);
throw error;
}
};
/**
* 获取微信账号概览信息
* @param id 微信账号ID
* @returns 微信账号概览信息
*/
export const fetchWechatAccountSummary = async (wechatId: string): Promise<ApiResponse<WechatAccountSummary>> => {
try {
return get<ApiResponse<WechatAccountSummary>>(`/v1/wechats/${wechatId}/summary`);
} catch (error) {
console.error("获取账号概览失败:", error);
throw error;
}
};
/**
* 获取好友详情信息
* @param wechatId 微信账号ID
* @param friendId 好友ID
* @returns 好友详情信息
*/
export interface WechatFriendDetail {
id: number;
avatar: string;
nickname: string;
region: string;
wechatId: string;
addDate: string;
tags: string[];
memo: string;
source: string;
}
export const fetchWechatFriendDetail = async (wechatId: string): Promise<ApiResponse<WechatFriendDetail>> => {
try {
return get<ApiResponse<WechatFriendDetail>>(`/v1/wechats/${wechatId}/friend-detail`);
} catch (error) {
console.error("获取好友详情失败:", error);
throw error;
}
};

View File

@@ -0,0 +1,30 @@
/* 弹层在底栏之下(底栏 10200弹层本体 10150为 Tab 留出空间 */
.popup {
--z-index: 10150;
}
.popupBody {
bottom: calc(
var(--ckb-tabbar-h, 64px) + env(safe-area-inset-bottom, 0px)
) !important;
height: calc(
100dvh - var(--ckb-tabbar-h, 64px) - env(safe-area-inset-bottom, 0px) - 8vh
) !important;
max-height: calc(
100dvh - var(--ckb-tabbar-h, 64px) - env(safe-area-inset-bottom, 0px) - 8vh
) !important;
display: flex !important;
flex-direction: column !important;
overflow: hidden !important;
padding: 0 !important;
border-radius: 20px 20px 0 0;
}
.panelWrap {
flex: 1;
min-height: 0;
height: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
}

View File

@@ -0,0 +1,59 @@
import React, { useEffect } from "react";
import { Popup } from "antd-mobile";
import { useLocation } from "react-router-dom";
import { useAIAssistantStore } from "@/store/module/aiAssistant";
import { AIAssistantPanel } from "@/pages/mobile/workspace/ai-assistant/AIAssistant";
import styles from "./AIAssistantGlobalSheet.module.scss";
/** 底栏切换路由时自动收起小宝 AI 弹层 */
const AIAssistantRouteSync: React.FC = () => {
const location = useLocation();
const { visible, close } = useAIAssistantStore();
const prevPathRef = React.useRef(location.pathname);
useEffect(() => {
if (prevPathRef.current !== location.pathname) {
if (visible) close();
prevPathRef.current = location.pathname;
}
}, [location.pathname, visible, close]);
return null;
};
const AIAssistantGlobalSheet: React.FC = () => {
const { visible, initialPrompt, openId, close } = useAIAssistantStore();
return (
<>
<AIAssistantRouteSync />
<Popup
visible={visible}
onMaskClick={close}
position="bottom"
destroyOnClose
className={styles.popup}
bodyClassName={styles.popupBody}
style={
{
"--z-index": 10150,
} as React.CSSProperties
}
maskStyle={{ zIndex: 10140 }}
>
{visible && (
<div className={styles.panelWrap}>
<AIAssistantPanel
key={`ai-panel-${openId}`}
embedded
initialPrompt={initialPrompt}
onClose={close}
/>
</div>
)}
</Popup>
</>
);
};
export default AIAssistantGlobalSheet;

View File

@@ -0,0 +1,10 @@
import request from "@/api/request";
// 获取好友列表
export function getAccountList(params: {
page: number;
limit: number;
keyword?: string;
}) {
return request("/v1/workbench/account-list", params, "GET");
}

View File

@@ -0,0 +1,35 @@
// 账号对象类型
export interface AccountItem {
id: number;
userName: string;
realName: string;
departmentName: string;
avatar?: string;
[key: string]: any;
}
//弹窗的
export interface SelectionPopupProps {
visible: boolean;
onVisibleChange: (visible: boolean) => void;
selectedOptions: AccountItem[];
onSelect: (options: AccountItem[]) => void;
readonly?: boolean;
onConfirm?: (selectedOptions: AccountItem[]) => void;
}
// 组件属性接口
export interface AccountSelectionProps {
selectedOptions: AccountItem[];
onSelect: (options: AccountItem[]) => void;
accounts?: AccountItem[]; // 可选:用于在外层显示已选账号详情
placeholder?: string;
className?: string;
visible?: boolean;
onVisibleChange?: (visible: boolean) => void;
selectedListMaxHeight?: number;
showInput?: boolean;
showSelectedList?: boolean;
readonly?: boolean;
onConfirm?: (selectedOptions: AccountItem[]) => void;
accountGroups?: any[]; // 传递账号组数据
}

View File

@@ -0,0 +1,233 @@
.inputWrapper {
position: relative;
}
.inputIcon {
position: absolute;
left: 12px;
top: 50%;
transform: translateY(-50%);
color: #bdbdbd;
font-size: 20px;
}
.input {
padding-left: 38px !important;
height: 48px;
border-radius: 16px !important;
border: 1px solid #e5e6eb !important;
font-size: 16px;
background: #f8f9fa;
}
.popupContainer {
display: flex;
flex-direction: column;
height: 100vh;
background: #fff;
}
.popupHeader {
padding: 24px;
}
.popupTitle {
text-align: center;
font-size: 20px;
font-weight: 600;
margin-bottom: 24px;
}
.searchWrapper {
position: relative;
margin-bottom: 16px;
}
.searchInput {
padding-left: 40px !important;
padding-top: 8px !important;
padding-bottom: 8px !important;
border-radius: 24px !important;
border: 1px solid #e5e6eb !important;
font-size: 15px;
background: #f8f9fa;
}
.searchIcon {
position: absolute;
left: 12px;
top: 50%;
transform: translateY(-50%);
color: #bdbdbd;
font-size: 16px;
}
.clearBtn {
position: absolute;
right: 8px;
top: 50%;
transform: translateY(-50%);
height: 24px;
width: 24px;
border-radius: 50%;
min-width: 24px;
}
.friendList {
height: 100%;
min-height: 0;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
.friendListInner {
border-top: 1px solid #f0f0f0;
}
.friendItem {
display: flex;
align-items: center;
padding: 16px 24px;
border-bottom: 1px solid #f0f0f0;
cursor: pointer;
transition: background 0.2s;
&:hover {
background: #f5f6fa;
}
}
.radioWrapper {
margin-right: 12px;
display: flex;
align-items: center;
justify-content: center;
}
.radioSelected {
width: 20px;
height: 20px;
border-radius: 50%;
border: 2px solid #1890ff;
display: flex;
align-items: center;
justify-content: center;
}
.radioUnselected {
width: 20px;
height: 20px;
border-radius: 50%;
border: 2px solid #e5e6eb;
display: flex;
align-items: center;
justify-content: center;
}
.radioDot {
width: 12px;
height: 12px;
border-radius: 50%;
background: #1890ff;
}
.friendInfo {
display: flex;
align-items: center;
gap: 12px;
flex: 1;
}
.friendAvatar {
width: 40px;
height: 40px;
border-radius: 50%;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 14px;
font-weight: 500;
overflow: hidden;
}
.avatarImg {
width: 100%;
height: 100%;
object-fit: cover;
}
.friendDetail {
flex: 1;
}
.friendName {
font-weight: 500;
font-size: 16px;
color: #222;
margin-bottom: 2px;
}
.friendId {
font-size: 13px;
color: #888;
margin-bottom: 2px;
}
.friendCustomer {
font-size: 13px;
color: #bdbdbd;
}
.loadingBox {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.loadingText {
color: #888;
font-size: 15px;
}
.emptyBox {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.emptyText {
color: #888;
font-size: 15px;
}
.paginationRow {
border-top: 1px solid #f0f0f0;
padding: 16px;
display: flex;
align-items: center;
justify-content: space-between;
background: #fff;
}
.totalCount {
font-size: 14px;
color: #888;
}
.paginationControls {
display: flex;
align-items: center;
gap: 8px;
}
.pageBtn {
padding: 0 8px;
height: 32px;
min-width: 32px;
}
.pageInfo {
font-size: 14px;
color: #222;
}
.popupFooter {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px;
border-top: 1px solid #f0f0f0;
background: #fff;
}
.selectedCount {
font-size: 14px;
color: #888;
}
.footerBtnGroup {
display: flex;
gap: 12px;
}
.cancelBtn {
padding: 0 24px;
border-radius: 24px;
border: 1px solid #e5e6eb;
}
.confirmBtn {
padding: 0 24px;
border-radius: 24px;
}

View File

@@ -0,0 +1,139 @@
import React, { useState } from "react";
import { SearchOutlined, DeleteOutlined } from "@ant-design/icons";
import { Button, Input } from "antd";
import style from "./index.module.scss";
import SelectionPopup from "./selectionPopup";
import { AccountItem, AccountSelectionProps } from "./data";
export default function AccountSelection({
selectedOptions,
onSelect,
accounts: propAccounts = [],
placeholder = "选择账号",
className = "",
visible,
onVisibleChange,
selectedListMaxHeight = 300,
showInput = true,
showSelectedList = true,
readonly = false,
onConfirm,
}: AccountSelectionProps) {
const [popupVisible, setPopupVisible] = useState(false);
// 受控弹窗逻辑
const realVisible = visible !== undefined ? visible : popupVisible;
const setRealVisible = (v: boolean) => {
if (onVisibleChange) onVisibleChange(v);
if (visible === undefined) setPopupVisible(v);
};
// 打开弹窗
const openPopup = () => {
if (readonly) return;
setRealVisible(true);
};
// 获取显示文本
const getDisplayText = () => {
if (selectedOptions.length === 0) return "";
return `已选择 ${selectedOptions.length} 个账号`;
};
// 删除已选账号
const handleRemoveAccount = (id: number) => {
if (readonly) return;
onSelect(selectedOptions.filter(d => d.id !== id));
};
return (
<>
{/* 输入框 */}
{showInput && (
<div className={`${style.inputWrapper} ${className}`}>
<Input
placeholder={placeholder}
value={getDisplayText()}
onClick={openPopup}
prefix={<SearchOutlined />}
allowClear={!readonly}
size="large"
readOnly={readonly}
disabled={readonly}
style={
readonly ? { background: "#f5f5f5", cursor: "not-allowed" } : {}
}
/>
</div>
)}
{/* 已选账号列表窗口 */}
{showSelectedList && selectedOptions.length > 0 && (
<div
className={style.selectedListWindow}
style={{
maxHeight: selectedListMaxHeight,
overflowY: "auto",
marginTop: 8,
border: "1px solid #e5e6eb",
borderRadius: 8,
background: "#fff",
}}
>
{selectedOptions.map(acc => (
<div
key={acc.id}
className={style.selectedListRow}
style={{
display: "flex",
alignItems: "center",
padding: "4px 8px",
borderBottom: "1px solid #f0f0f0",
fontSize: 14,
}}
>
<div
style={{
flex: 1,
minWidth: 0,
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
}}
>
{acc.realName} {acc.userName}
</div>
{!readonly && (
<Button
type="text"
icon={<DeleteOutlined />}
size="small"
style={{
marginLeft: 4,
color: "#ff4d4f",
border: "none",
background: "none",
minWidth: 24,
height: 24,
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
onClick={() => handleRemoveAccount(acc.id)}
/>
)}
</div>
))}
</div>
)}
{/* 弹窗 */}
<SelectionPopup
visible={realVisible}
onVisibleChange={setRealVisible}
selectedOptions={selectedOptions}
onSelect={onSelect}
readonly={readonly}
onConfirm={onConfirm}
/>
</>
);
}

View File

@@ -0,0 +1,248 @@
import React, { useEffect, useMemo, useRef, useState } from "react";
import { Popup } from "antd-mobile";
import Layout from "@/components/Layout/Layout";
import PopupHeader from "@/components/PopuLayout/header";
import PopupFooter from "@/components/PopuLayout/footer";
import {
selectionPopupBodyStyle,
selectionPopupLayoutStyle,
selectionPopupStyle,
} from "@/components/PopuLayout/popupShell";
import style from "./index.module.scss";
import { getAccountList } from "./api";
import { AccountItem, SelectionPopupProps } from "./data";
export default function SelectionPopup({
visible,
onVisibleChange,
selectedOptions,
onSelect,
readonly = false,
onConfirm,
}: SelectionPopupProps) {
const [accounts, setAccounts] = useState<AccountItem[]>([]);
const [searchQuery, setSearchQuery] = useState("");
const [currentPage, setCurrentPage] = useState(1);
const [totalPages, setTotalPages] = useState(1);
const [totalAccounts, setTotalAccounts] = useState(0);
const [loading, setLoading] = useState(false);
const [tempSelectedOptions, setTempSelectedOptions] = useState<AccountItem[]>(
[],
);
// 累积已加载过的账号,确保确认时能返回更完整的对象
const loadedAccountMapRef = useRef<Map<number, AccountItem>>(new Map());
const pageSize = 20;
const fetchAccounts = async (page: number, keyword: string = "") => {
setLoading(true);
try {
const params: any = { page, limit: pageSize };
if (keyword.trim()) params.keyword = keyword.trim();
const response = await getAccountList(params);
if (response && response.list) {
setAccounts(response.list);
const total: number = response.total || response.list.length || 0;
setTotalAccounts(total);
setTotalPages(Math.max(1, Math.ceil(total / pageSize)));
// 累积到映射表
response.list.forEach((acc: AccountItem) => {
loadedAccountMapRef.current.set(acc.id, acc);
});
} else {
setAccounts([]);
setTotalAccounts(0);
setTotalPages(1);
}
} catch (error) {
console.error("获取账号列表失败:", error);
} finally {
setLoading(false);
}
};
const handleAccountToggle = (account: AccountItem) => {
if (readonly || !onSelect) return;
const isSelected = tempSelectedOptions.some(opt => opt.id === account.id);
const next = isSelected
? tempSelectedOptions.filter(opt => opt.id !== account.id)
: tempSelectedOptions.concat(account);
setTempSelectedOptions(next);
};
// 全选当前页
const handleSelectAllCurrentPage = (checked: boolean) => {
if (readonly) return;
if (checked) {
// 全选:添加当前页面所有未选中的账号
const currentPageAccounts = accounts.filter(
account => !tempSelectedOptions.some(a => a.id === account.id),
);
setTempSelectedOptions(prev => [...prev, ...currentPageAccounts]);
} else {
// 取消全选:移除当前页面的所有账号
const currentPageAccountIds = accounts.map(a => a.id);
setTempSelectedOptions(prev =>
prev.filter(a => !currentPageAccountIds.includes(a.id)),
);
}
};
// 检查当前页是否全选
const isCurrentPageAllSelected =
accounts.length > 0 &&
accounts.every(account =>
tempSelectedOptions.some(a => a.id === account.id),
);
const handleConfirm = () => {
if (onConfirm) {
onConfirm(tempSelectedOptions);
}
if (onSelect) {
onSelect(tempSelectedOptions);
}
onVisibleChange(false);
};
// 弹窗打开时初始化数据
useEffect(() => {
if (visible) {
setCurrentPage(1);
setSearchQuery("");
loadedAccountMapRef.current.clear();
// 复制一份selectedOptions到临时变量
setTempSelectedOptions([...selectedOptions]);
fetchAccounts(1, "");
}
}, [visible, selectedOptions]);
// 搜索防抖
useEffect(() => {
if (!visible) return;
if (searchQuery === "") return;
const timer = setTimeout(() => {
setCurrentPage(1);
fetchAccounts(1, searchQuery);
}, 500);
return () => clearTimeout(timer);
}, [searchQuery, visible]);
// 页码变化
useEffect(() => {
if (!visible) return;
fetchAccounts(currentPage, searchQuery);
}, [currentPage, visible, searchQuery]);
const selectedIdSet = useMemo(
() => new Set(tempSelectedOptions.map(opt => opt.id)),
[tempSelectedOptions],
);
return (
<Popup
visible={visible && !readonly}
onMaskClick={() => onVisibleChange(false)}
position="bottom"
style={selectionPopupStyle}
bodyStyle={selectionPopupBodyStyle}
closeOnMaskClick
destroyOnClose
>
<Layout
embedded
style={selectionPopupLayoutStyle}
header={
<PopupHeader
title="选择账号"
searchQuery={searchQuery}
setSearchQuery={setSearchQuery}
searchPlaceholder="搜索账号"
loading={loading}
onRefresh={() => fetchAccounts(currentPage, searchQuery)}
onClose={() => onVisibleChange(false)}
/>
}
footer={
<PopupFooter
currentPage={currentPage}
totalPages={totalPages}
loading={loading}
selectedCount={tempSelectedOptions.length}
onPageChange={setCurrentPage}
onCancel={() => onVisibleChange(false)}
onConfirm={handleConfirm}
isAllSelected={isCurrentPageAllSelected}
onSelectAll={handleSelectAllCurrentPage}
/>
}
>
<div className={style.friendList}>
{loading ? (
<div className={style.loadingBox}>
<div className={style.loadingText}>...</div>
</div>
) : accounts.length > 0 ? (
<div className={style.friendListInner}>
{accounts.map(acc => (
<label
key={acc.id}
className={style.friendItem}
onClick={() => !readonly && handleAccountToggle(acc)}
>
<div className={style.radioWrapper}>
<div
className={
selectedIdSet.has(acc.id)
? style.radioSelected
: style.radioUnselected
}
>
{selectedIdSet.has(acc.id) && (
<div className={style.radioDot}></div>
)}
</div>
</div>
<div className={style.friendInfo}>
<div className={style.friendAvatar}>
{acc.avatar ? (
<img
src={acc.avatar}
alt={acc.userName}
className={style.avatarImg}
/>
) : (
(acc.userName?.charAt(0) ?? "?")
)}
</div>
<div className={style.friendDetail}>
<div className={style.friendName}>{acc.userName}</div>
<div className={style.friendId}>
: {acc.realName}
</div>
<div className={style.friendId}>
: {acc.departmentName}
</div>
</div>
</div>
</label>
))}
</div>
) : (
<div className={style.emptyBox}>
<div className={style.emptyText}>
{searchQuery
? `没有找到包含"${searchQuery}"的账号`
: "没有找到账号"}
</div>
</div>
)}
</div>
</Layout>
</Popup>
);
}

View File

@@ -0,0 +1,228 @@
import React, { useEffect, useState } from "react";
interface AndroidCompatibilityInfo {
isAndroid: boolean;
androidVersion: number;
chromeVersion: number;
webViewVersion: number;
issues: string[];
suggestions: string[];
}
const AndroidCompatibilityCheck: React.FC = () => {
const [compatibility, setCompatibility] = useState<AndroidCompatibilityInfo>({
isAndroid: false,
androidVersion: 0,
chromeVersion: 0,
webViewVersion: 0,
issues: [],
suggestions: [],
});
useEffect(() => {
const checkAndroidCompatibility = () => {
const ua = navigator.userAgent;
const issues: string[] = [];
const suggestions: string[] = [];
let isAndroid = false;
let androidVersion = 0;
let chromeVersion = 0;
let webViewVersion = 0;
// 检测Android系统
if (ua.indexOf("Android") > -1) {
isAndroid = true;
const androidMatch = ua.match(/Android\s+(\d+)/);
if (androidMatch) {
androidVersion = parseInt(androidMatch[1]);
}
// 检测Chrome版本
const chromeMatch = ua.match(/Chrome\/(\d+)/);
if (chromeMatch) {
chromeVersion = parseInt(chromeMatch[1]);
}
// 检测WebView版本
const webViewMatch = ua.match(/Version\/\d+\.\d+/);
if (webViewMatch) {
const versionMatch = webViewMatch[0].match(/\d+/);
if (versionMatch) {
webViewVersion = parseInt(versionMatch[0]);
}
}
// Android 7 (API 24) 兼容性检查
if (androidVersion === 7) {
issues.push("Android 7 系统对ES6+特性支持不完整");
suggestions.push("建议升级到Android 8+或使用最新版Chrome");
}
// Android 6 (API 23) 兼容性检查
if (androidVersion === 6) {
issues.push("Android 6 系统对现代Web特性支持有限");
suggestions.push("强烈建议升级系统或使用最新版Chrome");
}
// Chrome版本检查
if (chromeVersion > 0 && chromeVersion < 50) {
issues.push(`Chrome版本过低 (${chromeVersion})建议升级到50+`);
suggestions.push("请在Google Play商店更新Chrome浏览器");
}
// WebView版本检查
if (webViewVersion > 0 && webViewVersion < 50) {
issues.push(`WebView版本过低 (${webViewVersion}),可能影响应用功能`);
suggestions.push("建议使用Chrome浏览器或更新系统WebView");
}
// 检测特定问题
const features = {
Promise: typeof Promise !== "undefined",
fetch: typeof fetch !== "undefined",
"Array.from": typeof Array.from !== "undefined",
"Object.assign": typeof Object.assign !== "undefined",
"String.includes": typeof String.prototype.includes !== "undefined",
"Array.includes": typeof Array.prototype.includes !== "undefined",
requestAnimationFrame: typeof requestAnimationFrame !== "undefined",
IntersectionObserver: typeof IntersectionObserver !== "undefined",
ResizeObserver: typeof ResizeObserver !== "undefined",
URLSearchParams: typeof URLSearchParams !== "undefined",
TextEncoder: typeof TextEncoder !== "undefined",
AbortController: typeof AbortController !== "undefined",
};
Object.entries(features).forEach(([feature, supported]) => {
if (!supported) {
issues.push(`${feature} 特性不支持`);
}
});
// 微信内置浏览器检测
if (ua.indexOf("MicroMessenger") > -1) {
issues.push("微信内置浏览器对某些Web特性支持有限");
suggestions.push("建议在系统浏览器中打开以获得最佳体验");
}
// QQ内置浏览器检测
if (ua.indexOf("QQ/") > -1) {
issues.push("QQ内置浏览器对某些Web特性支持有限");
suggestions.push("建议在系统浏览器中打开以获得最佳体验");
}
}
setCompatibility({
isAndroid,
androidVersion,
chromeVersion,
webViewVersion,
issues,
suggestions,
});
};
checkAndroidCompatibility();
}, []);
if (!compatibility.isAndroid || compatibility.issues.length === 0) {
return null;
}
return (
<div
style={{
position: "fixed",
top: 0,
left: 0,
right: 0,
backgroundColor: "#fff3cd",
border: "1px solid #ffeaa7",
padding: "15px",
zIndex: 9999,
textAlign: "center",
fontSize: "14px",
maxHeight: "50vh",
overflowY: "auto",
}}
>
<div
style={{ fontWeight: "bold", marginBottom: "10px", color: "#856404" }}
>
🚨 Android
</div>
<div style={{ marginBottom: "8px", fontSize: "12px" }}>
系统版本: Android {compatibility.androidVersion}
{compatibility.chromeVersion > 0 &&
` | Chrome: ${compatibility.chromeVersion}`}
{compatibility.webViewVersion > 0 &&
` | WebView: ${compatibility.webViewVersion}`}
</div>
<div style={{ marginBottom: "10px" }}>
<div
style={{ fontWeight: "bold", marginBottom: "5px", color: "#856404" }}
>
:
</div>
<div style={{ color: "#856404", fontSize: "12px" }}>
{compatibility.issues.map((issue, index) => (
<div key={index} style={{ marginBottom: "3px" }}>
{issue}
</div>
))}
</div>
</div>
{compatibility.suggestions.length > 0 && (
<div style={{ marginBottom: "10px" }}>
<div
style={{
fontWeight: "bold",
marginBottom: "5px",
color: "#155724",
}}
>
:
</div>
<div style={{ color: "#155724", fontSize: "12px" }}>
{compatibility.suggestions.map((suggestion, index) => (
<div key={index} style={{ marginBottom: "3px" }}>
{suggestion}
</div>
))}
</div>
</div>
)}
<div style={{ fontSize: "11px", color: "#6c757d", marginTop: "10px" }}>
💡
</div>
<button
onClick={() => {
const element = document.querySelector(
'[style*="position: fixed"][style*="top: 0"]',
) as HTMLElement;
if (element) {
element.style.display = "none";
}
}}
style={{
position: "absolute",
top: "5px",
right: "10px",
background: "none",
border: "none",
fontSize: "18px",
cursor: "pointer",
color: "#856404",
}}
>
×
</button>
</div>
);
};
export default AndroidCompatibilityCheck;

View File

@@ -1,92 +0,0 @@
import React from 'react';
import { useNavigate } from 'react-router-dom';
import { ChevronLeft, ArrowLeft } from 'lucide-react';
interface BackButtonProps {
/** 返回按钮的样式变体 */
variant?: 'icon' | 'button' | 'text';
/** 自定义返回逻辑如果不提供则使用navigate(-1) */
onBack?: () => void;
/** 按钮文本仅在button和text变体时使用 */
text?: string;
/** 自定义CSS类名 */
className?: string;
/** 图标大小 */
iconSize?: number;
/** 是否显示图标 */
showIcon?: boolean;
/** 自定义图标 */
icon?: React.ReactNode;
}
/**
* 通用返回上一页按钮组件
* 使用React Router的navigate方法实现返回功能
*/
export const BackButton: React.FC<BackButtonProps> = ({
variant = 'icon',
onBack,
text = '返回',
className = '',
iconSize = 6,
showIcon = true,
icon
}) => {
const navigate = useNavigate();
const handleBack = () => {
if (onBack) {
onBack();
} else {
navigate(-1);
}
};
const defaultIcon = variant === 'icon' ? (
<ChevronLeft className={`h-${iconSize} w-${iconSize}`} />
) : (
<ArrowLeft className={`h-${iconSize} w-${iconSize}`} />
);
const buttonIcon = icon || (showIcon ? defaultIcon : null);
switch (variant) {
case 'icon':
return (
<button
onClick={handleBack}
className={`p-2 hover:bg-gray-100 rounded-lg transition-colors ${className}`}
title="返回上一页"
>
{buttonIcon}
</button>
);
case 'button':
return (
<button
onClick={handleBack}
className={`flex items-center gap-2 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors ${className}`}
>
{buttonIcon}
{text}
</button>
);
case 'text':
return (
<button
onClick={handleBack}
className={`flex items-center gap-2 text-blue-600 hover:text-blue-700 transition-colors ${className}`}
>
{buttonIcon}
{text}
</button>
);
default:
return null;
}
};
export default BackButton;

View File

@@ -1,66 +0,0 @@
import React from 'react';
import { Link, useLocation } from 'react-router-dom';
import { Home, Users, LayoutGrid, User } from 'lucide-react';
const navItems = [
{
id: "home",
name: "首页",
href: "/",
icon: Home,
active: (pathname: string) => pathname === "/",
},
{
id: "scenarios",
name: "场景获客",
href: "/scenarios",
icon: Users,
active: (pathname: string) => pathname.startsWith("/scenarios"),
},
{
id: "workspace",
name: "工作台",
href: "/workspace",
icon: LayoutGrid,
active: (pathname: string) => pathname.startsWith("/workspace"),
},
{
id: "profile",
name: "我的",
href: "/profile",
icon: User,
active: (pathname: string) => pathname.startsWith("/profile"),
},
];
interface BottomNavProps {
activeTab?: string;
}
export default function BottomNav({ activeTab }: BottomNavProps) {
const location = useLocation();
return (
<div className="fixed bottom-0 left-0 right-0 z-50 bg-white border-t border-gray-200 safe-area-pb">
<div className="flex justify-around items-center h-16 max-w-md mx-auto">
{navItems.map((item) => {
const IconComponent = item.icon;
const isActive = activeTab ? activeTab === item.id : item.active(location.pathname);
return (
<Link
key={item.href}
to={item.href}
className={`flex flex-col items-center justify-center flex-1 h-full transition-colors ${
isActive ? "text-blue-500" : "text-gray-500 hover:text-gray-900"
}`}
>
<IconComponent className="w-5 h-5" />
<span className="text-xs mt-1">{item.name}</span>
</Link>
);
})}
</div>
</div>
);
}

View File

@@ -0,0 +1,125 @@
import React, { useEffect, useState } from "react";
interface CompatibilityInfo {
isCompatible: boolean;
browser: string;
version: string;
issues: string[];
}
const CompatibilityCheck: React.FC = () => {
const [compatibility, setCompatibility] = useState<CompatibilityInfo>({
isCompatible: true,
browser: "",
version: "",
issues: [],
});
useEffect(() => {
const checkCompatibility = () => {
const ua = navigator.userAgent;
const issues: string[] = [];
let browser = "Unknown";
let version = "Unknown";
// 检测浏览器类型和版本
if (ua.indexOf("Chrome") > -1) {
browser = "Chrome";
const match = ua.match(/Chrome\/(\d+)/);
version = match ? match[1] : "Unknown";
if (parseInt(version) < 50) {
issues.push("Chrome版本过低建议升级到50+");
}
} else if (ua.indexOf("Firefox") > -1) {
browser = "Firefox";
const match = ua.match(/Firefox\/(\d+)/);
version = match ? match[1] : "Unknown";
if (parseInt(version) < 50) {
issues.push("Firefox版本过低建议升级到50+");
}
} else if (ua.indexOf("Safari") > -1 && ua.indexOf("Chrome") === -1) {
browser = "Safari";
const match = ua.match(/Version\/(\d+)/);
version = match ? match[1] : "Unknown";
if (parseInt(version) < 10) {
issues.push("Safari版本过低建议升级到10+");
}
} else if (ua.indexOf("MSIE") > -1 || ua.indexOf("Trident") > -1) {
browser = "Internet Explorer";
const match = ua.match(/(?:MSIE |rv:)(\d+)/);
version = match ? match[1] : "Unknown";
issues.push("Internet Explorer不受支持建议使用现代浏览器");
} else if (ua.indexOf("Edge") > -1) {
browser = "Edge";
const match = ua.match(/Edge\/(\d+)/);
version = match ? match[1] : "Unknown";
if (parseInt(version) < 12) {
issues.push("Edge版本过低建议升级到12+");
}
}
// 检测ES6+特性支持
const features = {
Promise: typeof Promise !== "undefined",
fetch: typeof fetch !== "undefined",
"Array.from": typeof Array.from !== "undefined",
"Object.assign": typeof Object.assign !== "undefined",
"String.includes": typeof String.prototype.includes !== "undefined",
"Array.includes": typeof Array.prototype.includes !== "undefined",
};
Object.entries(features).forEach(([feature, supported]) => {
if (!supported) {
issues.push(`${feature} 特性不支持`);
}
});
setCompatibility({
isCompatible: issues.length === 0,
browser,
version,
issues,
});
};
checkCompatibility();
}, []);
if (compatibility.isCompatible) {
return null; // 兼容时不需要显示
}
return (
<div
style={{
position: "fixed",
top: 0,
left: 0,
right: 0,
backgroundColor: "#fff3cd",
border: "1px solid #ffeaa7",
padding: "10px",
zIndex: 9999,
textAlign: "center",
fontSize: "14px",
}}
>
<div style={{ fontWeight: "bold", marginBottom: "5px" }}>
</div>
<div style={{ marginBottom: "5px" }}>
: {compatibility.browser} {compatibility.version}
</div>
<div style={{ color: "#856404" }}>
{compatibility.issues.map((issue, index) => (
<div key={index}>{issue}</div>
))}
</div>
<div style={{ marginTop: "10px", fontSize: "12px" }}>
使 Chrome 50+Firefox 50+Safari 10+ Edge 12+
</div>
</div>
);
};
export default CompatibilityCheck;

View File

@@ -1,210 +0,0 @@
import React, { useState, useEffect, useCallback } from "react";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Search, RefreshCw, Loader2 } from "lucide-react";
import { fetchContentLibraryList } from "@/api/content";
import { ContentLibrary } from "@/api/content";
import { useToast } from "@/components/ui/toast";
interface ContentLibrarySelectionDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
selectedLibraries: string[];
onSelect: (libraries: string[]) => void;
}
export function ContentLibrarySelectionDialog({
open,
onOpenChange,
selectedLibraries,
onSelect,
}: ContentLibrarySelectionDialogProps) {
const { toast } = useToast();
const [searchQuery, setSearchQuery] = useState("");
const [loading, setLoading] = useState(false);
const [libraries, setLibraries] = useState<ContentLibrary[]>([]);
const [tempSelected, setTempSelected] = useState<string[]>([]);
// 获取内容库列表
const fetchLibraries = useCallback(async () => {
setLoading(true);
try {
const response = await fetchContentLibraryList(1, 100, searchQuery);
if (response.code === 200 && response.data) {
setLibraries(response.data.list);
} else {
toast({
title: "获取内容库列表失败",
description: response.msg,
variant: "destructive",
});
}
} catch (error) {
console.error("获取内容库列表失败:", error);
toast({
title: "获取内容库列表失败",
description: "请检查网络连接",
variant: "destructive",
});
} finally {
setLoading(false);
}
}, [searchQuery, toast]);
useEffect(() => {
if (open) {
fetchLibraries();
setTempSelected(selectedLibraries);
}
}, [open, selectedLibraries, fetchLibraries]);
const handleRefresh = () => {
fetchLibraries();
};
const handleSelectAll = () => {
if (tempSelected.length === libraries.length) {
setTempSelected([]);
} else {
setTempSelected(libraries.map((lib) => lib.id));
}
};
const handleLibraryToggle = (libraryId: string) => {
setTempSelected((prev) =>
prev.includes(libraryId)
? prev.filter((id) => id !== libraryId)
: [...prev, libraryId]
);
};
const handleDialogOpenChange = (open: boolean) => {
if (!open) {
setTempSelected(selectedLibraries);
}
onOpenChange(open);
};
const handleConfirm = () => {
onSelect(tempSelected);
onOpenChange(false);
};
return (
<Dialog open={open} onOpenChange={handleDialogOpenChange}>
<DialogContent className="flex flex-col bg-white">
<DialogHeader>
<DialogTitle></DialogTitle>
</DialogHeader>
<div className="flex items-center space-x-2 my-4">
<div className="relative flex-1">
<Search className="absolute left-3 top-2.5 h-4 w-4 text-gray-400" />
<Input
placeholder="搜索内容库"
className="pl-9"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
</div>
<Button
variant="outline"
size="icon"
onClick={handleRefresh}
disabled={loading}
>
{loading ? (
<Loader2 className="h-4 w-4 animate-spin" />
) : (
<RefreshCw className="h-4 w-4" />
)}
</Button>
</div>
<div className="flex justify-between items-center mb-2">
<div className="text-sm text-gray-500">
{tempSelected.length}
</div>
<div className="flex gap-2">
<Button
variant="outline"
size="sm"
onClick={handleSelectAll}
disabled={loading || libraries.length === 0}
>
{tempSelected.length === libraries.length ? "取消全选" : "全选"}
</Button>
</div>
</div>
<div className="flex-1 overflow-y-auto -mx-6 px-6 max-h-[400px]">
<div className="space-y-2">
{loading ? (
<div className="flex items-center justify-center h-full text-gray-500">
...
</div>
) : libraries.length === 0 ? (
<div className="flex items-center justify-center h-full text-gray-500">
</div>
) : (
libraries.map((library) => (
<label
key={library.id}
className="flex items-start space-x-3 p-4 rounded-lg hover:bg-gray-50 cursor-pointer border"
>
<input
type="checkbox"
checked={tempSelected.includes(library.id)}
onChange={() => handleLibraryToggle(library.id)}
className="mt-1 w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 focus:ring-2"
/>
<div className="flex-1">
<div className="flex items-center justify-between">
<span className="font-medium">{library.name}</span>
<Badge variant="outline">
{library.sourceType === 1
? "文本"
: library.sourceType === 2
? "图片"
: "视频"}
</Badge>
</div>
<div className="text-sm text-gray-500 mt-1">
<div>: {library.creatorName || "-"}</div>
<div>
:{" "}
{new Date(library.updateTime).toLocaleString()}
</div>
</div>
</div>
</label>
))
)}
</div>
</div>
<div className="flex justify-between items-center mt-4 pt-4 border-t">
<div className="text-sm text-gray-500">
{tempSelected.length}
</div>
<div className="flex space-x-2">
<Button variant="outline" onClick={() => onOpenChange(false)}>
</Button>
<Button onClick={handleConfirm}>
{tempSelected.length > 0 ? ` (${tempSelected.length})` : ""}
</Button>
</div>
</div>
</DialogContent>
</Dialog>
);
}

View File

@@ -0,0 +1,5 @@
import request from "@/api/request";
export function getContentLibraryList(params: any) {
return request("/v1/content/library/list", { ...params, formType: 0 }, "GET");
}

View File

@@ -0,0 +1,21 @@
// 内容库接口类型
export interface ContentItem {
id: number;
name: string;
[key: string]: any;
}
// 组件属性接口
export interface ContentSelectionProps {
selectedOptions: ContentItem[];
onSelect: (selectedItems: ContentItem[]) => void;
placeholder?: string;
className?: string;
visible?: boolean;
onVisibleChange?: (visible: boolean) => void;
selectedListMaxHeight?: number;
showInput?: boolean;
showSelectedList?: boolean;
readonly?: boolean;
onConfirm?: (selectedItems: ContentItem[]) => void;
}

Some files were not shown because too many files have changed in this diff Show More