CRMEB

GitHub

🔥CRMEB开源商城免费开源多语言商城系统,Tp6框架商城,系统可商用;包含小程序商城、H5商城、公众号商城、PC商城、App,支持分销、拼团、砍价、秒杀、优惠券、积分、会员等级、小程序直播、页面DIY,前后端分离,方便二开,更有详细使用文档、接口文档、数据字典、二开文档/视频教程,欢迎大家提出宝贵意见和建议

RAW Doc

README (README.md)

<div align="center" >
<img src="https://www.crmeb.com/static/images/dark_logo.png" />
</div>

<div align="center" style="font-size: 15px;">

CRMEB高品质开源商城系统(PHP版)

</div>


<div align="center" style="font-size: 15px;">
用心做开源,我们也很需要你的鼓励!右上角Star🌟,等你点亮
</div>


####

<div align="center">

[](https://zread.ai/crmeb/CRMEB)

</div>

<div align="center">

官网 |
在线体验 |
帮助文档 |
应用市场 |
技术社区 |
主题广场

</div>

---

📝 项目介绍

开源自由

CRMEB开源商城系统代码100%开源,基于 Apache-2.0协议 免费商用,无任何隐藏费用或功能限制,真正实现“零成本”部署与二次开发自由!

技术架构

采用 ThinkPHP 6 + ElementUI + UniApp 技术栈,前后端分离设计,支持模块化开发与高效维护。前端适配微信小程序、H5、APP、PC等多端,后端统一管理全平台数据,保障流畅体验与高并发性能。

全场景覆盖

无缝对接公众号、小程序、H5、APP、PC端,数据实时互通,助力商家一站式运营多渠道业务,满足全场景电商需求。

原生营销引擎

内置 20+核心营销模块(拼团、砍价、秒杀、优惠券、积分体系、直播带货、付费会员、等级会员、用户充值、分销裂变、渠道码、新人礼等),支持零插件自定义活动规则。通过 首页DIY功能 ,商家可拖拽式设计商城首页,无需技术背景即可快速搭建高转化场景,实现「所见即所得」的运营效率。

社区共建计划

我们致力于打造开发者友好生态,开放源码、持续更新功能模块,并新增主题市场,支持商家一键套用精美商城主题快速装修,开发者与设计师可上架原创主题供用户下载使用,实现创意共享与价值变现。同时欢迎开发者提交优化建议或贡献代码,通过共享技术成果,降低行业重复造轮子成本,推动开源电商系统的可持续发展。

---

📝 主题广场

免费下载

来CRMEB主题广场畅享海量精选模板,零成本打造个性化商城。无需具备专业设计能力,海量免费模版直接下载使用,多样化主题风格可精准匹配不同行业需求,快速提升店铺形象与用户体验,让您的商城在起步阶段就赢在视觉起跑线上。

一键导入

化繁为简,极速焕新商城界面。彻底告别过去繁琐的手动DIY配置流程,一键导入主题包,即可将整套主题(包含页面布局与全局配色)无缝融合至您的系统中。系统自动完成组件匹配与数据挂载,无需编写任何代码,即时预览生效。让商城改版升级像换手机壁纸一样轻松,极大节省了运营与开发的时间成本。

上架主题广场

不仅随心用,更能轻松赚。您可以利用系统强大的DIY功能,基于原有模块自由组合配色、布局与组件,打造出独具特色的专属主题,并直接上架至主题广场。当其他用户付费下载您的作品时,您将获得相应的收益分成。这不仅为您的设计能力与技术沉淀提供了直接的变现渠道,更助力共建繁荣的开源商城生态,实现创意与价值的双赢。

主题广场:<a href="https://www.crmeb.com/theme" target="_blank">主题广场</a>

<img width="1476" height="1880" alt="主题广场" src="https://github.com/user-attachments/assets/7d273820-41d9-45a8-a85c-af9cb9a50148" />


🔗 <a href="https://doc.crmeb.com/single_open/open_v60/39233" target="_blank">功能列表</a> | 🔗 <a href="https://www.crmeb.com/theme" target="_blank">主题广场</a>

---

docker一键体验


text

拉取并运行CRMEB Docker镜像


docker run -d --name crmeb -p 8080:80 ccr.ccs.tencentyun.com/crmebky_php/crmebky:latest

#### 访问服务
- 网站: http://localhost:8080
- 后台: http://localhost:8080/admin (账号: admin,密码: crmeb.com)
- MySQL: localhost:3306(账号: root,密码: 123456)
- Redis: localhost:6379

详细说明点击查看 帮助文档

---

🫧 技术特点

~~~
关于二开:
1.代码规范:遵循PSR-2命名规范、Restful标准接口、代码严格分层、注释齐全、统一错误码;
2.权限管理:内置强大灵活的权限管理,可以控制到每一个菜单;
3.开发配置:低代码增加配置、系统组合数据模块;
4.代码生成:快速生成后台菜单、页面,快速实现增删改查;
5.定时任务:系统内置10中定时任务,还有自定义任务,可以自行设置执行周期,执行代码,完美兼容;
6.系统事件:埋入30+系统事件锚点,可在后台页面进行事件添加;
7.在线编辑:可以在后台对系统的代码进行编辑修改操作,不用登录服务器去修改代码文件,方便快捷;
8.接口管理:后台页面可以看到系统中所有的接口数据,并且可以在线调试接口;
9.二开效率:应用form-builder PHP可以快速生成表单;
10.快速上手:后台接口管理、后台数据库字典、系统文件管理备注、代码注释、一键安装;
~~~
~~~
性能与拓展:
1.系统安全:系统操作日志、系统生产日志、文件校验、数据备份;
2.高性能:支持Redis缓存、队列、长连接、多种云储存、支持集群部署;
3.多语言:支持自动识别浏览器多语言展示;
4.驱动扩展:支持多种支付方式、多种短信、多种云储存等;
5.云存储:云存储支持图片和视频的远程云存储,支持阿里云,腾讯云,七牛云,京东云,天翼云,华为云
6.一号通:通用的第三方扩展,支持短信,物流查询,电子面单,电子发票,商品采集,商家寄件
~~~

---

📖 系统功能

<img width="1920" height="2500" alt="核心功能" src="https://github.com/user-attachments/assets/944897ae-67f0-438d-9ca5-455d5956eddb" />

---

📖 UI界面展示

<img width="1200" height="1950" alt="PHP_06" src="https://github.com/user-attachments/assets/85e40dfd-222c-4b53-ad34-eb746f7f8eec" />


---

📖 后台界面展示

<img width="1200" height="2100" alt="PHP_05" src="https://github.com/user-attachments/assets/866e3b17-9845-4e19-b3f0-2dee653766c1" />

---


📱 系统演示

<img width="1400" height="597" alt="contact2" src="https://github.com/user-attachments/assets/4165e6fd-307d-47aa-9c3c-49590d49134b" />


管理后台: http://v6.crmeb.net/admin

账号:demo 密码:crmeb.com

H5端:http://v6.crmeb.net/ (移动端打开)

PC端:http://v6.crmeb.net/ (电脑端打开)

APP下载:http://app.crmeb.cn/bzv (苹果手机直接在APP Store里搜索CRMEB下载)

主题:https://www.crmeb.com/theme (电脑端打开)

听说,大神你想看看CRMEB开源项目的完整框架?<a href="https://doc.crmeb.com/single_open/open_v60/39235" target="_blank">戳这儿,轻松获取!</a>

---

🔐 运行环境


| 运行环境 | 要求 |
|------------------|------------------------------------------------------------------------|
| 操作系统 | Linux / Windows |
| WEB 服务 | Nginx / Apache / IIS |
| PHP 版本 | PHP 7.1 ~ 7.4 |
| 数据库 | MySQL 5.7 ~ 8.0(引擎:InnoDB) |
| 缓存 | Redis(可选,不安装则使用文件缓存) |
| 管理器 | Supervisor(用于管理消息队列) |
| 推荐工具 | 宝塔面板(简单易用) |
| 云服务器 | 阿里云 ECS / 腾讯云 CVM / 京东云ECS |
| 开放端口 | 80, 21, 8888, 888, 443, 3306, 6379(授权对象:0.0.0.0/0) |
| PHP 扩展 | fileinfo(可选)、redis(可选) |
| 禁用函数 | proc_open, pcntl_signal, pcntl_signal_dispatch, pcntl_fork, pcntl_wait, pcntl_alarm |
| 消息队列 | 运行命令:php think queue:listen --queue (使用Supervisor) |
| 长连接 | 运行命令:sudo -u www php think workerman start --d (命令行执行) |
| 定时任务 | 运行命令:php think timer start --d (命令行执行) |

温馨提示:虚拟空间不支持,推荐使用bt宝塔面板,服务器推荐京东云服务器:<a href="https://partner.jdcloud.com/partner/notice/b06c3232b6394fdfa496923b8e00b286" target="_blank">注册即享6.5折专属优惠,点我领取!</a>

---

📺 开发环境及使用技术

开发环境:


| 工具 | 版本 | 下载链接 |
|--------------|--------------------|-------------------------------------------------------------------------|
| PHP | 7.1-7.4 | PHP 官方下载 |
| MySQL | 5.7 | MySQL 官网 |
| Redis | 7.0 | Redis 官网 |
| Nginx | 1.22 | Nginx 官网 |
| Apache | 2.4 | Apache HTTP Server |
| Node.js | 14/18 | Node.js LTS 版本 |

后端技术栈


| 技术 | 名称 | 网址 |
|---------------------|-----------------------------------------------------------------------------|-------------------------------------------------------------------------|
| php扩展库 | PHP 基础运行环境,JSON 数据处理,高精度数学计算等 | https://www.php.net/ |
| topthink | ThinkPHP 视图模板引擎,验证码生成组件,队列任务支持,数据库迁移工具 | https://www.thinkphp.cn/ |
| overtrue | 微信生态开发(公众号/小程序/支付) | https://github.com/w7corp/easywechat |
| php-jwt | JWT 令牌生成与验证 | https://github.com/firebase/php-jwt |
| var-dumper | 调试输出工具(格式化变量) | https://symfony.com/doc/current/components/var_dumper.html |
| phpoffice | 文件处理 | https://github.com/PHPOffice/PhpSpreadsheet |
| guzzlehttp|psr7 | HTTP 客户端库,PSR-7 HTTP 消息接口实现 | https://guzzle-cn.readthedocs.io/zh-cn/latest |
| form-builder | 快速构建表单的 UI 工具 | https://form-create.com |
| workerman | 高性能 Socket 服务器框架,定时任务调度 | https://www.workerman.net |

移动端技术栈


| 技术 | 名称 | 官网 |
| --- | --- | --- |
| uniapp | 跨端框架 | https://uniapp.dcloud.net.cn/ |
| vuex | 状态管理库 | https://vuex.vuejs.org/ |
| socket | WebSocket通信 | https://socket.io/ |
| dayjs | 时间处理库 | https://day.js.org/ |
| animate | CSS动画库 | https://animate.style/ |
| easy-loadimage | 图片懒加载 | https://github.com/TSjianjiao/easy-loadimage |

Admin端技术栈


| 技术 | 名称 | 官网 |
| --- | --- | --- |
| vue2 | Vue框架 | https://v2.vuejs.org/ |
| vuex | 状态管理库 | https://vuex.vuejs.org/ |
| element-ui | UI框架 | https://element.eleme.io/ |
| axios | HTTP客户端 | https://axios-http.com/ |
| vxe-table | 高级表格组件 | https://vxetable.cn/ |
| wangeditor | 富文本编辑器 | https://www.wangeditor.com/ |
| qs | 查询字符串解析 | https://github.com/ljharb/qs |
| xlsx | Excel处理库 | https://sheetjs.com/ |
| sass | CSS预处理器 | https://sass-lang.com/ |
| prettier | 代码格式化 | https://prettier.io/ |
| v-viewer | 图片查看器 | https://github.com/mirari/v-viewer |

PC端技术栈


| 技术 | 名称 | 官网 |
| --- | --- | --- |
| nuxt | Vue服务端渲染框架 | https://nuxtjs.org/ |
| element | UI框架 | https://element.eleme.io/ |
| axios | HTTP客户端 | https://axios-http.com/ |
| sass | CSS预处理器 | https://sass-lang.com/ |
| cookie-universal-nuxt | Nuxt Cookie处理 | https://github.com/microcipcip/cookie-universal |
| postcss | CSS转换工具 | https://postcss.org/ |
| qs | 查询字符串解析 | https://github.com/ljharb/qs |

想要快速安装,教程来助攻!

快速一键安装部署:https://doc.crmeb.com/single_open/open_v54/20366

手动配置安装:https://doc.crmeb.com/single_open/open_v54/20389

docker-compose一键部署:https://doc.crmeb.com/single_open/open_v54/20145

宝塔环境一键安装:https://doc.crmeb.com/single_open/open_v54/19892

二开支持:


使用文档:https://doc.crmeb.com/single_open/open_v54/19849

接口文档:https://doc.crmeb.com/single_open/open_v54/21040

数据字典:https://doc.crmeb.com/single_open/open_v54/20136

代码生成:https://doc.crmeb.com/single_open/open_v54/20135

二开文档:https://doc.crmeb.com/single_open/open_v54/19851

视频教程:https://www.bilibili.com/video/BV1kh4y1872K/

技术社区:https://www.crmeb.com/ask/thread/list/147

---

📞 CRMEB互动


#### CRMEB开源技术交流群(扫码进群可领取开源版接口文档、产品功能清单、思维脑图!)
<img width="1150" height="360" alt="开源群php" src="https://github.com/user-attachments/assets/cca751c6-c9fd-48e7-b61f-65323e54d877" />

#### 技术社区!找方法、提bug、看官方消息、拿活跃大奖!都在 <a href="https://www.crmeb.com/ask/?from=githubphp" target="_blank">CRMEB 技术社区</a> 应有尽有


📕 CRMEB 多商户版


<a href="https://www.crmeb.com/index/merchant?from=giteephp"><img width="3840" height="1600" alt="duoshanghu2" src="https://github.com/user-attachments/assets/041dbbf2-faa2-40bc-be58-b9cd8a00efd4" /></a>

---

---

Crmeb/Composer.Json (crmeb/composer.json)

{
"name": "topthink/think",
"description": "the new thinkphp framework",
"type": "project",
"keywords": [
"framework",
"thinkphp",
"ORM"
],
"homepage": "http://thinkphp.cn/",
"license": "Apache-2.0",
"authors": [
{
"name": "liu21st",
"email": "[email protected]"
}
],
"require": {
"php": ">=7.1.0",
"ext-json": "*",
"ext-curl": "*",
"ext-bcmath": "*",
"ext-mbstring": "*",
"topthink/think-view": "^1.0",
"symfony/var-dumper":"^4.2",
"overtrue/wechat": "^3.3",
"topthink/think-captcha": "^3.0",
"topthink/think-image": "^1.0",
"xaboy/form-builder": "2.0.17",
"firebase/php-jwt": "^5.0",
"aliyuncs/oss-sdk-php": "^2.3",
"qcloud/cos-sdk-v5": "v1.3.5",
"qiniu/php-sdk": "^7.2",
"workerman/workerman": "^3.5",
"workerman/channel": "^1.0",
"topthink/think-queue": "^3.0",
"spatie/macroable": "^1.0",
"dh2y/think-qrcode": "^2.0",
"topthink/think-multi-app": "^1.0",
"topthink/think-template": "^2.0",
"phpoffice/phpspreadsheet": "^1.12",
"godruoyi/php-snowflake": "^1.0",
"qcloud_sts/qcloud-sts-sdk": "^3.0",
"guzzlehttp/psr7": "^1.7",
"guzzlehttp/guzzle": "6.5.5",
"alipaysdk/easysdk": "2.0",
"lizhichao/word": "^2.1",
"alibabacloud/dysmsapi-20170525": "2.0.16",
"fastknife/ajcaptcha": "^1.1",
"volcengine/volc-sdk-php": "^1.0",
"workerman/crontab": "^1.0",
"topthink/think-migration": "^3.0",
"topthink/think-filesystem": "^2.0",
"aws/aws-sdk-php": "^3.173",
"ext-zip": "*",
"ext-simplexml": "*",
"crmeb/easypay": "^1.0"
},
"autoload": {
"psr-4": {
"app\\": "app",
"crmeb\\": "crmeb"
},
"psr-0": {
"": "extend/"
}
},
"config": {
"preferred-install": "dist",
"platform-check": false
},
"scripts": {
"post-autoload-dump": [
"@php think service:discover",
"@php think vendor:publish"
]
},
"minimum-stability": "dev",
"prefer-stable": true
}

---

Crmeb/FILE GUIDE (crmeb/FILE_GUIDE.md)

crmeb 目录文件说明

目录结构概览


text
crmeb/
├── app/ # 应用程序核心代码(控制器、模型、服务等)
├── backup/ # 数据备份文件
├── config/ # 配置文件(数据库、缓存、接口等)
├── crmeb/ # 项目内部公共模块或扩展库
├── public/ # Web 可访问入口(静态资源、index.php)
├── route/ # 路由定义
├── runtime/ # 运行时缓存、日志、Session 等(需忽略版本控制)

├── .constant # 常量定义文件(需忽略版本控制)
├── .dockerignore # Docker 构建忽略规则
├── .env # 环境变量配置(敏感信息)(需忽略版本控制)
├── .env.example # 环境变量示例文件
├── .htaccess # Apache 重写规则
├── .phpstorm.meta.php # PhpStorm 元数据
├── .travis.yml # Travis CI 配置
├── .version # 版本信息
├── Dockerfile # Docker 镜像构建文件
├── LICENSE.txt # 开源许可协议
├── README.md # 项目说明
├── build.example.php # 构建示例脚本
├── composer.json # Composer 依赖配置
├── composer.lock # Composer 锁定版本
├── filetree.txt # 文件树结构快照
├── index.html # 默认首页(防访问目录)
├── my.cnf # MySQL 自定义配置(需忽略版本控制)
├── nginx.conf # Nginx 配置(需忽略版本控制)
├── php-fpm.conf # PHP-FPM 配置(需忽略版本控制)
├── php-ini-overrides.ini# PHP 自定义 ini 覆盖(需忽略版本控制)
├── redis.conf # Redis 配置(需忽略版本控制)
├── start.sh # 项目启动脚本(需忽略版本控制)
├── supervisord.conf # Supervisor 进程管理配置(需忽略版本控制)
├── think # ThinkPHP 框架入口文件
├── vhost.conf # 虚拟主机配置(需忽略版本控制)
└── workerman.bat # Windows 下 Workerman 启动脚本

主要目录说明


- app/
存放业务逻辑的核心代码,包括控制器(Controller)、模型(Model)、服务层(Service)等,遵循 MVC 或类似分层架构。
- backup/
用于存放数据库或重要数据的备份文件,建议定期清理旧备份。
- config/
各种环境与应用配置文件,如数据库、缓存、队列、接口认证等。
- crmeb/
项目内部的公共模块或第三方 SDK 集成,可能包含一些工具类或扩展功能。
- public/
Web 服务器根目录,放置可直接通过浏览器访问的资源(如图片、JS、CSS)以及入口文件 index.php
- route/
路由定义文件,用于映射 URL 请求到具体的控制器方法。
- runtime/
存放运行时生成的缓存、日志、Session 等临时数据;此目录应在 .gitignore 中忽略。

主要文件说明


- .env / .env.example
环境变量配置与示例,.env 含敏感信息,不要提交到代码库。
- composer.json / composer.lock
PHP 项目依赖管理配置与锁定文件。
- Dockerfile / docker-compose 相关
用于容器化部署的配置。
- my.cnf / redis.conf / nginx.conf
各类服务的自定义配置。
- start.sh
项目本地或服务器启动入口脚本。
- think
ThinkPHP 框架的统一入口文件,负责初始化框架并分发请求。

---

Crmeb/Filetree (crmeb/filetree.txt)

.
├── app 程序主目录
├── backup 数据库/程序升级备份目录
├── config 系统配置
├── crmeb crmeb核心文件目录
├── public 程序入口目录
├── route 程序入口路由配置
├── runtime 缓存目录
├── temp docker临时文件目录
├── vendor 扩展包compose 安装目录
├── LICENSE.txt 开源协议
├── README.md 系统说明
├── baota.sh 宝塔快速配置环境文件
├── build.example.php
├── composer.json
├── composer.lock
├── filetree.txt
├── think tp命令文件入口
├── timer.pid 定时任务生成文件
├── updatesql.sql
├── workerman.bat windows 启动workerman命令文件
└── workerman.pid workerman生成文件

9 directories, 12 files

---

Crmeb/.Travis.Yml (crmeb/.travis.yml)

sudo: false

language: php

branches:
only:
- stable

cache:
directories:
- $HOME/.composer/cache

before_install:
- composer self-update

install:
- composer install --no-dev --no-interaction --ignore-platform-reqs
- zip -r --exclude='.git' --exclude='.zip' --exclude='.travis.yml' ThinkPHP_Core.zip .
- composer require --update-no-dev --no-interaction "topthink/think-image:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-migration:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-captcha:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-mongo:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-worker:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-helper:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-queue:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-angular:^1.0"
- composer require --dev --update-no-dev --no-interaction "topthink/think-testing:^1.0"
- zip -r --exclude='.git' --exclude='.zip' --exclude='.travis.yml' ThinkPHP_Full.zip .

script:
- php think unit

deploy:
provider: releases
api_key:
secure: TSF6bnl2JYN72UQOORAJYL+CqIryP2gHVKt6grfveQ7d9rleAEoxlq6PWxbvTI4jZ5nrPpUcBUpWIJHNgVcs+bzLFtyh5THaLqm39uCgBbrW7M8rI26L8sBh/6nsdtGgdeQrO/cLu31QoTzbwuz1WfAVoCdCkOSZeXyT/CclH99qV6RYyQYqaD2wpRjrhA5O4fSsEkiPVuk0GaOogFlrQHx+C+lHnf6pa1KxEoN1A0UxxVfGX6K4y5g4WQDO5zT4bLeubkWOXK0G51XSvACDOZVIyLdjApaOFTwamPcD3S1tfvuxRWWvsCD5ljFvb2kSmx5BIBNwN80MzuBmrGIC27XLGOxyMerwKxB6DskNUO9PflKHDPI61DRq0FTy1fv70SFMSiAtUv9aJRT41NQh9iJJ0vC8dl+xcxrWIjU1GG6+l/ZcRqVx9V1VuGQsLKndGhja7SQ+X1slHl76fRq223sMOql7MFCd0vvvxVQ2V39CcFKao/LB1aPH3VhODDEyxwx6aXoTznvC/QPepgWsHOWQzKj9ftsgDbsNiyFlXL4cu8DWUty6rQy8zT2b4O8b1xjcwSUCsy+auEjBamzQkMJFNlZAIUrukL/NbUhQU37TAbwsFyz7X0E/u/VMle/nBCNAzgkMwAUjiHM6FqrKKBRWFbPrSIixjfjkCnrMEPw=
file:
- ThinkPHP_Core.zip
- ThinkPHP_Full.zip
skip_cleanup: true
on:
tags: true

---

Crmeb/App/README (crmeb/app/README.md)

系统目录介绍优化方案

#### 1. 引言
在优化系统目录介绍时,我们的目标是使目录结构更加清晰、易于理解,并突出每个目录的核心功能和作用。

#### 2. 目录结构优化概述
我们将通过以下几个步骤来优化目录介绍:
- 明确目录层级:清晰展示主目录与子目录的关系。
- 突出核心功能:简要概括每个目录的主要作用和包含的文件类型。
- 增加示例或用途说明:对于关键目录,提供简短的示例或用途描述,帮助开发者快速理解。

#### 3. 优化后的目录介绍

目录结构

text
.
├── adminapi/ # 后台管理端API接口
├── api/ # 移动端API接口
├── dao/ # DAO层(数据访问对象)
├── http/ # HTTP中间件
├── jobs/ # 队列任务
├── kefuapi/ # 客服端API接口
├── lang/ # 语言包
├── listener/ # 事件监听器目录
├── model/ # Model层
├── services/ # Services层
├── subscribes/ # 事件订阅
├── AppService.php # 应用服务类
├── ExceptionHandle.php # 异常处理器
├── Request.php # 封装Request类
├── build.php # 构建配置
├── common.php # 公共方法
├── event.php # 事件配置
├── middleware.php # 中间件配置
├── provider.php # 容器Provider定义文件
└── service.php # 服务配置

##### app/
- 核心目录:存放应用程序的核心代码和资源。
- 包含内容:业务逻辑、控制器、模型、视图等。

###### app/adminapi/
- 功能:管理端应用控制器。
- 用途:处理管理端用户请求、业务逻辑和数据交互。
- 示例:管理员登录、权限管理等。

###### app/api/
- 功能:用户端应用控制器。
- 用途:处理用户端请求、业务逻辑和数据交互。
- 示例:用户注册、商品浏览等。

###### app/dao/
- 功能:数据访问对象(DAO)。
- 用途:封装数据访问操作,提供统一接口。
- 文件类型:类文件。

###### app/http/
- 功能:HTTP请求和响应跨域中间键。
- 用途:处理跨域请求,确保前后端通信顺畅。

###### app/jobs/
- 功能:消息队列任务。
- 用途:处理异步任务,如邮件发送、数据同步等。

###### app/kefuapi/
- 功能:客服端应用控制器。
- 用途:处理客服端请求、业务逻辑和数据交互。
- 示例:客服聊天、工单处理等。

###### app/lang/
- 功能:语言包。
- 用途:支持多语言功能,提供不同语言的文本资源。

###### app/listener/
- 功能:事件监听器。
- 用途:监听和处理系统事件,如用户登录、订单生成等。

###### app/model/
- 功能:模型类。
- 用途:封装数据访问操作,提供统一接口。
- 与dao区别:模型类更侧重于业务逻辑层面的数据操作。

###### app/outapi/
- 功能:对外接口应用控制器。
- 用途:处理外部系统请求、业务逻辑和数据交互。
- 示例:第三方支付回调、API对接等。

###### app/service/
- 功能:服务类。
- 用途:封装业务逻辑和数据交互操作,提供统一服务接口。
- 示例:用户服务、订单服务等。

#### 4. 结语
通过上述优化,我们使app目录及其子目录的介绍更加清晰、条理分明。每个目录的核心功能和用途都得到了突出展示,有助于开发者快速理解和定位代码。同时,增加的示例和用途说明也进一步降低了理解门槛,提升了开发效率。

---

Crmeb/App/Filetree (crmeb/app/filetree.txt)

.
├── adminapi //后台管理端API接口
├── api //移动端API接口
├── dao //dao层
├── http //中间件
├── jobs //队列
├── kefuapi //客服端API接口
├── lang //语言包
├── listener //事件目录
├── model //model层
├── services //services层
├── subscribes //订阅事件
├── AppService.php //
├── ExceptionHandle.php //异常处理
├── Request.php //封装request类
├── build.php //
├── common.php //公共方法
├── event.php //事件配置
├── middleware.php //中间件
├── provider.php //容器Provider定义文件
├── service.php
└── filetree.txt //目录说明

11 directories, 12 files

---

Crmeb/App/Adminapi/README (crmeb/app/adminapi/README.md)

crmeb/app/adminapi这个目录主要是后台管理系统的API接口文件。

具体来说:

- adminapi目录下的文件都是后台管理系统的控制器(Controller)文件,这些控制器被用来处理后台系统的各种请求。

- 每一个控制器文件对应后台管理系统某个功能模块,比如AuthController处理认证模块请求,StoreProduct处理商品模块请求等。

- 控制器内有各种方法,这些方法就相当于API接口,可以处理GET、POST请求,返回JSON数据。

- 浏览器或APP在调用这些API接口时,会发送请求到相应的控制器方法,例如登录接口请求到Login文件的login方法。

- 控制器处理完请求后,通过返回Response对象返回处理结果给浏览器或APP。

所以简单来说,adminapi目录负责后台管理系统的所有API接口,这些接口被APP或前端调用来完成各种管理操作,如查询数据、添加修改删除等。开发者在新增后台功能时,也需要在此目录增加对应的控制器和接口。

它实际上负责后台系统的通信交互层,解耦了后端逻辑和前端展示,采用 RESTful规范设计。

adminapi 目录结构说明

目录结构

text
.
├── config/ # 配置目录
├── controller/ # 控制器目录
├── lang/ # 语言包目录
├── middleware/ # 中间件目录
├── route/ # 路由配置目录
├── validate/ # 验证器目录
├── AdminApiExceptionHandle.php # 异常处理器
├── common.php # 公共方法
├── event.php # 事件配置
└── provider.php # 服务提供者

目录说明

- config/ - 后台管理端专用配置
- controller/ - 后台管理控制器,处理管理端业务逻辑
- lang/ - 后台管理端多语言文件
- middleware/ - 后台管理中间件,如权限验证、日志记录等
- route/ - 后台管理路由配置
- validate/ - 后台管理数据验证器

功能说明

adminapi模块专门用于处理后台管理系统的API接口,包括:
- 用户权限管理
- 商品管理
- 订单处理
- 数据统计
- 系统设置等后台管理功能

---

Crmeb/App/Adminapi/Filetree (crmeb/app/adminapi/filetree.txt)

.
├── config
├── controller
├── lang
├── middleware
├── route
├── validate
├── AdminApiExceptionHandle.php
├── common.php
├── event.php
├── filetree.txt
└── provider.php

6 directories, 5 files

---

Crmeb/App/Api/Filetree (crmeb/app/api/filetree.txt)

.
├── config
├── controller
├── lang
├── middleware
├── route
├── validate
├── ApiExceptionHandle.php
├── common.php
├── event.php
├── filetree.txt
└── provider.php

6 directories, 5 files

---

Crmeb/App/Dao/README (crmeb/app/dao/README.md)

crmeb/app/dao目录是项目数据访问对象(DAO)层的代码目录。

DAO层主要职责和作用如下:

1. 实现数据持久层访问,对数据库进行CURD操作。

2. 依赖数据库连接,实现对表的基本增删改查功能。

3. 封装数据库操作原语(查询,插入,更新等),简化开发难度。

4. 与数据库解藕,提供统一接口,便于扩展和维护。

具体来说:

- dao目录下每个文件对应一个数据表或业务模块
- 文件内封装了对表基本操作的方法,如查找,插入,更新等
- 方法的参数和返回值类型为模型对象(Model),实现数据和业务的解耦
- 提供丰富的查询条件以方便调用
- 底层利用ThinkPHP的ActiveRecord实现数据操作

使用DAO层的好处:

- 提供对象化的数据操作接口
- 屏蔽数据库差异,提高移植性
- 方便测试和扩展
- 实现业务和数据层的分离

所以该目录负责项目的底层数据操作,其他业务需要调用它来操作数据库。

---

Crmeb/App/Dao/Filetree (crmeb/app/dao/filetree.txt)

.
├── activity
│   ├── advance
│   ├── bargain
│   ├── combination
│   ├── coupon
│   ├── integral
│   ├── live
│   ├── lottery
│   └── seckill
├── agent
│   ├── AgentLevelDao.php
│   ├── AgentLevelTaskDao.php
│   ├── AgentLevelTaskRecordDao.php
│   └── DivisionAgentApplyDao.php
├── article
│   ├── ArticleCategoryDao.php
│   ├── ArticleContentDao.php
│   └── ArticleDao.php
├── diy
│   ├── DiyDao.php
│   ├── PageCategoryDao.php
│   └── PageLinkDao.php
├── order
│   ├── DeliveryServiceDao.php
│   ├── OtherOrderDao.php
│   ├── OtherOrderStatusDao.php
│   ├── StoreCartDao.php
│   ├── StoreOrderCartInfoDao.php
│   ├── StoreOrderDao.php
│   ├── StoreOrderEconomizeDao.php
│   ├── StoreOrderInvoiceDao.php
│   ├── StoreOrderRefundDao.php
│   ├── StoreOrderStatusDao.php
│   ├── StoreOrderStoreOrderCartInfoDao.php
│   └── StoreOrderStoreOrderStatusDao.php
├── other
│   ├── AgreementDao.php
│   ├── AuxiliaryDao.php
│   ├── CacheDao.php
│   ├── CategoryDao.php
│   ├── QrcodeDao.php
│   └── TemplateMessageDao.php
├── product
│   ├── product
│   └── sku
├── service
│   ├── StoreServiceAuxiliaryDao.php
│   ├── StoreServiceDao.php
│   ├── StoreServiceFeedbackDao.php
│   ├── StoreServiceLogDao.php
│   ├── StoreServiceRecordDao.php
│   └── StoreServiceSpeechcraftDao.php
├── shipping
│   ├── ExpressDao.php
│   ├── ShippingTemplatesDao.php
│   ├── ShippingTemplatesFreeCityDao.php
│   ├── ShippingTemplatesFreeDao.php
│   ├── ShippingTemplatesNoDeliveryCityDao.php
│   ├── ShippingTemplatesNoDeliveryDao.php
│   ├── ShippingTemplatesRegionCityDao.php
│   ├── ShippingTemplatesRegionDao.php
│   └── SystemCityDao.php
├── sms
│   ├── SmsAdminDao.php
│   └── SmsRecordDao.php
├── system
│   ├── admin
│   ├── attachment
│   ├── config
│   ├── log
│   ├── statistics
│   ├── store
│   ├── AppVersionDao.php
│   ├── MessageSystemDao.php
│   ├── SystemMenusDao.php
│   ├── SystemNotificationDao.php
│   └── SystemUserLevelDao.php
├── user
│   ├── MemberCardBatchDao.php
│   ├── MemberCardDao.php
│   ├── MemberRightDao.php
│   ├── MemberShipDao.php
│   ├── UserAddressDao.php
│   ├── UserAuthDao.php
│   ├── UserBillDao.php
│   ├── UserBillStoreOrderDao.php
│   ├── UserBrokerageDao.php
│   ├── UserBrokerageFrozenDao.php
│   ├── UserCancelDao.php
│   ├── UserDao.php
│   ├── UserExtractDao.php
│   ├── UserFriendsDao.php
│   ├── UserGroupDao.php
│   ├── UserInvoiceDao.php
│   ├── UserLabelCateDao.php
│   ├── UserLabelDao.php
│   ├── UserLabelRelationDao.php
│   ├── UserLevelDao.php
│   ├── UserMoneyDao.php
│   ├── UserRechargeDao.php
│   ├── UserSearchDao.php
│   ├── UserSignDao.php
│   ├── UserSpreadDao.php
│   ├── UserStoreOrderDao.php
│   ├── UserTaskFinishDao.php
│   ├── UserUserBillDao.php
│   ├── UserUserBrokerageDao.php
│   ├── UserVisitDao.php
│   └── UserWechatUserDao.php
├── wechat
│   ├── WechatKeyDao.php
│   ├── WechatMediaDao.php
│   ├── WechatMenuDao.php
│   ├── WechatMessageDao.php
│   ├── WechatNewsCategoryDao.php
│   ├── WechatQrcodeCateDao.php
│   ├── WechatQrcodeDao.php
│   ├── WechatQrcodeRecordDao.php
│   ├── WechatReplyDao.php
│   ├── WechatReplyKeyDao.php
│   └── WechatUserDao.php
├── BaseDao.php
└── filetree.txt

29 directories, 95 files

---

Crmeb/App/Jobs/README (crmeb/app/jobs/README.md)

crmeb/app/jobs目录是CRMEB项目队列任务类的代码目录。

队列任务在项目开发中有以下几个重要作用:

1. 异步处理。可以将一些耗时较长的任务放入队列以异步处理,不阻塞主线程。

2. 延迟处理。可以指定队列任务在一定时间后异步执行,比如发送短信或邮件。

3. 分布处理。可以将队列任务分布到不同服务器进行处理,提高服务器使用效率。

此目录下主要包含以下内容:

- 每个任务类对应一个业务任务,实现Job接口。

- 任务类内定义具体任务业务逻辑,如发送短信/邮件等。

- 通过Broker进行任务的发送和异步处理。

- 支持任务延时、失败重试等功能。

使用队列可以使得项目性能更优:

- 阻塞任务剥离出来异步执行。

- 分布式下每个任务独立运行,不阻塞其他进程。

- 通过Broker复用同一服务,且伸缩性好。

所以此目录负责项目中所有异步任务的编写和调度,起到优化系统性能和扩展能力的重要作用。

---

Crmeb/App/Jobs/Filetree (crmeb/app/jobs/filetree.txt)

.
├── notice
│   ├── EnterpriseWechatJob.php
│   ├── PrintJob.php
│   └── SmsJob.php
├── AgentJob.php
├── AutoCommentJob.php
├── LiveJob.php
├── OrderCreateAfterJob.php
├── OrderJob.php
├── OtherOrderJob.php
├── PinkJob.php
├── PosterJob.php
├── ProductCopyJob.php
├── ProductLogJob.php
├── RoutineTemplateJob.php
├── TakeOrderJob.php
├── TaskJob.php
├── TemplateJob.php
├── UnpaidOrderCancelJob.php
├── UnpaidOrderSend.php
├── UserJob.php
├── WechatTemplateJob.php
└── filetree.txt

1 directory, 22 files

---

Crmeb/App/Kefuapi/README (crmeb/app/kefuapi/README.md)

crmeb/app/kefuapi这个目录是用来放置客服相关接口的。

主要作用和特征:

1. 提供客服系统与商城前后端交互的API接口。

2. 接口主要用于聊天记录的增删改查以及发送消息等功能。

3. 使用ThinkPHP的Restful风格定义接口请求方式和参数。

4. 接口供移动端APP和PC网站调用实现客服聊天功能。

5. 后台也可以调用相关接口对客服记录进行管理。

具体包含:

- 控制器定义各API接口方法接受请求。

- 业务处理逻辑以及与数据库的交互。

- 数据验证和结果输出。

使用这个目录定义的客服API,可以:

- 商城各端实现在线客服功能。

- 查看历史记录。

- 服务端管理客服信息。

- 第三方也可以实现其它客服系统对接。

所以总之,此目录主要对客服系统开放API接口,便于商城多端整合用户支持体系。

---

Crmeb/App/Listener/README (crmeb/app/listener/README.md)

crmeb/app/listener目录用来定义项目的事件监听器。

在ThinkPHP框架中,事件监听器是一个重要的机制。它可以用于:

- 项目运行过程中的各个时间点自动调用指定的监听方法。

- 监听特定事物(如请求、响应等)发生后自动执行回调。

- 监听其它模块触发的事件,实现扩展钩子函数。

具体来说:

- 监听器类实现接口定义监听方法。

- 方法内可以完成业务逻辑,也可以触发下一个监听器。

- 监听器在配置中注册,在特定点自动调用定义的回调方法。

- 常见监听点有请求开始、响应结束等生命周期点。

这种设计可以:

- 实现跨模块调用无需依赖。

- 解耦业务和基础模块。

- 让第三方功能易于插拔扩展。

所以此目录定义的就是项目各种事件监听回调,起到系统级的扩展与定制作用。

---

Crmeb/App/Listener/Filetree (crmeb/app/listener/filetree.txt)

.
├── http
│   └── HttpEnd.php
├── notice
│   └── Notice.php
├── order
│   ├── OrderCreateAfter.php
│   ├── OrderDelivery.php
│   ├── OrderPaySuccess.php
│   ├── OrderRefund.php
│   └── OrderTake.php
├── user
│   ├── Login.php
│   ├── Register.php
│   ├── UserLevel.php
│   └── UserVisit.php
├── wechat
│   └── Auth.php
└── filetree.txt

5 directories, 13 files

---

Crmeb/App/Model/README (crmeb/app/model/README.md)

crmeb/app/model目录用于定义项目的数据模型类。

数据模型类的主要作用和特征有:

1. 每个模型类对应数据库中的一张表。

2. 类属性定义表结构,与表结构一一对应。

3. 包含读写数据相关方法,通过ActiveRecord实现。

4. 提供数据与数据库层解耦,统一的数据访问接口。

5. 数据验证机制,保证数据完整性和一致性。

具体包含:

- 定义模型属性,字段名称对应表结构。

- 自动返回属性值和赋值属性值。

- 实现基础的CRUD方法操作数据库。

- 可扩展自定义数据逻辑和验证规则。

使用模型类可以:

- 减少直接操作数据库带来的复杂性。

- 跨项目重用数据层逻辑。

- 提高项目的可扩展性与复用性。

所以该目录定义的数据模型层,统一封装了项目运用的数据表模型和操作方式。

---

Crmeb/App/Model/Filetree (crmeb/app/model/filetree.txt)

.
├── activity
│   ├── advance
│   ├── bargain
│   ├── combination
│   ├── coupon
│   ├── integral
│   ├── live
│   ├── lottery
│   └── seckill
├── agent
│   ├── AgentLevel.php
│   ├── AgentLevelTask.php
│   ├── AgentLevelTaskRecord.php
│   └── DivisionAgentApply.php
├── article
│   ├── Article.php
│   ├── ArticleCategory.php
│   └── ArticleContent.php
├── diy
│   ├── Diy.php
│   ├── PageCategory.php
│   └── PageLink.php
├── order
│   ├── DeliveryService.php
│   ├── OtherOrder.php
│   ├── OtherOrderStatus.php
│   ├── StoreCart.php
│   ├── StoreOrder.php
│   ├── StoreOrderCartInfo.php
│   ├── StoreOrderEconomize.php
│   ├── StoreOrderInvoice.php
│   ├── StoreOrderRefund.php
│   ├── StoreOrderStatus.php
│   └── StorePink.php
├── other
│   ├── Agreement.php
│   ├── Auxiliary.php
│   ├── Cache.php
│   ├── Category.php
│   ├── Express.php
│   ├── Qrcode.php
│   └── TemplateMessage.php
├── product
│   ├── product
│   └── sku
├── service
│   ├── StoreService.php
│   ├── StoreServiceFeedback.php
│   ├── StoreServiceLog.php
│   ├── StoreServiceRecord.php
│   └── StoreServiceSpeechcraft.php
├── shipping
│   ├── ShippingTemplates.php
│   ├── ShippingTemplatesFree.php
│   ├── ShippingTemplatesNoDelivery.php
│   ├── ShippingTemplatesRegion.php
│   └── SystemCity.php
├── sms
│   └── SmsRecord.php
├── system
│   ├── admin
│   ├── attachment
│   ├── config
│   ├── log
│   ├── statistics
│   ├── store
│   ├── AppVersion.php
│   ├── MessageSystem.php
│   ├── SystemMenus.php
│   ├── SystemNotification.php
│   ├── SystemUserLevel.php
│   └── SystemUserTask.php
├── user
│   ├── MemberCard.php
│   ├── MemberCardBatch.php
│   ├── MemberRight.php
│   ├── MemberShip.php
│   ├── User.php
│   ├── UserAddress.php
│   ├── UserBill.php
│   ├── UserBrokerage.php
│   ├── UserBrokerageFrozen.php
│   ├── UserCancel.php
│   ├── UserExtract.php
│   ├── UserFriends.php
│   ├── UserGroup.php
│   ├── UserInvoice.php
│   ├── UserLabel.php
│   ├── UserLabelCate.php
│   ├── UserLabelRelation.php
│   ├── UserLevel.php
│   ├── UserMoney.php
│   ├── UserRecharge.php
│   ├── UserSearch.php
│   ├── UserSign.php
│   ├── UserSpread.php
│   ├── UserTaskFinish.php
│   └── UserVisit.php
├── wechat
│   ├── WechatKey.php
│   ├── WechatMedia.php
│   ├── WechatMessage.php
│   ├── WechatNewsCategory.php
│   ├── WechatQrcode.php
│   ├── WechatQrcodeCate.php
│   ├── WechatQrcodeRecord.php
│   ├── WechatReply.php
│   └── WechatUser.php
└── filetree.txt

29 directories, 80 files

---

Crmeb/App/Outapi/README (crmeb/app/outapi/README.md)

crmeb/app/outapi目录用于定义项目对外开放的接口。

具体来说:

- 是项目对合作第三方开放的API接口定义目录

- 这里的接口可以被第三方直接调用来获取数据或完成相关业务

- 这类API接口与内部使用的API有区别:

- 对外开放,不需要登录授权
- 安全限制较严,只提供必要接口
- 接口规范遵循RESTful原则

- 常见场景:

- 第方小程序/APP直接获取商品数据
- 第方商户后台系统同步订单信息
- 小程序支付回调通知接口

使用这个目录定义外部接口可以:

- 实现与其他系统的深度集成

- 让更多场景能够使用CRMEB提供的能力

- 降低对第方的侵入性,仅开放必要接口

所以总结来说,outapi用于项目对外部开放的公开API,扩展第三方接入能力。

---

Crmeb/App/Outapi/Mcp (crmeb/app/outapi/mcp.md)

CRMEB MCP Server

基于 Model Context Protocol (MCP) 的 CRMEB API 工具服务器,已集成到 CRMEB outapi 模块中,允许 AI 助手通过标准协议调用 CRMEB 对外开放接口。

功能特性

- 🔗 集成到 CRMEB outapi 模块,无需额外部署
- 📦 商品管理(列表、详情、创建)
- 📂 分类管理(列表、详情、创建)
- 🛒 订单管理(列表、详情、发货)
- 💰 售后管理(列表、详情、同意/拒绝退款)
- 🎫 优惠券管理
- 👥 用户管理(列表、详情、赠送余额/积分)

环境要求

- CRMEB 系统
- PHP >= 7.4

快速开始

1. 创建开放接口账号

1. 登录 CRMEB 管理后台
2. 进入 设置 -> 系统设置 -> 开放接口
3. 创建应用获取账号和密码

2. 配置到 Claude Desktop

编辑配置文件:

macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json

json
{
"mcpServers": {
"crmeb": {
"url": "http://your-domain/outapi/mcp",
"headers": {
"account": "your_account",
"password": "your_password",
"Content-Type": "application/json"
},
"disabled": false
}
}
}

配置示例(演示环境):

json
{
"mcpServers": {
"crmebdemo": {
"url": "https://v5.crmeb.net/outapi/mcp",
"headers": {
"account": "ceshi",
"password": "ceshiceshi",
"Content-Type": "application/json"
},
"disabled": false
}
}
}

3. 配置到 Cursor

在 Cursor 设置中添加:

json
{
"mcp.servers": {
"crmeb": {
"url": "http://your-domain/outapi/mcp",
"headers": {
"account": "your_account",
"password": "your_password",
"Content-Type": "application/json"
},
"disabled": false
}
}
}

参数说明:

| 参数 | 说明 | 获取方式 |
|------|------|---------|
| url | CRMEB MCP 接口地址 | 固定值:http://域名/outapi/mcp |
| account | 开放接口账号 | CRMEB 后台 -> 设置 -> 开放接口 |
| password | 开放接口密码 | CRMEB 后台 -> 设置 -> 开放接口 |
| disabled | 是否禁用该服务 | 可选,默认为 false |

注意:直接配置 account 和 password 即可,系统会自动完成认证

支持的 MCP 客户端应用

以下是目前主流的支持 MCP 协议的应用程序,您可以在这些应用中配置和使用 CRMEB MCP 服务。

1. Claude Desktop

Anthropic 官方桌面应用,首个原生支持 MCP 的客户端。

配置步骤:
1. 下载并安装 Claude Desktop
2. 找到配置文件:
- macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
- Windows: %APPDATA%\Claude\claude_desktop_config.json
3. 添加 CRMEB MCP 配置:

json
{
"mcpServers": {
"crmeb": {
"url": "http://your-domain/outapi/mcp",
"headers": {
"account": "your_account",
"password": "your_password",
"Content-Type": "application/json"
},
"disabled": false
}
}
}

4. 重启 Claude Desktop

使用方法:
在对话中直接询问,例如:

text
帮我查询 CRMEB 中的商品分类列表

2. Cursor

AI 驱动的代码编辑器,内置 MCP 支持。

配置步骤:
1. 下载并安装 Cursor
2. 打开设置(Settings -> Features -> Model Context Protocol)
3. 添加 MCP 服务器配置:

json
{
"mcp.servers": {
"crmeb": {
"url": "http://your-domain/outapi/mcp",
"headers": {
"account": "your_account",
"password": "your_password",
"Content-Type": "application/json"
},
"disabled": false
}
}
}

4. 或者直接编辑配置文件:
- macOS/Linux: ~/.cursor/mcp.json
- Windows: %APPDATA%\Cursor\mcp.json

使用方法:
在 Cursor 的 AI 聊天窗口中直接使用:

text
查询 CRMEB 中的订单列表

3. Cline (VS Code 扩展)

VS Code 中的自主 AI 编程助手扩展。

配置步骤:
1. 在 VS Code 中安装 Cline 扩展
2. 打开 VS Code 设置
3. 搜索 "Cline MCP" 或在 Cline 面板中找到 MCP 配置
4. 添加 MCP 服务器:

json
{
"mcpServers": {
"crmeb": {
"url": "http://your-domain/outapi/mcp",
"headers": {
"account": "your_account",
"password": "your_password",
"Content-Type": "application/json"
},
"disabled": false
}
}
}

使用方法:
在 Cline 面板中输入指令:

text
获取 CRMEB 商品 ID 为 1 的详情

4. Windsurf

Codeium 推出的 AI 原生 IDE。

配置步骤:
1. 下载并安装 Windsurf
2. 打开设置 -> Developer Settings -> MCP Servers
3. 添加配置:

json
{
"mcpServers": {
"crmeb": {
"url": "http://your-domain/outapi/mcp",
"headers": {
"account": "your_account",
"password": "your_password",
"Content-Type": "application/json"
}
}
}
}

5. Continue (VS Code/JetBrains 扩展)

开源的 AI 代码助手扩展。

配置步骤:
1. 安装 Continue 扩展
- VS Code
- JetBrains
2. 打开 Continue 配置文件(~/.continue/config.json
3. 添加 MCP 配置:

json
{
"models": [...],
"mcpServers": {
"crmeb": {
"url": "http://your-domain/outapi/mcp",
"headers": {
"account": "your_account",
"password": "your_password",
"Content-Type": "application/json"
}
}
}
}

6. Zed

高性能代码编辑器,支持 MCP 协议。

配置步骤:
1. 下载并安装 Zed
2. 打开配置文件(~/.zed/settings.json
3. 添加 MCP 服务器配置:

json
{
"mcp_servers": {
"crmeb": {
"url": "http://your-domain/outapi/mcp",
"headers": {
"account": "your_account",
"password": "your_password",
"Content-Type": "application/json"
}
}
}
}

7. 其他支持 MCP 的应用

以下应用也在逐步支持 MCP 协议:

- Codeium:AI 代码补全工具
- Tabnine:AI 代码助手
- Sourcegraph Cody:代码智能助手

💡 提示:MCP 是一个开放协议,越来越多的 AI 应用正在支持。如果您的应用支持 MCP,通常可以在设置中找到 MCP 或 Model Context Protocol 相关配置项。

可用工具

分类管理

| 工具名称 | 描述 | 必需参数 | 可选参数 |
|---------|------|---------|---------|
| crmeb_category_list | 获取分类列表 | - | page, limit |
| crmeb_category_detail | 获取分类详情 | id | - |
| crmeb_category_create | 创建分类 | name | pid, sort |

商品管理

| 工具名称 | 描述 | 必需参数 | 可选参数 |
|---------|------|---------|---------|
| crmeb_product_list | 获取商品列表 | - | page, limit, cate_id, keyword, stock_min, stock_max |
| crmeb_product_detail | 获取商品详情 | id | - |
| crmeb_product_create | 创建商品 | name, cate_id, price, stock | image, unit |

订单管理

| 工具名称 | 描述 | 必需参数 | 可选参数 |
|---------|------|---------|---------|
| crmeb_order_list | 获取订单列表 | - | page, limit, status, keyword |
| crmeb_order_detail | 获取订单详情 | order_id | - |
| crmeb_order_delivery | 订单发货 | order_id, delivery_type | delivery_name, delivery_id |
| crmeb_order_express_list | 获取物流公司列表 | - | - |

售后管理

| 工具名称 | 描述 | 必需参数 | 可选参数 |
|---------|------|---------|---------|
| crmeb_refund_list | 获取售后列表 | - | page, limit |
| crmeb_refund_detail | 获取售后详情 | order_id | - |
| crmeb_refund_agree | 同意退款 | order_id | - |
| crmeb_refund_refuse | 拒绝退款 | order_id, refuse_reason | - |

优惠券管理

| 工具名称 | 描述 | 必需参数 | 可选参数 |
|---------|------|---------|---------|
| crmeb_coupon_list | 获取优惠券列表 | - | page, limit |

用户管理

| 工具名称 | 描述 | 必需参数 | 可选参数 |
|---------|------|---------|---------|
| crmeb_user_list | 获取用户列表 | - | page, limit, keyword |
| crmeb_user_detail | 获取用户详情 | uid | - |
| crmeb_user_give_balance | 赠送余额 | uid, balance | title |
| crmeb_user_give_point | 赠送积分 | uid, point | title |

使用示例

在 Claude 或 Cursor 中,您可以这样使用:

text
帮我查询 CRMEB 中的商品列表

text
创建一个新商品:名称"测试商品",分类ID 1,价格 99.00,库存 100

text
查询订单号 202403130001 的详情

text
给用户 ID 为 1 的用户赠送 100 积分

接口测试

text
/ Detailed source-code truncated for AI context efficiency. /

项目结构

text
crmeb/app/outapi/
├── controller/
│ ├── Mcp.php # MCP 控制器
│ ├── Login.php # 认证控制器
│ ├── StoreProduct.php # 商品控制器
│ ├── StoreCategory.php # 分类控制器
│ ├── StoreOrder.php # 订单控制器
│ ├── RefundOrder.php # 售后控制器
│ ├── StoreCoupon.php # 优惠券控制器
│ ├── User.php # 用户控制器
│ └── ...
├── route/
│ └── route.php # 路由配置
├── middleware/
│ └── AuthTokenMiddleware.php
├── mcp.md # 本文档
└── README.md # outapi 模块说明

协议说明

MCP 协议版本

- 支持版本:2024-11-05

JSON-RPC 2.0 格式

请求格式:

json
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "工具名称",
"arguments": { "参数": "值" }
}
}

成功响应:

json
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "{...结果数据...}"
}
]
}
}

错误响应:

json
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32603,
"message": "错误信息"
}
}

错误码说明

| 错误码 | 说明 |
|-------|------|
| -32700 | JSON 解析错误 |
| -32600 | 请求无效(认证失败等) |
| -32601 | 方法不存在 |
| -32603 | 内部错误 |

相关链接

- Model Context Protocol 文档
- CRMEB 开放接口

---

Crmeb/App/Services/README (crmeb/app/services/README.md)

crmeb/app/services目录用于定义项目的业务服务类。

服务类的主要特征和作用包括:

1. 服务类封装具体的业务逻辑和规则。

2. 完成功能模块的抽象,提供统一的业务接口。

3. 解耦项目各部分,降低他们之间的耦合度。

4. 提供给上下文的整个环境使用。

具体来说:

- 每个服务类对应一个独立的业务功能或规则集合。

- 类内部可以调用其它模块完成业务需求。

- 对外提供简单的业务接口,隐藏内部实现细节。

- 服务类存在依赖关系,可以互相调用实现聚合服务。

使用服务层设计可以:

- 松耦合各个模块,提高扩展和重用能力。

- 同一个业务规则在多个场景复用。

- 加强项目的可测试性与维护性。

所以此目录定义了项目核心业务服务模块,对外提供可复用的核心能力。

---

Crmeb/Backup/Readme (crmeb/backup/readme.md)

crmeb/backup目录在CRMEB项目中的主要作用是用于保存项目的数据备份文件。

该目录用于存储系统运行过程中生成的各类备份数据,保障数据安全和灾难恢复能力。

具体来说:

- 数据库备份文件,用于数据恢复和迁移
- 系统配置文件备份,防止配置丢失
- 重要业务数据的历史归档
- 升级前的数据快照,便于回滚操作
- 定时任务自动生成的备份文件

使用这个目录有以下优点:

- 实现数据的定期备份与版本管理
- 与运行数据隔离,确保备份数据安全
- 便于快速恢复系统到指定时间点
- 支持手动和自动化的备份策略
- 方便进行数据迁移和系统升级

总体来说,它承担了项目数据安全保护和灾难恢复的核心职责。

通过合理利用这个目录,可以有效降低数据丢失风险,提升系统的可靠性和可维护性。

---

Crmeb/Config/README (crmeb/config/README.md)

crmeb/config目录用来存放项目的配置文件。

在PHP项目开发中,配置文件扮演着非常重要的角色:

- 放置各种系统级参数和设置,如数据库连接信息等
- 分离软件代码和运行环境设置,方便部署
- 运行时根据配置加载系统服务和组件
- 参数可在不修改代码的情况下进行变更

CRMEB项目中config目录负责:

- 放置如数据库、本地缓存、第三方开放API等系统配置
- 定义项目组件自动加载机制
- 路由和URL重写规则
- 错误和日志输出级别
- 各环境参数差异配置隔离

项目在运行时会加载并解析这些配置:

- 初始化系统服务如数据库连接
- 注册组件到容器
- 根据配置加载运行环境
- 提供参数和变量给其它模块

所以该目录定义了项目的系统架构和运行环境,对项目有重要影响。

它通过配置实现项目的可配置性和扩展性。

---

Crmeb/Config/Filetree (crmeb/config/filetree.txt)

.
├── app.php //
├── cache.php //缓存配置
├── captcha.php //验证码配置
├── console.php //命令行配置
├── cookie.php //cookie配置
├── database.php //数据库配置
├── filesystem.php //系统文件目录配置
├── lang.php //多语言配置
├── log.php //日志配置
├── pay.php //支付配置
├── plat.php //对接平台配置
├── printer.php //小票打印机配置
├── qrcode.php //二维码配置
├── queue.php //队列配置
├── route.php //路由配置
├── session.php //session配置
├── sms.php //短信发送配置
├── template.php //微信模版消息配置
├── trace.php //调试配置
├── upload.php //上传配置
├── view.php //模版配置
├── workerman.php //workerman配置
└── filetree.txt //目录文件说明

0 directories, 23 files

---

Crmeb/Crmeb/README (crmeb/crmeb/README.md)

crmeb目录在CRMEB项目中的作用是一个特殊目录

- crmeb目录实际上是整个项目的核心库目录
- 它包含项目的核心类、traits、异常定义等
- 这些核心文件提供给整个项目 reused
- 例如请求处理类、响应处理类等
- 它实现了项目特定的封装和扩展
- 使项目各部分能够在一套框架体系下开发

简而言之,crmeb目录:

- 包含项目的各种核心基础支持类
- 为整个项目提供基础功能定定义
- 使项目具备一致性和可扩展性
- 是项目最核心和基础的代码库

---

Crmeb/Crmeb/Filetree (crmeb/crmeb/filetree.txt)

.
├── basic
│   ├── BaseController.php //控制器基类
│   ├── BaseJobs.php //队列基类
│   ├── BaseManager.php //驱动管理基类
│   ├── BaseModel.php //model基类
│   └── BaseStorage.php //驱动基类
├── command
│   ├── stubs //命令模版
│   ├── Dao.php //创建Dao类命令
│   ├── Service.php //创建Service类命令
│   ├── Timer.php //定时任务命令类
│   └── Workerman.php //workman命令类
├── exceptions
│   ├── AdminException.php //后台管理端异常处理
│   ├── ApiException.php //移动端接口异常处理
│   ├── AuthException.php //用户授权异常处理
│   ├── PayException.php //支付异常处理
│   ├── SmsException.php //短信异常处理
│   ├── TemplateException.php //微信模版消息异常处理
│   ├── UploadException.php //上传异常处理
│   └── WechatReplyException.php //微信自动回复异常处理
├── interfaces
│   ├── JobInterface.php //队列任务
│   ├── ListenerInterface.php //事件
│   ├── MiddlewareInterface.php //中间件
│   └── ProviderInterface.php //容器
├── services
│   ├── app //应用端
│   ├── easywechat //easywechat
│   ├── express //物流查询
│   ├── pay //支付
│   ├── printer //打印机
│   ├── copyproduct //采集商品
│   ├── serve //服务平台
│   ├── sms //短信
│   ├── template //模版消息
│   ├── upload //上传
│   ├── workerman //workerman
│   ├── AccessTokenServeService.php //获取token
│   ├── AliPayService.php
│   ├── CacheService.php //缓存类
│   ├── FileService.php //文件处理类
│   ├── FormBuilder.php //自动生成表单类
│   ├── GroupDataService.php //组合数据类
│   ├── HttpService.php //curl 请求处理类
│   ├── MysqlBackupService.php //数据库备份管理类
│   ├── SpreadsheetExcelService.php //excel处理类
│   ├── SystemConfigService.php //系统配置获取类
│   ├── UpgradeService.php //系统更新类
│   └── UploadService.php //文件上传类
├── traits
│   ├── ErrorTrait.php //错误处理扩展类
│   ├── JwtAuthModelTrait.php //Jwt鉴权扩展类
│   ├── ModelTrait.php //model扩展类
│   ├── QueueTrait.php //队列扩展累
│   ├── SearchDaoTrait.php //dao扩展类
│   └── ServicesTrait.php //Services扩展类
├── utils
│   ├── Arr.php //操作数组帮助类
│   ├── Canvas.php //图片处理类
│   ├── Captcha.php //验证码类
│   ├── DownloadImage.php //远程图片下载类
│   ├── ErrorCode.php //错误码处理类
│   ├── Hook.php //钩子类
│   ├── Json.php //Json处理类
│   ├── JwtAuth.php //Jwt鉴权类
│   ├── QRcode.php //二维码获取类 TODO
│   ├── Queue.php //队列类
│   └── Str.php //字符处理类
└── filetree.txt

17 directories, 70 files

---

Crmeb/Public/Admin/Manifest.Json (crmeb/public/admin/manifest.json)

{
"name":"CRMEB",
"display":"standalone",
"start_url":".",
"id": "index.html",
"background_color": "#999",
"theme_color":"#292d3e",
"icons":[{
"src":"./image/logo-small.png",
"sizes":"144x144",
"type":"image/png"
}]
}

---

Crmeb/Public/Statics/Mp View/App.Json (crmeb/public/statics/mp_view/app.json)

{
"pages": [
"pages/guide/index",
"pages/index/index",
"pages/order_addcart/order_addcart",
"pages/user/index",
"pages/goods_cate/goods_cate"
],
"subPackages": [
{
"root": "pages/goods_details",
"pages": [
"index"
],
"name": "goods_details"
},
{
"root": "pages/extension",
"pages": [
"customer_list/chat",
"news_list/index",
"news_details/index"
],
"name": "extension"
},
{
"root": "pages/goods",
"pages": [
"goods_list/index",
"goods_search/index",
"order_pay_status/index",
"admin_order_detail/index",
"goods_comment_con/index",
"goods_comment_con/lottery_comment",
"goods_comment_list/index",
"goods_details_store/index",
"goods_logistics/index",
"goods_return/index",
"goods_return_list/index",
"lottery/grids/index",
"lottery/grids/record",
"order_confirm/index",
"order_details/index",
"order_list/index",
"order_refund_goods/index",
"receive_gifts_status/index",
"receive_gift/index",
"cashier/index"
],
"name": "goods"
},
{
"root": "pages/users",
"pages": [
"user_vip_areer/index",
"privacy/index",
"user_cancellation/index",
"message_center/index",
"message_center/messageDetail",
"user_invoice_order/index",
"scan_login/index",
"user_invoice_list/index",
"user_invoice_form/index",
"wechat_login/index",
"binding_phone/index",
"retrievePassword/index",
"user_info/index",
"user_get_coupon/index",
"visit_list/index",
"user_goods_collection/index",
"user_sgin/index",
"user_sgin_list/index",
"user_money/index",
"user_bill/index",
"user_integral/index",
"user_coupon/index",
"user_spread_user/index",
"user_spread_code/index",
"user_spread_money/index",
"user_spread_money/receiving",
"user_cash/index",
"user_vip/index",
"user_distribution_level/index",
"user_address_list/index",
"user_address/index",
"user_phone/index",
"user_payment/index",
"user_pwd_edit/index",
"promoter-list/index",
"promoter-order/index",
"promoter_rank/index",
"commission_rank/index",
"user_return_list/index",
"login/index",
"payment_on_behalf/index",
"payment_on_behalf/pay_status",
"staff_list/index"
],
"name": "users",
"plugins": {
"live-player-plugin": {
"version": "1.3.5",
"provider": "wx2b03c6e691cd7370"
}
}
},
{
"root": "pages/activity",
"pages": [
"goods_bargain/index",
"goods_bargain_details/index",
"goods_combination/index",
"goods_combination_details/index",
"goods_combination_status/index",
"goods_seckill/index",
"goods_seckill_details/index",
"poster-poster/index",
"bargain/index",
"presell/index"
],
"name": "activity"
},
{
"root": "pages/admin",
"pages": [
"distribution/index",
"distribution/scanning/index",
"distribution/scanning/detail/index",
"distribution/orderDetail/index",
"custom_date/index",
"order/index",
"orderList/index",
"orderDetail/index",
"delivery/index",
"refund/index",
"logistics/index",
"refund_order_list/index",
"refund_order_detail/index",
"goods/index",
"goods/specs",
"goods/addGoods",
"user/list",
"user/index",
"statistics/index",
"order_cancellation/index"
],
"name": "adminOrder"
},
{
"root": "pages/columnGoods",
"pages": [
"HotNewGoods/index",
"HotNewGoods/feedback",
"live_list/index"
],
"name": "columnGoods"
},
{
"root": "pages/annex",
"pages": [
"web_view/index",
"vip_paid/index",
"vip_coupon/index",
"vip_clause/index",
"vip_active/index",
"offline_pay/index",
"offline_result/index",
"special/index",
"settled/index"
]
},
{
"root": "pages/points_mall",
"pages": [
"index",
"integral_goods_list",
"integral_goods_details",
"exchange_record",
"integral_order",
"user_address",
"integral_order_status",
"integral_order_details",
"logistics_details"
]
},
{
"root": "subpackage/diyComponents",
"pages": [
"pages/placeholder"
],
"name": "diyComponents"
}
],
"window": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "加载中",
"navigationBarBackgroundColor": "#fff",
"backgroundColor": "#F8F8F8",
"titleNView": false,
"pageOrientation": "portrait"
},
"tabBar": {
"color": "#282828",
"selectedColor": "#ff3366",
"borderStyle": "white",
"backgroundColor": "#ffffff",
"list": [
{
"pagePath": "pages/index/index",
"iconPath": "static/images/1-001.png",
"selectedIconPath": "static/images/1-002.png",
"text": "首页"
},
{
"pagePath": "pages/goods_cate/goods_cate",
"iconPath": "static/images/2-001.png",
"selectedIconPath": "static/images/2-002.png",
"text": "分类"
},
{
"pagePath": "pages/order_addcart/order_addcart",
"iconPath": "static/images/3-001.png",
"selectedIconPath": "static/images/3-002.png",
"text": "购物车"
},
{
"pagePath": "pages/user/index",
"iconPath": "static/images/4-001.png",
"selectedIconPath": "static/images/4-002.png",
"text": "我的"
}
]
},
"permission": {
"scope.userLocation": {
"desc": "你的位置信息将用于查看与门店的距离"
}
},
"requiredPrivateInfos": [
"getLocation",
"onLocationChange",
"startLocationUpdateBackground",
"chooseAddress"
],
"__usePrivacyCheck__": true,
"usingComponents": {
"skeleton": "/components/skeleton/index",
"page-loading": "/components/pageLoading",
"easy-loadimage": "/components/easy-loadimage/easy-loadimage",
"base-money": "/components/BaseMoney",
"base-tag": "/components/BaseTag",
"base-drawer": "/components/tuiDrawer/tui-drawer"
},
"sitemapLocation": "sitemap.json"
}

---

Crmeb/Public/Statics/Mp View/Project.Config.Json (crmeb/public/statics/mp_view/project.config.json)

{
"description": "项目配置文件。",
"packOptions": {
"ignore": [],
"include": []
},
"setting": {
"urlCheck": false,
"es6": true,
"postcss": true,
"minified": true,
"newFeature": true,
"bigPackageSizeSupport": true,
"babelSetting": {
"ignore": [],
"disablePlugins": [],
"outputPath": ""
}
},
"compileType": "miniprogram",
"libVersion": "3.15.2",
"appid": "wx3b82801238ca1b57",
"projectname": "CRMEB标准版",
"condition": {},
"editorSetting": {
"tabIndent": "insertSpaces",
"tabSize": 2
}
}

---

Crmeb/Public/Statics/Mp View/Project.Private.Config.Json (crmeb/public/statics/mp_view/project.private.config.json)

{
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
"projectname": "CRMEB标准版",
"setting": {
"compileHotReLoad": true
}
}

---

Crmeb/Public/Statics/Mp View/Sitemap.Json (crmeb/public/statics/mp_view/sitemap.json)

{
"desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
"rules": [{
"action": "allow",
"page": "*"
}]
}

---

Crmeb/Public/Statics/Mp View/Components/Jyf Parser/Jyf Parser.Json (crmeb/public/statics/mp_view/components/jyf-parser/jyf-parser.json)

{
"component": true,
"usingComponents": {
"trees": "/components/jyf-parser/libs/trees"
}
}

---

Crmeb/Public/Statics/Mp View/Components/Jyf Parser/Libs/Trees.Json (crmeb/public/statics/mp_view/components/jyf-parser/libs/trees.json)

{
"component": true,
"usingComponents": {
"trees": "/components/jyf-parser/libs/trees"
}
}

---

{
"component": true,
"usingComponents": {
"base-badge": "/components/BaseBadge/index"
}
}

---

Crmeb/Public/Statics/Mp View/Components/Recommend/Index.Json (crmeb/public/statics/mp_view/components/recommend/index.json)

{
"component": true,
"usingComponents": {
"easy-loadimage": "/components/easy-loadimage/easy-loadimage"
}
}

---

Crmeb/Public/Statics/Mp View/Components/WaterfallsFlow/WaterfallsFlow.Json (crmeb/public/statics/mp_view/components/WaterfallsFlow/WaterfallsFlow.json)

{
"component": true,
"usingComponents": {
"waterfalls-flow-item": "/components/WaterfallsFlow/WaterfallsFlowItem"
}
}

---

Crmeb/Public/Statics/Mp View/Components/WaterfallsFlow/WaterfallsFlowItem.Json (crmeb/public/statics/mp_view/components/WaterfallsFlow/WaterfallsFlowItem.json)

{
"component": true,
"usingComponents": {
"easy-loadimage": "/components/easy-loadimage/easy-loadimage"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Activity/Bargain/Index.Json (crmeb/public/statics/mp_view/pages/activity/bargain/index.json)

{
"navigationBarTitleText": "砍价记录",
"usingComponents": {
"count-down": "/components/countDown/index",
"loading": "/components/Loading/index",
"empty-page": "/components/emptyPage",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Activity/Goods Bargain/Index.Json (crmeb/public/statics/mp_view/pages/activity/goods_bargain/index.json)

{
"navigationBarTitleText": "砍价列表",
"usingComponents": {
"home": "/components/home/index",
"authorize": "/components/Authorize"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Activity/Goods Bargain Details/Index.Json (crmeb/public/statics/mp_view/pages/activity/goods_bargain_details/index.json)

{
"navigationBarTitleText": "砍价活动",
"usingComponents": {
"jyf-parser": "/components/jyf-parser/jyf-parser",
"count-down": "/components/countDown/index",
"authorize": "/components/Authorize",
"home": "/components/home/index",
"bargain-poster": "/pages/activity/poster-poster/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Activity/Goods Combination/Index.Json (crmeb/public/statics/mp_view/pages/activity/goods_combination/index.json)

{
"navigationBarTitleText": "拼团活动",
"usingComponents": {
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Activity/Goods Combination Details/Index.Json (crmeb/public/statics/mp_view/pages/activity/goods_combination_details/index.json)

{
"navigationStyle": "custom",
"usingComponents": {
"product-con-swiper": "/components/productConSwiper/index",
"kefu-icon": "/components/kefuIcon/index",
"authorize": "/components/Authorize",
"product-window": "/components/productWindow/index",
"user-evaluation": "/components/userEvaluation/index",
"count-down": "/components/countDown/index",
"cus-preview-img": "/components/cusPreviewImg/index",
"parser": "/components/jyf-parser/jyf-parser",
"menu-icon": "/components/menuIcon",
"home-list": "/components/homeList/index",
"swiper-previe": "/components/cusPreviewImg/swiperPrevie"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Activity/Goods Combination Status/Index.Json (crmeb/public/statics/mp_view/pages/activity/goods_combination_status/index.json)

{
"navigationBarTitleText": "拼团",
"usingComponents": {
"count-down": "/components/countDown/index",
"product-window": "/components/productWindow/index",
"home": "/components/home/index",
"authorize": "/components/Authorize"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Activity/Goods Seckill/Index.Json (crmeb/public/statics/mp_view/pages/activity/goods_seckill/index.json)

{
"navigationBarTitleText": "限时秒杀",
"usingComponents": {
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Activity/Goods Seckill Details/Index.Json (crmeb/public/statics/mp_view/pages/activity/goods_seckill_details/index.json)

{
"navigationStyle": "custom",
"navigationBarTextStyle": "white",
"usingComponents": {
"product-con-swiper": "/components/productConSwiper/index",
"product-window": "/components/productWindow/index",
"user-evaluation": "/components/userEvaluation/index",
"kefu-icon": "/components/kefuIcon/index",
"menu-icon": "/components/menuIcon",
"count-down": "/components/countDown/index",
"cus-preview-img": "/components/cusPreviewImg/index",
"swiper-previe": "/components/cusPreviewImg/swiperPrevie",
"parser": "/components/jyf-parser/jyf-parser",
"home-list": "/components/homeList/index",
"authorize": "/components/Authorize"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Activity/Poster Poster/Index.Json (crmeb/public/statics/mp_view/pages/activity/poster-poster/index.json)

{
"navigationBarTitleText": "砍价海报",
"usingComponents": {
"zb-code": "/components/zb-code/zb-code"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Activity/Presell/Index.Json (crmeb/public/statics/mp_view/pages/activity/presell/index.json)

{
"navigationBarTitleText": "预售列表",
"usingComponents": {
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/Components/Uni Calendar/Uni Calendar.Json (crmeb/public/statics/mp_view/pages/admin/components/uni-calendar/uni-calendar.json)

{
"component": true,
"usingComponents": {
"uni-calendar-item": "/pages/admin/components/uni-calendar/uni-calendar-item"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/Custom Date/Index.Json (crmeb/public/statics/mp_view/pages/admin/custom_date/index.json)

{
"navigationBarTitleText": "选择日期",
"usingComponents": {
"uni-calendar": "/pages/admin/components/uni-calendar/uni-calendar"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/Delivery/Index.Json (crmeb/public/statics/mp_view/pages/admin/delivery/index.json)

{
"navigationBarTitleText": "订单发货",
"usingComponents": {
"split-order": "/pages/admin/components/splitOrder/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/Distribution/Index.Json (crmeb/public/statics/mp_view/pages/admin/distribution/index.json)

{
"navigationStyle": "custom",
"usingComponents": {
"loading": "/components/Loading/index",
"empty-page": "/components/emptyPage",
"nav-bar": "/components/NavBar"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/Distribution/OrderDetail/Index.Json (crmeb/public/statics/mp_view/pages/admin/distribution/orderDetail/index.json)

{
"navigationStyle": "custom",
"usingComponents": {
"custom-form": "/pages/admin/components/customForm/index",
"nav-bar": "/components/NavBar"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/Distribution/Scanning/Index.Json (crmeb/public/statics/mp_view/pages/admin/distribution/scanning/index.json)

{
"navigationBarTitleText": "订单核销",
"usingComponents": {
"write-off-list": "/pages/admin/components/writeOffList/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/Distribution/Scanning/Detail/Index.Json (crmeb/public/statics/mp_view/pages/admin/distribution/scanning/detail/index.json)

{
"navigationBarTitleText": "订单核销",
"usingComponents": {
"write-off-switching": "/pages/admin/components/writeOffSwitching/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/Goods/AddGoods.Json (crmeb/public/statics/mp_view/pages/admin/goods/addGoods.json)

{
"navigationBarTitleText": "添加商品",
"usingComponents": {
"nav-bar": "/components/NavBar",
"classify": "/pages/admin/goods/components/classify/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/Goods/Index.Json (crmeb/public/statics/mp_view/pages/admin/goods/index.json)

{
"navigationStyle": "custom",
"navigationBarTitleText": "商品管理",
"usingComponents": {
"edit-price": "/pages/admin/goods/components/editPrice/index",
"edit-lable": "/pages/admin/goods/components/label/index",
"classify": "/pages/admin/goods/components/classify/index",
"footer-page": "/pages/admin/components/footerPage/index",
"empty-page": "/components/emptyPage",
"loading": "/components/Loading/index",
"base-drawer": "/components/tuiDrawer/tui-drawer"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/Goods/Specs.Json (crmeb/public/statics/mp_view/pages/admin/goods/specs.json)

{
"navigationBarTitleText": "修改价格/库存",
"navigationBarBackgroundColor": "#F5F5F5",
"usingComponents": {
"edit-price": "/pages/admin/goods/components/editPrice/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/Goods/Components/Classify/Index.Json (crmeb/public/statics/mp_view/pages/admin/goods/components/classify/index.json)

{
"component": true,
"usingComponents": {
"empty-page": "/components/emptyPage",
"base-drawer": "/components/tuiDrawer/tui-drawer"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/Goods/Components/EditPrice/Index.Json (crmeb/public/statics/mp_view/pages/admin/goods/components/editPrice/index.json)

{
"component": true,
"usingComponents": {
"base-drawer": "/components/tuiDrawer/tui-drawer"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/Goods/Components/Label/Index.Json (crmeb/public/statics/mp_view/pages/admin/goods/components/label/index.json)

{
"component": true,
"usingComponents": {
"empty-page": "/components/emptyPage",
"base-drawer": "/components/tuiDrawer/tui-drawer"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/Logistics/Index.Json (crmeb/public/statics/mp_view/pages/admin/logistics/index.json)

{
"navigationBarTitleText": "物流信息",
"navigationStyle": "custom",
"usingComponents": {
"nav-bar": "/components/NavBar",
"empty-page": "/components/emptyPage"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/Order/Index.Json (crmeb/public/statics/mp_view/pages/admin/order/index.json)

{
"navigationBarTitleText": "订单统计",
"usingComponents": {
"loading": "/components/Loading/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/Order Cancellation/Index.Json (crmeb/public/statics/mp_view/pages/admin/order_cancellation/index.json)

{
"navigationBarTitleText": "订单核销",
"usingComponents": {
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/OrderDetail/Index.Json (crmeb/public/statics/mp_view/pages/admin/orderDetail/index.json)

{
"navigationBarTitleText": "订单详情",
"usingComponents": {
"price-change": "/pages/admin/components/PriceChange/index",
"custom-form": "/pages/admin/components/customForm/index",
"count-down": "/components/countDown/index",
"nav-bar": "/components/NavBar"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/OrderList/Index.Json (crmeb/public/statics/mp_view/pages/admin/orderList/index.json)

{
"navigationBarTitleText": "订单列表",
"usingComponents": {
"loading": "/components/Loading/index",
"price-change": "/pages/admin/components/PriceChange/index",
"footer-page": "/pages/admin/components/footerPage/index",
"count-down": "/components/countDown/index",
"empty-page": "/components/emptyPage",
"nav-bar": "/components/NavBar"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/Refund/Index.Json (crmeb/public/statics/mp_view/pages/admin/refund/index.json)

{
"navigationBarTitleText": "售后退款",
"navigationStyle": "custom",
"usingComponents": {
"split-order": "/pages/admin/components/splitOrder/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/Refund Order Detail/Index.Json (crmeb/public/statics/mp_view/pages/admin/refund_order_detail/index.json)

{
"navigationBarTitleText": "售后订单详情",
"navigationStyle": "custom",
"usingComponents": {
"price-change": "/pages/admin/components/PriceChange/index",
"custom-form": "/pages/admin/components/customForm/index",
"nav-bar": "/components/NavBar"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/Refund Order List/Index.Json (crmeb/public/statics/mp_view/pages/admin/refund_order_list/index.json)

{
"navigationBarTitleText": "售后订单列表",
"navigationStyle": "custom",
"usingComponents": {
"loading": "/components/Loading/index",
"price-change": "/pages/admin/components/PriceChange/index",
"empty-page": "/components/emptyPage",
"nav-bar": "/components/NavBar",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/Statistics/Index.Json (crmeb/public/statics/mp_view/pages/admin/statistics/index.json)

{
"navigationBarTitleText": "订单数据统计",
"usingComponents": {
"uni-calendar": "/pages/admin/components/uni-calendar/uni-calendar"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/User/Index.Json (crmeb/public/statics/mp_view/pages/admin/user/index.json)

{
"navigationStyle": "custom",
"navigationBarTitleText": "用户详情",
"usingComponents": {
"edit-lable": "/pages/admin/user/components/userLable/index",
"edit-balance": "/pages/admin/user/components/editBalance/index",
"member": "/pages/admin/user/components/member/index",
"coupon": "/pages/admin/user/components/coupon/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/User/List.Json (crmeb/public/statics/mp_view/pages/admin/user/list.json)

{
"navigationStyle": "custom",
"navigationBarTitleText": "用户管理",
"usingComponents": {
"edit-lable": "/pages/admin/user/components/userLable/index",
"edit-balance": "/pages/admin/user/components/editBalance/index",
"member": "/pages/admin/user/components/member/index",
"coupon": "/pages/admin/user/components/coupon/index",
"user-filter": "/pages/admin/user/components/filter/index",
"footer-page": "/pages/admin/components/footerPage/index",
"empty-page": "/components/emptyPage",
"loading": "/components/Loading/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/User/Components/Coupon/Index.Json (crmeb/public/statics/mp_view/pages/admin/user/components/coupon/index.json)

{
"component": true,
"usingComponents": {
"empty-page": "/components/emptyPage"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Admin/User/Components/UserLable/Index.Json (crmeb/public/statics/mp_view/pages/admin/user/components/userLable/index.json)

{
"component": true,
"usingComponents": {
"empty-page": "/components/emptyPage"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Annex/Components/Verify/Verify.Json (crmeb/public/statics/mp_view/pages/annex/components/verify/verify.json)

{
"component": true,
"usingComponents": {
"verify-slide": "/pages/annex/components/verify/verifySlider/verifySlider",
"verify-point": "/pages/annex/components/verify/verifyPoint/verifyPoint",
"verify-slider-pc": "/pages/annex/components/verify/verifySlider/verifySliderPc"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Annex/Offline Pay/Index.Json (crmeb/public/statics/mp_view/pages/annex/offline_pay/index.json)

{
"navigationBarTitleText": "支付",
"usingComponents": {}
}

---

Crmeb/Public/Statics/Mp View/Pages/Annex/Offline Result/Index.Json (crmeb/public/statics/mp_view/pages/annex/offline_result/index.json)

{
"navigationBarTitleText": "支付结果",
"usingComponents": {}
}

---

Crmeb/Public/Statics/Mp View/Pages/Annex/Settled/Index.Json (crmeb/public/statics/mp_view/pages/annex/settled/index.json)

{
"navigationBarTitleText": "分销申请",
"usingComponents": {
"jyf-parser": "/components/jyf-parser/jyf-parser",
"verify": "/pages/annex/components/verify/verify",
"authorize": "/components/Authorize"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Annex/Special/Index.Json (crmeb/public/statics/mp_view/pages/annex/special/index.json)

{
"navigationBarTextStyle": "white",
"navigationBarBackgroundColor": "#333333",
"navigationBarTitleText": "专题页",
"componentPlaceholder": {
"page-design": "view"
},
"usingComponents": {
"page-design": "/subpackage/diyComponents/pageDesign",
"loading": "/components/Loading/index",
"page-footer": "/components/pageFooter/index",
"coupon-window": "/components/couponWindow/index",
"waterfalls-flow": "/components/WaterfallsFlow/WaterfallsFlow",
"empty-page": "/components/emptyPage"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Annex/Vip Active/Index.Json (crmeb/public/statics/mp_view/pages/annex/vip_active/index.json)

{
"navigationBarTitleText": "激活会员",
"usingComponents": {}
}

---

Crmeb/Public/Statics/Mp View/Pages/Annex/Vip Clause/Index.Json (crmeb/public/statics/mp_view/pages/annex/vip_clause/index.json)

{
"navigationBarTitleText": "会员协议",
"usingComponents": {}
}

---

Crmeb/Public/Statics/Mp View/Pages/Annex/Vip Coupon/Index.Json (crmeb/public/statics/mp_view/pages/annex/vip_coupon/index.json)

{
"navigationBarTitleText": "会员优惠券",
"usingComponents": {
"authorize": "/components/Authorize",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Annex/Vip Paid/Index.Json (crmeb/public/statics/mp_view/pages/annex/vip_paid/index.json)

{
"navigationBarTitleText": "SVIP会员",
"usingComponents": {
"home": "/components/home/index",
"payment": "/components/payment/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/ColumnGoods/HotNewGoods/Feedback.Json (crmeb/public/statics/mp_view/pages/columnGoods/HotNewGoods/feedback.json)

{
"navigationBarTitleText": "我的客服",
"navigationBarTextStyle": "white",
"navigationBarBackgroundColor": "#3A3A3A",
"usingComponents": {}
}

---

Crmeb/Public/Statics/Mp View/Pages/ColumnGoods/HotNewGoods/Index.Json (crmeb/public/statics/mp_view/pages/columnGoods/HotNewGoods/index.json)

{
"navigationBarTitleText": "精品推荐",
"usingComponents": {
"good-list": "/components/goodList/index",
"empty-page": "/components/emptyPage",
"home": "/components/home/index",
"page-footer": "/components/pageFooter/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/ColumnGoods/Live List/Index.Json (crmeb/public/statics/mp_view/pages/columnGoods/live_list/index.json)

{
"navigationBarTitleText": "精彩内容",
"usingComponents": {}
}

---

Crmeb/Public/Statics/Mp View/Pages/Extension/Customer List/Chat.Json (crmeb/public/statics/mp_view/pages/extension/customer_list/chat.json)

{
"navigationBarTitleText": "对话详情",
"navigationBarBackgroundColor": "#3875EA",
"navigationBarTextStyle": "white",
"usingComponents": {
"loading": "/components/Loading/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Extension/News Details/Index.Json (crmeb/public/statics/mp_view/pages/extension/news_details/index.json)

{
"navigationBarTitleText": "资讯详情",
"usingComponents": {
"share-info": "/pages/extension/components/shareInfo/index",
"home": "/components/home/index",
"parser": "/components/jyf-parser/jyf-parser"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Extension/News List/Index.Json (crmeb/public/statics/mp_view/pages/extension/news_list/index.json)

{
"navigationBarTitleText": "资讯",
"usingComponents": {
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods/Admin Order Detail/Index.Json (crmeb/public/statics/mp_view/pages/goods/admin_order_detail/index.json)

{
"navigationBarTitleText": "订单详情",
"usingComponents": {}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods/Cashier/Index.Json (crmeb/public/statics/mp_view/pages/goods/cashier/index.json)

{
"navigationBarTitleText": "收银台",
"usingComponents": {
"count-down": "/components/countDown/index",
"number-scroll": "/components/numberScroll"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods/Goods Comment Con/Index.Json (crmeb/public/statics/mp_view/pages/goods/goods_comment_con/index.json)

{
"navigationBarTitleText": "商品评价",
"usingComponents": {
"authorize": "/components/Authorize"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods/Goods Comment Con/Lottery Comment.Json (crmeb/public/statics/mp_view/pages/goods/goods_comment_con/lottery_comment.json)

{
"navigationBarTitleText": "订单评价",
"usingComponents": {
"authorize": "/components/Authorize",
"grids-lottery": "/pages/goods/components/lottery/index",
"lottery-aleart": "/pages/goods/goods_comment_con/components/lotteryAleart",
"user-address": "/pages/goods/goods_comment_con/components/userAddress"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods/Goods Comment Con/Components/UserAddress.Json (crmeb/public/statics/mp_view/pages/goods/goods_comment_con/components/userAddress.json)

{
"component": true,
"usingComponents": {
"authorize": "/components/Authorize",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods/Goods Comment List/Index.Json (crmeb/public/statics/mp_view/pages/goods/goods_comment_list/index.json)

{
"navigationBarTitleText": "商品评分",
"usingComponents": {
"user-evaluation": "/components/userEvaluation/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods/Goods Details Store/Index.Json (crmeb/public/statics/mp_view/pages/goods/goods_details_store/index.json)

{
"navigationBarTitleText": "门店列表",
"usingComponents": {
"loading": "/components/Loading/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods/Goods List/Index.Json (crmeb/public/statics/mp_view/pages/goods/goods_list/index.json)

{
"navigationBarTitleText": "商品列表",
"usingComponents": {
"recommend": "/components/recommend/index",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods/Goods Logistics/Index.Json (crmeb/public/statics/mp_view/pages/goods/goods_logistics/index.json)

{
"navigationBarTitleText": "物流信息",
"usingComponents": {
"recommend": "/components/recommend/index",
"authorize": "/components/Authorize"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods/Goods Return/Index.Json (crmeb/public/statics/mp_view/pages/goods/goods_return/index.json)

{
"navigationBarTitleText": "申请退货",
"usingComponents": {
"authorize": "/components/Authorize"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods/Goods Return List/Index.Json (crmeb/public/statics/mp_view/pages/goods/goods_return_list/index.json)

{
"navigationBarTitleText": "退货列表",
"usingComponents": {
"split-order": "/pages/goods/components/splitOrder/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods/Goods Search/Index.Json (crmeb/public/statics/mp_view/pages/goods/goods_search/index.json)

{
"navigationBarTitleText": "搜索商品",
"usingComponents": {
"good-list": "/components/goodList/index",
"recommend": "/components/recommend/index",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods/Lottery/Components/UserAddress.Json (crmeb/public/statics/mp_view/pages/goods/lottery/components/userAddress.json)

{
"component": true,
"usingComponents": {
"authorize": "/components/Authorize",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods/Lottery/Grids/Index.Json (crmeb/public/statics/mp_view/pages/goods/lottery/grids/index.json)

{
"navigationBarTitleText": "抽奖活动",
"usingComponents": {
"grids-lottery": "/pages/goods/components/lottery/index",
"show-box": "/pages/goods/lottery/components/showbox",
"notice-bar": "/pages/goods/lottery/components/noticeBar",
"lottery-aleart": "/pages/goods/lottery/components/lotteryAleart",
"user-address": "/pages/goods/lottery/components/userAddress",
"zb-code": "/components/zb-code/zb-code",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods/Lottery/Grids/Record.Json (crmeb/public/statics/mp_view/pages/goods/lottery/grids/record.json)

{
"navigationBarTitleText": "中奖记录",
"usingComponents": {
"empty-page": "/components/emptyPage",
"user-address": "/pages/goods/lottery/components/userAddress"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods/Order Confirm/Index.Json (crmeb/public/statics/mp_view/pages/goods/order_confirm/index.json)

{
"navigationBarTitleText": "提交订单",
"usingComponents": {
"payment": "/components/payment/index",
"invoice-picker": "/pages/goods/components/invoicePicker/index",
"coupon-list-window": "/components/couponListWindow/index",
"address-window": "/components/addressWindow/index",
"order-goods": "/components/orderGoods/index",
"home": "/components/home/index",
"authorize": "/components/Authorize"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods/Order Details/Index.Json (crmeb/public/statics/mp_view/pages/goods/order_details/index.json)

{
"navigationBarTitleText": "订单详情",
"usingComponents": {
"zb-code": "/components/zb-code/zb-code",
"home": "/components/home/index",
"invoice-picker": "/pages/goods/components/invoicePicker/index",
"invoice-modal": "/pages/goods/components/invoiceModal/index",
"order-goods": "/components/orderGoods/index",
"gift-modal": "/pages/goods/order_pay_status/components/giftModal",
"authorize": "/components/Authorize"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods/Order List/Index.Json (crmeb/public/statics/mp_view/pages/goods/order_list/index.json)

{
"navigationBarTitleText": "我的订单",
"usingComponents": {
"easy-loadimage": "/components/easy-loadimage/easy-loadimage",
"home": "/components/home/index",
"empty-page": "/components/emptyPage",
"authorize": "/components/Authorize"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods/Order Pay Status/Index.Json (crmeb/public/statics/mp_view/pages/goods/order_pay_status/index.json)

{
"navigationBarTitleText": "支付成功",
"usingComponents": {
"lottery-model": "/pages/goods/order_pay_status/payLottery",
"gift-modal": "/pages/goods/order_pay_status/components/giftModal",
"authorize": "/components/Authorize"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods/Order Pay Status/PayLottery.Json (crmeb/public/statics/mp_view/pages/goods/order_pay_status/payLottery.json)

{
"component": true,
"usingComponents": {
"authorize": "/components/Authorize",
"grids-lottery": "/pages/goods/components/lottery/index",
"lottery-aleart": "/pages/goods/order_pay_status/components/lotteryAleart",
"user-address": "/pages/goods/order_pay_status/components/userAddress"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods/Order Pay Status/Components/UserAddress.Json (crmeb/public/statics/mp_view/pages/goods/order_pay_status/components/userAddress.json)

{
"component": true,
"usingComponents": {
"authorize": "/components/Authorize",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods/Order Refund Goods/Index.Json (crmeb/public/statics/mp_view/pages/goods/order_refund_goods/index.json)

{
"navigationBarTitleText": "退回商品",
"usingComponents": {}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods/Receive Gift/Index.Json (crmeb/public/statics/mp_view/pages/goods/receive_gift/index.json)

{
"navigationBarTitleText": "领取礼物",
"navigationBarBackgroundColor": "#e93323",
"navigationBarTextStyle": "white",
"usingComponents": {}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods/Receive Gifts Status/Index.Json (crmeb/public/statics/mp_view/pages/goods/receive_gifts_status/index.json)

{
"navigationBarTitleText": "领取结果",
"usingComponents": {}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods Cate/Goods Cate.Json (crmeb/public/statics/mp_view/pages/goods_cate/goods_cate.json)

{
"navigationBarTitleText": "商品分类",
"usingComponents": {
"goods-cate1": "/pages/goods_cate/goods_cate1",
"goods-cate2": "/pages/goods_cate/goods_cate2",
"goods-cate3": "/pages/goods_cate/goods_cate3",
"page-footer": "/components/pageFooter/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods Cate/Goods Cate1.Json (crmeb/public/statics/mp_view/pages/goods_cate/goods_cate1.json)

{
"component": true,
"usingComponents": {
"page-footer": "/components/pageFooter/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods Cate/Goods Cate2.Json (crmeb/public/statics/mp_view/pages/goods_cate/goods_cate2.json)

{
"component": true,
"usingComponents": {
"product-window": "/components/productWindow/index",
"good-list": "/components/catGoodList/index",
"cart-list": "/components/cartList/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods Cate/Goods Cate3.Json (crmeb/public/statics/mp_view/pages/goods_cate/goods_cate3.json)

{
"component": true,
"usingComponents": {
"product-window": "/components/productWindow/index",
"good-class": "/components/goodClass/index",
"cart-list": "/components/cartList/index",
"parabala-ball": "/components/parabolaBall/ParabolaBall"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods Details/Index.Json (crmeb/public/statics/mp_view/pages/goods_details/index.json)

{
"navigationStyle": "custom",
"transparentTitle": "auto",
"componentPlaceholder": {
"page-design": "view",
"product-bottom": "view"
},
"usingComponents": {
"coupon-list-window": "/components/couponListWindow/index",
"product-window": "/components/productWindow/index",
"share-red-packets": "/components/shareRedPackets/index",
"kefu-icon": "/components/kefuIcon/index",
"menu-icon": "/components/menuIcon",
"cus-preview-img": "/components/cusPreviewImg/index",
"swiper-previe": "/components/cusPreviewImg/swiperPrevie",
"authorize": "/components/Authorize",
"home-list": "/components/homeList/index",
"specs": "/pages/goods_details/components/specs/index",
"service-modal": "/pages/goods_details/components/serviceModal/index",
"page-design": "/subpackage/diyComponents/pageDesign",
"product-bottom": "/subpackage/diyComponents/productBottom"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods Details/Components/ServiceModal/Index.Json (crmeb/public/statics/mp_view/pages/goods_details/components/serviceModal/index.json)

{
"component": true,
"usingComponents": {
"base-drawer": "/components/tuiDrawer/tui-drawer"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Goods Details/Components/Specs/Index.Json (crmeb/public/statics/mp_view/pages/goods_details/components/specs/index.json)

{
"component": true,
"usingComponents": {
"base-drawer": "/components/tuiDrawer/tui-drawer"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Guide/Index.Json (crmeb/public/statics/mp_view/pages/guide/index.json)

{
"usingComponents": {
"guide": "/components/guide/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Index/Index.Json (crmeb/public/statics/mp_view/pages/index/index.json)

{
"navigationBarTitleText": "",
"navigationStyle": "custom",
"navigationBarTextStyle": "black",
"componentPlaceholder": {
"page-design": "view"
},
"usingComponents": {
"page-design": "/subpackage/diyComponents/pageDesign",
"loading": "/components/Loading/index",
"coupon-window": "/components/couponWindow/index",
"waterfalls-flow": "/components/WaterfallsFlow/WaterfallsFlow",
"empty-page": "/components/emptyPage"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Order Addcart/Order Addcart.Json (crmeb/public/statics/mp_view/pages/order_addcart/order_addcart.json)

{
"navigationBarTitleText": "购物车",
"usingComponents": {
"page-footer": "/components/pageFooter/index",
"recommend": "/components/recommend/index",
"product-window": "/components/productWindow/index",
"authorize": "/components/Authorize"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Points Mall/Exchange Record.Json (crmeb/public/statics/mp_view/pages/points_mall/exchange_record.json)

{
"navigationBarTitleText": "兑换记录",
"usingComponents": {
"count-down": "/components/countDown/index",
"loading": "/components/Loading/index",
"empty-page": "/components/emptyPage",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Points Mall/Index.Json (crmeb/public/statics/mp_view/pages/points_mall/index.json)

{
"navigationBarTextStyle": "white",
"navigationBarBackgroundColor": "#333333",
"navigationBarTitleText": "积分商城",
"usingComponents": {}
}

---

Crmeb/Public/Statics/Mp View/Pages/Points Mall/Integral Goods Details.Json (crmeb/public/statics/mp_view/pages/points_mall/integral_goods_details.json)

{
"navigationStyle": "custom",
"usingComponents": {
"jyf-parser": "/components/jyf-parser/jyf-parser",
"product-con-swiper": "/components/productConSwiper/index",
"product-window": "/pages/points_mall/component/productWindow",
"user-evaluation": "/components/userEvaluation/index",
"kefu-icon": "/components/kefuIcon/index",
"count-down": "/components/countDown/index",
"cus-preview-img": "/components/cusPreviewImg/index",
"home-list": "/components/homeList/index",
"authorize": "/components/Authorize"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Points Mall/Integral Goods List.Json (crmeb/public/statics/mp_view/pages/points_mall/integral_goods_list.json)

{
"navigationBarTitleText": "商品列表",
"usingComponents": {
"recommend": "/components/recommend/index",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Points Mall/Integral Order.Json (crmeb/public/statics/mp_view/pages/points_mall/integral_order.json)

{
"navigationBarTitleText": "积分订单",
"usingComponents": {
"coupon-list-window": "/components/couponListWindow/index",
"address-window": "/components/addressWindow/index",
"order-goods": "/components/orderGoods/index",
"home": "/components/home/index",
"authorize": "/components/Authorize"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Points Mall/Integral Order Details.Json (crmeb/public/statics/mp_view/pages/points_mall/integral_order_details.json)

{
"navigationBarTitleText": "兑换订单详情",
"usingComponents": {
"home": "/components/home/index",
"order-goods": "/components/orderGoods/index",
"authorize": "/components/Authorize"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Points Mall/Integral Order Status.Json (crmeb/public/statics/mp_view/pages/points_mall/integral_order_status.json)

{
"navigationBarTitleText": "兑换成功",
"usingComponents": {
"authorize": "/components/Authorize"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Points Mall/Logistics Details.Json (crmeb/public/statics/mp_view/pages/points_mall/logistics_details.json)

{
"navigationBarTitleText": "兑换物流详情",
"usingComponents": {
"recommend": "/components/recommend/index",
"authorize": "/components/Authorize"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Points Mall/User Address.Json (crmeb/public/statics/mp_view/pages/points_mall/user_address.json)

{
"navigationBarTitleText": "选择地址",
"usingComponents": {
"authorize": "/components/Authorize",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/User/Index.Json (crmeb/public/statics/mp_view/pages/user/index.json)

{
"navigationBarTitleText": "个人中心",
"enablePullDownRefresh": true,
"navigationStyle": "custom",
"navigationBarTextStyle": "black",
"componentPlaceholder": {
"page-design": "view"
},
"usingComponents": {
"page-footer": "/components/pageFooter/index",
"edit-user-modal": "/components/eidtUserModal/index",
"page-design": "/subpackage/diyComponents/pageDesign",
"coupon-window": "/components/couponWindow/index",
"waterfalls-flow": "/components/WaterfallsFlow/WaterfallsFlow",
"empty-page": "/components/emptyPage",
"loading": "/components/Loading/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/Binding Phone/Index.Json (crmeb/public/statics/mp_view/pages/users/binding_phone/index.json)

{
"navigationBarTitleText": "",
"navigationStyle": "custom",
"usingComponents": {
"verify": "/pages/users/components/verify/index",
"edit-user-modal": "/components/eidtUserModal/index",
"privacy-agreement-popup": "/components/privacyAgreementPopup/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/Commission Rank/Index.Json (crmeb/public/statics/mp_view/pages/users/commission_rank/index.json)

{
"navigationBarTitleText": "佣金排行",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black",
"usingComponents": {
"authorize": "/components/Authorize",
"empty-page": "/components/emptyPage"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/Components/Login Mobile/Index.Json (crmeb/public/statics/mp_view/pages/users/components/login_mobile/index.json)

{
"component": true,
"usingComponents": {
"verify": "/pages/users/components/verify/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/Components/Verify/Index.Json (crmeb/public/statics/mp_view/pages/users/components/verify/index.json)

{
"component": true,
"usingComponents": {
"verify-slide": "/pages/users/components/verify/verifySlider/index",
"verify-point": "/pages/users/components/verify/verifyPoint/verifyPoint",
"verify-slider-pc": "/pages/users/components/verify/verifySlider/verifySliderPc"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/Login/Index.Json (crmeb/public/statics/mp_view/pages/users/login/index.json)

{
"navigationBarTitleText": "登录",
"usingComponents": {
"verify": "/pages/users/components/verify/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/Message Center/Index.Json (crmeb/public/statics/mp_view/pages/users/message_center/index.json)

{
"navigationBarTitleText": "消息中心",
"enablePullDownRefresh": true,
"usingComponents": {
"home": "/components/home/index",
"tui-drawer": "/components/tuiDrawer/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/Message Center/MessageDetail.Json (crmeb/public/statics/mp_view/pages/users/message_center/messageDetail.json)

{
"navigationBarTitleText": "消息详情",
"usingComponents": {
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/Payment On Behalf/Index.Json (crmeb/public/statics/mp_view/pages/users/payment_on_behalf/index.json)

{
"navigationBarTitleText": "好友代付",
"usingComponents": {
"order-goods": "/components/orderGoods/index",
"payment": "/components/payment/index",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/Payment On Behalf/Pay Status.Json (crmeb/public/statics/mp_view/pages/users/payment_on_behalf/pay_status.json)

{
"navigationBarTitleText": "代付成功",
"usingComponents": {}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/Privacy/Index.Json (crmeb/public/statics/mp_view/pages/users/privacy/index.json)

{
"navigationBarTitleText": "隐私协议",
"usingComponents": {
"jyf-parser": "/components/jyf-parser/jyf-parser"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/Promoter List/Index.Json (crmeb/public/statics/mp_view/pages/users/promoter-list/index.json)

{
"navigationBarTitleText": "推广人列表",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black",
"usingComponents": {
"authorize": "/components/Authorize",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/Promoter Order/Index.Json (crmeb/public/statics/mp_view/pages/users/promoter-order/index.json)

{
"navigationBarTitleText": "推广人订单",
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#FFFFFF",
"usingComponents": {
"authorize": "/components/Authorize",
"empty-page": "/components/emptyPage",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/Promoter Rank/Index.Json (crmeb/public/statics/mp_view/pages/users/promoter_rank/index.json)

{
"navigationBarTitleText": "推广人排行",
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#FFFFFF",
"usingComponents": {
"authorize": "/components/Authorize",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/RetrievePassword/Index.Json (crmeb/public/statics/mp_view/pages/users/retrievePassword/index.json)

{
"navigationBarTitleText": "忘记密码",
"usingComponents": {}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/Scan Login/Index.Json (crmeb/public/statics/mp_view/pages/users/scan_login/index.json)

{
"navigationBarTitleText": "授权登录",
"usingComponents": {}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/Staff List/Index.Json (crmeb/public/statics/mp_view/pages/users/staff_list/index.json)

{
"navigationBarTitleText": "员工列表",
"navigationBarBackgroundColor": "#e93323",
"navigationBarTextStyle": "white",
"usingComponents": {
"authorize": "/components/Authorize",
"home": "/components/home/index",
"zb-code": "/components/zb-code/zb-code"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Address/Index.Json (crmeb/public/statics/mp_view/pages/users/user_address/index.json)

{
"navigationBarTitleText": "添加地址",
"usingComponents": {
"authorize": "/components/Authorize",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Address List/Index.Json (crmeb/public/statics/mp_view/pages/users/user_address_list/index.json)

{
"navigationBarTitleText": "地址管理",
"usingComponents": {
"authorize": "/components/Authorize",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Bill/Index.Json (crmeb/public/statics/mp_view/pages/users/user_bill/index.json)

{
"navigationBarTitleText": "账单明细",
"usingComponents": {
"authorize": "/components/Authorize",
"empty-page": "/components/emptyPage",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Cancellation/Index.Json (crmeb/public/statics/mp_view/pages/users/user_cancellation/index.json)

{
"navigationBarTitleText": "注销协议",
"usingComponents": {}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Cash/Index.Json (crmeb/public/statics/mp_view/pages/users/user_cash/index.json)

{
"navigationBarTitleText": "提现",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black",
"usingComponents": {
"authorize": "/components/Authorize"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Coupon/Index.Json (crmeb/public/statics/mp_view/pages/users/user_coupon/index.json)

{
"navigationBarTitleText": "我的优惠券",
"usingComponents": {
"authorize": "/components/Authorize",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Distribution Level/Index.Json (crmeb/public/statics/mp_view/pages/users/user_distribution_level/index.json)

{
"navigationBarTitleText": "分销等级",
"navigationBarBackgroundColor": "#232323",
"navigationBarTextStyle": "white",
"usingComponents": {
"recommend": "/components/recommend/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Get Coupon/Index.Json (crmeb/public/statics/mp_view/pages/users/user_get_coupon/index.json)

{
"navigationBarTitleText": "领取优惠券",
"usingComponents": {
"authorize": "/components/Authorize",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Goods Collection/Index.Json (crmeb/public/statics/mp_view/pages/users/user_goods_collection/index.json)

{
"navigationBarTitleText": "收藏商品",
"usingComponents": {
"recommend": "/components/recommend/index",
"authorize": "/components/Authorize",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Info/Index.Json (crmeb/public/statics/mp_view/pages/users/user_info/index.json)

{
"navigationBarTitleText": "设置",
"usingComponents": {
"authorize": "/components/Authorize"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Integral/Index.Json (crmeb/public/statics/mp_view/pages/users/user_integral/index.json)

{
"navigationBarTitleText": "积分详情",
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#FFFFFF",
"usingComponents": {
"authorize": "/components/Authorize",
"empty-page": "/components/emptyPage"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Invoice Form/Index.Json (crmeb/public/statics/mp_view/pages/users/user_invoice_form/index.json)

{
"navigationBarTitleText": "添加新发票",
"usingComponents": {
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Invoice List/Index.Json (crmeb/public/statics/mp_view/pages/users/user_invoice_list/index.json)

{
"navigationBarTitleText": "发票管理",
"usingComponents": {
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Invoice Order/Index.Json (crmeb/public/statics/mp_view/pages/users/user_invoice_order/index.json)

{
"navigationBarTitleText": "发票详情",
"usingComponents": {
"payment": "/components/payment/index",
"home": "/components/home/index",
"order-goods": "/components/orderGoods/index",
"authorize": "/components/Authorize"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Money/Index.Json (crmeb/public/statics/mp_view/pages/users/user_money/index.json)

{
"navigationBarTitleText": "我的账户",
"usingComponents": {
"recommend": "/components/recommend/index",
"authorize": "/components/Authorize",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Payment/Index.Json (crmeb/public/statics/mp_view/pages/users/user_payment/index.json)

{
"navigationBarTitleText": "余额充值",
"usingComponents": {
"payment": "/components/payment/index",
"authorize": "/components/Authorize",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Phone/Index.Json (crmeb/public/statics/mp_view/pages/users/user_phone/index.json)

{
"navigationBarTitleText": "绑定手机",
"usingComponents": {
"authorize": "/components/Authorize",
"verify": "/pages/users/components/verify/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Pwd Edit/Index.Json (crmeb/public/statics/mp_view/pages/users/user_pwd_edit/index.json)

{
"navigationBarTitleText": "修改密码",
"usingComponents": {
"authorize": "/components/Authorize",
"verify": "/pages/users/components/verify/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Return List/Index.Json (crmeb/public/statics/mp_view/pages/users/user_return_list/index.json)

{
"navigationBarTitleText": "退货列表",
"usingComponents": {
"home": "/components/home/index",
"empty-page": "/components/emptyPage",
"authorize": "/components/Authorize"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Sgin/Index.Json (crmeb/public/statics/mp_view/pages/users/user_sgin/index.json)

{
"navigationBarTitleText": "签到",
"usingComponents": {
"authorize": "/components/Authorize"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Sgin List/Index.Json (crmeb/public/statics/mp_view/pages/users/user_sgin_list/index.json)

{
"navigationBarTitleText": "签到记录",
"usingComponents": {
"empty-page": "/components/emptyPage",
"authorize": "/components/Authorize"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Spread Code/Index.Json (crmeb/public/statics/mp_view/pages/users/user_spread_code/index.json)

{
"navigationBarTitleText": "分销海报",
"usingComponents": {
"zb-code": "/components/zb-code/zb-code",
"authorize": "/components/Authorize",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Spread Money/Index.Json (crmeb/public/statics/mp_view/pages/users/user_spread_money/index.json)

{
"navigationBarTitleText": "佣金记录",
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#FFFFFF",
"usingComponents": {
"authorize": "/components/Authorize",
"empty-page": "/components/emptyPage",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Spread Money/Receiving.Json (crmeb/public/statics/mp_view/pages/users/user_spread_money/receiving.json)

{
"navigationBarTitleText": "收款",
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#FFFFFF",
"usingComponents": {}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Spread User/Index.Json (crmeb/public/statics/mp_view/pages/users/user_spread_user/index.json)

{
"navigationBarTitleText": "我的推广",
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#FFFFFF",
"usingComponents": {
"authorize": "/components/Authorize",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Vip/Index.Json (crmeb/public/statics/mp_view/pages/users/user_vip/index.json)

{
"navigationBarTitleText": "我的等级",
"navigationBarBackgroundColor": "#232323",
"navigationBarTextStyle": "white",
"usingComponents": {
"recommend": "/components/recommend/index",
"authorize": "/components/Authorize"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/User Vip Areer/Index.Json (crmeb/public/statics/mp_view/pages/users/user_vip_areer/index.json)

{
"navigationBarTitleText": "经验记录",
"usingComponents": {}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/Visit List/Index.Json (crmeb/public/statics/mp_view/pages/users/visit_list/index.json)

{
"navigationBarTitleText": "浏览记录",
"usingComponents": {
"recommend": "/components/recommend/index",
"home": "/components/home/index"
}
}

---

Crmeb/Public/Statics/Mp View/Pages/Users/Wechat Login/Index.Json (crmeb/public/statics/mp_view/pages/users/wechat_login/index.json)

{
"navigationBarTitleText": "",
"navigationStyle": "custom",
"usingComponents": {
"mobile-login": "/pages/users/components/login_mobile/index",
"routine-phone": "/pages/users/components/login_mobile/routine_phone",
"edit-user-modal": "/components/eidtUserModal/index",
"privacy-agreement-popup": "/components/privacyAgreementPopup/index"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/ArticleList.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/articleList.json)

{
"component": true,
"usingComponents": {
"easy-loadimage": "/components/easy-loadimage/easy-loadimage",
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/Bargain.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/bargain.json)

{
"component": true,
"usingComponents": {
"easy-loadimage": "/components/easy-loadimage/easy-loadimage",
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/BlankPage.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/blankPage.json)

{
"component": true,
"usingComponents": {
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/Combination.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/combination.json)

{
"component": true,
"usingComponents": {
"easy-loadimage": "/components/easy-loadimage/easy-loadimage",
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/Coupon.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/coupon.json)

{
"component": true,
"usingComponents": {
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/CustomComponent.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/customComponent.json)

{
"component": true,
"usingComponents": {
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/Follow.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/follow.json)

{
"component": true,
"usingComponents": {
"easy-loadimage": "/components/easy-loadimage/easy-loadimage",
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/GoodList.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/goodList.json)

{
"component": true,
"usingComponents": {
"easy-loadimage": "/components/easy-loadimage/easy-loadimage",
"product-window": "/components/productWindow/index",
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/Guide.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/guide.json)

{
"component": true,
"usingComponents": {
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/HeaderSerch.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/headerSerch.json)

{
"component": true,
"usingComponents": {
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/HomeComb.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/homeComb.json)

{
"component": true,
"usingComponents": {
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/HomePaidVip.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/homePaidVip.json)

{
"component": true,
"usingComponents": {
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/HomeProductService.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/homeProductService.json)

{
"component": true,
"usingComponents": {
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/HomeReviews.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/homeReviews.json)

{
"component": true,
"usingComponents": {
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/HomeUserInfor.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/homeUserInfor.json)

{
"component": true,
"usingComponents": {
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/Hotspot.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/hotspot.json)

{
"component": true,
"usingComponents": {
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/LiveBroadcast.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/liveBroadcast.json)

{
"component": true,
"usingComponents": {
"easy-loadimage": "/components/easy-loadimage/easy-loadimage",
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/Menus.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/menus.json)

{
"component": true,
"usingComponents": {
"easy-loadimage": "/components/easy-loadimage/easy-loadimage",
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/News.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/news.json)

{
"component": true,
"usingComponents": {
"uni-notice-bar": "/components/uniNoticeBar/uni-notice-bar",
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/NewVip.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/newVip.json)

{
"component": true,
"usingComponents": {
"easy-loadimage": "/components/easy-loadimage/easy-loadimage",
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/PageDesign.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/pageDesign.json)

{
"component": true,
"usingComponents": {
"page-footer": "/components/pageFooter/index",
"home-comb": "/subpackage/diyComponents/homeComb",
"header-serch": "/subpackage/diyComponents/headerSerch",
"tab-nav": "/subpackage/diyComponents/tabNav",
"user-infor": "/subpackage/diyComponents/userInfor",
"home-user-infor": "/subpackage/diyComponents/homeUserInfor",
"new-vip": "/subpackage/diyComponents/newVip",
"article-list": "/subpackage/diyComponents/articleList",
"bargain": "/subpackage/diyComponents/bargain",
"blank-page": "/subpackage/diyComponents/blankPage",
"combination": "/subpackage/diyComponents/combination",
"coupon": "/subpackage/diyComponents/coupon",
"customer-service": "/subpackage/diyComponents/customerService",
"good-list": "/subpackage/diyComponents/goodList",
"guide": "/subpackage/diyComponents/guide",
"live-broadcast": "/subpackage/diyComponents/liveBroadcast",
"menus": "/subpackage/diyComponents/menus",
"news": "/subpackage/diyComponents/news",
"picture-cube": "/subpackage/diyComponents/pictureCube",
"promotion-list": "/subpackage/diyComponents/promotionList",
"seckill": "/subpackage/diyComponents/seckill",
"swiper-bg": "/subpackage/diyComponents/swiperBg",
"swipers": "/subpackage/diyComponents/swipers",
"titles": "/subpackage/diyComponents/titles",
"presale": "/subpackage/diyComponents/presale",
"points-mall": "/subpackage/diyComponents/pointsMall",
"rich-text": "/subpackage/diyComponents/richText",
"videos": "/subpackage/diyComponents/videos",
"sign-in": "/subpackage/diyComponents/signIn",
"hotspot": "/subpackage/diyComponents/hotspot",
"follow": "/subpackage/diyComponents/follow",
"product-info": "/subpackage/diyComponents/productInfo",
"home-paid-vip": "/subpackage/diyComponents/homePaidVip",
"home-product-service": "/subpackage/diyComponents/homeProductService",
"home-reviews": "/subpackage/diyComponents/homeReviews",
"product-desc": "/subpackage/diyComponents/productDesc",
"custom-component": "/subpackage/diyComponents/customComponent"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/PictureCube.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/pictureCube.json)

{
"component": true,
"usingComponents": {
"easy-loadimage": "/components/easy-loadimage/easy-loadimage",
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/PointsMall.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/pointsMall.json)

{
"component": true,
"usingComponents": {
"easy-loadimage": "/components/easy-loadimage/easy-loadimage",
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/Presale.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/presale.json)

{
"component": true,
"usingComponents": {
"easy-loadimage": "/components/easy-loadimage/easy-loadimage",
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/ProductBottom.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/productBottom.json)

{
"component": true,
"usingComponents": {
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/ProductDesc.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/productDesc.json)

{
"component": true,
"usingComponents": {
"parser": "/components/jyf-parser/jyf-parser",
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/ProductInfo.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/productInfo.json)

{
"component": true,
"usingComponents": {
"base-tag": "/components/BaseTag",
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/PromotionList.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/promotionList.json)

{
"component": true,
"usingComponents": {
"good-list": "/subpackage/diyComponents/goodList",
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/RichText.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/richText.json)

{
"component": true,
"usingComponents": {
"jyf-parser": "/components/jyf-parser/jyf-parser",
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/Seckill.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/seckill.json)

{
"component": true,
"usingComponents": {
"easy-loadimage": "/components/easy-loadimage/easy-loadimage",
"count-down": "/components/countDown/index",
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/SignIn.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/signIn.json)

{
"component": true,
"usingComponents": {
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/SwiperBg.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/swiperBg.json)

{
"component": true,
"usingComponents": {
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/Swipers.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/swipers.json)

{
"component": true,
"usingComponents": {
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/TabNav.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/tabNav.json)

{
"component": true,
"usingComponents": {
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/Titles.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/titles.json)

{
"component": true,
"usingComponents": {
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/UserInfor.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/userInfor.json)

{
"component": true,
"usingComponents": {
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Public/Statics/Mp View/Subpackage/DiyComponents/Videos.Json (crmeb/public/statics/mp_view/subpackage/diyComponents/videos.json)

{
"component": true,
"usingComponents": {
"common-wrapper": "/subpackage/diyComponents/commonWrapper"
}
}

---

Crmeb/Route/README (crmeb/route/README.md)

crmeb/route目录在CRMEB项目中的主要作用是用于定义项目的路由规则。

1. 定义一个 Route::miss 方法处理路由未匹配的情况

2. 根据请求路径获取应用名称(如 admin、app 等)

3. 根据应用名称返回不同的视图文件

- admin前台后台分别返回不同入口

- app/kefu定义了对应的视图

- home覆盖移动端和PC入口

- 其它情况判断是否移动端返回不同视图

4. 完整定义了项目所有可能的路由入口

5. 根据请求信息智能匹配视图资源文件

主要作用:

- 统一处理所有路由匹配
- 隐藏实际控制器入口
- 根据应用名分发页面
- 实现PC端和移动端自动切换

这种设计可以:

- 完整覆盖所有路由情况
- 隐藏实际路由层次结构
- 实现智能的页面分发

是动态路由设计的一个很好范例。

---

Crmeb/Runtime/Readme (crmeb/runtime/readme.md)

runtime目录说明

此目录用于存储CRMEB系统运行期间生成的各种临时文件和运行时数据。包含以下子目录:

- cache/ - 系统缓存文件
- log/ - 系统日志文件
- session/ - 用户会话数据
- temp/ - 临时文件

请勿手动删除此目录下的文件,除非明确知道其用途。

---

Crmeb/Upgrade/Versions/README (crmeb/upgrade/versions/README.md)

crmeb/upgrade/versions目录在CRMEB项目中的主要作用是用于存放系统升级相关的版本文件和升级脚本。

CRMEB系统在迭代更新过程中,需要一套完整的升级机制来保证数据迁移和版本兼容。这个目录就承担了集中管理各版本升级资源的职责。

具体来说:

- 存放各版本的升级说明文档,记录版本变更内容
- 放置数据库迁移脚本,处理表结构变更和数据迁移
- 存储升级所需的静态资源文件
- 记录版本依赖关系和升级顺序
- 保存版本检测和升级状态标识文件

使用这个目录有以下优点:

- 实现版本升级的模块化管理,便于追溯和回滚
- 与核心业务代码隔离,降低升级风险
- 支持多版本增量升级,灵活适配不同起始版本
- 便于自动化部署工具识别和执行升级流程

总体来说,它承担了系统版本迭代和数据库迁移的协调工作。

通过规范使用这个目录,可以确保升级过程的安全可控和可追溯。

---

Help/Dev Docs/错误码说明文档 (help/dev-docs/错误码说明文档.md)

CRMEB 错误码说明文档

1. 引言

1.1 文档目的


- 规范 CRMEB 系统中的错误码使用
- 提供错误码的分类和定义标准
- 为开发人员提供错误处理的参考指南
- 确保系统错误信息的一致性和可维护性

1.2 适用范围


- CRMEB 系统所有模块的开发和维护
- API 接口错误处理
- 后台管理系统错误处理
- 移动端应用错误处理

1.3 术语定义


- 错误码:系统中用于标识特定错误类型的数字编码
- 异常类:用于处理和抛出错误的类
- 多语言:系统支持的不同语言错误信息

2. 错误码设计规范

2.1 错误码格式


- 格式:纯数字,长度为 3-6 位
- 示例:400, 401, 400001, 400086

2.2 错误码分类

| 范围 | 分类 | 说明 | 示例 |
|------|------|------|------|
| 100-199 | 信息提示 | 一般性信息提示 | 100 |
| 200-299 | 成功响应 | 请求处理成功 | 200 |
| 300-399 | 重定向 | 需要重定向 | 301, 302 |
| 400-499 | 客户端错误 | 客户端请求错误 | 400, 401, 403, 404 |
| 500-599 | 服务器错误 | 服务器内部错误 | 500, 501, 503 |
| 400000-499999 | 业务错误 | 具体业务逻辑错误 | 400086, 400087 |
| 600000-699999 | 系统错误 | 系统级错误 | 600001 |
| 700000-799999 | 第三方错误 | 第三方服务错误 | 700001 |

2.3 错误码命名规则


- 错误码应具有语义化,便于理解和记忆
- 同一模块的错误码应集中在一个范围内
- 错误码应保持唯一性,避免重复

3. 错误处理机制

3.1 异常类体系

CRMEB 系统使用以下异常类处理错误:

| 异常类 | 命名空间 | 用途 |
|--------|----------|------|
| ApiException | crmeb\exceptions | API 接口错误 |
| AuthException | crmeb\exceptions | 认证授权错误 |
| AdminException | crmeb\exceptions | 后台管理错误 |
| PayException | crmeb\exceptions | 支付相关错误 |
| CrudException | crmeb\exceptions | CRUD 操作错误 |
| ApiStatusException | crmeb\exceptions | 带状态码的 API 错误 |
| OAuthException | crmeb\services\oauth | OAuth 认证错误 |

3.2 错误抛出方式

#### 3.2.1 直接抛出异常

php
// 使用错误信息
throw new ApiException('参数错误');

// 使用错误码
throw new ApiException(400086);

// 使用错误码和替换参数
throw new ApiException(400086, ['name' => '用户名']);

// 使用数组形式
throw new ApiException([400086, '参数错误']);

#### 3.2.2 在验证器中使用

php
protected $message = [
'name.require' => '400086',
'sort.require' => '400087',
'sort.number' => '400088'
];

3.3 错误信息获取

系统使用 getLang() 函数获取错误信息,支持多语言:

php
// 获取错误信息
$message = getLang($code, $replace);

4. 常见错误码列表

4.1 基础错误码

| 错误码 | 错误信息 | 说明 | 分类 |
|--------|----------|------|------|
| 200 | 操作成功 | 请求处理成功 | 成功响应 |
| 400 | 参数错误 | 请求参数格式错误 | 客户端错误 |
| 401 | 未授权 | 未登录或登录已过期 | 客户端错误 |
| 403 | 禁止访问 | 没有权限执行此操作 | 客户端错误 |
| 404 | 资源不存在 | 请求的资源不存在 | 客户端错误 |
| 500 | 服务器内部错误 | 服务器处理请求时发生错误 | 服务器错误 |
| 501 | 功能未实现 | 请求的功能尚未实现 | 服务器错误 |
| 503 | 服务不可用 | 服务器暂时无法处理请求 | 服务器错误 |

4.2 业务错误码

#### 4.2.1 用户相关

| 错误码 | 错误信息 | 说明 |
|--------|----------|------|
| 400001 | 用户名已存在 | 注册时用户名已被使用 |
| 400002 | 手机号已被注册 | 注册时手机号已被使用 |
| 400003 | 邮箱已被注册 | 注册时邮箱已被使用 |
| 400004 | 用户名或密码错误 | 登录时用户名或密码不正确 |
| 400005 | 用户不存在 | 请求的用户不存在 |
| 400006 | 账号已被禁用 | 用户账号被管理员禁用 |
| 400007 | 验证码错误 | 验证码不正确 |
| 400008 | 验证码已过期 | 验证码已超过有效期 |

#### 4.2.2 商品相关

| 错误码 | 错误信息 | 说明 |
|--------|----------|------|
| 400101 | 商品不存在 | 请求的商品不存在 |
| 400102 | 商品已下架 | 商品已被下架 |
| 400103 | 商品库存不足 | 商品库存不足 |
| 400104 | 商品价格异常 | 商品价格不符合要求 |
| 400105 | 商品分类不存在 | 请求的商品分类不存在 |

#### 4.2.3 订单相关

| 错误码 | 错误信息 | 说明 |
|--------|----------|------|
| 400201 | 订单不存在 | 请求的订单不存在 |
| 400202 | 订单状态错误 | 订单状态不符合操作要求 |
| 400203 | 订单金额错误 | 订单金额计算错误 |
| 400204 | 支付失败 | 支付过程中发生错误 |
| 400205 | 退款失败 | 退款过程中发生错误 |
| 400206 | 地址信息错误 | 收货地址信息不正确 |

#### 4.2.4 权限相关

| 错误码 | 错误信息 | 说明 |
|--------|----------|------|
| 400301 | 无权限操作 | 用户没有权限执行此操作 |
| 400302 | 角色不存在 | 请求的角色不存在 |
| 400303 | 菜单不存在 | 请求的菜单不存在 |
| 400304 | 权限不足 | 用户权限不足 |

#### 4.2.5 系统相关

| 错误码 | 错误信息 | 说明 |
|--------|----------|------|
| 400401 | 配置错误 | 系统配置错误 |
| 400402 | 网络错误 | 网络连接失败 |
| 400403 | 文件上传失败 | 文件上传过程中发生错误 |
| 400404 | 数据库错误 | 数据库操作失败 |
| 400405 | 缓存错误 | 缓存操作失败 |

4.3 验证器错误码

| 错误码 | 错误信息 | 说明 |
|--------|----------|------|
| 400086 | 名称不能为空 | 验证名称字段必填 |
| 400087 | 排序不能为空 | 验证排序字段必填 |
| 400088 | 排序必须为数字 | 验证排序字段必须为数字 |

5. 错误码管理

5.1 错误码定义

错误码应在语言文件中统一定义,便于管理和多语言支持:

php
// 语言文件示例
return [
400001 => '用户名已存在',
400002 => '手机号已被注册',
// 更多错误码...
];

5.2 错误码分配

- 错误码应按模块分配不同的范围
- 新增错误码时应避免与现有错误码冲突
- 错误码分配应记录在文档中,便于查阅

5.3 错误码维护

- 定期检查错误码使用情况
- 清理不再使用的错误码
- 统一错误码的命名和描述规范

6. 错误处理最佳实践

6.1 前端错误处理

1. 统一错误提示:使用统一的错误提示组件
2. 错误码映射:根据错误码显示相应的错误信息
3. 用户友好:错误信息应简洁明了,便于用户理解
4. 错误日志:记录前端错误日志,便于排查问题

6.2 后端错误处理

1. 分层处理:不同层次使用不同的异常类
2. 详细日志:记录详细的错误日志,包括错误码、错误信息、请求参数等
3. 错误码规范:严格按照错误码规范使用错误码
4. 异常捕获:合理捕获异常,避免系统崩溃
5. 错误信息国际化:支持多语言错误信息

6.3 错误码使用建议

1. 语义化:错误码应具有语义,便于理解
2. 一致性:相同类型的错误应使用相同范围的错误码
3. 可扩展性:预留足够的错误码空间,便于后续扩展
4. 文档化:及时更新错误码文档,确保文档与代码一致

7. 错误码扩展

7.1 自定义错误码

开发人员可以根据业务需求自定义错误码,遵循以下步骤:

1. 确定错误码的范围和分类
2. 在语言文件中定义错误信息
3. 在代码中使用错误码
4. 更新错误码文档

7.2 错误码版本管理

当系统版本升级时,错误码的管理应注意:

1. 保持向后兼容:避免修改现有错误码的含义
2. 新增错误码:在预留范围内新增错误码
3. 废弃错误码:标记不再使用的错误码

8. 常见问题

8.1 错误码重复

问题:不同模块使用了相同的错误码

解决方案
- 按模块分配错误码范围
- 建立错误码管理机制
- 定期检查错误码使用情况

8.2 错误信息不明确

问题:错误信息不够明确,难以理解

解决方案
- 错误信息应简洁明了
- 错误信息应包含具体的错误原因
- 错误信息应便于用户理解

8.3 错误处理不一致

问题:不同模块的错误处理方式不一致

解决方案
- 统一错误处理机制
- 使用统一的异常类
- 遵循错误处理最佳实践

9. 总结

错误码是系统中重要的组成部分,合理的错误码设计和使用可以提高系统的可维护性和用户体验。本文档提供了 CRMEB 系统错误码的设计规范、使用方法和最佳实践,希望能够帮助开发人员更好地理解和使用错误码。

在实际开发中,开发人员应严格遵循本文档的规范,确保错误码的一致性和可维护性。同时,应根据业务需求不断完善和扩展错误码体系,以适应系统的发展和变化。

提示:该文档由AI生成,仅供参考。

---

Help/Dev Docs/Admin/后台管理前端架构说明 (help/dev-docs/admin/后台管理前端架构说明.md)

CRMEB 后台管理前端架构说明

📋 技术栈概览

| 技术 | 版本 | 说明 |
|------|------|------|
| Vue.js | 2.x | 前端核心框架 |
| Element UI | 2.x | UI组件库 |
| Vuex | 3.x | 状态管理 |
| Axios | 0.x | HTTP客户端 |
| VXE-Table | 高级表格组件 | |
| WangEditor | 富文本编辑器 | |
| Sass | CSS预处理器 | |
| Prettier | 代码格式化工具 | |
| Vue-Viewer | 图片查看器 | |

??️ 整体架构

text
/ Detailed source-code truncated for AI context efficiency. /

📂 目录结构

标准后台管理前端目录结构

text
/ Detailed source-code truncated for AI context efficiency. /

🔧 核心模块详解

1. 路由模块 (Router)

#### 路由配置结构

javascript
// src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import { constantRoutes } from './modules'

Vue.use(VueRouter)

// 创建路由实例
export const createRouter = () => new VueRouter({
routes: constantRoutes,
mode: 'history',
scrollBehavior: () => ({ y: 0 })
})

// 静态路由
export const constantRoutes = [
{
path: '/login',
component: () => import('@/views/login/index'),
meta: { title: '登录' }
},
{
path: '/404',
component: () => import('@/views/error/404')
},
{
path: '/',
component: Layout,
redirect: '/dashboard',
children: [
{
path: 'dashboard',
name: 'Dashboard',
component: () => import('@/views/dashboard/index'),
meta: { title: '控制台', icon: 'dashboard' }
}
]
}
]

#### 动态路由(权限控制)

javascript
// src/router/modules/permission.js
export const asyncRoutes = [
{
path: '/user',
component: Layout,
meta: {
title: '用户管理',
icon: 'user',
roles: ['admin', 'manager']
},
children: [
{
path: 'list',
name: 'UserList',
component: () => import('@/views/user/list'),
meta: {
title: '用户列表',
roles: ['admin']
}
}
]
}
]

2. 状态管理 (Vuex)

#### Store结构

javascript
// src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user'
import app from './modules/app'
import permission from './modules/permission'

Vue.use(Vuex)

export default new Vuex.Store({
modules: {
user,
app,
permission
},
getters: {
token: state => state.user.token,
roles: state => state.user.roles,
sidebarOpened: state => app.sidebarOpened,
permissionRoutes: state => permission.routes
}
})

#### 用户状态模块

javascript
// src/store/modules/user.js
const state = {
token: localStorage.getItem('token') || '',
userInfo: {},
roles: []
}

const mutations = {
SET_TOKEN(state, token) {
state.token = token
localStorage.setItem('token', token)
},
SET_USER_INFO(state, userInfo) {
state.userInfo = userInfo
},
SET_ROLES(state, roles) {
state.roles = roles
}
}

const actions = {
// 登录
async login({ commit }, userInfo) {
const res = await login(userInfo)
commit('SET_TOKEN', res.data.token)
return res
},

// 获取用户信息
async getInfo({ commit }) {
const res = await getUserInfo()
commit('SET_USER_INFO', res.data)
commit('SET_ROLES', res.data.roles)
return res
},

// 退出登录
async logout({ commit }) {
await logout()
commit('SET_TOKEN', '')
commit('SET_USER_INFO', {})
}
}

export default {
namespaced: true,
state,
mutations,
actions
}

3. API服务层

#### Axios封装

javascript
// src/utils/request.js
import axios from 'axios'
import { Message, MessageBox } from 'element-ui'
import store from '@/store'
import router from '@/router'

// 创建axios实例
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API,
timeout: 30000
})

// 请求拦截器
service.interceptors.request.use(
config => {
// 添加token
if (store.getters.token) {
config.headers['Authorization'] = Bearer ${store.getters.token}
}
return config
},
error => {
return Promise.reject(error)
}
)

// 响应拦截器
service.interceptors.response.use(
response => {
const res = response.data
if (res.code === 200) {
return res
}
Message.error(res.msg || '请求失败')
return Promise.reject(new Error(res.msg || '请求失败'))
},
error => {
if (error.response) {
const { status } = error.response
if (status === 401) {
MessageBox.confirm('登录状态已过期,请重新登录', '确认登录', {
confirmButtonText: '重新登录',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
store.dispatch('user/logout')
router.push('/login')
})
}
}
return Promise.reject(error)
}
)

export default service

#### API接口定义

javascript
// src/api/user.js
import request from '@/utils/request'

// 获取用户列表
export function getUserList(params) {
return request({
url: '/adminapi/v1/user/list',
method: 'get',
params
})
}

// 获取用户详情
export function getUserDetail(id) {
return request({
url: /adminapi/v1/user/${id},
method: 'get'
})
}

// 编辑用户
export function editUser(data) {
return request({
url: '/adminapi/v1/user/edit',
method: 'post',
data
})
}

// 删除用户
export function deleteUser(id) {
return request({
url: /adminapi/v1/user/${id},
method: 'delete'
})
}

4. 布局组件 (Layout)

#### 主布局组件

vue
<template>
<el-container class="app-wrapper">

<el-aside :width="sidebarOpened ? '200px' : '64px'">
<Sidebar />
</el-aside>

<el-container>

<el-header>
<Navbar />
</el-header>


<el-main>
<router-view />
</el-main>
</el-container>
</el-container>
</template>

<script>
import { mapGetters } from 'vuex'
import Sidebar from './Sidebar'
import Navbar from './Navbar'

export default {
name: 'Layout',
components: { Sidebar, Navbar },
computed: {
...mapGetters(['sidebarOpened'])
}
}
</script>

<style lang="scss" scoped>
.app-wrapper {
height: 100vh;
}
.el-aside {
transition: width 0.3s;
}
.el-header {
padding: 0;
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
}
.el-main {
background-color: #f0f2f5;
padding: 20px;
}
</style>

#### 侧边栏组件

vue
<template>
<el-menu
:default-active="activeMenu"
:collapse="!sidebarOpened"
:unique-opened="true"
background-color="#304156"
text-color="#bfcbd9"
active-text-color="#409EFF"
router
>
<sidebar-item
v-for="route in permissionRoutes"
:key="route.path"
:item="route"
:base-path="route.path"
/>
</el-menu>
</template>

<script>
import { mapGetters } from 'vuex'
import SidebarItem from './SidebarItem'

export default {
name: 'Sidebar',
components: { SidebarItem },
computed: {
...mapGetters(['permissionRoutes']),
activeMenu() {
const route = this.$route
const { meta, path } = route
if (meta.activeMenu) {
return meta.activeMenu
}
return path
}
}
}
</script>

5. 列表页面组件

#### 通用列表页面模板

text
/ Detailed source-code truncated for AI context efficiency. /

6. 表单页面组件

#### 通用表单页面模板

text
/ Detailed source-code truncated for AI context efficiency. /

🎨 样式规范

SCSS 变量定义


scss
// src/assets/styles/variables.scss

// 主题色
$primary-color: #409EFF;
$success-color: #67C23A;
$warning-color: #E6A23C;
$danger-color: #F56C6C;
$info-color: #909399;

// 背景色
$bg-color: #f0f2f5;
$white: #ffffff;

// 文字颜色
$text-primary: #303133;
$text-regular: #606266;
$text-secondary: #909399;
$text-placeholder: #c0c4cc;

// 边框颜色
$border-color: #dcdfe6;
$border-color-light: #e4e7ed;
$border-color-lighter: #ebeef5;

// 字体
$font-size-base: 14px;
$font-size-small: 12px;
$font-size-large: 16px;

通用样式


scss
// src/assets/styles/common.scss

// 通用页面容器
.app-container {
padding: 20px;
}

// 卡片样式
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}

// 表格操作按钮
.table-action-btn {
margin: 0 5px;
}

// 表单样式
.form-container {
max-width: 600px;
margin: 0 auto;
}

🔐 权限控制

权限指令


javascript
// src/directive/permission.js
import Vue from 'vue'

// v-permission 指令
Vue.directive('permission', {
inserted: function(el, binding) {
const { value } = binding
const permissions = Vue.prototype.$store.getters.permissions

if (value && value instanceof Array) {
const hasPermission = value.some(permission => {
return permissions.includes(permission)
})

if (!hasPermission) {
el.parentNode && el.parentNode.removeChild(el)
}
} else {
throw new Error('v-permission value must be array')
}
}
})

使用示例


vue
<template>
<div>

<el-button v-permission="['user:add']" type="primary" @click="handleAdd">
新增用户
</el-button>

<el-button v-permission="['user:export']" type="warning" @click="handleExport">
导出数据
</el-button>
</div>
</template>

📊 常用组件使用

表格组件 (VXE-Table)


vue
<template>
<vxe-table
:data="tableData"
:loading="loading"
:columns="columns"
:pagination="pagination"
@page-change="handlePageChange"
>
<vxe-column field="name" title="名称" />
<vxe-column field="status" title="状态">
<template #default="{ row }">
<el-tag :type="row.status ? 'success' : 'danger'">
{{ row.status ? '启用' : '禁用' }}
</el-tag>
</template>
</vxe-column>
<vxe-column title="操作">
<template #default="{ row }">
<el-button size="mini" type="text" @click="handleEdit(row)">编辑</el-button>
</template>
</vxe-column>
</vxe-table>
</template>

富文本编辑器 (WangEditor)


vue
<template>
<div class="editor-container">
<wang-editor
v-model="form.content"
:height="400"
:menus="menus"
/>
</div>
</template>

<script>
import WangEditor from 'wangeditor'

export default {
components: { WangEditor },
data() {
return {
menus: [
'head', 'bold', 'italic', 'underline', 'strikeThrough',
'list', 'justify', 'quote', 'link', 'image'
],
content: ''
}
}
}
</script>

🧪 测试配置

Jest 测试配置


javascript
// jest.config.js
module.exports = {
testURL: 'http://localhost',
moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
transform: {
'^.+\\.vue$': 'vue-jest',
'^.+\\.js$': 'babel-jest'
},
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1'
},
testMatch: ['<rootDir>/tests//*.spec.js'],
collectCoverageFrom: [
'src//*.{js,vue}',
'!src/main.js'
]
}

测试示例


javascript
// tests/unit/user.spec.js
import { shallowMount } from '@vue/test-utils'
import UserList from '@/views/user/list.vue'

describe('UserList', () => {
it('renders user list correctly', () => {
const wrapper = shallowMount(UserList, {
mocks: {
$route: { path: '/user/list' },
$store: {
getters: { roles: ['admin'] }
}
}
})

expect(wrapper.find('.el-table').exists()).toBe(true)
expect(wrapper.find('.pagination').exists()).toBe(true)
})
})

🚀 构建部署

环境配置


bash

.env.development


VUE_APP_BASE_API = 'http://localhost:8000'
VUE_APP_WS_API = 'ws://localhost:8000'

.env.production


VUE_APP_BASE_API = 'https://api.crmeb.com'
VUE_APP_WS_API = 'wss://api.crmeb.com'

构建命令


bash

安装依赖


npm install

开发环境


npm run dev

生产环境构建


npm run build:prod

代码检查


npm run lint

单元测试


npm run test

Nginx 配置


nginx
server {
listen 80;
server_name admin.crmeb.com;

# 前端静态资源
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
}

# API代理
location /adminapi/ {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}

# WebSocket代理
location /ws/ {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}

📝 开发规范

代码风格


- 使用 ESLint + Prettier 进行代码格式化
- Vue组件使用单文件组件 (.vue)
- 组件名使用 PascalCase 命名
- 样式使用 SCSS 预处理器

Git 提交规范


text
feat: 新增用户管理功能
fix: 修复订单列表分页问题
docs: 更新接口文档
style: 代码格式调整
refactor: 重构用户模块代码
test: 添加单元测试
chore: 更新构建配置

---
文档版本: v1.0
最后更新: 2024-01-17
适用版本: CRMEB 5.6.4+
维护团队: 前端开发组

💡 提示:后台管理前端采用 Element UI 组件库,配合 Vuex 进行状态管理,通过 Axios 封装统一处理 HTTP 请求,实现了完整的权限控制和数据交互功能。

---

提示:该文档由AI生成,仅供参考。

---

Help/Dev Docs/Phpapi/API接口文档 (help/dev-docs/phpapi/API接口文档.md)

CRMEB API 接口文档

📍 API 入口划分


- 后台管理: /adminapi/controller/v1/ (需要管理员权限)
- 前端用户: /api/controller/v1/ (需要用户登录)
- 公共接口: /api/controller/publics/ (无需登录)

🔐 认证机制


php
// JWT Token 认证
'middleware' => [
AuthTokenMiddleware::class, // 用户token验证
AdminAuthTokenMiddleware::class // 管理员token验证
]

📋 核心接口示例

用户管理接口


text
GET  /adminapi/v1/user/list      # 用户列表
POST /adminapi/v1/user/edit # 编辑用户
GET /api/v1/user/info # 获取用户信息

订单管理接口


text
GET  /adminapi/v1/order/list     # 订单列表
POST /api/v1/order/create # 创建订单
GET /api/v1/order/detail # 订单详情

🏷️ 统一响应格式


json
{
"status": 200,
"msg": "success",
"data": {...},
"time": "2024-01-01 10:00:00"
}

⚠️ 错误码规范


- 200: 成功
- 400: 参数错误
- 401: 未授权
- 403: 权限不足
- 500: 服务器错误

---

提示:该文档由AI生成,仅供参考。

---

Help/Dev Docs/Phpapi/业务流程说明 (help/dev-docs/phpapi/业务流程说明.md)

业务流程说明

📋 核心业务流程

🛒 订单创建流程


1. 用户选择商品 → 加入购物车 → 生成订单
2. 订单验证(库存、价格、优惠券)
3. 创建订单数据
4. 扣减库存
5. 发送订单通知

💳 支付处理流程


1. 用户选择支付方式
2. 调用支付接口
3. 支付结果回调
4. 更新订单状态
5. 记录支付流水

📦 发货流程


1. 订单状态检查(已支付)
2. 生成发货单
3. 调用物流接口
4. 更新发货状态
5. 通知用户物流信息

🔄 售后流程


1. 用户提交售后申请
2. 审核售后请求
3. 处理退款/换货
4. 更新库存和财务
5. 完成售后流程

⏱️ 异步任务流程


- 消息队列处理订单相关任务
- 定时任务处理数据统计
- 后台任务处理批量操作

---

提示:该文档由AI生成,仅供参考。

---

Help/Dev Docs/Phpapi/会员管理开发文档 (help/dev-docs/phpapi/会员管理开发文档.md)

会员管理开发文档

1. 文档概述

1.1 文档目的


本文档旨在详细说明CRMEB系统中会员管理模块的设计架构、核心功能、代码实现及开发规范,为系统开发人员提供完整的开发参考。

1.2 适用范围


本文档适用于CRMEB系统开发人员、维护人员及二次开发人员,用于指导会员管理模块的开发、扩展和维护工作。

1.3 术语定义


| 术语 | 解释 |
|------|------|
| 会员等级 | 基于用户经验值划分的等级体系,不同等级享有不同权益 |
| 经验值 | 用户通过各种行为获得的数值,用于提升会员等级 |
| 会员权益 | 不同会员等级享有的专属福利,如折扣、优惠券等 |
| 会员卡片 | 展示会员等级、有效期、权益等信息的可视化卡片 |
| 积分 | 用户通过各种行为获得的可用于消费的数值 |
| 积分商城 | 用于兑换商品或服务的积分兑换平台 |
| 会员有效期 | 会员等级的有效期限,过期后可能降级或失效 |

2. 核心功能模块

2.1 会员等级管理


- 等级列表:展示系统配置的会员等级,支持搜索、分页
- 等级添加:添加新的会员等级,设置等级名称、折扣、经验值要求等
- 等级编辑:修改会员等级信息,包括名称、折扣、经验值要求等
- 等级删除:删除会员等级
- 等级状态管理:启用/禁用会员等级
- 等级排序:调整会员等级的显示顺序

2.2 用户等级管理


- 用户等级列表:展示用户当前等级信息,支持搜索、分页
- 等级赠送:手动为用户赠送会员等级
- 等级清除:清除用户的会员等级
- 等级有效期管理:设置和修改会员等级的有效期
- 等级自动检测:定期检测用户是否达到升级条件,自动升级

2.3 经验值管理


- 经验值配置:配置各种行为获得的经验值数量
- 经验值记录:记录用户经验值的变动情况
- 经验值查询:查询用户经验值的获取和使用记录
- 经验值统计:统计用户经验值的来源分布

2.4 积分管理


- 积分配置:配置各种行为获得的积分数量
- 积分增加:手动为用户增加积分
- 积分扣除:手动为用户扣除积分
- 积分记录:记录用户积分的变动情况
- 积分查询:查询用户积分的获取和使用记录
- 积分统计:统计用户积分的来源和使用分布

2.5 会员权益管理


- 折扣权益:配置不同等级的商品折扣比例
- 等级图标:配置各等级的专属图标和背景图
- 会员卡片:生成和管理会员卡片
- 权益规则:配置会员享有的其他权益,如专属客服、优先发货等

2.6 会员等级升级机制


- 经验值累积:通过签到、下单、邀请等行为累积经验值
- 升级条件检测:定期检测用户是否达到升级条件
- 自动升级:达到升级条件后自动更新会员等级
- 升级通知:发送等级升级通知给用户

3. 代码结构与设计

3.1 架构设计


系统采用分层架构设计,严格遵循MVC设计模式:
text
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│ Models │ │ Daos │ │ Services │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
└───────────────────────┼───────────────────────┘

┌─────────────────┐
│ Controllers │
└─────────────────┘

┌─────────────────┐
│ Routes │
└─────────────────┘

3.2 核心文件结构

#### 3.2.1 模型层(Model)
会员相关模型
- UserLevel.php - 用户实际会员等级信息模型
- SystemUserLevel.php - 系统会员等级配置模型
- User.php - 用户基本信息模型,包含经验值、积分等字段

#### 3.2.2 服务层(Services)
会员管理Services
- UserLevelServices.php - 会员等级设置与管理,自动检测用户升级条件
- UserBillServices.php - 积分增加与扣除,积分记录管理
- UserServices.php - 用户基本信息管理,包括等级、经验值、积分等

#### 3.2.3 控制器层(Controller)
会员控制器
- UserLevel.php - 会员等级管理控制器
- User.php - 用户管理控制器,包含等级、经验值、积分等管理功能

#### 3.2.4 路由配置
会员路由
- user.php - 包含会员管理相关的API路由

4. 数据库设计

4.1 系统会员等级表(system_user_level)

| 字段名 | 数据类型 | 描述 |
|--------|----------|------|
| id | int(10) unsigned | 等级ID |
| name | varchar(20) | 等级名称 |
| icon | varchar(255) | 等级图标 |
| bg | varchar(255) | 等级背景图 |
| grade | int(10) | 等级 |
| experience_min | int(10) | 最低经验值 |
| experience_max | int(10) | 最高经验值 |
| discount | decimal(10,2) | 折扣比例 |
| status | tinyint(1) | 状态(0-禁用,1-启用) |
| is_show | tinyint(1) | 是否显示(0-隐藏,1-显示) |
| sort | int(10) | 排序 |
| add_time | int(10) | 添加时间 |

4.2 用户等级表(user_level)

| 字段名 | 数据类型 | 描述 |
|--------|----------|------|
| id | int(10) unsigned | 记录ID |
| uid | int(10) | 用户ID |
| level_id | int(10) | 会员等级ID |
| is_forever | tinyint(1) | 是否永久(0-否,1-是) |
| start_time | int(10) | 开始时间 |
| end_time | int(10) | 结束时间 |
| status | tinyint(1) | 状态(0-过期,1-有效) |
| add_time | int(10) | 添加时间 |

4.3 用户表(user)

| 字段名 | 数据类型 | 描述 |
|--------|----------|------|
| uid | int(10) unsigned | 用户ID |
| user_level | int(10) | 当前会员等级ID |
| experience | int(10) | 经验值 |
| integral | int(10) | 积分 |
| sign_num | int(10) | 连续签到天数 |
| sign_integral | int(10) | 已领取签到积分 |
| // 其他用户信息字段 | // 数据类型 | // 描述 |

4.4 用户账单表(user_bill)

| 字段名 | 数据类型 | 描述 |
|--------|----------|------|
| id | int(10) unsigned | 账单ID |
| uid | int(10) | 用户ID |
| category | varchar(20) | 资金类型(integral-积分,experience-经验值) |
| type | varchar(20) | 变动类型(sign-签到,order-订单,invite-邀请) |
| pm | tinyint(1) | 收支方向(1-收入,0-支出) |
| number | varchar(50) | 流水号 |
| money | decimal(10,2) | 变动金额 |
| balance | decimal(10,2) | 变动后余额/积分/经验值 |
| mark | varchar(255) | 备注 |
| add_time | int(10) | 添加时间 |

5. API接口说明

5.1 会员等级管理

#### 5.1.1 获取系统会员等级列表
- 请求URL/adminapi/v1/user/level/list
- 请求方法:GET
- 权限要求:user/user_level/list
- 返回结果:系统会员等级列表数据

#### 5.1.2 添加系统会员等级
- 请求URL/adminapi/v1/user/level/create
- 请求方法:POST
- 权限要求:user/user_level/create
- 请求参数
- name:等级名称
- grade:等级
- experience_min:最低经验值
- experience_max:最高经验值
- discount:折扣比例
- icon:等级图标
- bg:等级背景图
- 返回结果:操作结果

#### 5.1.3 获取用户等级列表
- 请求URL/adminapi/v1/user/user_level/list
- 请求方法:GET
- 权限要求:user/user/user_level_list
- 请求参数
- page:页码
- limit:每页数量
- keyword:搜索关键词
- 返回结果:用户等级列表数据

#### 5.1.4 为用户赠送会员等级
- 请求URL/adminapi/v1/user/user_level/give/{uid}
- 请求方法:POST
- 权限要求:user/user/user_level_give
- 请求参数
- level_id:会员等级ID
- is_forever:是否永久(0-否,1-是)
- days:有效期(天)
- 返回结果:操作结果

5.2 积分管理

#### 5.2.1 获取积分记录列表
- 请求URL/adminapi/v1/user/integral/list
- 请求方法:GET
- 权限要求:user/integral/list
- 请求参数
- page:页码
- limit:每页数量
- uid:用户ID
- type:变动类型
- 返回结果:积分记录列表数据

#### 5.2.2 为用户增加积分
- 请求URL/adminapi/v1/user/integral/add/{uid}
- 请求方法:POST
- 权限要求:user/integral/add
- 请求参数
- integral:积分数量
- mark:备注
- 返回结果:操作结果

#### 5.2.3 为用户扣除积分
- 请求URL/adminapi/v1/user/integral/sub/{uid}
- 请求方法:POST
- 权限要求:user/integral/sub
- 请求参数
- integral:积分数量
- mark:备注
- 返回结果:操作结果

5.3 用户端接口

#### 5.3.1 获取会员等级列表
- 请求URL/api/v1/user/level/list
- 请求方法:GET
- 权限要求:登录用户
- 返回结果:会员等级列表数据

#### 5.3.2 获取用户等级信息
- 请求URL/api/v1/user/level/info
- 请求方法:GET
- 权限要求:登录用户
- 返回结果:当前用户的等级信息

#### 5.3.3 获取积分记录
- 请求URL/api/v1/user/integral/list
- 请求方法:GET
- 权限要求:登录用户
- 请求参数
- page:页码
- limit:每页数量
- 返回结果:当前用户的积分记录

5. 开发规范与流程

5.1 代码规范


1. 命名规范
- 类名采用大驼峰命名法,如 UserLevelServices
- 方法名采用小驼峰命名法,如 checkUpgradeCondition
- 变量名采用小驼峰命名法,如 userExperience
- 常量名采用全大写,下划线分隔,如 LEVEL_STATUS_ENABLE

2. 代码结构
- 严格遵循分层架构,禁止跨层调用
- 每个方法职责单一,代码行数控制在50行以内
- 适当添加注释,说明方法功能、参数含义和返回值
- 经验值和积分变动必须记录变动原因和相关业务ID

3. 数据一致性
- 所有经验值和积分变动都必须通过事务确保数据一致性
- 会员等级变动必须同步更新相关表的数据
- 必须记录完整的变动日志,便于追溯

5.2 开发流程


1. 需求分析:明确会员管理的功能需求和业务逻辑
2. 设计阶段:设计数据结构、API接口和业务流程
3. 编码实现:按照分层架构编写代码
4. 单元测试:编写单元测试,确保功能正确性
5. 集成测试:进行模块集成测试,测试会员与其他模块的交互
6. 性能测试:对经验值和积分变动等高频操作进行性能测试
7. 代码审查:提交代码审查,确保代码质量
8. 部署上线:部署到生产环境

6. 常见问题与解决方案

6.1 会员等级升级不及时


问题:用户达到升级条件后,等级没有自动升级
解决方案
1. 检查自动检测任务是否正常运行
2. 检查升级条件配置是否正确
3. 检查升级逻辑是否存在bug
4. 考虑添加手动触发升级的功能

6.2 积分计算不准确


问题:用户积分的计算与预期不符
解决方案
1. 检查积分配置是否正确
2. 检查积分变动记录,找出问题所在
3. 确保所有积分变动都通过统一的接口处理
4. 添加积分对账功能,定期检查积分一致性

6.3 会员权益不生效


问题:用户享有某等级权益,但实际未生效
解决方案
1. 检查会员等级是否正确
2. 检查权益配置是否正确
3. 检查权益生效逻辑是否存在bug
4. 添加权益生效日志,便于排查问题

6.4 大量用户同时升级导致性能问题


问题:系统中有大量用户同时达到升级条件,导致系统性能下降
解决方案
1. 优化升级检测算法,减少数据库查询
2. 使用异步处理方式,避免阻塞主流程
3. 考虑分级处理,先处理活跃用户
4. 增加系统资源,提高并发处理能力

7. 扩展与定制

7.1 添加新的经验值获取渠道


1. 配置经验值:在系统配置中添加新的经验值获取渠道和数量
2. 修改代码
- 在相关业务逻辑中添加经验值增加的调用
- 在UserBillServices中添加对应的经验值记录类型
3. 前端修改:在前端添加对应的经验值获取入口和说明

7.2 添加新的积分使用方式


1. 配置积分:在系统配置中添加新的积分使用方式和消耗规则
2. 修改代码
- 在相关业务逻辑中添加积分扣除的调用
- 在UserBillServices中添加对应的积分记录类型
3. 前端修改:在前端添加对应的积分使用入口和说明

7.3 扩展会员权益


1. 数据库修改:在system_user_level表中添加新的权益字段
2. 代码修改
- 修改会员等级配置和管理功能
- 在相关业务逻辑中添加权益判断和生效代码
3. 前端修改:在前端添加对应的权益展示和使用入口

8. 文档更新记录

| 版本 | 更新日期 | 更新内容 | 更新人 |
|------|----------|----------|--------|
| 1.0 | 2026-01-19 | 初始版本,包含会员等级管理、用户等级管理、经验值管理、积分管理、会员权益管理、会员等级升级机制等核心功能 | AI Assistant |

9. 附录

9.1 核心类关系图

text
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│ Models │ │ Daos │ │ Services │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
└───────────────────────┼───────────────────────┘

┌─────────────────┐
│ Controllers │
└─────────────────┘

┌─────────────────┐
│ Routes │
└─────────────────┘

9.2 会员等级升级流程图

text
会员等级升级流程:
1. 用户执行获取经验值的行为(签到、下单、邀请等)
2. 系统增加用户经验值,记录经验值变动
3. 检查用户当前经验值是否达到下一级别要求
4. 达到要求,更新用户等级
5. 记录等级变动日志
6. 发送等级升级通知给用户
7. 更新用户享有的权益

9.3 积分获取与使用流程图

text
积分获取与使用流程:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 积分获取 │ │ 积分管理 │ │ 积分使用 │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 签到获得积分 │ │ 积分增加 │ │ 抵扣商品金额 │
│ 下单获得积分 │ │ 积分扣除 │ │ 积分商城兑换 │
│ 邀请获得积分 │ │ 积分记录 │ │ 参与活动消耗 │
│ 活动获得积分 │ │ 积分统计 │ └─────────────────┘
└─────────────────┘ └─────────────────┘

9.4 会员权益列表

| 权益名称 | 描述 |
|----------|------|
| 折扣优惠 | 不同等级享受不同的商品折扣 |
| 等级图标 | 每个等级拥有专属图标和背景图 |
| 经验值加速 | 高级会员获得经验值的速度更快 |
| 专属客服 | 高级会员享受专属客服服务 |
| 优先发货 | 高级会员订单优先发货 |
| 生日福利 | 会员生日获得专属福利 |
| 专属活动 | 高级会员参与专属活动 |
| 积分翻倍 | 高级会员获得积分的倍数更高 |

---

提示:该文档由AI生成,仅供参考。

---

Help/Dev Docs/Phpapi/分销系统说明文档 (help/dev-docs/phpapi/分销系统说明文档.md)

💳 佣金提现流程

提现申请处理


php
public function handleWithdraw($id, $status, $rejectReason = '')
{
$withdraw = $this->dao->get($id);
if (!$withdraw) {
throw new AdminException('提现记录不存在');
}

if ($withdraw['status'] != 0) {
throw new AdminException('提现已处理');
}

// 更新状态
$updateData = [
'status' => $status,
'handle_time' => time()
];

if ($status == 2) { // 拒绝
$updateData['reject_reason'] = $rejectReason;
$this->dao->update($id, $updateData);

// 返还金额到用户余额
$this->returnAmountToUser($withdraw);
} else { // 通过
$this->dao->update($id, $updateData);

// 实际打款操作
$this->transferToUser($withdraw);
}

// 发送通知
$this->sendWithdrawResultNotify($withdraw['uid'], $status, $rejectReason);
}

提现打款方式


1. 手动打款
- 管理员后台手动转账
- 记录转账凭证

2. 自动打款(需配置)
- 微信企业付款
- 支付宝转账
- 银行卡转账

📊 数据统计与分析

分销业绩报表


sql
SELECT 
a.uid,
u.nickname,
COUNT(DISTINCT o.order_id) AS order_count,
SUM(o.pay_price) AS order_amount,
SUM(c.commission_amount) AS total_commission,
COUNT(DISTINCT s.uid) AS spread_count
FROM
eb_user_agent a
LEFT JOIN
eb_user u ON a.uid = u.uid
LEFT JOIN
eb_store_order o ON o.uid = a.uid AND o.paid = 1
LEFT JOIN
eb_agent_commission c ON c.uid = a.uid AND c.status = 1
LEFT JOIN
eb_user_spread s ON s.spread_uid = a.uid
GROUP BY
a.uid
ORDER BY
total_commission DESC

团队业绩查询


php
public function getTeamPerformance($uid, $startTime, $endTime)
{
// 获取团队用户ID
$teamUids = $this->getTeamUids($uid);

// 查询团队业绩
return $this->dao->getPerformanceByUids(
$teamUids,
$startTime,
$endTime
);
}

🛠️ 分销系统API

核心API列表


| 接口名称 | 请求方式 | 路径 | 描述 |
|---------|---------|------|------|
| 申请成为分销商 | POST | /api/agent/apply | 提交分销申请 |
| 获取分销信息 | GET | /api/agent/info | 获取分销商信息 |
| 获取佣金明细 | GET | /api/agent/commission | 佣金记录查询 |
| 提现申请 | POST | /api/agent/withdraw | 提交提现申请 |
| 获取团队列表 | GET | /api/agent/team | 获取下级分销商 |

🔍 常见问题处理

1. 分销关系未正确建立


- 检查点
- 用户是否满足分销条件
- 分销功能是否开启
- 推广链接参数是否正确传递

2. 佣金未计算


- 检查点
- 订单是否已完成
- 分销商状态是否正常
- 佣金比例是否配置

3. 提现失败


- 检查点
- 余额是否充足
- 提现信息是否完整
- 风控规则是否触发

📝 版本更新记录

| 版本 | 日期 | 更新内容 |
|------|------|---------|
| v1.0 | 2024-01-17 | 初版文档创建 |
| v1.1 | 2024-01-18 | 增加多级分销配置 |

---
文档维护:技术团队
最后更新:2024-01-17

💡 提示:分销系统涉及资金流转,请定期审核佣金计算和提现记录,确保财务数据准确。

---

提示:该文档由AI生成,仅供参考。

---

Help/Dev Docs/Phpapi/后端代码目录结构说明 (help/dev-docs/phpapi/后端代码目录结构说明.md)

CRMEB 后端代码目录结构说明

项目概述

CRMEB 是一个基于 ThinkPHP 6.x 框架开发的电商系统,采用多应用架构模式,支持管理后台、用户端API、客服系统等多个应用模块。

核心架构

架构模式


- 框架: ThinkPHP 6.x
- 架构模式: 多应用架构 (Multi-App)
- 设计模式: MVC + Service + DAO 分层架构
- 依赖注入: 容器管理
- 数据库: MySQL (支持主从分离)

目录结构总览

text
crmeb/
├── app/ # 应用目录
│ ├── adminapi/ # 管理后台API应用
│ ├── api/ # 用户端API应用
│ ├── kefuapi/ # 客服系统API应用
│ ├── outapi/ # 外部API应用
│ ├── dao/ # 数据访问层 (DAO)
│ ├── http/ # HTTP相关类
│ ├── jobs/ # 队列任务
│ ├── lang/ # 多语言包
│ ├── listener/ # 事件监听器
│ ├── model/ # 数据模型层
│ └── services/ # 业务逻辑服务层
├── config/ # 配置文件目录
├── crmeb/ # 核心框架扩展
├── public/ # 公共资源目录
├── route/ # 路由定义
├── runtime/ # 运行时文件
└── vendor/ # 第三方依赖

详细目录说明

1. 应用目录 (app/)

#### 1.1 管理后台API (app/adminapi/)

text
/ Detailed source-code truncated for AI context efficiency. /

#### 1.2 用户端API (app/api/)

text
api/
├── config/route.php # 用户端路由配置
├── controller/ # 控制器层
│ ├── pc/ # PC端控制器
│ ├── v1/ # API版本1
│ │ ├── activity/ # 活动相关
│ │ ├── admin/ # 管理相关
│ │ ├── order/ # 订单相关
│ │ ├── publics/ # 公共接口
│ │ ├── store/ # 商店相关
│ │ ├── user/ # 用户相关
│ │ └── wechat/ # 微信相关
│ ├── v2/ # API版本2
│ ├── CrontabController.php # 定时任务控制器
│ ├── LoginController.php # 登录控制器
│ ├── PayController.php # 支付控制器
│ └── PublicController.php # 公共控制器
├── middleware/ # 中间件
│ ├── AuthTokenMiddleware.php # Token验证中间件
│ ├── BlockerMiddleware.php # 访问限制中间件
│ ├── CustomerMiddleware.php # 客户中间件
│ └── StationOpenMiddleware.php # 站点开放中间件
├── route/ # 路由定义
│ ├── pc.php # PC端路由
│ ├── v1.php # API v1路由
│ └── v2.php # API v2路由
└── validate/ # 验证器
└── user/ # 用户验证器

#### 1.3 数据访问层 (app/dao/)

text
/ Detailed source-code truncated for AI context efficiency. /

#### 1.4 服务层 (app/services/)

text
services/
├── activity/ # 活动服务
├── admin/ # 管理服务
├── agent/ # 代理服务
├── app/ # 应用服务
├── clone/ # 克隆服务
├ ├── community/ # 社区服务
├── crud/ # CRUD代码生成服务
├ ├── diy/ # DIY服务
├ ├── export/ # 导出服务
├ ├── file/ # 文件服务
├ ├── goods/ # 商品服务
├ ├── import/ # 导入服务
├ ├── invoice/ # 发票服务
├ ├── ka/ # 客服服务
├ ├── lang/ # 多语言服务
├ ├── live/ # 直播服务
├ ├── message/ # 消息服务
├ ├── ota/ # OTA服务
├ ├── other/ # 其他服务
├ ├── pay/ # 支付服务
├ ├── phonestore/ # 手机商店服务
├ ├── product/ # 商品服务
├ ├── protect/ # 保护服务
├ ├── queue/ # 队列服务
├ ├── scan/ # 扫码服务
├ ├── serve/ # 服务服务
├ ├── setting/ # 设置服务
├ ├── shipping/ # 物流服务
├ ├── stat/ # 统计服务
├ ├── store/ # 商店服务
├ ├── system/ # 系统服务
├ ├── template/ # 模板服务
├ ├── user/ # 用户服务
├ ├── utils/ # 工具服务
└── work/ # 工作服务

#### 1.5 模型层 (app/model/)

text
model/
├── activity/ # 活动模型
├── card/ # 卡券模型
├── community/ # 社区模型
├── configure/ # 配置模型
├── diy/ # DIY模型
├── log/ # 日志模型
├── message/ # 消息模型
├── ota/ # OTA模型
├── other/ # 其他模型
├── pay/ # 支付模型
├── product/ # 商品模型
├── queue/ # 队列模型
├── shipping/ # 物流模型
├── store/ # 商店模型
├── system/ # 系统模型
├── user/ # 用户模型
└── work/ # 工作模型

2. 核心框架扩展 (crmeb/)

#### 2.1 基础类 (crmeb/basic/)

text
basic/
├── BaseController.php # 控制器基类
├── BaseJobs.php # 任务基类
├── BaseManager.php # 管理器基类
├── BaseModel.php # 模型基类
└── BaseStorage.php # 存储基类

#### 2.2 命令行 (crmeb/command/)

text
command/
├── Npm.php # NPM命令
├── Timer.php # 定时器命令
├── Util.php # 工具命令
└── Workerman.php # Workerman命令

#### 2.3 异常处理 (crmeb/exceptions/)

text
exceptions/
├── AdminException.php # 管理异常
├── ApiException.php # API异常
├── ApiStatusException.php # API状态异常
├── AuthException.php # 认证异常
├── CrudException.php # CRUD异常
├── PayException.php # 支付异常
└── UploadException.php # 上传异常

#### 2.4 接口定义 (crmeb/interfaces/)

text
interfaces/
├── JobInterface.php # 任务接口
├── ListenerInterface.php # 监听器接口
├── MiddlewareInterface.php # 中间件接口
└── ProviderInterface.php # 提供者接口

#### 2.5 服务层 (crmeb/services/)

text
services/
├── app/ # 应用服务
│ ├── MiniProgramService.php # 小程序服务
│ ├── WechatOpenService.php # 微信开放服务
│ └── WechatService.php # 微信服务
├── copyproduct/ # 商品复制服务
├── crud/ # CRUD代码生成服务
├── easywechat/ # 微信SDK服务
├── express/ # 快递服务
├── invoice/ # 发票服务
├── oauth/ # OAuth认证服务
├── pay/ # 支付服务
├── printer/ # 打印服务
├── serve/ # 系统服务
├── sms/ # 短信服务
├── template/ # 模板消息服务
├── upload/ # 上传服务
├── workerman/ # Workerman服务
└── 核心服务文件...

#### 2.6 特性 (crmeb/traits/)

text
traits/
├── JwtAuthModelTrait.php # JWT认证特性
├── ModelTrait.php # 模型特性
└── QueueTrait.php # 队列特性

#### 2.7 工具类 (crmeb/utils/)

text
utils/
├── Arr.php # 数组工具
├── Canvas.php # 画布工具
├── Captcha.php # 验证码工具
├── DownloadImage.php # 图片下载工具
├── fileVerification.php # 文件验证工具
├── Hook.php # 钩子工具
├── Json.php # JSON工具
├── JwtAuth.php # JWT认证工具
├── Queue.php # 队列工具
├── Rsa.php # RSA加密工具
├── Str.php # 字符串工具
├── Terminal.php # 终端工具
└── Translate.php # 翻译工具

3. 配置文件 (config/)

text
config/
├── ajcaptcha.php # 验证码配置
├── app.php # 应用配置
├── cache.php # 缓存配置
├── captcha.php # 图片验证码配置
├── console.php # 控制台配置
├── cookie.php # Cookie配置
├── database.php # 数据库配置
├── filesystem.php # 文件系统配置
├── lang.php # 多语言配置
├── log.php # 日志配置
├── pay.php # 支付配置
├── plat.php # 平台配置
├── printer.php # 打印配置
├── qrcode.php # 二维码配置
├── queue.php # 队列配置
├── route.php # 路由配置
├── session.php # 会话配置
├── sms.php # 短信配置
├── trace.php # 调试跟踪配置
├── upload.php # 上传配置
├── view.php # 视图配置
└── workerman.php # Workerman配置

4. 公共资源 (public/)

text
public/
├── admin/ # 管理后台前端
├── assets/ # 静态资源
├── install/ # 安装程序
├── pages/ # 页面文件
├── static/ # 静态文件
├── statics/ # 系统静态文件
├── upgrade/ # 升级程序
├── .htaccess # Apache重写规则
├── favicon.ico # 网站图标
├── index.html # 默认首页
└── 入口文件...

5. 路由定义 (route/)

text
route/
├── README.md # 路由说明
└── route.php # 主路由文件

架构设计模式

1. 分层架构


- Controller层: 处理HTTP请求,参数验证,调用Service
- Service层: 业务逻辑处理,事务管理,调用DAO
- DAO层: 数据访问,SQL操作,模型映射
- Model层: 数据模型定义,关联关系

2. 依赖注入


- 使用ThinkPHP容器管理对象依赖
- 通过构造函数注入Service依赖
- 支持接口编程和面向切面编程

3. 中间件机制


- 认证授权中间件
- 权限检查中间件
- 操作日志中间件
- 参数过滤中间件

4. 事件监听


- 订单状态变更事件
- 用户注册事件
- 支付完成事件
- 商品库存变更事件

核心功能模块

1. 商品管理


- 商品分类、规格、属性管理
- 库存管理、价格策略
- 商品审核、上下架管理
- 商品导入导出功能

2. 订单管理


- 订单创建、支付、发货流程
- 订单状态管理和追踪
- 退款、售后处理
- 订单统计分析

3. 用户管理


- 用户注册、登录、认证
- 用户等级、会员体系
- 用户标签、分组管理
- 用户行为分析

4. 营销活动


- 优惠券、满减活动
- 拼团、砍价、秒杀
- 积分商城、签到奖励
- 推广分销系统

5. 支付系统


- 微信支付、支付宝支付
- 余额支付、积分支付
- 支付回调处理
- 退款对账功能

6. 物流配送


- 快递公司对接
- 运费模板管理
- 物流信息查询
- 配送状态跟踪

技术特性

1. 多应用架构


- 管理后台、用户端、客服系统独立部署
- 统一的认证授权机制
- 模块化设计便于扩展

2. 微服务支持


- 队列任务异步处理
- 缓存服务集成
- 分布式文件存储
- 多数据库支持

3. 安全机制


- JWT Token认证
- 接口签名验证
- SQL注入防护
- XSS攻击防护

4. 性能优化


- 数据库读写分离
- 缓存策略优化
- 静态资源CDN
- 接口响应压缩

开发规范

1. 命名规范


- 类名: PascalCase (如 StoreProductServices)
- 方法名: camelCase (如 getProductList)
- 变量名: camelCase (如 productId)
- 常量名: UPPER_CASE (如 API_VERSION)

2. 文件组织


- Controller按业务模块分组
- Service按功能领域划分
- DAO按数据实体组织
- Model对应数据库表结构

3. 注释规范


- 类和方法的PHPDoc注释
- 复杂业务逻辑说明
- API接口文档注释
- 数据库字段说明

4. 错误处理


- 统一异常处理机制
- 自定义业务异常类
- 错误日志记录
- 用户友好错误提示

部署要求

1. 环境要求


- PHP >= 7.4
- MySQL >= 5.7
- Redis >= 4.0
- Nginx/Apache

2. 扩展要求


- PDO MySQL
- GD2/ImageMagick
- Curl
- OpenSSL
- Fileinfo

3. 权限设置


- runtime目录可写
- public/uploads可写
- 日志目录可写
- 缓存目录可写

维护建议

1. 代码维护


- 定期代码审查
- 单元测试覆盖
- 性能监控分析
- 安全漏洞扫描

2. 数据库维护


- 定期数据备份
- 索引优化调整
- 慢查询分析
- 数据清理归档

3. 系统监控


- 服务器资源监控
- 应用性能监控
- 错误日志监控
- 用户行为分析

---

本文档详细说明了CRMEB后端代码的目录结构、架构设计和开发规范,为开发团队提供完整的技术指导和参考。

---

提示:该文档由AI生成,仅供参考。

---

Help/Dev Docs/Phpapi/开发规范说明 (help/dev-docs/phpapi/开发规范说明.md)

开发规范说明

🎯 基于已有规范的扩展

1. Service层命名和使用规范


php
// ✅ 正确示例
class UserServices extends BaseServices {
public function getUserInfo(int $uid) {}
public function updateUserStatus(int $uid, int $status) {}
}

// ❌ 避免在Controller中直接操作数据库
// 不要这样写:Db::name('user')->where('id', $uid)->update($data)

2. DAO层职责划分


php
// ✅ DAO只负责基础CRUD
class UserDao extends BaseDao {
public function getById(int $id) {}
public function updateById(int $id, array $data) {}
}

// Service调用DAO
class UserServices {
public function complexBusiness() {
$user = $this->dao->getById($id);
// 业务逻辑处理
$this->dao->updateById($id, $data);
}
}

3. 异常处理标准


php
// 使用项目特定异常类
throw new ApiException('错误信息', 400);
throw new AdminException('管理端错误', 500);

// 统一返回格式
return $this->success($data);
return $this->fail('错误信息');

4. 参数验证位置


php
// 验证放在validate目录下对应文件
// adminapi/validate/user/UserValidata.php
class UserValidata extends Validate {
protected $rule = [
'nickname' => 'require|max:25',
'phone' => 'require|mobile'
];
}

5. 注释标准补充


php
/
* 获取用户信息(包含扩展信息)
* @param int $uid 用户ID
* @param array $with 关联查询 ['order', 'address']
* @return array
* @throws ApiException
*/
public function getUserDetail(int $uid, array $with = []) {
// 业务逻辑
}

🔧 工具类使用规范


- 使用 crmeb\utils\ 下的工具类
- 配置获取使用 SystemConfigService
- 缓存操作使用 CacheService
- 文件上传使用 UploadService

📝 代码提交规范


1. 提交前运行测试
2. 提交信息格式:[类型] 描述
- [feat] 新增用户积分功能
- [fix] 修复订单状态更新问题
- [docs] 更新API文档
- [style] 调整代码格式
3. 避免大块提交,每个提交专注于一个功能或修复

🚧 分支管理


- master - 生产环境代码
- develop - 开发分支
- feature/xxx - 功能开发分支
- hotfix/xxx - 紧急修复分支

🧪 测试规范


1. 单元测试覆盖核心业务逻辑
2. 集成测试覆盖API接口
3. 测试数据使用工厂模式生成
4. 测试用例命名:testMethodNameWhenConditionThenResult

---

提示:该文档由AI生成,仅供参考。

---

Help/Dev Docs/Phpapi/支付开发流程文档 V2 (help/dev-docs/phpapi/支付开发流程文档-V2.md)

CRMEB 支付开发流程文档

🎯 支付功能概述

基于CRMEB 5.6.4+版本的支付系统分析,项目采用统一的支付服务架构,支持多种支付方式集成。

支持的支付方式


php
// app/services/pay/PayServices.php
const WEIXIN_PAY = 'weixin'; // 微信支付
const YUE_PAY = 'yue'; // 余额支付
const OFFLINE_PAY = 'offline'; // 线下支付
const ALIAPY_PAY = 'alipay'; // 支付宝
const ALLIN_PAY = 'allinpay'; // 通联支付
const FRIEND = 'friend'; // 好友代付
const BANK = 'bank'; // 银行转账

🏗️ 支付系统架构

核心服务类结构


text
app/services/pay/
├── PayServices.php # 统一支付入口服务
├── OrderPayServices.php # 订单支付服务
├── PayNotifyServices.php # 支付回调服务
├── YuePayServices.php # 余额支付服务
└── RechargeServices.php # 充值服务

crmeb/services/pay/
├── Pay.php # 支付基础驱动
├── storage/
│ ├── WechatPay.php # 微信支付驱动
│ ├── AliPay.php # 支付宝驱动
│ ├── AllinPay.php # 通联支付驱动
│ └── V3WechatPay.php # 微信支付V3驱动

支付流程

#### 1. 支付请求流程

mermaid
graph TD
A[客户端] --> B[支付控制器]
B --> C[PayServices]
C --> D[支付驱动 WechatPay/AliPay]
D --> E[第三方支付平台]
E --> F[返回支付参数]
F --> A

#### 2. 支付回调流程

mermaid
graph TD
A[第三方支付] --> B[支付回调接口]
B --> C[PayNotifyServices]
C --> D[订单状态更新]
C --> E[支付记录更新]
D --> F[业务处理]

🔧 核心代码解析

统一支付入口 (PayServices.php)


php
public function pay(string $payType, string $orderId, string $price, string $successAction, string $body, array $options = [])
{
try {
// 支付类型映射处理
if (in_array($payType, ['routine', 'weixinh5', 'weixin', 'pc', 'store'])) {
$payType = 'wechat_pay';
// V3接口判断
if (sys_config('pay_wechat_type') == 1) {
$payType = 'v3_wechat_pay';
}
} elseif ($payType == 'alipay') {
$payType = 'ali_pay';
} elseif ($payType == 'allinpay') {
$payType = 'allin_pay';
}

// 创建支付实例
$pay = app()->make(Pay::class, [$payType]);

return $pay->create($orderId, $price, $successAction, $body, '', $options);

} catch (\Exception $e) {
throw new ApiException($e->getMessage());
}
}

微信支付驱动 (WechatPay.php)


php
public function create(string $orderId, string $totalFee, string $attach, string $body, string $detail, array $options = [])
{
$this->authSetPayType();

switch ($this->payType) {
case Order::NATIVE: // 扫码支付
return WechatService::nativePay(null, $orderId, $totalFee, $attach, $body, $detail);
case Order::APP: // APP支付
return WechatService::appPay($options['openid'], $orderId, $totalFee, $attach, $body, $detail);
case Order::JSAPI: // 小程序/公众号支付
if (request()->isRoutine()) {
// 小程序支付
if ($options['pay_new_weixin_open']) {
return MiniProgramService::newJsPay($options['openid'], $orderId, $totalFee, $attach, $body, $detail, $options);
}
return MiniProgramService::jsPay($options['openid'], $orderId, $totalFee, $attach, $body, $detail);
}
return WechatService::jsPay($options['openid'], $orderId, $totalFee, $attach, $body, $detail);
case 'h5': // H5支付
return WechatService::paymentPrepare(null, $orderId, $totalFee, $attach, $body, $detail, 'MWEB');
default:
throw new PayException('微信支付:支付类型错误');
}
}

支付回调处理 (PayNotifyServices.php)


php
public function wechatProduct(string $order_id = null, string $trade_no = null, string $payType = PayServices::WEIXIN_PAY)
{
try {
$services = app()->make(StoreOrderSuccessServices::class);
$orderInfo = $services->getOne(['order_id' => $order_id]);

if (!$orderInfo) return true;
if ($orderInfo->paid) return true;

return $services->paySuccess($orderInfo->toArray(), $payType, ['trade_no' => $trade_no]);
} catch (\Exception $e) {
return false;
}
}

🛠️ 开发指南

1. 支付配置设置


在后台管理系统配置:
- 微信支付参数(APPID、商户号、API密钥、证书)
- 支付宝配置
- 通联支付配置
- 支付方式开关

2. 发起支付调用


php
// 在控制器中调用
public function createPayment()
{
$params = $this->request->post();

// 参数验证
validate(PaymentValidate::class)->scene('create')->check($params);

$payServices = app()->make(PayServices::class);
$result = $payServices->pay(
$params['pay_type'],
$params['order_id'],
$params['amount'],
url('api/v1/payment/notify/wechat', [], true, true),
'商品购买'
);

return $this->success($result);
}

3. 支付回调配置


php
// 路由配置
Route::post('api/v1/payment/notify/:type', 'api/v1/payment/notify');

// 回调控制器
public function notify($type)
{
$notifyService = app()->make(PayNotifyServices::class);

switch ($type) {
case 'wechat':
return $notifyService->wechatProduct(
$this->request->post('out_trade_no'),
$this->request->post('transaction_id')
);
case 'alipay':
// 支付宝回调处理
break;
}

return response('SUCCESS');
}

🧪 测试指南

单元测试示例


php
class PaymentTest extends TestCase
{
public function testWechatPaymentCreation()
{
$payService = new PayServices();
$result = $payService->pay(
'weixin',
'TEST20240117001',
'100.00',
'https://domain.com/notify',
'测试商品'
);

$this->assertArrayHasKey('timeStamp', $result);
$this->assertArrayHasKey('nonceStr', $result);
$this->assertArrayHasKey('package', $result);
}
}

沙箱环境配置


bash

微信支付沙箱


WECHAT_SANDBOX=true
WECHAT_APPID=sandbox_appid
WECHAT_MCHID=sandbox_mchid

支付宝沙箱


ALIPAY_SANDBOX=true
ALIPAY_GATEWAY=https://openapi.alipaydev.com/gateway.do

📊 数据库设计

支付记录表 (eb_store_pay)


sql
CREATE TABLE eb_store_pay (
id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
uid int(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '用户id',
oid int(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '订单id',
order_id varchar(32) NOT NULL DEFAULT '' COMMENT '订单号',
out_trade_no varchar(32) NOT NULL DEFAULT '' COMMENT '支付流水号',
pay_type varchar(20) NOT NULL DEFAULT '' COMMENT '支付方式',
pay_price decimal(10,2) UNSIGNED NOT NULL DEFAULT '0.00' COMMENT '支付金额',
trade_no varchar(64) DEFAULT NULL COMMENT '第三方支付流水号',
paid tinyint(1) UNSIGNED NOT NULL DEFAULT '0' COMMENT '支付状态',
pay_time int(10) UNSIGNED DEFAULT NULL COMMENT '支付时间',
add_time int(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间',
PRIMARY KEY (id),
UNIQUE KEY out_trade_no (out_trade_no),
KEY order_id (order_id),
KEY paid (paid)
) ENGINE=InnoDB COMMENT='支付记录表';

🚀 部署运维

生产环境配置


bash

微信支付配置


WECHAT_APPID=your_appid
WECHAT_MCHID=your_mchid
WECHAT_KEY=your_key
WECHAT_CERT_PATH=/path/to/cert.pem
WECHAT_KEY_PATH=/path/to/key.pem

SSL证书配置


ssl_certificate /path/to/ssl/cert.pem;
ssl_certificate_key /path/to/ssl/key.pem;

监控告警


php
// 支付监控指标
$metrics = [
'payment_success_rate' => ($successCount / $totalCount) * 100,
'payment_response_time' => microtime(true) - $startTime,
'payment_error_count' => $errorCount
];

// 日志记录
Log::info('支付监控', $metrics);

🔧 故障处理

常见问题


1. 支付回调失败:检查nginx配置、SSL证书、防火墙
2. 签名错误:验证支付密钥配置
3. 金额不一致:检查金额单位和优惠计算
4. 重复支付:添加防重机制和状态检查

应急处理


bash

查看支付日志


tail -f runtime/log/payment.log

禁用问题支付方式


php think pay:disable weixin

启用备用支付


php think pay:enable alipay

---
文档版本: v2.0
更新日期: 2024-01-17
适用版本: CRMEB 5.6.4+

💡 提示:支付功能涉及资金安全,请严格遵循安全规范,定期进行安全审计。

---

提示:该文档由AI生成,仅供参考。

---

Help/Dev Docs/Phpapi/支付开发流程文档 (help/dev-docs/phpapi/支付开发流程文档.md)

支付开发流程文档

🎯 支付功能概述

支付场景


- 商品购买支付:普通商品订单支付
- 服务购买支付:虚拟服务、会员购买
- 充值支付:余额充值、积分充值
- 保证金支付:商户保证金、服务保证金
- 退款处理:订单退款、冲正处理

支持的支付方式


php
const PAY_TYPE_WECHAT = 'wechat';      // 微信支付
const PAY_TYPE_ALIPAY = 'alipay'; // 支付宝
const PAY_TYPE_BALANCE = 'balance'; // 余额支付
const PAY_TYPE_INTEGRAL = 'integral'; // 积分支付
const PAY_TYPE_UNION = 'union'; // 云闪付
const PAY_TYPE_BANK = 'bank'; // 银行卡支付

🏗️ 支付系统架构

支付模块架构


text
┌─────────────────────────────────────────────────────┐
│ 支付控制器 (Controller) │
│ - 支付入口处理 │
│ - 参数验证 │
│ - 结果返回 │
└─────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────┐
│ 支付服务层 (PaymentService) │
│ - 支付逻辑处理 │
│ - 支付方式路由 │
│ - 支付状态管理 │
└─────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────┐
│ 支付渠道适配层 (PaymentAdapter) │
│ - 微信支付适配器 (WechatPayment) │
│ - 支付宝适配器 (AlipayPayment) │
│ - 余额支付适配器 (BalancePayment) │
│ - 积分支付适配器 (IntegralPayment) │
└─────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────┐
│ 第三方支付SDK │
│ - 微信支付官方SDK │
│ - 支付宝官方SDK │
│ - 银行支付接口 │
└─────────────────────────────────────────────────────┘

数据库设计


sql
-- 支付记录表
CREATE TABLE store_pay (
id int(11) NOT NULL AUTO_INCREMENT,
order_id varchar(32) NOT NULL COMMENT '订单号',
out_trade_no varchar(32) NOT NULL COMMENT '支付流水号',
pay_type varchar(20) NOT NULL COMMENT '支付方式',
pay_price decimal(10,2) NOT NULL COMMENT '支付金额',
trade_no varchar(64) DEFAULT NULL COMMENT '第三方支付流水号',
pay_status tinyint(1) NOT NULL DEFAULT '0' COMMENT '支付状态',
pay_time int(11) DEFAULT NULL COMMENT '支付时间',
create_time int(11) NOT NULL COMMENT '创建时间',
update_time int(11) NOT NULL COMMENT '更新时间',
PRIMARY KEY (id),
UNIQUE KEY idx_out_trade_no (out_trade_no),
KEY idx_order_id (order_id),
KEY idx_pay_status (pay_status)
) ENGINE=InnoDB COMMENT='支付记录表';

-- 退款记录表
CREATE TABLE store_refund (
id int(11) NOT NULL AUTO_INCREMENT,
order_id varchar(32) NOT NULL COMMENT '订单号',
refund_no varchar(32) NOT NULL COMMENT '退款流水号',
refund_amount decimal(10,2) NOT NULL COMMENT '退款金额',
refund_reason varchar(255) DEFAULT NULL COMMENT '退款原因',
refund_status tinyint(1) NOT NULL DEFAULT '0' COMMENT '退款状态',
refund_time int(11) DEFAULT NULL COMMENT '退款时间',
create_time int(11) NOT NULL COMMENT '创建时间',
PRIMARY KEY (id),
UNIQUE KEY idx_refund_no (refund_no),
KEY idx_order_id (order_id)
) ENGINE=InnoDB COMMENT='退款记录表';

🔧 开发流程

1. 需求分析与设计


markdown
1. 确定支付场景和需求
2. 选择支持的支付方式
3. 设计支付流程和状态流转
4. 确定退款政策和规则
5. 设计对账和清算流程

2. 环境准备


bash

安装支付SDK依赖


composer require overtrue/wechat
composer require alipay-sdk/php-all

配置支付参数


cp .env.example .env

配置微信支付参数


WECHAT_APPID=your_appid
WECHAT_MCHID=your_mchid
WECHAT_KEY=your_key
WECHAT_APPSECRET=your_appsecret

配置支付宝参数


ALIPAY_APPID=your_appid
ALIPAY_PRIVATE_KEY=your_private_key
ALIPAY_PUBLIC_KEY=your_public_key

3. 支付控制器开发


php
<?php
namespace app\api\controller\v1;

use app\services\PaymentService;
use app\validate\PaymentValidate;

class PaymentController
{
/
* 发起支付
* @route('api/v1/payment/create')
*/
public function createPayment()
{
// 参数验证
$params = $this->request->post();
validate(PaymentValidate::class)->scene('create')->check($params);

// 调用支付服务
$paymentService = app()->make(PaymentService::class);
$result = $paymentService->createPayment($params);

return $this->success($result);
}

/
* 支付回调处理
* @route('api/v1/payment/notify/:type')
*/
public function paymentNotify($type)
{
try {
$paymentService = app()->make(PaymentService::class);
$result = $paymentService->handleNotify($type, $this->request->post());

// 返回第三方支付要求的成功响应
return response($result['response']);
} catch (\Exception $e) {
Log::error('支付回调处理失败: ' . $e->getMessage());
return response('FAIL');
}
}
}

4. 支付服务层开发


text
/ Detailed source-code truncated for AI context efficiency. /

5. 支付适配器开发(以微信支付为例)


text
/ Detailed source-code truncated for AI context efficiency. /

6. 支付接口定义


php
<?php
namespace app\services\payment;

interface PaymentInterface
{
/
* 创建支付
*/
public function createPayment(array $payData): array;

/
* 处理支付回调
*/
public function verifyNotify(array $notifyData): array;

/
* 查询支付状态
*/
public function queryPayment(string $outTradeNo): array;

/
* 申请退款
*/
public function refund(array $refundData): array;
}

🧪 测试流程

1. 单元测试


php
<?php
namespace tests\services;

use app\services\PaymentService;
use app\services\payment\WechatPayment;
use think\testing\TestCase;

class PaymentServiceTest extends TestCase
{
public function testCreatePayment()
{
// 模拟支付参数
$params = [
'order_id' => 'TEST202401170001',
'pay_type' => 'wechat',
'pay_amount' => 100.00
];

// 创建支付服务实例
$paymentService = new PaymentService();

// 测试支付创建
$result = $paymentService->createPayment($params);

$this->assertArrayHasKey('pay_params', $result);
$this->assertEquals('wechat', $result['pay_type']);
}

public function testPaymentNotify()
{
// 模拟微信支付回调数据
$notifyData = [
'return_code' => 'SUCCESS',
'result_code' => 'SUCCESS',
'out_trade_no' => 'TEST202401170001',
'transaction_id' => '420000202401170001',
'total_fee' => '10000',
'time_end' => '20240117153000'
];

$paymentService = new PaymentService();
$result = $paymentService->handleNotify('wechat', $notifyData);

$this->assertEquals('SUCCESS', $result['response']);
}
}

2. 集成测试


bash

运行支付相关测试


php think test tests/services/PaymentServiceTest
php think test tests/services/payment/WechatPaymentTest
php think test tests/services/payment/AlipayPaymentTest

生成测试覆盖率报告


php think test --coverage-html coverage/payment

3. 沙箱环境测试


php
// 配置沙箱环境
'wechat' => [
'app_id' => '沙箱appid',
'mch_id' => '沙箱商户号',
'key' => '沙箱key',
'sandbox' => true, // 开启沙箱模式
]

// 支付宝沙箱配置
'alipay' => [
'app_id' => '沙箱appid',
'gateway_url' => 'https://openapi.alipaydev.com/gateway.do',
'sign_type' => 'RSA2',
'sandbox' => true,
]

🚀 部署上线

1. 生产环境配置


bash

设置生产环境配置


cp .env.production .env

配置生产环境支付参数


WECHAT_APPID=生产环境appid
WECHAT_MCHID=生产环境商户号
WECHAT_KEY=生产环境key
WECHAT_CERT_PATH=/path/to/cert/apiclient_cert.pem
WECHAT_KEY_PATH=/path/to/cert/apiclient_key.pem

ALIPAY_APPID=生产环境appid
ALIPAY_PRIVATE_KEY=生产环境私钥
ALIPAY_PUBLIC_KEY=生产环境公钥

2. SSL证书配置


nginx

Nginx SSL配置


server {
listen 443 ssl http2;
server_name yourdomain.com;

ssl_certificate /path/to/ssl/cert.pem;
ssl_certificate_key /path/to/ssl/key.pem;

# 支付回调接口
location /api/v1/payment/notify/ {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}

3. 监控告警配置


yaml

支付监控指标


payment:
success_rate:
type: gauge
help: 支付成功率
labels: [pay_type]

response_time:
type: histogram
help: 支付响应时间分布
labels: [pay_type]

error_count:
type: counter
help: 支付错误次数
labels: [pay_type, error_code]

📊 运维监控

1. 日志监控


php
// 支付关键日志记录
Log::info('支付创建', [
'order_id' => $orderId,
'pay_type' => $payType,
'amount' => $amount,
'user_id' => $userId
]);

Log::error('支付失败', [
'order_id' => $orderId,
'error_code' => $errorCode,
'error_msg' => $errorMsg,
'trace' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3)
]);

2. 性能监控


bash

监控支付接口性能


平均响应时间 < 200ms


95%响应时间 < 500ms


错误率 < 0.1%

使用Prometheus监控


payment_api_duration_seconds_bucket{pay_type="wechat",le="0.1"} 12345
payment_api_duration_seconds_bucket{pay_type="wechat",le="0.5"} 23456

3. 对账处理


php
/
* 每日对账任务
*/
public function dailyReconciliation()
{
$yesterday = strtotime('yesterday');
$today = strtotime('today');

// 查询本地支付记录
$localRecords = $this->payDao->getRecordsByTime($yesterday, $today);

// 查询第三方支付记录
foreach (['wechat', 'alipay'] as $payType) {
$adapter = $this->getPaymentAdapter($payType);
$thirdPartyRecords = $adapter->queryBill($yesterday, $today);

// 对账处理
$result = $this->reconcile($localRecords, $thirdPartyRecords);

// 记录对账结果
$this->saveReconciliationResult($result);
}
}

🔧 故障处理

常见问题处理


markdown
1. 支付回调失败
- 检查网络连通性
- 验证证书有效性
- 检查回调地址配置

2. 支付签名错误
- 检查密钥配置
- 验证签名算法
- 检查参数编码

3. 支付金额不符
- 检查金额单位(分/元)
- 验证金额计算逻辑
- 检查优惠券抵扣

4. 重复支付
- 检查支付状态验证
- 添加防重机制
- 人工审核处理

应急处理流程


bash

1. 暂停支付功能


php think payment:disable wechat

2. 查看支付日志


tail -f runtime/log/payment.log

3. 回滚有问题的版本


git revert <commit-hash>

4. 启用备用支付通道


php think payment:enable alipay

---
文档版本: v1.0
最后更新: 2024-01-17
维护人员: 支付开发团队

💡 提示: 支付功能涉及资金安全,请严格遵循安全规范和审计要求。

---

提示:该文档由AI生成,仅供参考。

---

Help/Dev Docs/Phpapi/系统事件开发文档 (help/dev-docs/phpapi/系统事件开发文档.md)

CRMEB 系统事件开发文档

1. 事件机制概述

CRMEB 后端系统采用事件驱动架构,通过事件机制实现模块间的解耦和通信。事件系统允许在不直接依赖的情况下,实现不同模块间的交互和业务逻辑扩展。

1.1 核心概念

- 事件(Event):系统中发生的特定动作或状态变化,如订单创建、用户注册等
- 监听器(Listener):监听特定事件并执行相应处理逻辑的类
- 事件触发(Trigger):在特定业务逻辑点调用事件,通知相关监听器执行

2. 事件系统架构

2.1 监听器接口定义

所有监听器必须实现 crmeb\interfaces\ListenerInterface 接口,该接口定义了统一的事件处理方法:

php
<?php
namespace crmeb\interfaces;

interface ListenerInterface
{
public function handle($event): void;
}

2.2 事件配置与注册

事件通过 app/event.php 文件进行定义和注册,该文件返回一个包含事件配置的数组:

php
return [
'bind' => [], // 事件绑定
'listen' => [ // 事件监听
'EventName' => [
'Listener1::class',
'Listener2::class',
],
],
];

示例配置

php
return [
'listen' => [
'HttpEnd' => [\app\listener\http\HttpEndListener::class], //HTTP请求结束回调事件
'UserRegisterListener' => [\app\listener\user\RegisterListener::class], //用户注册后置事件
'OrderCreateAfterListener' => [\app\listener\order\OrderCreateAfterListener::class], //订单创建后置事件
// 更多事件...
],
];

3. 系统内置事件

CRMEB 系统内置了丰富的事件,涵盖了系统运行的各个方面:

| 事件类别 | 事件名称 | 触发时机 | 监听器类 |
|---------|---------|---------|---------|
| 基础事件 | HttpEnd | HTTP请求结束 | \app\listener\http\HttpEndListener::class |
| | QueueStartListener | 队列启动 | \app\listener\queue\QueueStartListener::class |
| 用户相关 | UserLoginListener | 用户登录 | \app\listener\user\LoginListener::class |
| | AdminLoginListener | 管理员登录 | \app\listener\admin\AdminLoginListener::class |
| | UserRegisterListener | 用户注册 | \app\listener\user\RegisterListener::class |
| | WechatAuthListener | 微信授权 | \app\listener\wechat\AuthListener::class |
| | UserLevelListener | 用户升级 | \app\listener\user\UserLevelListener::class |
| | UserVisitListener | 用户访问 | \app\listener\user\UserVisitListener::class |
| 订单相关 | OrderCreateAfterListener | 订单创建 | \app\listener\order\OrderCreateAfterListener::class |
| | OrderPaySuccessListener | 订单支付成功 | \app\listener\order\OrderPaySuccessListener::class |
| | OrderDeliveryListener | 订单发货 | \app\listener\order\OrderDeliveryListener::class |
| | OrderTakeListener | 订单收货 | \app\listener\order\OrderTakeListener::class |
| | OrderRefundCreateAfterListener | 售后单生成 | \app\listener\order\OrderRefundCreateAfterListener::class |
| | OrderRefundCancelAfterListener | 售后单取消 | \app\listener\order\OrderRefundCancelAfterListener::class |
| 其他事件 | OutPushListener | 对外推送 | \app\listener\out\OutPushListener::class |
| | NoticeListener | 通知消息 | \app\listener\notice\NoticeListener::class |
| | CustomEventListener | 自定义事件 | \app\listener\CustomEventListener::class |

4. 事件触发与处理

4.1 事件触发方式

事件通过 event() 函数进行触发,该函数是 ThinkPHP 框架提供的全局函数:

php
// 触发事件
event('EventName', $eventData);

// 示例:触发订单创建事件
event('OrderCreateAfterListener', [$order, $group, $uid, $key, $combinationId, $seckillId, $bargainId]);

4.2 事件处理流程

1. 事件触发:在业务逻辑中通过 event() 函数触发特定事件
2. 事件分发:系统根据事件名称查找对应的监听器列表
3. 监听器执行:依次调用每个监听器的 handle() 方法,并传递事件数据
4. 业务处理:监听器执行各自的业务逻辑,如数据处理、消息发送等
5. 处理完成:所有监听器执行完成后,事件处理流程结束

5. 监听器实现

5.1 监听器创建步骤

1. 创建监听器类:在 app/listener/ 目录下创建相应的监听器类
2. 实现接口:实现 crmeb\interfaces\ListenerInterface 接口
3. 编写处理逻辑:在 handle() 方法中编写事件处理逻辑
4. 注册监听器:在 app/event.php 文件中注册监听器

5.2 监听器实现示例

#### 5.2.1 订单创建事件监听器

text
/ Detailed source-code truncated for AI context efficiency. /

#### 5.2.2 用户注册事件监听器

text
/ Detailed source-code truncated for AI context efficiency. /

6. 自定义事件

CRMEB 支持自定义事件,通过 CustomEventListener 实现灵活的业务扩展:

6.1 自定义事件触发

php
// 触发自定义事件
event('CustomEventListener', ['event_mark', ['data1' => 'value1', 'data2' => 'value2']]);

6.2 自定义事件处理

自定义事件由 app\listener\CustomEventListener 处理,该监听器从数据库中获取配置的自定义代码并执行:

php
<?php
namespace app\listener;

use app\services\system\SystemEventServices;
use think\facade\Log;

class CustomEventListener
{
public function handle($event)
{
[$mark, $data] = $event;
try {
$list = app()->make(SystemEventServices::class)->selectList(['mark' => $mark, 'is_del' => 0, 'is_open' => 1])->toArray();
foreach ($list as $item) {
eval(json_decode($item['customCode']));
}
} catch (\Throwable $e) {
$listener_log_open = config("log.listener_log", false);
if ($listener_log_open) {
$date = date('Y-m-d H:i:s', time());
Log::write($date . '自定义事件错误:' . $e->getMessage(), 'listener');
}
}
}
}

6.3 自定义事件配置

自定义事件可以通过后台管理系统进行配置,在 "系统设置" -> "事件管理" 中添加和管理自定义事件。

7. 最佳实践

7.1 事件命名规范

- 事件名称应清晰表达事件的含义和触发时机,如 OrderCreateAfterListener 表示订单创建后的事件
- 使用驼峰命名法,首字母大写

7.2 监听器设计原则

- 单一职责:每个监听器应只负责处理一个特定的业务逻辑
- 无副作用:监听器处理不应修改原始事件数据,避免影响其他监听器
- 异常处理:在监听器中适当捕获异常,避免单个监听器失败影响整个事件处理流程

7.3 性能优化

- 异步处理:对于耗时的操作,建议使用队列进行异步处理,如发送短信、生成报表等
- 缓存使用:合理使用缓存减少数据库查询,提高处理效率
- 避免循环依赖:监听器之间不应相互依赖,避免形成循环调用

8. 常见问题与解决方案

8.1 事件不触发

问题:调用 event() 函数后,监听器未执行。

解决方案
- 检查事件名称是否与 event.php 中注册的名称一致
- 检查监听器类是否正确实现了 ListenerInterface 接口
- 检查监听器类是否正确注册到对应的事件中

8.2 监听器执行顺序

问题:需要控制监听器的执行顺序。

解决方案
- 在 event.php 中,监听器的注册顺序决定了执行顺序
- 如需更复杂的控制,可以在监听器中手动触发其他事件

8.3 事件数据传递

问题:监听器无法获取完整的事件数据。

解决方案
- 确保事件触发时传递了所有必要的数据
- 使用数组形式传递数据,便于扩展和维护
- 在监听器中对数据进行适当的验证和转换

9. 代码优化建议

9.1 监听器异常处理优化

问题:部分监听器可能缺少完善的异常处理机制,导致单个监听器失败影响整个事件处理流程。

建议:在监听器的 handle() 方法中添加 try-catch 块,捕获并记录异常,确保即使某个监听器失败,也不会影响其他监听器的执行。

php
public function handle($event): void
{
try {
// 监听器逻辑
} catch (\Exception $e) {
// 记录异常日志
Log::error('Listener error: ' . $e->getMessage(), [
'listener' => __CLASS__,
'event' => $event,
'trace' => $e->getTraceAsString()
]);
// 可以根据需要添加其他处理逻辑
}
}

9.2 事件数据验证优化

问题:监听器对事件数据的依赖较强,但缺少对数据有效性的验证,可能导致运行时错误。

建议:在监听器中添加数据验证逻辑,确保接收到的数据符合预期格式和要求。

php
public function handle($event): void
{
// 验证事件数据
if (!is_array($event) || count($event) < 4) {
Log::warning('Invalid event data', [
'listener' => __CLASS__,
'event' => $event
]);
return;
}

[$order, $group, $uid, $key] = $event;

// 验证必要参数
if (empty($order['id']) || empty($uid)) {
Log::warning('Missing required parameters', [
'listener' => __CLASS__,
'order_id' => $order['id'] ?? null,
'uid' => $uid
]);
return;
}

// 监听器逻辑
}

9.3 事件触发点优化

问题:事件触发点可能过于分散,导致难以追踪事件的触发位置和时机。

建议:建立事件触发点的文档或注释规范,明确记录每个事件的触发位置、时机和传递的数据结构,便于后续维护和扩展。

php
/
* 创建订单
* @param array $data 订单数据
* @return array 订单信息
* @event OrderCreateAfterListener 订单创建后触发,传递参数:[$order, $group, $uid, $key, $combinationId, $seckillId, $bargainId]
*/
public function createOrder(array $data)
{
// 订单创建逻辑

// 触发事件
event('OrderCreateAfterListener', [$order, $group, $uid, $key, $combinationId, $seckillId, $bargainId]);

return $order;
}

10. 输入输出示例

10.1 触发订单创建事件

输入

php
// 订单创建完成后触发事件
$order = [
'id' => 1001,
'order_sn' => '2023120100001',
'uid' => 101,
'total_price' => 99.99,
// 其他订单信息
];
$group = [
// 订单商品组信息
];
$uid = 101;
$key = 'order_cache_key';
$combinationId = 0;
$seckillId = 0;
$bargainId = 0;

// 触发事件
event('OrderCreateAfterListener', [$order, $group, $uid, $key, $combinationId, $seckillId, $bargainId]);

输出

text
// 事件触发后,监听器执行以下操作:
1. 计算商品实际金额、佣金、优惠折扣
2. 设置默认地址
3. 清理购物车
4. 清除订单缓存
5. 写入订单记录表
6. 加入订单自动取消延迟队列
7. 记录下单行为
8. 触发小票打印

10.2 触发用户注册事件

输入

php
// 用户注册完成后触发事件
$spreadUid = 201; // 推荐人ID
$userType = 1; // 用户类型
$name = '张三'; // 用户名
$uid = 301; // 新用户ID
$isNew = true; // 是否新用户

// 触发事件
event('UserRegisterListener', [$spreadUid, $userType, $name, $uid, $isNew]);

输出

text
// 事件触发后,监听器执行以下操作:
1. 邀请新用户增加推荐人经验
2. 增加推荐人推广佣金
3. 处理分销等级升级
4. 记录推广绑定关系
5. 发送下级用户绑定成功通知
6. 发送新人优惠券
7. 开启推广权限(如果开启了人人分销)

11. 总结

CRMEB 的事件系统提供了一种灵活、解耦的模块间通信机制,通过事件和监听器的配合,实现了业务逻辑的分离和扩展。合理使用事件系统可以:

1. 提高代码的可维护性:将相关业务逻辑集中到监听器中,便于管理和维护
2. 增强系统的可扩展性:通过事件机制,可以轻松添加新的业务逻辑,而无需修改原有代码
3. 降低模块间的耦合度:模块间通过事件进行通信,而不是直接依赖,减少了模块间的耦合
4. 提高系统的响应速度:对于耗时的操作,可以通过队列进行异步处理,提高系统的响应速度

在开发过程中,应遵循事件命名规范、监听器设计原则和性能优化建议,确保事件系统的高效运行。通过合理利用事件机制,可以大大提高代码质量和开发效率,为系统的长期维护和扩展奠定良好的基础。

---

Help/Dev Docs/Phpapi/系统安装流程文档 (help/dev-docs/phpapi/系统安装流程文档.md)

CRMEB 系统安装流程文档

📋 文档概述

本文档提供CRMEB开源商城系统的完整安装流程,适用于CRMEB 5.6.4+版本。

🖥️ 服务器环境要求

基础配置要求

| 配置项 | 最低配置 | 推荐配置 |
|--------|---------|---------|
| CPU | 1核 | 2核及以上 |
| 内存 | 1GB | 2GB及以上 |
| 硬盘 | 20GB SSD | 50GB SSD及以上 |
| 带宽 | 1Mbps | 5Mbps及以上 |

操作系统要求

| 系统类型 | 支持版本 |
|---------|---------|
| Linux | CentOS 7+/Ubuntu 18+/Debian 10+ |
| Windows | Windows Server 2012+ |
| macOS | 仅用于开发环境 |

软件环境要求

| 软件 | 最低版本 | 推荐版本 | 说明 |
|------|---------|---------|------|
| PHP | 7.1 | 7.4 | 必须开启PDO扩展 |
| MySQL | 5.7 | 8.0 | 推荐InnoDB引擎 |
| Redis | 3.0 | 7.0 | 可选,提升性能 |
| Nginx | 1.18 | 1.22 | 反向代理服务器 |
| Composer | 1.8 | 2.x | PHP依赖管理 |
| Git | 2.0 | 最新版本 | 代码版本控制 |

PHP扩展要求

text
必须开启的扩展:
- fileinfo (文件信息)
- pdo (数据库操作)
- pdo_mysql (MySQL驱动)
- openssl (加密处理)
- mbstring (字符串处理)
- curl (HTTP请求)
- json (JSON处理)
- session (会话管理)

推荐开启的扩展:
- redis (Redis缓存)
- gd (图片处理)
- zip (压缩处理)
- bcmath (高精度计算)

禁用函数列表

php
// php.ini 中需要取消禁用的函数
disable_functions =
; 移除以下函数:
; proc_open
; pcntl_signal
; pcntl_signal_dispatch
; pcntl_fork
; pcntl_wait
; pcntl_alarm

🐳 方式一:Docker 一键部署(推荐)

1. 环境准备

bash

检查Docker是否安装


docker --version

Docker version 20.10.x, build xxxxx

检查Docker Compose


docker-compose --version

Docker Compose version v2.x.x

如未安装,请先安装Docker


Ubuntu系统安装:


curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER

安装Docker Compose


sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

2. 获取项目代码

bash

克隆项目


git clone https://gitee.com/ZhongBangKeJi/CRMEB.git crmeb
cd crmeb

切换到稳定版本分支(根据需要选择)


git checkout -b v5.6.4 origin/v5.6.4

3. 配置环境变量

bash

复制环境变量模板


cp .env.example .env

编辑环境变量


vim .env

ini

数据库配置


DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=crmeb
DB_USERNAME=root
DB_PASSWORD=crmeb123456

Redis配置


REDIS_HOST=redis
REDIS_PORT=6379
REDIS_PASSWORD=

应用配置


APP_DEBUG=true
APP_URL=http://localhost

Admin后台配置


ADMIN_HTTPS=false

4. 一键启动

bash

构建并启动所有服务


docker-compose up -d --build

查看服务状态


docker-compose ps

输出示例:


Name Command State Ports


----------------------------------------------------------------------


crmeb-app docker-php-entrypoint apach ... Up 0.0.0.0:80->80/tcp


crmeb-mysql docker-entrypoint.sh mysqld ... Up 3306/tcp


crmeb-redis docker-entrypoint.sh redis ... Up 6379/tcp

5. 访问安装向导

打开浏览器访问:http://your-server-ip

按照安装向导步骤完成系统安装:
1. 环境检测
2. 目录权限检查
3. 数据库配置
4. 管理员账号设置
5. 安装完成

Docker 管理命令

bash

启动服务


docker-compose start

停止服务


docker-compose stop

重启服务


docker-compose restart

查看日志


docker-compose logs -f

删除服务(保留数据)


docker-compose down

删除服务(包含数据卷)


docker-compose down -v

🖥️ 方式二:手动部署(宝塔面板)

1. 安装宝塔面板

bash

CentOS系统


yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh

Ubuntu/Debian系统


wget -O install.sh http://download.bt.cn/install/install-ubuntu_6.0.sh && sudo bash install.sh

2. 登录宝塔面板

安装完成后,记录面板登录地址、用户名和密码,登录宝塔面板。

3. 安装环境套件

在宝塔面板中:
1. 点击「软件商店」
2. 安装以下软件:
- Nginx 1.22
- MySQL 5.7/8.0
- PHP 7.4
- phpMyAdmin 4.7(可选,用于数据库管理)

4. 创建站点

1. 点击「网站」→「添加站点」
2. 填写站点信息:
- 域名:your-domain.com(或IP用于测试)
- 根目录:/www/wwwroot/crmeb
- PHP版本:选择 7.4
- 数据库:选择创建数据库
- 数据库用户名和密码
- FTP:选择创建

5. 上传项目代码

bash

方法一:通过宝塔面板上传


1. 在本地下载项目源码


2. 通过宝塔文件管理上传并解压

方法二:通过命令行


cd /www/wwwroot
wget https://gitee.com/ZhongBangKeJi/CRMEB/repository/archive/master.zip
unzip master.zip
mv CRMEB-master crmeb

6. 配置目录权限

bash

设置目录权限


chmod -R 755 /www/wwwroot/crmeb
chmod -R 755 /www/wwwroot/crmeb/runtime
chmod -R 755 /www/wwwroot/crmeb/public/uploads

设置所有者


chown -R www:www /www/wwwroot/crmeb

7. 配置伪静态

在宝塔面板中:
1. 点击对应站点的「设置」
2. 选择「伪静态」
3. 添加以下规则:

nginx

ThinkPHP 伪静态规则


location / {
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php?s=$1 last;
break;
}
}

PHP配置


location ~ \.php$ {
fastcgi_pass unix:/tmp/php-cgi-74.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}

8. 配置PHP上传限制

在宝塔「软件商店」→「PHP 7.4」→「配置修改」中:
- upload_max_filesize:100M
- post_max_size:100M
- max_execution_time:300
- max_input_time:300
- memory_limit:256M

9. 访问安装

打开浏览器访问:http://your-domain.com

按照安装向导完成系统安装。

🖥️ 方式三:手动部署(命令行)

1. 安装PHP环境

bash

CentOS 7


yum install epel-release -y
yum install -y yum-utils

添加Remi源


yum install http://rpms.remirepo.net/enterprise/remi-release-7.rpm -y

安装PHP 7.4


yum-config-manager --enable remi-php74
yum install -y php php-cli php-fpm php-mysql php-xml php-mbstring php-curl php-redis php-gd php-zip php-bcmath

启动PHP-FPM


systemctl start php-fpm
systemctl enable php-fpm

2. 安装Nginx

bash

CentOS


yum install -y nginx

启动Nginx


systemctl start nginx
systemctl enable nginx

3. 安装MySQL

bash

CentOS 7 - 安装MySQL 5.7


wget https://dev.mysql.com/get/mysql57-community-release-el7-9.noarch.rpm
rpm -ivh mysql57-community-release-el7-9.noarch.rpm
yum install -y mysql-community-server

启动MySQL


systemctl start mysqld
systemctl enable mysqld

查看初始密码


grep 'temporary password' /var/log/mysqld.log

登录并修改密码


mysql -u root -p

sql
-- MySQL 5.7 初始化
ALTER USER 'root'@'localhost' IDENTIFIED BY 'YourNewPassword!';

-- 创建数据库
CREATE DATABASE crmeb DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 创建用户并授权
CREATE USER 'crmeb'@'localhost' IDENTIFIED BY 'crmeb_password!';
GRANT ALL PRIVILEGES ON crmeb.* TO 'crmeb'@'localhost';
FLUSH PRIVILEGES;

4. 安装Redis

bash

CentOS


yum install -y redis

启动Redis


systemctl start redis
systemctl enable redis

配置密码(编辑 /etc/redis.conf)


requirepass your_redis_password

5. 安装Composer

bash

下载安装


curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer

切换中国镜像(加速下载)


composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/

6. 获取项目代码

bash

克隆项目


cd /var/www
git clone https://gitee.com/ZhongBangKeJi/CRMEB.git crmeb
cd crmeb

切换到稳定版本


git checkout -b v5.6.4 origin/v5.6.4

7. 配置环境变量

bash

复制环境变量模板


cp .env.example .env

编辑配置


vim .env

ini
[APP]
DEBUG = true
DEFAULT_TIMEZONE = Asia/Shanghai

[DATABASE]
TYPE = mysql
HOSTNAME = 127.0.0.1
DATABASE = crmeb
USERNAME = crmeb
PASSWORD = crmeb_password!
HOSTPORT = 3306
CHARSET = utf8mb4
DEBUG = true
PREFIX = eb_

[CACHE]
TYPE = redis
HOST = 127.0.0.1
PORT = 6379
PREFIX = crmeb:

[LANG]
default_lang = zh-cn

8. 安装依赖

bash

切换到项目目录


cd /var/www/crmeb

安装项目依赖


composer install --no-dev --optimize-autoloader

9. 配置Nginx站点

bash

创建站点配置


vim /etc/nginx/conf.d/crmeb.conf

nginx
server {
listen 80;
server_name your-domain.com;
root /var/www/crmeb/public;
index index.php index.html;

# 日志配置
access_log /var/log/nginx/crmeb_access.log;
error_log /var/log/nginx/crmeb_error.log;

# 静态文件缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}

# 主路由规则
location / {
try_files $uri $uri/ /index.php?s=$uri&$args;
}

# PHP处理
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;

# 超时配置
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
}

# 禁止访问敏感文件
location ~ /\.(env|git|htaccess) {
deny all;
}
}

bash

测试配置


nginx -t

重载Nginx


nginx -s reload

10. 配置目录权限

bash

设置权限


chmod -R 755 /var/www/crmeb
chmod -R 755 /var/www/crmeb/runtime
chmod -R 755 /var/www/crmeb/public/uploads

设置所有者


chown -R nginx:nginx /var/www/crmeb

11. 启动消息队列(可选)

bash

使用Supervisor管理队列


yum install -y supervisor

配置Supervisor


vim /etc/supervisord.d/crmeb.ini

ini
[program:crmeb-queue]
command=php /var/www/crmeb/think queue:listen --queue
directory=/var/www/crmeb
user=nginx
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true

bash

启动Supervisor


systemctl start supervisord
systemctl enable supervisord

启动队列任务


supervisorctl update
supervisorctl start crmeb-queue

12. 启动定时任务(可选)

bash

编辑定时任务


crontab -e

添加以下任务


* cd /var/www/crmeb && php think timer start >> /dev/null 2>&1

13. 访问安装

打开浏览器访问:http://your-domain.com

按照安装向导完成系统安装。

🔧 安装后配置

1. 配置HTTPS(推荐)

nginx
server {
listen 443 ssl http2;
server_name your-domain.com;

ssl_certificate /etc/nginx/ssl/crmeb.crt;
ssl_certificate_key /etc/nginx/ssl/crmeb.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;

# 其他配置同上...
}

HTTP重定向到HTTPS


server {
listen 80;
server_name your-domain.com;
return 301 https://$server_name$request_uri;
}

2. 配置七牛云存储(可选)

在后台管理系统中:
1. 进入「系统设置」→「附件配置」
2. 选择「七牛云存储」
3. 配置以下参数:
- AccessKey
- SecretKey
- Bucket(存储空间名称)
- Domain(访问域名)

3. 配置短信服务(可选)

在后台管理系统中:
1. 进入「系统设置」→「短信设置」
2. 选择短信服务商(阿里云、腾讯云等)
3. 配置API密钥和签名

🧪 常见问题处理

问题1:页面显示500错误

bash

检查PHP错误日志


tail -f /var/log/php-fpm/error.log

检查Nginx错误日志


tail -f /var/log/nginx/crmeb_error.log

检查项目runtime日志


tail -f /var/www/crmeb/runtime/log/xxx.log

问题2:数据库连接失败

bash

测试MySQL连接


mysql -h localhost -u crmeb -p

检查数据库配置


cat /var/www/crmeb/.env | grep DB_

问题3:验证码不显示

bash

检查PHP GD扩展


php -m | grep gd

检查目录权限


ls -la /var/www/crmeb/runtime/

问题4:上传文件失败

bash

检查upload目录权限


chmod -R 755 /var/www/crmeb/public/uploads
chown -R nginx:nginx /var/www/crmeb/public/uploads

检查PHP配置


php -i | grep file_uploads
php -i | grep upload_max_filesize

问题5:微信支付回调失败

bash

检查防火墙


systemctl status firewalld
iptables -L -n | grep 80

检查域名配置


确保回调域名已备案且可访问

🔐 安全加固建议

1. 修改默认后台路径

bash

重命名admin目录


mv public/admin public/backend

修改路由配置


vim config/route.php

2. 配置安全密钥

bash

在.env中配置


APP_KEY=your_random_string_32_chars

3. 定期更新系统

bash

定期更新CRMEB


cd /var/www/crmeb
git fetch origin
git pull origin v5.6.4

更新依赖


composer update

📞 获取技术支持

- 官方文档:https://doc.crmeb.com/
- 技术社区:https://www.crmeb.com/ask/
- Gitee Issues:https://gitee.com/ZhongBangKeJi/CRMEB/issues

---
文档版本: v1.0
更新日期: 2024-01-17
适用版本: CRMEB 5.6.4+

💡 提示:建议生产环境使用HTTPS协议,定期备份数据库和文件。

---

提示:该文档由AI生成,仅供参考。

---

Help/Dev Docs/Phpapi/系统错误码说明 (help/dev-docs/phpapi/系统错误码说明.md)

系统错误码说明

📋 错误码规范

总体规范


- 格式: 3位数字错误码 + 错误信息
- 分类: 按照模块和错误类型分类
- 统一响应: 所有错误都通过统一异常处理返回

响应格式


json
{
"status": 400,
"msg": "参数错误",
"data": null,
"time": "2024-01-17 15:30:00"
}

🔢 错误码分类

| 错误码范围 | 错误类型 | 说明 |
|-----------|---------|------|
| 200 | 成功 | 请求成功 |
| 400-499 | 客户端错误 | 参数错误、权限不足等 |
| 500-599 | 服务器错误 | 系统异常、数据库错误等 |
| 1000-1999 | 用户相关错误 | 登录、注册、用户信息等 |
| 2000-2999 | 订单相关错误 | 订单创建、支付、售后等 |
| 3000-3999 | 商品相关错误 | 商品信息、库存、分类等 |
| 4000-4999 | 营销相关错误 | 优惠券、活动、积分等 |
| 5000-5999 | 支付相关错误 | 支付处理、退款等 |
| 6000-6999 | 第三方服务错误 | 微信、短信、物流等 |

📊 通用错误码

成功状态


| 错误码 | 错误信息 | 说明 |
|--------|---------|------|
| 200 | success | 请求成功 |

系统级错误


| 错误码 | 错误信息 | 说明 |
|--------|---------|------|
| 400 | 参数错误 | 请求参数不符合要求 |
| 401 | 未授权 | 用户未登录或Token无效 |
| 403 | 权限不足 | 用户没有操作权限 |
| 404 | 资源不存在 | 请求的资源不存在 |
| 405 | 方法不允许 | 请求方法不正确 |
| 408 | 请求超时 | 请求处理超时 |
| 429 | 请求过于频繁 | 请求频率超过限制 |
| 500 | 服务器内部错误 | 服务器处理异常 |
| 501 | 功能未实现 | 请求的功能暂未实现 |
| 502 | 网关错误 | 上游服务不可用 |
| 503 | 服务不可用 | 服务暂时不可用 |
| 504 | 网关超时 | 上游服务响应超时 |

👥 用户相关错误码 (1000-1999)

认证相关


| 错误码 | 错误信息 | 说明 |
|--------|---------|------|
| 1001 | 用户名或密码错误 | 登录认证失败 |
| 1002 | 验证码错误 | 图形验证码或短信验证码错误 |
| 1003 | 验证码已过期 | 验证码超过有效时间 |
| 1004 | 账号已被禁用 | 用户账号被管理员禁用 |
| 1005 | 账号未激活 | 用户账号未完成激活流程 |
| 1006 | Token已过期 | JWT Token超过有效期 |
| 1007 | Token无效 | JWT Token格式错误或已失效 |
| 1008 | 登录状态异常 | 登录状态检查失败 |

注册相关


| 错误码 | 错误信息 | 说明 |
|--------|---------|------|
| 1101 | 手机号已注册 | 手机号已经被其他用户注册 |
| 1102 | 邮箱已注册 | 邮箱已经被其他用户注册 |
| 1103 | 用户名已存在 | 用户名已经被其他用户使用 |
| 1104 | 邀请码无效 | 注册时使用的邀请码无效 |
| 1105 | 注册信息不完整 | 注册必填信息缺失 |

用户信息相关


| 错误码 | 错误信息 | 说明 |
|--------|---------|------|
| 1201 | 用户不存在 | 指定的用户ID不存在 |
| 1202 | 用户信息更新失败 | 更新用户信息时发生错误 |
| 1203 | 原密码错误 | 修改密码时原密码验证失败 |
| 1204 | 手机号格式错误 | 手机号格式不符合要求 |
| 1205 | 邮箱格式错误 | 邮箱格式不符合要求 |
| 1206 | 实名认证失败 | 实名认证信息验证失败 |

🛒 订单相关错误码 (2000-2999)

订单创建


| 错误码 | 错误信息 | 说明 |
|--------|---------|------|
| 2001 | 商品库存不足 | 下单时商品库存不足 |
| 2002 | 商品已下架 | 下单时商品已下架 |
| 2003 | 收货地址无效 | 选择的收货地址不可用 |
| 2004 | 优惠券不可用 | 选择的优惠券不符合使用条件 |
| 2005 | 积分不足 | 积分支付时积分余额不足 |
| 2006 | 余额不足 | 余额支付时余额不足 |
| 2007 | 订单金额计算错误 | 订单金额计算异常 |

订单支付


| 错误码 | 错误信息 | 说明 |
|--------|---------|------|
| 2101 | 支付方式不支持 | 选择的支付方式不可用 |
| 2102 | 支付密码错误 | 余额支付时支付密码错误 |
| 2103 | 支付超时 | 支付操作超时 |
| 2104 | 支付金额不匹配 | 支付金额与订单金额不一致 |
| 2105 | 支付状态异常 | 支付状态不符合预期 |

订单操作


| 错误码 | 错误信息 | 说明 |
|--------|---------|------|
| 2201 | 订单状态不允许操作 | 当前订单状态不支持该操作 |
| 2202 | 订单不存在 | 指定的订单ID不存在 |
| 2203 | 订单取消失败 | 取消订单时发生错误 |
| 2204 | 订单删除失败 | 删除订单时发生错误 |
| 2205 | 订单确认收货失败 | 确认收货操作失败 |

售后相关


| 错误码 | 错误信息 | 说明 |
|--------|---------|------|
| 2301 | 申请售后时间已过 | 超过可申请售后的时间限制 |
| 2302 | 售后申请重复提交 | 同一订单重复提交售后申请 |
| 2303 | 退款金额超过限制 | 退款金额超过可退款金额 |
| 2304 | 售后状态不允许操作 | 当前售后状态不支持该操作 |
| 2305 | 退货物流信息错误 | 退货物流单号或公司错误 |

🏪 商品相关错误码 (3000-3999)

商品信息


| 错误码 | 错误信息 | 说明 |
|--------|---------|------|
| 3001 | 商品不存在 | 指定的商品ID不存在 |
| 3002 | 商品已删除 | 商品已被逻辑删除 |
| 3003 | 商品分类不存在 | 指定的分类ID不存在 |
| 3004 | 商品规格无效 | 商品规格选择错误 |
| 3005 | 商品属性错误 | 商品属性信息错误 |

库存相关


| 错误码 | 错误信息 | 说明 |
|--------|---------|------|
| 3101 | 库存扣减失败 | 扣减商品库存时发生错误 |
| 3102 | 库存回滚失败 | 回滚商品库存时发生错误 |
| 3103 | 库存锁定失败 | 锁定商品库存时发生错误 |
| 3104 | 库存不足 | 操作时商品库存不足 |

购物车相关


| 错误码 | 错误信息 | 说明 |
|--------|---------|------|
| 3201 | 购物车商品不存在 | 购物车中商品不存在 |
| 3202 | 购物车商品数量超限 | 商品数量超过购买限制 |
| 3203 | 购物车操作失败 | 购物车添加、删除操作失败 |

🎯 营销相关错误码 (4000-4999)

优惠券相关


| 错误码 | 错误信息 | 说明 |
|--------|---------|------|
| 4001 | 优惠券不存在 | 指定的优惠券不存在 |
| 4002 | 优惠券已领完 | 优惠券已被领取完毕 |
| 4003 | 优惠券领取超限 | 超过单人领取数量限制 |
| 4004 | 优惠券已过期 | 优惠券已超过有效期 |
| 4005 | 优惠券使用条件不满足 | 不符合优惠券使用条件 |
| 4006 | 优惠券状态异常 | 优惠券状态不可用 |

活动相关


| 错误码 | 错误信息 | 说明 |
|--------|---------|------|
| 4101 | 活动不存在 | 指定的活动不存在 |
| 4102 | 活动未开始 | 活动尚未开始 |
| 4103 | 活动已结束 | 活动已经结束 |
| 4104 | 活动参与人数已满 | 活动参与人数达到上限 |
| 4105 | 活动资格不足 | 不符合活动参与条件 |

积分相关


| 错误码 | 错误信息 | 说明 |
|--------|---------|------|
| 4201 | 积分不足 | 积分余额不足 |
| 4202 | 积分操作失败 | 积分增减操作失败 |
| 4203 | 积分规则不存在 | 积分规则配置错误 |

💳 支付相关错误码 (5000-5999)

支付处理


| 错误码 | 错误信息 | 说明 |
|--------|---------|------|
| 5001 | 支付渠道不可用 | 支付渠道配置错误或不可用 |
| 5002 | 支付签名错误 | 支付签名验证失败 |
| 5003 | 支付回调验证失败 | 支付回调数据验证失败 |
| 5004 | 支付订单不存在 | 支付订单记录不存在 |
| 5005 | 支付金额错误 | 支付金额异常 |

退款相关


| 错误码 | 错误信息 | 说明 |
|--------|---------|------|
| 5101 | 退款申请失败 | 退款申请操作失败 |
| 5102 | 退款金额错误 | 退款金额超过可退款金额 |
| 5103 | 退款状态异常 | 退款状态不符合预期 |
| 5104 | 退款凭证错误 | 退款凭证信息错误 |

🌐 第三方服务错误码 (6000-6999)

微信相关


| 错误码 | 错误信息 | 说明 |
|--------|---------|------|
| 6001 | 微信授权失败 | 微信授权登录失败 |
| 6002 | 微信支付失败 | 微信支付操作失败 |
| 6003 | 微信模板消息发送失败 | 模板消息发送失败 |
| 6004 | 微信公众号配置错误 | 公众号配置信息错误 |

短信相关


| 错误码 | 错误信息 | 说明 |
|--------|---------|------|
| 6101 | 短信发送失败 | 短信发送接口调用失败 |
| 6102 | 短信模板不存在 | 短信模板配置错误 |
| 6103 | 短信验证码失效 | 短信验证码验证失败 |

物流相关


| 错误码 | 错误信息 | 说明 |
|--------|---------|------|
| 6201 | 物流查询失败 | 物流信息查询失败 |
| 6202 | 物流公司不支持 | 不支持的物流公司 |
| 6203 | 物流单号错误 | 物流单号格式错误 |

文件存储相关


| 错误码 | 错误信息 | 说明 |
|--------|---------|------|
| 6301 | 文件上传失败 | 文件上传到服务器失败 |
| 6302 | 文件格式不支持 | 不支持的文件格式 |
| 6303 | 文件大小超限 | 文件大小超过限制 |
| 6304 | 云存储配置错误 | 云存储服务配置错误 |

🛠️ 错误处理最佳实践

控制器层处理


php
try {
// 业务逻辑处理
$result = $service->doSomething($params);
return $this->success($result);
} catch (ApiException $e) {
// 捕获业务异常
return $this->fail($e->getMessage(), $e->getCode());
} catch (\Exception $e) {
// 捕获系统异常
Log::error('系统异常: ' . $e->getMessage());
return $this->fail('系统繁忙,请稍后重试', 500);
}

服务层抛出异常


php
// 业务验证失败时抛出异常
if (!$user) {
throw new ApiException('用户不存在', 1201);
}

if ($stock < $quantity) {
throw new ApiException('商品库存不足', 2001);
}

自定义异常类


php
class ApiException extends \Exception
{
public function __construct($message = "", $code = 400, \Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
}

class AdminException extends ApiException
{
// 管理端专用异常
}

📝 错误码维护规范

新增错误码


1. 选择合适的错误码范围
2. 在本文档中记录错误码和说明
3. 在对应的异常处理中添加错误码映射

错误码使用原则


1. 唯一性: 每个错误码对应唯一的错误场景
2. 可读性: 错误信息清晰明确,便于理解
3. 一致性: 相同类型的错误使用相同的错误码范围
4. 扩展性: 为后续功能扩展预留错误码空间

🔍 错误排查指南

常见错误排查步骤


1. 确认错误码: 根据返回的错误码定位问题类别
2. 查看日志: 检查相关业务逻辑的日志记录
3. 验证参数: 检查请求参数是否符合要求
4. 检查状态: 确认相关数据的状态是否正常
5. 测试环境: 在测试环境复现问题并调试

日志记录规范


php
// 记录错误日志
Log::error('错误信息', [
'error_code' => $errorCode,
'params' => $requestParams,
'user_id' => $userId,
'trace' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 5)
]);

---
最后更新: 2024-01-17
维护人员: 开发团队
文档版本: v1.0

---

提示:该文档由AI生成,仅供参考。

---

Help/Dev Docs/Phpapi/系统队列任务开发文档 (help/dev-docs/phpapi/系统队列任务开发文档.md)

系统队列任务开发文档

1. 队列机制概述

CRMEB系统采用基于ThinkPHP Queue的队列任务机制,用于处理耗时操作,提高系统响应速度和并发能力。队列任务支持异步执行、延迟执行、失败重试等功能,适用于订单处理、消息推送、数据分析等场景。

1.1 核心组件

- 任务接口JobInterface - 定义任务执行的标准接口
- 任务基类BaseJobs - 提供任务执行的基础实现
- 队列工具Queue - 提供队列任务的创建和管理功能
- 队列特性QueueTrait - 提供快捷的队列调度方法
- 配置文件queue.php - 配置队列的驱动和参数

2. 队列配置

2.1 配置文件

队列配置文件位于 /crmeb/config/queue.php,主要配置项包括:

php
return [
// 默认队列驱动
'default' => 'redis',

// 队列连接方式配置
'connections' => [
'sync' => [
'type' => 'sync',
],
'database' => [
'type' => 'database',
'queue' => 'default',
'table' => 'jobs',
'connection' => null,
],
'redis' => [
'type' => 'redis',
'queue' => 'default',
'host' => env('redis.host', '127.0.0.1'),
'port' => env('redis.port', 6379),
'password' => env('redis.password', ''),
'select' => env('redis.select', 0),
'timeout' => 0,
'persistent' => false,
],
],

// 失败队列配置
'failed' => [
'type' => 'none',
'table' => 'failed_jobs',
],
];

2.2 配置说明

- default:默认队列驱动,支持sync(同步)、database(数据库)、redis(Redis)
- connections:队列连接配置,可配置多种队列驱动
- failed:失败队列配置,用于存储执行失败的任务

3. 任务接口定义

3.1 JobInterface

任务接口定义了队列任务的标准执行方法:

php
namespace crmeb\interfaces;

use think\queue\Job;

interface JobInterface
{
public function fire(Job $job, $data): void;
}

- fire:任务执行的入口方法,接收Job对象和任务数据

4. 任务基类

4.1 BaseJobs

任务基类实现了JobInterface接口,提供了任务执行的基础逻辑:

php
namespace crmeb\basic;

use crmeb\interfaces\JobInterface;
use think\queue\Job;
use think\facade\Log;

abstract class BaseJobs implements JobInterface
{
/
* @param Job $job
* @param $data
*/
public function fire(Job $job, $data): void
{
try {
$method = $data['method'] ?? 'doJob';
if (method_exists($this, $method)) {
if (!isset($data['data'])) {
$res = $this->{$method}();
} else {
$res = $this->{$method}(...$data['data']);
}
if ($res) {
$job->delete();
} else {
if ($job->attempts() > 3) {
$job->delete();
} else {
$job->release();
}
}
} else {
$job->delete();
}
} catch (\Throwable $e) {
Log::error('队列任务执行失败:' . $e->getMessage());
if ($job->attempts() > 3) {
$job->delete();
} else {
$job->release();
}
}
}
}

- fire:实现JobInterface接口的方法,处理任务执行、错误捕获和失败重试
- doJob:默认的任务执行方法,子类可以重写

5. 队列工具类

5.1 Queue

队列工具类提供了链式调用的方式来创建和管理队列任务:

php
namespace crmeb\utils;

use think\facade\Config;
use think\facade\Queue as QueueThink;
use think\facade\Log;

class Queue
{
// 任务执行方法
protected $do = 'doJob';

// 任务类名
protected $job;

// 错误次数
protected $errorCount = 3;

// 数据
protected $data;

// 队列名
protected $queueName = null;

// 延迟执行秒数
protected $secs = 0;

// ... 其他方法
}

5.2 QueueTrait

队列特性提供了快捷的队列调度方法:

php
namespace crmeb\traits;

trait QueueTrait
{
/
* 加入队列
* @param string $queueName
* @param array $data
* @return bool
*/
public static function dispatch(string $queueName = null, ...$data)
{
$class = get_called_class();
return Queue::instance()->job($class)->data($data)->queue($queueName)->push();
}

/
* 延迟加入队列
* @param int $secs
* @param string|null $queueName
* @param array $data
* @return bool
*/
public static function dispatchSecs(int $secs, string $queueName = null, ...$data)
{
$class = get_called_class();
return Queue::instance()->job($class)->data($data)->secs($secs)->queue($queueName)->push();
}
}

6. 创建队列任务

6.1 任务创建步骤

1. 创建任务类,继承BaseJobs
2. 实现doJob方法或自定义方法
3. 使用QueueTrait提供的快捷方法调度任务

6.2 任务示例

php
namespace app\jobs;

use crmeb\basic\BaseJobs;
use crmeb\traits\QueueTrait;
use think\facade\Log;

class OrderCreateAfterJob extends BaseJobs
{
use QueueTrait;

/
* 订单后置处理
* @param $orderInfo
* @param $data
* @param $activity
* @return bool
*/
public function doJob($orderInfo, $data, $activity)
{
try {
// 处理订单逻辑
// ...

return true;
} catch (\Throwable $e) {
Log::error('订单后置处理失败:' . $e->getMessage());
return false;
}
}
}

7. 调度队列任务

7.1 基本调度

使用QueueTrait提供的dispatch方法调度任务:

php
// 调度订单后置处理任务
OrderCreateAfterJob::dispatch(null, $orderInfo, $data, $activity);

7.2 延迟调度

使用QueueTrait提供的dispatchSecs方法延迟调度任务:

php
// 延迟10秒执行订单后置处理任务
OrderCreateAfterJob::dispatchSecs(10, null, $orderInfo, $data, $activity);

7.3 使用Queue工具调度

使用Queue工具类进行更灵活的调度:

php
use crmeb\utils\Queue;

// 创建并调度任务
Queue::instance()
->job(OrderCreateAfterJob::class)
->data($orderInfo, $data, $activity)
->secs(10)
->queue('order')
->push();

8. 任务执行流程

1. 任务调度:通过dispatchQueue工具将任务加入队列
2. 任务消费:队列消费者进程从队列中获取任务
3. 任务执行:调用任务类的fire方法执行任务
4. 结果处理
- 执行成功:删除任务
- 执行失败:根据重试次数决定是否重新执行
- 重试超限:将任务移至失败队列(如果配置)

9. 队列管理

9.1 启动队列消费者

使用ThinkPHP的命令行工具启动队列消费者:

bash

启动默认队列的消费者


php think queue:listen

启动指定队列的消费者


php think queue:listen --queue order

启动守护进程模式的消费者


php think queue:work --daemon

9.2 查看队列状态

bash

查看队列任务数


php think queue:status

查看失败任务


php think queue:failed

重试失败任务


php think queue:retry all

删除失败任务


php think queue:flush

10. 最佳实践

10.1 任务设计原则

- 单一职责:每个任务只负责一个功能
- 幂等性:任务重复执行不会产生副作用
- 数据完整性:确保任务执行所需的数据完整
- 错误处理:妥善处理任务执行中的异常

10.2 性能优化

- 合理设置失败重试次数,避免无限重试
- 对耗时任务进行拆分,提高并发处理能力
- 使用合适的队列驱动,Redis适用于高并发场景
- 定期清理失败队列,避免数据堆积

10.3 监控与日志

- 记录任务执行日志,便于问题排查
- 监控队列长度,及时发现处理瓶颈
- 设置告警机制,当队列任务堆积时及时通知

11. 常见问题

11.1 任务执行失败

- 检查任务数据是否完整
- 检查任务依赖的服务是否可用
- 查看日志文件,定位错误原因
- 检查队列驱动是否正常工作

11.2 队列任务堆积

- 增加队列消费者进程数量
- 优化任务执行逻辑,减少执行时间
- 检查队列驱动的性能瓶颈
- 考虑使用更高效的队列驱动

11.3 延迟任务不执行

- 检查队列消费者是否正常运行
- 检查延迟时间设置是否正确
- 检查队列驱动是否支持延迟任务
- 查看队列日志,定位问题原因

12. 内置任务列表

CRMEB系统内置了多个队列任务,用于处理各种业务场景:

| 任务类名 | 功能描述 |
|---------|---------|
| OrderCreateAfterJob | 订单创建后置处理 |
| PinkJob | 拼团任务处理 |
| MiniOrderJob | 小程序订单处理 |
| StoreOrderStatusJob | 订单状态处理 |
| UserBrokerageJob | 用户佣金处理 |
| StoreProductStockJob | 商品库存处理 |
| StoreOrderRefundJob | 订单退款处理 |
| StoreOrderSendJob | 订单发货处理 |
| StoreOrderTakeJob | 订单收货处理 |
| StoreOrderPayJob | 订单支付处理 |

13. 总结

CRMEB系统的队列任务机制提供了强大的异步处理能力,通过合理使用队列任务,可以提高系统的响应速度和并发能力,改善用户体验。开发人员可以根据业务需求创建自定义队列任务,实现各种异步处理逻辑。
---

提示:该文档由AI生成,仅供参考。

---

Help/Dev Docs/Phpapi/系统队列任务文档说明 (help/dev-docs/phpapi/系统队列任务文档说明.md)

CRMEB 系统队列任务文档说明

概述

CRMEB 系统采用基于 Redis 的消息队列机制,通过 ThinkPHP 框架的队列组件实现异步任务处理。队列系统在提高系统性能、优化用户体验、保证数据一致性方面发挥着重要作用。

队列系统架构

1. 技术栈


- 队列驱动: Redis (主) + Database (备) + Sync (同步)
- 队列服务: ThinkPHP Queue
- 定时任务: Workerman + Crontab
- 任务调度: 基于事件的异步处理

2. 核心组件

#### 2.1 队列配置 (config/queue.php)

php
return [
'default' => 'redis', // 默认驱动
'prefix' => 'crmeb_', // 队列前缀
'connections' => [
'redis' => [
'driver' => 'redis',
'queue' => 'CRMEB', // 队列名称
'host' => '127.0.0.1',
'port' => 6379,
'password' => '',
'select' => 0,
],
],
'failed' => [
'type' => 'database',
'table' => 'failed_jobs', // 失败任务表
],
];

#### 2.2 基础任务类 (BaseJobs)

php
abstract class BaseJobs implements JobInterface
{
// 任务执行入口
public function fire(Job $job, $data): void

// 任务重试机制
protected function runJob(string $action, Job $job, array $infoData, int $errorCount = 3)
}

#### 2.3 队列特性 (QueueTrait)

php
trait QueueTrait
{
// 立即推送任务
public static function dispatch($action, array $data = [], string $queueName = null)

// 延迟推送任务
public static function dispatchSecs(int $secs, $action, array $data = [], string $queueName = null)
}

队列任务分类

1. 订单相关任务

#### 1.1 OrderJob - 订单处理任务
功能: 订单支付成功后的后续处理
触发时机: 订单支付成功时
主要处理:
- 计算商品节省金额
- 更新用户支付订单数量
- 检测并设置推广人身份
- 添加用户购买标签
- 发送客服通知消息
- 检测会员等级升级
- 向后台发送新订单消息

php
// 使用示例
OrderJob::dispatch('doJob', [$orderInfo]);

#### 1.2 OrderCreateAfterJob - 订单创建后处理
功能: 订单创建后的数据处理
触发时机: 订单创建完成后
主要处理:
- 计算订单实际价格
- 处理推广关系
- 计算佣金分配
- 更新订单附加信息

#### 1.3 UnpaidOrderCancelJob - 未支付订单取消
功能: 自动取消超时未支付订单
触发时机: 定时任务或延迟队列
处理逻辑:
- 检查订单支付状态
- 回退积分和优惠券
- 恢复商品库存
- 标记订单为已取消

php
// 延迟30分钟后执行
UnpaidOrderCancelJob::dispatchSecs(1800, 'doJob', [$orderId]);

2. 商品相关任务

#### 2.1 ProductLogJob - 商品日志记录
功能: 记录商品相关行为日志
触发时机: 商品浏览、加购、下单等
日志类型:
- visit: 商品访问
- cart: 加入购物车
- order: 下单
- pay: 支付
- collect: 收藏
- refund: 退款

php
ProductLogJob::dispatch('doJob', ['visit', $productData]);

#### 2.2 ProductStockJob - 商品库存处理
功能: 商品库存计算和更新
触发时机: 商品操作后
处理功能:
- 分布式库存计算
- 规格库存汇总
- 库存同步更新

#### 2.3 ProductCopyJob - 商品复制任务
功能: 异步复制商品信息
触发时机: 商品复制操作
处理内容:
- 商品基本信息复制
- 规格属性复制
- 图片资源复制

3. 通知相关任务

#### 3.1 SmsJob - 短信发送任务
功能: 异步发送短信通知
触发时机: 各种业务事件
支持场景:
- 订单通知
- 支付提醒
- 注册验证
- 营销推广

php
SmsJob::dispatch('doJob', [$phone, $data, $template]);

#### 3.2 TemplateJob - 模板消息任务
功能: 发送微信模板消息
触发时机: 业务状态变更
消息类型:
- 订单状态通知
- 支付成功通知
- 物流更新通知

#### 3.3 SyncMessageJob - 消息同步任务
功能: 多端消息同步
触发时机: 消息发送时
同步范围:
- 客服系统
- 管理后台
- 用户端

4. 营销相关任务

#### 4.1 PinkJob - 拼团任务
功能: 拼团活动处理
触发时机: 拼团相关操作
处理内容:
- 拼团状态更新
- 拼团失败处理
- 拼团成功通知

#### 4.2 LiveJob - 直播任务
功能: 直播相关处理
触发时机: 直播事件
处理内容:
- 直播状态同步
- 商品上下架
- 观众数据统计

#### 4.3 AutoCommentJob - 自动评论任务
功能: 自动生成商品评论
触发时机: 订单完成后
处理逻辑:
- 根据商品信息生成评论
- 模拟用户评价
- 提升商品活跃度

5. 系统维护任务

#### 5.1 TaskJob - 定时任务
功能: 系统定时维护
执行频率: 每日定时
维护内容:
- 清理过期文件
- 数据统计汇总
- 系统健康检查

php
// 清理昨日海报
TaskJob::dispatch('emptyYesterdayAttachment');

#### 5.2 UpgradeJob - 系统升级任务
功能: 系统升级处理
触发时机: 手动触发或定时
处理内容:
- 数据库结构更新
- 配置文件升级
- 兼容性检查

#### 5.3 CheckQueueJob - 队列检查任务
功能: 监控队列健康状态
执行频率: 定时检查
检查项目:
- 队列堆积情况
- 失败任务统计
- 系统资源使用

6. 用户相关任务

#### 6.1 UserJob - 用户处理任务
功能: 用户相关异步处理
触发时机: 用户操作
处理内容:
- 用户等级计算
- 积分统计分析
- 行为数据更新

#### 6.2 AgentJob - 代理任务
功能: 代理商相关处理
触发时机: 代理业务
处理内容:
- 佣金计算
- 等级升级
- 数据统计

7. 物流相关任务

#### 7.1 OrderExpressJob - 订单物流任务
功能: 物流信息处理
触发时机: 物流状态变更
处理内容:
- 物流信息同步
- 状态更新通知
- 异常情况处理

#### 7.2 TakeOrderJob - 订单接收任务
功能: 订单接收处理
触发时机: 订单创建
处理内容:
- 订单数据验证
- 库存检查
- 自动分配

8. 财务相关任务

#### 8.1 OrderInvoiceJob - 订单发票任务
功能: 发票处理
触发时机: 发票申请
处理内容:
- 发票生成
- 状态同步
- 通知发送

#### 8.2 OutPushJob - 外部推送任务
功能: 数据外部推送
触发时机: 数据变更
推送内容:
- 订单数据
- 用户数据
- 商品数据

定时任务系统

1. Timer 命令


基于 Workerman 实现的定时任务调度器

bash

启动定时任务


php think timer start

守护进程方式启动


php think timer start -d

停止定时任务


php think timer stop

重启定时任务


php think timer reload

2. 系统定时任务


数据库表: system_crontab

字段说明:
- name: 任务名称
- task_type: 任务类型
- mark: 任务标识
- content: 任务内容
- max_execution_time: 最大执行时间
- execution_cycle: 执行周期
- is_open: 是否开启
- next_execution_time: 下次执行时间
- last_execution_time: 上次执行时间

3. 内置定时任务

#### 3.1 订单相关
- 未支付订单取消: 每分钟检查一次
- 预售商品下架: 每小时检查一次
- 拼团失败处理: 每5分钟检查一次

#### 3.2 数据统计
- 日统计汇总: 每日凌晨执行
- 用户行为分析: 每小时执行
- 销售数据统计: 每日执行

#### 3.3 系统维护
- 日志清理: 每周执行
- 临时文件清理: 每日执行
- 缓存刷新: 定时执行

队列监控与管理

1. 队列状态监控


php
// 检查队列状态
Queue::instance()->getQueueInfo();

// 获取队列长度
Queue::instance()->getQueueLength();

// 获取失败任务
Queue::instance()->getFailedJobs();

2. 任务管理


php
// 重新执行失败任务
Queue::instance()->retryFailed($jobId);

// 清空队列
Queue::instance()->clearQueue($queueName);

// 暂停队列
Queue::instance()->pauseQueue($queueName);

3. 日志记录


所有队列任务都有详细的日志记录:
- 成功执行日志
- 失败重试日志
- 异常堆栈信息
- 性能执行统计

队列配置最佳实践

1. 队列分组


根据业务重要性分组:
php
// 高优先级队列
'order_pay' => 'CRMEB_ORDER_PAY'
'sms' => 'CRMEB_SMS'
'email' => 'CRMEB_EMAIL'

// 普通优先级队列
'statistics' => 'CRMEB_STATISTICS'
'log' => 'CRMEB_LOG'

// 低优先级队列
'report' => 'CRMEB_REPORT'
'cleanup' => 'CRMEB_CLEANUP'

2. 重试策略


php
// 不同任务的重试次数
'order_pay' => 3 // 支付任务重试3次
'sms' => 5 // 短信任务重试5次
'email' => 3 // 邮件任务重试3次
'statistics' => 1 // 统计任务重试1次

3. 延迟设置


php
// 常见延迟时间
UnpaidOrderCancelJob::dispatchSecs(1800, 'doJob', [$orderId]); // 30分钟
OrderRemindJob::dispatchSecs(86400, 'doJob', [$orderId]); // 24小时
CleanupJob::dispatchSecs(604800, 'doJob', [$data]); // 7天

性能优化建议

1. 队列优化


- 使用 Redis 集群提高可用性
- 合理设置队列数量避免热点
- 定期清理过期队列数据
- 监控队列长度及时扩容

2. 任务优化


- 避免单个任务过于复杂
- 合理拆分大任务为小任务
- 使用事务保证数据一致性
- 添加超时控制避免阻塞

3. 资源优化


- 控制并发任务数量
- 合理设置内存限制
- 优化数据库查询性能
- 使用连接池减少开销

故障处理

1. 常见问题

#### 1.1 队列堆积
现象: 队列长度持续增长
原因: 消费速度小于生产速度
解决:
- 增加消费者进程数
- 优化任务执行效率
- 检查系统资源使用

#### 1.2 任务重复执行
现象: 同一任务被执行多次
原因: 任务重复入队或幂等性问题
解决:
- 添加任务唯一标识
- 实现幂等性检查
- 优化任务重试逻辑

#### 1.3 内存泄漏
现象: 进程内存持续增长
原因: 任务中存在资源未释放
解决:
- 检查对象引用
- 及时释放大对象
- 定期重启消费者进程

2. 应急处理

#### 2.1 队列暂停

bash

暂停所有队列


php think queue:pause

暂停指定队列


php think queue:pause --queue=order_pay

#### 2.2 强制清空

bash

清空指定队列


php think queue:clear --queue=statistics

清空所有队列


php think queue:clear --all

#### 2.3 重建队列

bash

重建队列表


php think queue:table

重新发布失败任务


php think queue:retry all

开发指南

1. 创建新任务

#### 1.1 创建任务类

php
<?php
namespace app\jobs;

use crmeb\basic\BaseJobs;
use crmeb\traits\QueueTrait;

class CustomJob extends BaseJobs
{
use QueueTrait;

/
* 执行任务
* @param array $data
* @return bool
*/
public function doJob(array $data): bool
{
try {
// 业务逻辑处理
$this->processData($data);
return true;
} catch (\Exception $e) {
// 记录错误日志
Log::error('任务执行失败: ' . $e->getMessage());
return false;
}
}

private function processData(array $data): void
{
// 具体业务逻辑
}
}

#### 1.2 调度任务

php
// 立即执行
CustomJob::dispatch('doJob', [$data]);

// 延迟执行
CustomJob::dispatchSecs(300, 'doJob', [$data]);

// 指定队列
CustomJob::dispatch('doJob', [$data], 'custom_queue');

2. 测试队列任务

#### 2.1 单元测试

php
public function testCustomJob()
{
$job = new CustomJob();
$result = $job->doJob($testData);
$this->assertTrue($result);
}

#### 2.2 集成测试

php
public function testQueueDispatch()
{
// 模拟队列调度
Queue::fake();

CustomJob::dispatch('doJob', [$testData]);

Queue::assertPushed(CustomJob::class, function ($job) use ($testData) {
return $job->data[0] === $testData;
});
}

3. 监控和调试

#### 3.1 添加日志

php
public function doJob(array $data): bool
{
Log::info('任务开始执行', ['data' => $data]);

try {
// 业务逻辑
Log::info('任务执行成功');
return true;
} catch (\Exception $e) {
Log::error('任务执行失败', [
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
return false;
}
}

#### 3.2 性能监控

php
public function doJob(array $data): bool
{
$startTime = microtime(true);

try {
// 业务逻辑
$endTime = microtime(true);
$executeTime = ($endTime - $startTime) * 1000; // 毫秒

Log::info('任务执行完成', [
'execute_time' => $executeTime . 'ms',
'memory_usage' => memory_get_usage(true)
]);

return true;
} catch (\Exception $e) {
Log::error('任务执行失败', ['error' => $e->getMessage()]);
return false;
}
}

总结

CRMEB 的队列任务系统是系统高性能运行的关键组件,通过合理的任务分类、优先级管理、错误处理和监控机制,确保了系统的稳定性和可扩展性。在实际使用中,需要根据业务特点合理设计任务粒度,优化执行效率,并建立完善的监控告警机制。

队列系统的正确使用可以显著提升用户体验,降低系统负载,提高数据处理的一致性。建议开发团队充分理解队列机制,在合适场景下合理应用,并持续优化和改进队列性能。

---

提示:该文档由AI生成,仅供参考。

---

Help/Dev Docs/Phpapi/统计分析开发文档 (help/dev-docs/phpapi/统计分析开发文档.md)

统计分析开发文档

1. 文档概述

1.1 文档目的


本文档旨在详细说明CRMEB系统中统计分析模块的设计架构、核心功能、代码实现及开发规范,为系统开发人员提供完整的开发参考。

1.2 适用范围


本文档适用于CRMEB系统开发人员、维护人员及二次开发人员,用于指导统计分析模块的开发、扩展和维护工作。

1.3 术语定义


| 术语 | 解释 |
|------|------|
| PV | 页面访问量(Page View),即页面浏览次数 |
| UV | 独立访客数(Unique Visitor),即不同IP地址访问网站的用户数 |
| 转化率 | 转化次数与访问次数的比率,如注册转化率、下单转化率 |
| 复购率 | 重复购买用户数与总购买用户数的比率 |
| 环比 | 本期统计数据与上期统计数据的比较 |
| 同比 | 本期统计数据与上年同期统计数据的比较 |
| 资金流水 | 系统中所有资金的流入流出记录 |

2. 核心功能模块

2.1 流量统计


- PV/UV统计:统计网站的页面访问量和独立访客数
- 访问趋势分析:支持按小时、日、周、月维度查看访问趋势
- 访问来源分析:分析用户的访问来源渠道
- 页面热度分析:统计各个页面的访问热度
- 访问设备分析:分析用户使用的设备类型(PC、移动端、平板等)

2.2 用户统计


- 用户基础信息统计:新增用户数、成交用户数、充值用户数、付费用户数
- 用户增长趋势:按时间维度查看用户增长情况
- 用户地域分布:统计用户的地域分布(按省份、城市)
- 用户性别分布:统计用户的性别分布
- 用户年龄分布:统计用户的年龄分布
- 微信用户分析:微信用户关注/取关统计
- 用户行为分析:用户浏览、搜索、购买等行为分析

2.3 销售统计


- 订单金额统计:统计订单总金额、实付金额、退款金额等
- 订单数量统计:统计订单总数、成交订单数、退款订单数等
- 订单趋势分析:按时间维度查看订单趋势
- 订单来源分析:分析订单的来源渠道
- 订单类型分布:统计不同类型订单的分布情况
- 实时交易数据:实时展示交易数据
- 支付方式分析:分析不同支付方式的使用情况

2.4 资金统计


- 资金流水统计:统计系统中的资金流入流出记录
- 账单记录:生成日/周/月账单
- 余额统计:统计用户余额情况
- 余额趋势分析:按时间维度查看余额趋势
- 余额来源分析:分析余额的来源渠道
- 余额类型分析:分析不同类型余额的分布

2.5 商品统计


- 商品销售基础数据:商品销售额、销量、访客数、转化率等
- 商品销售趋势:按时间维度查看商品销售趋势
- 商品排行:商品销售额排行、销量排行、访客数排行等
- 商品分类统计:按商品分类统计销售情况
- 商品属性分析:分析商品不同属性的销售情况

3. 代码结构与设计

3.1 架构设计


系统采用分层架构设计,严格遵循MVC设计模式:
text
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│ Controllers │ │ Services │ │ Daos │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
└───────────────────────┼───────────────────────┘

┌─────────────────┐
│ Models │
└─────────────────┘

┌─────────────────┐
│ 数据库 │
└─────────────────┘

3.2 核心文件结构

#### 3.2.1 控制器层(Controller)
统计分析控制器/crmeb/app/adminapi/controller/v1/statistic/
- FlowStatistic.php - 资金流水统计控制器
- UserStatistic.php - 用户统计控制器
- OrderStatistic.php - 订单统计控制器
- TradeStatistic.php - 交易统计控制器
- ProductStatistic.php - 商品统计控制器
- BalanceStatistic.php - 余额统计控制器

#### 3.2.2 服务层(Services)
统计分析服务/crmeb/app/services/statistic/
- CapitalFlowServices.php - 资金流水统计服务
- UserStatisticServices.php - 用户统计服务
- OrderStatisticServices.php - 订单统计服务
- TradeStatisticServices.php - 交易统计服务
- ProductStatisticServices.php - 商品统计服务
- BalanceStatisticServices.php - 余额统计服务

#### 3.2.3 数据访问层(Dao)
统计分析Dao:与各个业务模块的Dao共用,如用户Dao、订单Dao、商品Dao等

#### 3.2.4 模型层(Model)
统计分析模型:与各个业务模块的模型共用,如用户模型、订单模型、商品模型等

4. 数据库设计

4.1 资金流水表(capital_flow)

| 字段名 | 数据类型 | 描述 |
|--------|----------|------|
| id | int(10) unsigned | 流水ID |
| uid | int(10) | 用户ID |
| link_id | int(10) | 关联ID(如订单ID、充值ID等) |
| type | varchar(20) | 交易类型(pay-支付订单,refund-退款,recharge-充值,extract-提现等) |
| money | decimal(10,2) | 交易金额 |
| pm | tinyint(1) | 收支方向(1-收入,0-支出) |
| balance | decimal(10,2) | 交易后余额 |
| mark | varchar(255) | 备注 |
| add_time | int(10) | 添加时间 |

4.2 访问记录表(visit_log)

| 字段名 | 数据类型 | 描述 |
|--------|----------|------|
| id | int(10) unsigned | 记录ID |
| uid | int(10) | 用户ID(0-游客) |
| ip | varchar(15) | 访问IP |
| url | varchar(255) | 访问URL |
| referer | varchar(255) | 来源URL |
| user_agent | text | 用户代理信息 |
| device | varchar(20) | 设备类型(pc, mobile, tablet) |
| browser | varchar(20) | 浏览器 |
| os | varchar(20) | 操作系统 |
| add_time | int(10) | 访问时间 |

4.3 销售统计表(sale_statistics)

| 字段名 | 数据类型 | 描述 |
|--------|----------|------|
| id | int(10) unsigned | 统计ID |
| date | date | 统计日期 |
| order_count | int(10) | 订单数量 |
| order_amount | decimal(10,2) | 订单总金额 |
| pay_amount | decimal(10,2) | 实付金额 |
| refund_count | int(10) | 退款订单数量 |
| refund_amount | decimal(10,2) | 退款金额 |
| user_count | int(10) | 成交用户数 |
| add_time | int(10) | 添加时间 |

5. API接口说明

5.1 流量统计接口

#### 5.1.1 获取PV/UV统计
- 请求URL/adminapi/v1/statistic/flow/pvuv
- 请求方法:GET
- 权限要求:statistic/flow/pvuv
- 请求参数
- type:时间维度(hour, day, week, month)
- start_time:开始时间
- end_time:结束时间
- 返回结果:PV/UV统计数据

#### 5.1.2 获取访问来源分析
- 请求URL/adminapi/v1/statistic/flow/source
- 请求方法:GET
- 权限要求:statistic/flow/source
- 请求参数
- start_time:开始时间
- end_time:结束时间
- 返回结果:访问来源分析数据

5.2 用户统计接口

#### 5.2.1 获取用户基础统计
- 请求URL/adminapi/v1/statistic/user/basic
- 请求方法:GET
- 权限要求:statistic/user/basic
- 请求参数
- start_time:开始时间
- end_time:结束时间
- 返回结果:用户基础统计数据

#### 5.2.2 获取用户增长趋势
- 请求URL/adminapi/v1/statistic/user/trend
- 请求方法:GET
- 权限要求:statistic/user/trend
- 请求参数
- type:时间维度(hour, day, week, month)
- start_time:开始时间
- end_time:结束时间
- 返回结果:用户增长趋势数据

#### 5.2.3 获取用户地域分布
- 请求URL/adminapi/v1/statistic/user/region
- 请求方法:GET
- 权限要求:statistic/user/region
- 请求参数
- start_time:开始时间
- end_time:结束时间
- 返回结果:用户地域分布数据

5.3 销售统计接口

#### 5.3.1 获取订单统计
- 请求URL/adminapi/v1/statistic/order/basic
- 请求方法:GET
- 权限要求:statistic/order/basic
- 请求参数
- start_time:开始时间
- end_time:结束时间
- 返回结果:订单统计数据

#### 5.3.2 获取订单趋势
- 请求URL/adminapi/v1/statistic/order/trend
- 请求方法:GET
- 权限要求:statistic/order/trend
- 请求参数
- type:时间维度(hour, day, week, month)
- start_time:开始时间
- end_time:结束时间
- 返回结果:订单趋势数据

5.4 资金统计接口

#### 5.4.1 获取资金流水列表
- 请求URL/adminapi/v1/statistic/flow/list
- 请求方法:GET
- 权限要求:statistic/flow/list
- 请求参数
- page:页码
- limit:每页数量
- type:交易类型
- start_time:开始时间
- end_time:结束时间
- 返回结果:资金流水列表数据

#### 5.4.2 获取账单记录
- 请求URL/adminapi/v1/statistic/flow/bill
- 请求方法:GET
- 权限要求:statistic/flow/bill
- 请求参数
- type:账单类型(day, week, month)
- date:统计日期
- 返回结果:账单记录数据

5.5 商品统计接口

#### 5.5.1 获取商品销售基础数据
- 请求URL/adminapi/v1/statistic/product/basic
- 请求方法:GET
- 权限要求:statistic/product/basic
- 请求参数
- product_id:商品ID
- start_time:开始时间
- end_time:结束时间
- 返回结果:商品销售基础数据

#### 5.5.2 获取商品销售排行
- 请求URL/adminapi/v1/statistic/product/rank
- 请求方法:GET
- 权限要求:statistic/product/rank
- 请求参数
- type:排行类型(sales, amount, visitor)
- start_time:开始时间
- end_time:结束时间
- limit:返回数量
- 返回结果:商品销售排行数据

5. 开发规范与流程

5.1 代码规范


1. 命名规范
- 类名采用大驼峰命名法,如 UserStatisticServices
- 方法名采用小驼峰命名法,如 getUserBasicInfo
- 变量名采用小驼峰命名法,如 visitorCount
- 常量名采用全大写,下划线分隔,如 STATISTIC_TYPE_HOUR

2. 代码结构
- 严格遵循分层架构,禁止跨层调用
- 每个方法职责单一,代码行数控制在50行以内
- 适当添加注释,说明方法功能、参数含义和返回值
- 所有统计数据必须包含完整的时间范围

3. 性能优化
- 统计查询必须使用索引,避免全表扫描
- 复杂统计查询必须使用缓存,减少数据库压力
- 统计数据必须定期汇总,避免实时计算大量数据
- 使用合适的统计周期,如小时、日、周、月

5.2 开发流程


1. 需求分析:明确统计分析的功能需求和业务逻辑
2. 设计阶段:设计数据结构、API接口和业务流程
3. 编码实现
- 实现统计服务层逻辑
- 实现统计控制器接口
- 实现数据汇总和缓存机制
4. 单元测试:编写单元测试,确保统计结果正确性
5. 性能测试:对统计查询进行性能测试,优化查询效率
6. 代码审查:提交代码审查,确保代码质量
7. 部署上线:部署到生产环境

6. 常见问题与解决方案

6.1 统计数据不准确


问题:统计数据与实际数据不符
解决方案
1. 检查统计逻辑,确保统计范围正确
2. 检查数据来源,确保数据完整
3. 检查时间范围,确保时间格式正确
4. 检查统计周期,确保周期划分正确
5. 实现数据校验机制,定期核对统计数据

6.2 统计查询性能问题


问题:统计查询耗时过长,影响系统性能
解决方案
1. 使用索引优化查询
2. 实现统计数据缓存
3. 定期预计算统计数据
4. 优化数据库结构,如分表、分区
5. 使用数据仓库或OLAP数据库处理复杂统计

6.3 统计维度不足


问题:无法满足多维度统计需求
解决方案
1. 设计灵活的统计架构,支持自定义统计维度
2. 实现统计维度扩展机制
3. 使用数据立方体技术,支持多维数据分析

6.4 实时统计问题


问题:实时统计数据延迟或不准确
解决方案
1. 使用流处理技术,如Kafka、Flink等
2. 实现准实时统计,平衡实时性和准确性
3. 优化实时数据处理流程,减少延迟

7. 扩展与定制

7.1 添加新的统计维度


1. 设计统计逻辑:确定新统计维度的计算逻辑
2. 修改服务层:在相应的统计服务中添加新的统计方法
3. 添加API接口:在相应的控制器中添加新的API接口
4. 前端修改:在前端页面中添加新的统计图表和展示

7.2 实现自定义统计报表


1. 设计报表结构:确定报表的字段、维度和指标
2. 实现报表生成逻辑:在统计服务中添加报表生成方法
3. 添加报表管理功能:实现报表的创建、编辑、删除功能
4. 前端修改:在前端页面中添加报表展示和导出功能

7.3 集成第三方统计工具


1. 设计集成方案:确定与第三方统计工具的集成方式
2. 实现数据同步:实现与第三方统计工具的数据同步
3. 添加API接口:添加获取第三方统计数据的API接口
4. 前端修改:在前端页面中集成第三方统计图表

8. 文档更新记录

| 版本 | 更新日期 | 更新内容 | 更新人 |
|------|----------|----------|--------|
| 1.0 | 2026-01-19 | 初始版本,包含流量统计、用户统计、销售统计、资金统计、商品统计等核心功能 | AI Assistant |

9. 附录

9.1 核心类关系图

text
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│ Controllers │ │ Services │ │ Daos │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
└───────────────────────┼───────────────────────┘

┌─────────────────┐
│ Models │
└─────────────────┘

┌─────────────────┐
│ 数据库 │
└─────────────────┘

9.2 统计流程示意图

text
统计流程:
1. 系统收集原始数据(访问日志、订单数据、用户数据等)
2. 定期汇总原始数据,生成统计数据
3. 将统计数据存储到统计表中
4. 提供API接口,供前端查询统计数据
5. 前端展示统计图表和数据
6. 支持统计数据导出

9.3 支持的统计维度

| 维度名称 | 描述 |
|----------|------|
| 时间维度 | 小时、日、周、月、年 |
| 地域维度 | 省份、城市 |
| 设备维度 | PC、移动端、平板 |
| 渠道维度 | 微信、支付宝、APP、小程序等 |
| 商品维度 | 商品分类、商品属性、品牌等 |
| 用户维度 | 性别、年龄、会员等级等 |
| 订单维度 | 订单类型、支付方式、配送方式等 |

9.4 统计指标列表

| 指标名称 | 描述 |
|----------|------|
| PV | 页面访问量 |
| UV | 独立访客数 |
| 新增用户数 | 新增注册用户数 |
| 成交用户数 | 完成交易的用户数 |
| 复购率 | 重复购买用户数与总购买用户数的比率 |
| 转化率 | 转化次数与访问次数的比率 |
| 订单总金额 | 订单的总金额 |
| 实付金额 | 实际支付的金额 |
| 订单数量 | 订单总数 |
| 客单价 | 平均每笔订单的金额 |
| 商品销售额 | 商品的销售总额 |
| 商品销量 | 商品的销售数量 |
| 资金流入 | 系统中的资金流入总额 |
| 资金流出 | 系统中的资金流出总额 |

---

提示:该文档由AI生成,仅供参考。

---

Help/Dev Docs/Phpapi/营销活动开发文档 (help/dev-docs/phpapi/营销活动开发文档.md)

营销活动开发文档

1. 文档概述

1.1 文档目的


本文档旨在详细说明CRMEB系统中营销活动模块的设计架构、核心功能、代码实现及开发规范,为系统开发人员提供完整的开发参考。

1.2 适用范围


本文档适用于CRMEB系统开发人员、维护人员及二次开发人员,用于指导营销活动模块的开发、扩展和维护工作。

1.3 术语定义


| 术语 | 解释 |
|------|------|
| 限时秒杀 | 在特定时间段内,商品以低于原价的价格销售 |
| 商品砍价 | 用户邀请好友帮忙砍价,以更低价格购买商品 |
| 多人拼团 | 多个用户联合购买商品,享受更低价格 |
| 优惠券 | 可用于抵扣商品价格的电子券 |
| SPU | 标准化产品单元,如"iPhone 13" |
| SKU | 库存量单位,如"iPhone 13 128G 白色" |
| 开团 | 创建拼团活动 |
| 参团 | 加入他人创建的拼团活动 |
| 助力 | 帮助好友砍价 |

2. 核心功能模块

2.1 限时秒杀


- 秒杀配置:设置秒杀时间段、参与商品、秒杀价格
- 秒杀商品管理:添加/编辑/删除参与秒杀的商品
- 秒杀时间段管理:设置秒杀活动的时间段
- 秒杀记录:查看用户秒杀记录
- 秒杀状态管理:开启/关闭秒杀活动

2.2 商品砍价


- 砍价商品配置:设置砍价商品、初始价格、最低价格、砍价次数
- 砍价活动管理:添加/编辑/删除砍价活动
- 砍价记录管理:查看用户砍价记录
- 砍价助力记录:查看用户砍价助力记录
- 砍价状态管理:开启/关闭砍价活动

2.3 多人拼团


- 拼团商品配置:设置拼团商品、拼团价格、成团人数、拼团有效期
- 拼团活动管理:添加/编辑/删除拼团活动
- 拼团记录管理:查看拼团记录、成团状态
- 拼团规则设置:设置拼团规则,如是否允许重复参团
- 拼团状态管理:开启/关闭拼团活动

2.4 优惠券管理


- 优惠券模板配置:设置优惠券类型(满减、折扣)、面值、使用条件、有效期
- 优惠券发放管理:手动发放、自动发放、批量发放优惠券
- 用户优惠券管理:查看用户领取的优惠券、使用情况
- 优惠券使用统计:统计优惠券领取量、使用率、优惠金额
- 优惠券状态管理:开启/关闭优惠券

2.5 积分商城


- 积分商品配置:设置积分商品、积分价格、库存
- 积分商品管理:添加/编辑/删除积分商品
- 积分兑换记录:查看用户积分兑换记录
- 积分规则设置:设置积分获取、使用规则

2.6 预售活动


- 预售商品配置:设置预售商品、预售价格、定金、尾款支付时间
- 预售活动管理:添加/编辑/删除预售活动
- 预售订单管理:查看预售订单、定金支付情况、尾款支付情况
- 预售状态管理:开启/关闭预售活动

3. 代码结构与设计

3.1 架构设计


系统采用分层架构设计,严格遵循MVC设计模式:
text
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│ ActivityModel │ │ ActivityDao │ │ ActivityServices│
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
└───────────────────────┼───────────────────────┘

┌─────────────────┐
│ ActivityController│
└─────────────────┘

┌─────────────────┐
│ Routes │
└─────────────────┘

3.2 核心文件结构

#### 3.2.1 模型层(Model)
所有营销活动模型均位于 crmeb/app/model/activity/ 目录下,按活动类型分类:

- 秒杀活动
- seckill/StoreSeckill.php - 秒杀商品模型

- 砍价活动
- bargain/StoreBargain.php - 砍价商品模型
- bargain/StoreBargainUser.php - 砍价用户参与记录模型
- bargain/StoreBargainUserHelp.php - 砍价助力记录模型

- 拼团活动
- combination/StoreCombination.php - 拼团商品模型
- combination/StorePink.php - 拼团记录模型

- 优惠券活动
- coupon/StoreCoupon.php - 优惠券模板模型
- coupon/StoreCouponIssue.php - 优惠券发放记录模型
- coupon/StoreCouponProduct.php - 优惠券适用商品模型
- coupon/StoreCouponUser.php - 用户优惠券模型

#### 3.2.2 数据访问层(DAO)
所有营销活动DAO均位于 crmeb/app/dao/activity/ 目录下,按活动类型分类:

- 秒杀活动
- seckill/StoreSeckillDao.php - 秒杀商品DAO

- 砍价活动
- bargain/StoreBargainDao.php - 砍价商品DAO
- bargain/StoreBargainUserDao.php - 砍价用户参与记录DAO
- bargain/StoreBargainUserHelpDao.php - 砍价助力记录DAO

- 拼团活动
- combination/StoreCombinationDao.php - 拼团商品DAO
- combination/StorePinkDao.php - 拼团记录DAO

- 优惠券活动
- coupon/StoreCouponDao.php - 优惠券模板DAO
- coupon/StoreCouponIssueDao.php - 优惠券发放记录DAO
- coupon/StoreCouponProductDao.php - 优惠券适用商品DAO
- coupon/StoreCouponUserDao.php - 用户优惠券DAO

#### 3.2.3 业务服务层(Services)
所有营销活动Services均位于 crmeb/app/services/activity/ 目录下,按活动类型分类:

- 秒杀活动
- seckill/StoreSeckillServices.php - 秒杀商品Services

- 砍价活动
- bargain/StoreBargainServices.php - 砍价商品Services
- bargain/StoreBargainUserServices.php - 砍价用户参与记录Services
- bargain/StoreBargainUserHelpServices.php - 砍价助力记录Services

- 拼团活动
- combination/StoreCombinationServices.php - 拼团商品Services
- combination/StorePinkServices.php - 拼团记录Services

- 优惠券活动
- coupon/StoreCouponServices.php - 优惠券模板Services
- coupon/StoreCouponIssueServices.php - 优惠券发放记录Services
- coupon/StoreCouponUserServices.php - 用户优惠券Services

#### 3.2.4 控制器层(Controller)
管理员API控制器位于 crmeb/app/adminapi/controller/v1/marketing/ 目录下:

- StoreSeckill.php - 秒杀活动控制器
- StoreBargain.php - 砍价活动控制器
- StoreCombination.php - 拼团活动控制器
- StoreCoupon.php - 优惠券控制器

移动端API控制器位于 crmeb/app/api/controller/v1/activity/ 目录下,提供移动端调用的活动接口。

#### 3.2.5 路由配置
营销活动路由配置位于 crmeb/app/adminapi/route/marketing.php 文件中,包含了各种活动的增删改查、状态管理、统计等路由。

移动端路由配置位于 crmeb/app/api/route/ 目录下,根据API版本分类。

4. 数据库设计

4.1 秒杀活动相关表

#### 秒杀商品表(store_seckill)
| 字段名 | 数据类型 | 描述 |
|--------|----------|------|
| id | int(10) unsigned | 秒杀商品ID |
| product_id | int(10) | 关联商品ID |
| title | varchar(100) | 秒杀活动标题 |
| image | varchar(255) | 秒杀商品图片 |
| unit_name | varchar(10) | 单位名称 |
| sec_price | decimal(10,2) | 秒杀价格 |
| price | decimal(10,2) | 原价 |
| cost | decimal(10,2) | 成本价 |
| description | varchar(255) | 秒杀活动描述 |
| start_time | int(10) | 开始时间 |
| end_time | int(10) | 结束时间 |
| status | tinyint(1) | 状态(0-关闭,1-开启) |
| sales | int(10) | 销量 |
| stock | int(10) | 库存 |
| give_integral | int(10) | 赠送积分 |
| sort | int(10) | 排序 |
| is_delete | tinyint(1) | 是否删除 |
| add_time | int(10) | 添加时间 |

4.2 砍价活动相关表

#### 砍价商品表(store_bargain)
| 字段名 | 数据类型 | 描述 |
|--------|----------|------|
| id | int(10) unsigned | 砍价商品ID |
| product_id | int(10) | 关联商品ID |
| title | varchar(100) | 砍价活动标题 |
| image | varchar(255) | 砍价商品图片 |
| unit_name | varchar(10) | 单位名称 |
| min_price | decimal(10,2) | 最低价格 |
| price | decimal(10,2) | 原价 |
| cost | decimal(10,2) | 成本价 |
| description | varchar(255) | 砍价活动描述 |
| start_time | int(10) | 开始时间 |
| end_time | int(10) | 结束时间 |
| status | tinyint(1) | 状态(0-关闭,1-开启) |
| sales | int(10) | 销量 |
| stock | int(10) | 库存 |
| people_num | int(10) | 每人可发起砍价次数 |
| bargain_num | int(10) | 每次砍价可邀请人数 |
| sort | int(10) | 排序 |
| is_delete | tinyint(1) | 是否删除 |
| add_time | int(10) | 添加时间 |

#### 砍价用户参与记录表(store_bargain_user)
| 字段名 | 数据类型 | 描述 |
|--------|----------|------|
| id | int(10) unsigned | 记录ID |
| uid | int(10) | 用户ID |
| bargain_id | int(10) | 砍价商品ID |
| price | decimal(10,2) | 最终砍价价格 |
| status | tinyint(1) | 状态(0-进行中,1-成功,2-失败) |
| add_time | int(10) | 开始时间 |
| stop_time | int(10) | 结束时间 |

#### 砍价助力记录表(store_bargain_user_help)
| 字段名 | 数据类型 | 描述 |
|--------|----------|------|
| id | int(10) unsigned | 记录ID |
| bargain_user_id | int(10) | 砍价用户记录ID |
| uid | int(10) | 助力用户ID |
| price | decimal(10,2) | 砍掉的价格 |
| add_time | int(10) | 助力时间 |

4.3 拼团活动相关表

#### 拼团商品表(store_combination)
| 字段名 | 数据类型 | 描述 |
|--------|----------|------|
| id | int(10) unsigned | 拼团商品ID |
| product_id | int(10) | 关联商品ID |
| title | varchar(100) | 拼团活动标题 |
| image | varchar(255) | 拼团商品图片 |
| unit_name | varchar(10) | 单位名称 |
| pink_price | decimal(10,2) | 拼团价格 |
| price | decimal(10,2) | 原价 |
| cost | decimal(10,2) | 成本价 |
| description | varchar(255) | 拼团活动描述 |
| start_time | int(10) | 开始时间 |
| end_time | int(10) | 结束时间 |
| status | tinyint(1) | 状态(0-关闭,1-开启) |
| sales | int(10) | 销量 |
| stock | int(10) | 库存 |
| people | int(10) | 成团人数 |
| sort | int(10) | 排序 |
| is_delete | tinyint(1) | 是否删除 |
| add_time | int(10) | 添加时间 |

#### 拼团记录表(store_pink)
| 字段名 | 数据类型 | 描述 |
|--------|----------|------|
| id | int(10) unsigned | 记录ID |
| cid | int(10) | 拼团商品ID |
| uid | int(10) | 开团用户ID |
| order_id | int(10) | 开团订单ID |
| people | int(10) | 成团人数 |
| price | decimal(10,2) | 拼团价格 |
| status | tinyint(1) | 状态(0-拼团中,1-成团,2-失败) |
| add_time | int(10) | 开团时间 |
| stop_time | int(10) | 结束时间 |

4.4 优惠券相关表

#### 优惠券模板表(store_coupon)
| 字段名 | 数据类型 | 描述 |
|--------|----------|------|
| id | int(10) unsigned | 优惠券ID |
| type | tinyint(1) | 优惠券类型(0-满减,1-折扣) |
| title | varchar(100) | 优惠券名称 |
| money | decimal(10,2) | 优惠券金额 |
| min_price | decimal(10,2) | 最低使用金额 |
| discount | decimal(10,2) | 折扣(如9.5折) |
| use_type | tinyint(1) | 使用类型(0-全场通用,1-指定商品,2-指定分类) |
| start_time | int(10) | 开始时间 |
| end_time | int(10) | 结束时间 |
| status | tinyint(1) | 状态(0-关闭,1-开启) |
| total_count | int(10) | 总发行量 |
| give_count | int(10) | 已发放数量 |
| use_count | int(10) | 已使用数量 |
| get_type | tinyint(1) | 获取方式(0-手动领取,1-自动发放) |
| is_perpetual | tinyint(1) | 是否永久有效 |
| effective_days | int(10) | 有效天数 |
| sort | int(10) | 排序 |
| add_time | int(10) | 添加时间 |

#### 用户优惠券表(store_coupon_user)
| 字段名 | 数据类型 | 描述 |
|--------|----------|------|
| id | int(10) unsigned | 记录ID |
| cid | int(10) | 优惠券ID |
| uid | int(10) | 用户ID |
| status | tinyint(1) | 状态(0-未使用,1-已使用,2-已过期) |
| get_time | int(10) | 领取时间 |
| use_time | int(10) | 使用时间 |
| order_id | int(10) | 使用订单ID |
| end_time | int(10) | 过期时间 |

5. API接口说明

5.1 秒杀活动接口

#### 5.1.1 秒杀商品列表
- 请求URL/adminapi/v1/marketing/seckill/list
- 请求方法:GET
- 权限要求:marketing/seckill/list
- 请求参数
- page:页码
- limit:每页数量
- keyword:搜索关键词
- status:状态(0-关闭,1-开启)
- 返回结果:秒杀商品列表数据

#### 5.1.2 添加秒杀商品
- 请求URL/adminapi/v1/marketing/seckill/create
- 请求方法:POST
- 权限要求:marketing/seckill/create
- 请求参数:秒杀商品信息
- 返回结果:操作结果

#### 5.1.3 编辑秒杀商品
- 请求URL/adminapi/v1/marketing/seckill/update/{id}
- 请求方法:PUT
- 权限要求:marketing/seckill/update
- 请求参数:秒杀商品信息
- 返回结果:操作结果

#### 5.1.4 删除秒杀商品
- 请求URL/adminapi/v1/marketing/seckill/delete/{id}
- 请求方法:DELETE
- 权限要求:marketing/seckill/delete
- 返回结果:操作结果

5.2 砍价活动接口

#### 5.2.1 砍价商品列表
- 请求URL/adminapi/v1/marketing/bargain/list
- 请求方法:GET
- 权限要求:marketing/bargain/list
- 请求参数
- page:页码
- limit:每页数量
- keyword:搜索关键词
- status:状态(0-关闭,1-开启)
- 返回结果:砍价商品列表数据

#### 5.2.2 添加砍价商品
- 请求URL/adminapi/v1/marketing/bargain/create
- 请求方法:POST
- 权限要求:marketing/bargain/create
- 请求参数:砍价商品信息
- 返回结果:操作结果

5.3 拼团活动接口

#### 5.3.1 拼团商品列表
- 请求URL/adminapi/v1/marketing/combination/list
- 请求方法:GET
- 权限要求:marketing/combination/list
- 请求参数
- page:页码
- limit:每页数量
- keyword:搜索关键词
- status:状态(0-关闭,1-开启)
- 返回结果:拼团商品列表数据

#### 5.3.2 添加拼团商品
- 请求URL/adminapi/v1/marketing/combination/create
- 请求方法:POST
- 权限要求:marketing/combination/create
- 请求参数:拼团商品信息
- 返回结果:操作结果

5.4 优惠券接口

#### 5.4.1 优惠券列表
- 请求URL/adminapi/v1/marketing/coupon/list
- 请求方法:GET
- 权限要求:marketing/coupon/list
- 请求参数
- page:页码
- limit:每页数量
- keyword:搜索关键词
- status:状态(0-关闭,1-开启)
- 返回结果:优惠券列表数据

#### 5.4.2 添加优惠券
- 请求URL/adminapi/v1/marketing/coupon/create
- 请求方法:POST
- 权限要求:marketing/coupon/create
- 请求参数:优惠券信息
- 返回结果:操作结果

5. 开发规范与流程

5.1 代码规范


1. 命名规范
- 类名采用大驼峰命名法,如 StoreSeckillServices
- 方法名采用小驼峰命名法,如 getSeckillList
- 变量名采用小驼峰命名法,如 seckillProduct
- 常量名采用全大写,下划线分隔,如 COUPON_TYPE_FULL

2. 代码结构
- 严格遵循分层架构,禁止跨层调用
- 每个方法职责单一,代码行数控制在50行以内
- 适当添加注释,说明方法功能、参数含义和返回值

3. 数据库操作
- 所有数据库操作必须通过Dao层进行
- 使用ORM提供的查询构建器,避免直接编写SQL
- 涉及资金、库存等关键数据操作必须使用事务处理

5.2 开发流程


1. 需求分析:明确营销活动的功能需求和业务逻辑
2. 设计阶段:设计数据结构、API接口和业务流程
3. 编码实现:按照分层架构编写代码
4. 单元测试:编写单元测试,确保功能正确性
5. 集成测试:进行模块集成测试,测试活动与商品、订单等模块的交互
6. 性能测试:对高并发场景进行性能测试,如秒杀活动
7. 代码审查:提交代码审查,确保代码质量
8. 部署上线:部署到生产环境

6. 常见问题与解决方案

6.1 高并发处理


问题:秒杀、拼团等活动在高并发场景下可能出现超卖、数据不一致等问题
解决方案
1. 使用数据库事务和乐观锁机制
2. 实现库存预扣和释放机制
3. 使用Redis等缓存技术,提高库存操作效率
4. 采用分布式锁,确保数据一致性
5. 实现流量削峰,如使用队列、限流等技术

6.2 活动时间管理


问题:活动开始和结束时间的精确控制
解决方案
1. 使用定时器任务,定期检查活动状态
2. 在关键操作(如用户参与活动)时,再次验证活动时间
3. 使用Redis的过期时间功能,自动更新活动状态

6.3 活动数据统计


问题:实时统计活动参与人数、销售额等数据
解决方案
1. 使用Redis缓存实时数据,定期同步到数据库
2. 采用异步处理方式,避免影响主业务流程
3. 实现数据报表功能,支持多维度查询

6.4 活动冲突处理


问题:同一商品参与多个活动时的冲突
解决方案
1. 设计活动优先级机制,明确活动执行顺序
2. 在用户参与活动时,验证商品是否可以同时参与多个活动
3. 提供活动冲突检测功能,在创建活动时提示冲突

7. 扩展与定制

7.1 功能扩展


系统设计具有良好的扩展性,可通过以下方式扩展功能:

1. 添加新活动类型
- 在 model/activity/ 目录下创建新的活动模型
- 在 dao/activity/ 目录下创建对应的DAO
- 在 services/activity/ 目录下创建对应的Services
- 在 controller/ 目录下创建对应的控制器
- 在路由文件中添加新的路由

2. 扩展现有活动功能
- 在现有模型中添加新字段
- 在现有Services中添加新方法
- 在现有控制器中添加新接口

7.2 事件扩展


系统在关键业务节点触发事件,可通过监听事件进行功能扩展:

1. 活动开始事件:ActivityStartEvent
2. 活动结束事件:ActivityEndEvent
3. 用户参与活动事件:UserJoinActivityEvent
4. 活动订单创建事件:ActivityOrderCreateEvent
5. 活动订单支付事件:ActivityOrderPayEvent

7.3 钩子扩展


系统提供了多个钩子点,可通过钩子函数进行功能扩展:

1. 活动创建前钩子:activity_create_before
2. 活动创建后钩子:activity_create_after
3. 活动编辑前钩子:activity_edit_before
4. 活动编辑后钩子:activity_edit_after
5. 活动删除前钩子:activity_delete_before
6. 活动删除后钩子:activity_delete_after
7. 用户参与活动前钩子:user_join_activity_before
8. 用户参与活动后钩子:user_join_activity_after

8. 文档更新记录

| 版本 | 更新日期 | 更新内容 | 更新人 |
|------|----------|----------|--------|
| 1.0 | 2026-01-19 | 初始版本,包含秒杀、砍价、拼团、优惠券等核心营销活动 | AI Assistant |

9. 附录

9.1 核心类关系图

text
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│ ActivityModel │ │ ActivityDao │ │ ActivityServices│
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
└───────────────────────┼───────────────────────┘

┌─────────────────┐
│ ActivityController│
└─────────────────┘

┌─────────────────┐
│ Routes │
└─────────────────┘

9.2 秒杀活动流程图

text
秒杀活动流程:
1. 用户进入秒杀活动页面
2. 系统验证活动是否开始
3. 用户点击秒杀按钮
4. 系统验证商品库存
5. 系统预扣商品库存
6. 用户创建订单
7. 用户支付订单
8. 系统确认订单,扣减库存
9. 活动结束,释放未支付订单的库存

9.3 拼团活动流程图

text
拼团活动流程:
1. 用户进入拼团活动页面
2. 选择商品和拼团规格
3. 选择开团或参团
a. 开团:创建新的拼团记录
b. 参团:加入已有拼团记录
4. 系统预扣商品库存
5. 用户创建订单
6. 用户支付订单
7. 系统检查是否达到成团人数
a. 达到:拼团成功
b. 未达到:等待其他用户参团
8. 拼团时间结束
a. 成团:订单生效
b. 未成团:退款给用户,释放库存

9.4 砍价活动流程图

text
砍价活动流程:
1. 用户进入砍价活动页面
2. 选择商品,点击开始砍价
3. 系统创建砍价记录
4. 用户邀请好友帮忙砍价
5. 好友点击助力,系统随机砍掉一定金额
6. 用户达到最低价格或砍价时间结束
7. 用户以砍价价格购买商品
8. 系统创建订单,扣减库存

---

提示:该文档由AI生成,仅供参考。

---

Help/Dev Docs/Phpapi/订单模块说明 (help/dev-docs/phpapi/订单模块说明.md)

订单模块说明

📦 订单状态流转

订单核心状态


php
const ORDER_STATUS_UNPAID = 0;       // 未支付
const ORDER_STATUS_PAID = 1; // 已支付
const ORDER_STATUS_SHIPPED = 2; // 已发货
const ORDER_STATUS_COMPLETED = 3; // 已完成
const ORDER_STATUS_CANCELLED = -1; // 已取消
const ORDER_STATUS_REFUNDING = -2; // 退款中
const ORDER_STATUS_REFUNDED = -3; // 已退款

支付状态


php
const PAY_STATUS_UNPAID = 0;         // 未支付
const PAY_STATUS_PAID = 1; // 已支付
const PAY_STATUS_REFUNDING = 2; // 退款中
const PAY_STATUS_REFUNDED = 3; // 已退款

🔄 订单创建流程

1. 参数验证


php
// 验证收货地址、商品信息、优惠券等
$validate = new OrderValidate();
if (!$validate->scene('create')->check($params)) {
throw new ApiException($validate->getError());
}

2. 商品校验


php
// 检查商品库存、价格、状态
foreach ($cartInfo as $item) {
$product = $productService->getProductInfo($item['product_id']);
if ($product['stock'] < $item['cart_num']) {
throw new ApiException('商品库存不足');
}
}

3. 优惠计算


php
// 计算优惠券、积分、满减等
$couponAmount = $couponService->calculateCoupon($uid, $cartInfo);
$integralAmount = $integralService->calculateIntegral($uid, $totalAmount);
$finalAmount = $totalAmount - $couponAmount - $integralAmount;

4. 创建订单


php
// 生成订单数据
$orderData = [
'order_id' => $this->getNewOrderId(),
'uid' => $uid,
'total_price' => $totalAmount,
'pay_price' => $finalAmount,
'status' => self::ORDER_STATUS_UNPAID,
'add_time' => time()
];

// 保存订单
$orderId = $this->dao->save($orderData);

💳 支付处理

支付方式


php
const PAY_TYPE_WECHAT = 'wechat';    // 微信支付
const PAY_TYPE_ALIPAY = 'alipay'; // 支付宝
const PAY_TYPE_BALANCE = 'balance'; // 余额支付
const PAY_TYPE_INTEGRAL = 'integral'; // 积分支付

支付回调处理


php
public function payNotify($params) {
// 验证支付结果
if ($this->verifyPayResult($params)) {
// 更新订单状态
$this->updateOrderStatus($params['order_id'], self::ORDER_STATUS_PAID);

// 记录支付流水
$this->savePayRecord($params);

// 发送支付成功通知
$this->sendPaySuccessNotify($params['order_id']);
}
}

📦 发货处理

发货流程


php
public function deliverOrder($orderId, $expressData) {
// 检查订单状态
$order = $this->getOrderInfo($orderId);
if ($order['status'] != self::ORDER_STATUS_PAID) {
throw new ApiException('订单状态不允许发货');
}

// 生成发货单
$deliverData = [
'order_id' => $orderId,
'express_code' => $expressData['code'],
'express_number' => $expressData['number'],
'deliver_time' => time()
];

// 更新订单状态
$this->updateOrderStatus($orderId, self::ORDER_STATUS_SHIPPED);

// 发送发货通知
$this->sendDeliverNotify($orderId);
}

🔄 售后处理

退款申请


php
public function applyRefund($orderId, $reason, $amount) {
// 检查订单是否可退款
if (!$this->canRefund($orderId)) {
throw new ApiException('该订单不可退款');
}

// 创建退款记录
$refundData = [
'order_id' => $orderId,
'refund_amount' => $amount,
'refund_reason' => $reason,
'status' => self::REFUND_STATUS_APPLY
];

// 更新订单状态
$this->updateOrderStatus($orderId, self::ORDER_STATUS_REFUNDING);
}

退款审核


php
public function auditRefund($refundId, $status, $remark = '') {
$refund = $this->getRefundInfo($refundId);

if ($status == self::REFUND_STATUS_APPROVED) {
// 执行退款
$this->doRefund($refund);

// 更新订单状态
$this->updateOrderStatus($refund['order_id'], self::ORDER_STATUS_REFUNDED);
} else {
// 拒绝退款
$this->updateRefundStatus($refundId, self::REFUND_STATUS_REJECTED, $remark);

// 恢复订单状态
$this->recoverOrderStatus($refund['order_id']);
}
}

📊 订单统计

常用统计方法


php
// 今日订单统计
public function getTodayOrderStats() {
$todayStart = strtotime('today');
$todayEnd = strtotime('tomorrow') - 1;

return [
'total' => $this->dao->where('add_time', 'between', [$todayStart, $todayEnd])->count(),
'amount' => $this->dao->where('add_time', 'between', [$todayStart, $todayEnd])->sum('pay_price'),
'paid' => $this->dao->where('add_time', 'between', [$todayStart, $todayEnd])
->where('status', '>', 0)->count()
];
}

---

提示:该文档由AI生成,仅供参考。

---

Help/Dev Docs/Phpapi/项目目录文档 (help/dev-docs/phpapi/项目目录文档.md)

CRMEB 项目目录文档

1. 引言


- 文档目的: 详细说明 CRMEB 项目的目录结构和各目录功能
- 适用范围: 项目开发人员、维护人员、新成员
- 术语定义: 无特殊术语

2. 项目根目录结构

2.1 目录树

text
CRMEB/
├── .comate/ # Comate 工具配置
├── .env # 环境配置文件
├── .git/ # Git 版本控制
├── .gitignore # Git 忽略文件
├── .idea/ # IDEA 编辑器配置
├── .trae/ # Trae 工具配置
│ ├── rules/ # 规则配置
│ └── skills/ # 技能配置
├── crmeb/ # 核心应用目录
├── docker-compose/ # Docker 配置
├── docs/ # 文档目录
├── docs.zip # 文档压缩包
├── LICENSE # 许可证文件
├── readme/ # 说明文档
├── README.md # 项目说明
├── template/ # 模板文件
└── 安装必读.docx # 安装说明

2.2 根目录说明


- .trae/: Trae 工具配置目录,包含规则和技能配置
- crmeb/: 项目核心应用目录,包含所有业务逻辑
- docker-compose/: Docker 容器配置,用于快速部署
- docs/: 项目文档目录,存放各类说明文档
- readme/: 项目说明文档,包含功能介绍和截图
- template/: 模板文件目录,用于生成代码和配置

3. 核心应用目录结构 (crmeb/)

3.1 目录树

text
crmeb/
├── .constant # 常量定义
├── .env # 应用环境配置
├── .htaccess # Apache 配置
├── .phpstorm.meta.php # PHPStorm 元数据
├── .travis.yml # Travis CI 配置
├── .version # 版本信息
├── app/ # 应用核心目录
├── backup/ # 备份目录
├── build.example.php # 构建配置示例
├── composer.json # Composer 依赖配置
├── composer.lock # Composer 依赖锁定
├── config/ # 配置文件目录
├── crmeb/ # 核心库目录
├── filetree.txt # 文件树结构
├── index.html # 入口 HTML
├── install.lock # 安装锁定
├── LICENSE.txt # 许可证文件
├── public/ # 静态资源目录
├── README.md # 应用说明
├── route/ # 路由配置目录
├── runtime/ # 运行时目录
├── think # ThinkPHP 命令行工具
├── vendor/ # 依赖库目录
└── workerman.bat # Workerman 启动脚本

3.2 核心目录说明


- app/: 应用核心目录,包含所有业务逻辑
- config/: 配置文件目录,存放应用配置
- crmeb/: 核心库目录,提供基础功能
- public/: 静态资源目录,存放前端文件
- route/: 路由配置目录,定义 URL 路由
- runtime/: 运行时目录,存放缓存和日志
- vendor/: 依赖库目录,Composer 安装的依赖

4. 应用核心目录结构 (app/)

4.1 目录树

text
app/
├── adminapi/ # 后台 API 接口
├── api/ # 前端 API 接口
├── AppService.php # 应用服务
├── build.php # 构建配置
├── common.php # 公共函数
├── dao/ # 数据访问层
├── event.php # 事件配置
├── ExceptionHandle.php # 异常处理
├── filetree.txt # 文件树结构
├── http/ # HTTP 相关
├── jobs/ # 队列任务
├── kefuapi/ # 客服 API 接口
├── lang/ # 语言包
├── listener/ # 事件监听器
├── middleware.php # 中间件配置
├── model/ # 数据模型
├── outapi/ # 外部 API 接口
├── provider.php # 服务提供者
├── README.md # 目录说明
├── Request.php # 请求基类
├── service.php # 服务配置
└── services/ # 业务逻辑层

4.2 核心目录说明


- adminapi/: 后台管理系统 API 接口,处理后台请求
- api/: 前端应用 API 接口,处理客户端请求
- dao/: 数据访问层,封装数据库操作
- jobs/: 队列任务,处理异步操作
- kefuapi/: 客服系统 API 接口
- model/: 数据模型,定义数据结构
- outapi/: 外部系统 API 接口
- services/: 业务逻辑层,实现核心业务功能

5. 核心模块说明

5.1 控制器层 (api/, adminapi/, kefuapi/)


- 处理 HTTP 请求
- 路由分发
- 参数验证
- 返回响应

5.2 业务逻辑层 (services/)


- 实现核心业务逻辑
- 调用数据访问层
- 处理业务规则

5.3 数据访问层 (dao/)


- 封装数据库操作
- 提供数据查询方法
- 处理数据持久化

5.4 数据模型层 (model/)


- 定义数据结构
- 关联关系
- 数据验证

5.5 配置层 (config/)


- 应用配置
- 数据库配置
- 缓存配置
- 日志配置

6. 静态资源目录 (public/)


- css/: 样式文件
- js/: JavaScript 文件
- images/: 图片文件
- fonts/: 字体文件
- uploads/: 上传文件

7. 配置文件说明

7.1 核心配置文件


- .env: 环境变量配置
- config/app.php: 应用配置
- config/database.php: 数据库配置
- config/cache.php: 缓存配置

7.2 路由配置


- route/api.php: API 路由
- route/adminapi.php: 后台 API 路由
- route/kefuapi.php: 客服 API 路由

8. 核心文件说明

8.1 入口文件


- public/index.php: 应用入口文件
- think: 命令行工具

8.2 基础类


- app/Request.php: 请求基类
- app/ExceptionHandle.php: 异常处理类
- app/AppService.php: 应用服务类

8.3 配置文件


- composer.json: 依赖管理
- .htaccess: Apache 重写规则

9. 目录使用建议

9.1 开发规范


- 新增文件: 按照对应模块目录结构存放
- 修改文件: 保持原有目录结构
- 删除文件: 确认无依赖后删除

9.2 命名规范


- 目录名: 小写单词,无特殊字符
- 文件名: 驼峰命名或小写下划线
- 类名: PascalCase
- 方法名: camelCase

10. 总结

10.1 目录结构特点


- 分层清晰: 遵循 MVC 架构,分层明确
- 模块分离: 按功能模块划分目录
- 配置集中: 配置文件统一管理
- 资源分离: 静态资源单独存放

10.2 后续计划


- 定期更新目录结构文档
- 根据项目演进调整目录结构
- 保持目录结构的合理性和可维护性

---

版本: 1.0
作者: 系统生成
更新日期: 2026-01-23
---

提示:该文档由AI生成,仅供参考。

---

Help/Dev Docs/Uniapp/Uniapp目录结构 (help/dev-docs/uniapp/uniapp目录结构.md)

CRMEB 项目 uniapp 目录结构文档

1. 引言


- 文档目的: 详细说明 CRMEB 项目中 uniapp 目录结构和各目录功能
- 适用范围: 移动端开发人员、前端开发人员、项目维护人员
- 术语定义: uniapp - 基于 Vue.js 的跨平台应用开发框架

2. 目录结构

2.1 目录树

text
uni-app/
├── androidPrivacy.json # Android 隐私政策配置
├── api/ # API 接口目录
├── App.vue # 应用入口组件
├── components/ # 公共组件目录
├── config/ # 配置文件目录
├── libs/ # 第三方库目录
├── main.js # 应用入口文件
├── manifest.json # 应用配置文件
├── mixins/ # 混入文件目录
├── package-lock.json # npm 依赖锁定文件
├── package.json # npm 依赖配置文件
├── pages/ # 页面目录
├── pages.json # 页面路由配置文件
├── plugin/ # 插件目录
├── static/ # 静态资源目录
├── store/ # 状态管理目录
├── uni.scss # 全局样式文件
├── utils/ # 工具函数目录
└── vue.config.js # Vue 配置文件

2.2 目录功能说明

#### 2.2.1 核心目录
- api/: 存放 API 接口定义,包含所有后端接口调用
- components/: 存放公共组件,可在多个页面复用
- pages/: 存放应用页面,每个页面对应一个子目录
- static/: 存放静态资源,如图片、字体、图标等
- utils/: 存放工具函数,如日期处理、请求封装等

#### 2.2.2 配置目录
- config/: 存放应用配置,如 API 地址、常量定义等
- mixins/: 存放混入文件,用于复用组件逻辑
- store/: 存放 Vuex 状态管理文件
- libs/: 存放第三方库,如 SDK、工具库等

#### 2.2.3 插件目录
- plugin/: 存放应用插件,如支付插件、分享插件等

3. 核心文件说明

3.1 入口文件


- App.vue: 应用根组件,全局配置和生命周期管理
- main.js: 应用入口文件,初始化 Vue 实例和全局配置

3.2 配置文件


- manifest.json: 应用配置文件,包含应用名称、版本、权限等
- pages.json: 页面路由配置文件,定义页面路径、导航栏等
- vue.config.js: Vue 项目配置文件,如代理配置、构建配置等

3.3 样式文件


- uni.scss: 全局样式文件,定义主题变量和通用样式

3.4 依赖文件


- package.json: npm 依赖配置文件,管理项目依赖
- package-lock.json: npm 依赖锁定文件,确保依赖版本一致

4. 页面目录结构

4.1 页面组织方式


text
pages/
├── index/ # 首页
│ ├── index.vue # 页面组件
│ └── main.js # 页面入口(可选)
├── goods/ # 商品相关页面
│ ├── list.vue # 商品列表
│ └── detail.vue # 商品详情
└── user/ # 用户相关页面
├── index.vue # 用户中心
└── login.vue # 登录页面

4.2 页面文件说明


- 页面组件 (.vue): 包含模板、脚本和样式
- 页面入口 (main.js): 页面级别的初始化配置(可选)

5. 开发规范

5.1 命名规范


- 目录名: 小写单词,多个单词用连字符(-)分隔
- 文件名: 小写单词,多个单词用连字符(-)分隔
- 组件名: PascalCase 命名法
- 变量名: camelCase 命名法
- 常量名: 全大写,多个单词用下划线(_)分隔

5.2 代码规范


- 遵循 Vue 官方风格指南
- 使用 ES6+ 语法
- 组件化开发,提高代码复用性
- 合理使用 Vuex 管理全局状态
- 页面逻辑清晰,避免过度嵌套

5.3 性能优化


- 图片资源优化,使用适当尺寸和格式
- 减少 HTTP 请求,合理使用缓存
- 组件懒加载,减少初始包大小
- 避免在模板中使用复杂计算
- 合理使用 uni-app 提供的性能优化 API

6. 注意事项

6.1 跨平台兼容性


- 注意不同平台的 API 差异
- 避免使用平台特定的特性
- 测试时覆盖主要平台(iOS、Android、微信小程序等)

6.2 打包配置


- 根据不同平台配置相应的打包参数
- 注意应用权限配置
- 合理配置应用图标和启动页

6.3 调试技巧


- 使用 uni-app 开发者工具进行调试
- 利用 console.log 输出调试信息
- 关注控制台警告和错误信息

7. 总结

7.1 目录结构特点


- 结构清晰: 遵循 uni-app 官方推荐的目录结构
- 模块化强: 按功能模块化组织代码
- 易于维护: 目录职责明确,代码结构合理
- 扩展性好: 便于添加新功能和页面

7.2 后续计划


- 完善组件库,提高代码复用性
- 优化页面性能,提升用户体验
- 增加自动化测试,确保代码质量
- 持续更新依赖库,保持框架先进性

---

版本: 1.0
作者: 系统生成
更新日期: 2026-01-23
---

提示:该文档由AI生成,仅供参考。

---

Help/Dev Docs/Uniapp/移动端前端架构说明 (help/dev-docs/uniapp/移动端前端架构说明.md)

CRMEB 移动端前端架构说明

📱 技术栈概览

| 技术 | 版本 | 说明 |
|------|------|------|
| UniApp | 2.x/3.x | 跨端开发框架 |
| Vue.js | 2.x/3.x | 核心框架 |
| Vuex | 3.x/4.x | 状态管理 |
| uView UI | 2.x | 移动端UI组件库 |
| Sass/Less | CSS预处理器 | |
| Axios | HTTP客户端 | 封装请求 |

🏗️ 整体架构

text
/ Detailed source-code truncated for AI context efficiency. /

🧩 核心功能模块

1. 商品模块


- 商品列表展示
- 商品详情页
- 商品搜索
- 商品分类

2. 购物车模块


- 添加商品到购物车
- 购物车管理
- 批量操作

3. 订单模块


- 订单创建
- 订单列表
- 订单详情
- 订单状态跟踪

4. 用户模块


- 用户登录注册
- 个人中心
- 地址管理
- 收藏管理

5. 支付模块


- 微信支付
- 支付宝支付
- 余额支付

🔧 开发最佳实践

1. 页面生命周期


javascript
export default {
// 页面加载
onLoad(options) {
this.initPage(options)
},

// 页面显示
onShow() {
this.refreshData()
},

// 下拉刷新
onPullDownRefresh() {
this.loadData().finally(() => {
uni.stopPullDownRefresh()
})
},

// 上拉加载
onReachBottom() {
this.loadMore()
},

methods: {
async initPage(options) {
// 初始化页面数据
},

async refreshData() {
// 刷新数据
}
}
}

2. 组件通信


javascript
// 父传子
<child-component :data="parentData" @custom-event="handleEvent" />

// 子组件
export default {
props: {
data: {
type: Object,
default: () => ({})
}
},
methods: {
emitEvent() {
this.$emit('custom-event', eventData)
}
}
}

3. 状态管理


javascript
// 使用 Vuex
import { mapState, mapActions } from 'vuex'

export default {
computed: {
...mapState('user', ['userInfo']),
...mapState('cart', ['cartList'])
},
methods: {
...mapActions('user', ['login']),
...mapActions('cart', ['addToCart'])
}
}

🎯 性能优化

1. 图片优化


javascript
// 使用懒加载
<image lazy-load src="image.jpg" />

// 使用webp格式
<image webp src="image.webp" />

// 使用合适的图片尺寸
<image :src="imageUrl + '?x-oss-process=image/resize,w_300'" />

2. 数据缓存


javascript
// 使用本地存储
uni.setStorageSync('key', data)
const data = uni.getStorageSync('key')

// 使用内存缓存
const cache = new Map()
cache.set('key', data)
const data = cache.get('key')

3. 请求优化


javascript
// 防抖处理
const debounce = (func, wait) => {
let timeout
return function() {
clearTimeout(timeout)
timeout = setTimeout(() => func.apply(this, arguments), wait)
}
}

// 使用
search: debounce(function(keyword) {
this.doSearch(keyword)
}, 300)

📦 多端适配

1. 条件编译


javascript
// #ifdef H5
console.log('只在H5平台显示')
// #endif

// #ifdef MP-WEIXIN
console.log('只在微信小程序显示')
// #endif

// #ifdef APP-PLUS
console.log('只在App显示')
// #endif

2. 平台差异处理


javascript
const platform = {
isH5: uni.getSystemInfoSync().platform === 'h5',
isWeapp: uni.getSystemInfoSync().platform === 'devtools',
isApp: uni.getSystemInfoSync().platform === 'app'
}

// 使用
if (platform.isH5) {
// H5特有逻辑
}

🚀 部署发布

1. 小程序发布


bash

微信小程序


npm run build:mp-weixin

然后使用微信开发者工具上传

支付宝小程序


npm run build:mp-alipay

2. H5部署


bash

构建H5


npm run build:h5

部署到服务器


scp -r dist/build/h5 user@server:/path/to/www

3. App发布


bash

构建App


npm run build:app

使用HBuilderX进行打包和发布

🔍 调试技巧

1. 开发工具使用


javascript
// 打印调试信息
console.log('调试信息', data)

// 使用debugger
debugger

// 性能监控
console.time('operation')
// 执行操作
console.timeEnd('operation')

2. 真机调试


javascript
// 使用uni-app调试工具
// 1. 连接手机和电脑
// 2. 开启USB调试
// 3. 使用HBuilderX真机运行

📝 代码规范

1. 命名规范


javascript
// 变量命名 - 小驼峰
const userName = 'John'
let isLoading = false

// 常量命名 - 全大写
const API_BASE_URL = 'https://api.example.com'
const MAX_COUNT = 100

// 组件命名 - 大驼峰
// MyComponent.vue
export default {
name: 'MyComponent'
}

2. 代码组织


javascript
// 文件结构
export default {
// 1. 组件名
name: 'ComponentName',

// 2. 组件属性
props: {},

// 3. 数据
data() {
return {}
},

// 4. 计算属性
computed: {},

// 5. 监听器
watch: {},

// 6. 生命周期
mounted() {},

// 7. 方法
methods: {}
}

---
文档版本: v1.0
更新日期: 2024-01-17
适用版本: CRMEB 5.6.4+

💡 提示:移动端开发需要特别注意性能优化和多端适配,建议使用uni-app的Conditional Compile功能处理平台差异。

---

提示:该文档由AI生成,仅供参考。

---

Help/Docker/README (help/docker/README.md)

安装docker


docker 官网下载


https://www.docker.com/products/docker-desktop

命令安装


text
curl -sSL https://get.daocloud.io/docker | sh

方式一:一键启动CRMEB 系统

text
docker run -d \
--name crmeb_app \
-p 8111:80 \
-v $(pwd)/crmeb/runtime:/var/www/crmeb/runtime \
-v $(pwd)/crmeb/uploads:/var/www/crmeb/public/uploads \
-v $(pwd)/crmeb_mysql:/var/lib/mysql \
-v $(pwd)/crmeb_redis:/var/lib/redis \
-e TZ=Asia/Shanghai \
ccr.ccs.tencentyun.com/zbkj/crmebky:latest


方式二:docker-compose 快速运行项目


1、安装docker-compose


https://www.runoob.com/docker/docker-compose.html

2、下载CRMEB程序


建议去下载最新开源代码 https://gitee.com/ZhongBangKeJi/CRMEB
程序放到docker 同级目录下

3、启动项目


text
进入docker-compose目录 cd /docker

运行命令:


docker-compose up -d

text

4、访问CRMEB 系统


移动端访问地址:http://localhost:8011/
PC端访问地址:http://localhost:8011/admin


5、安装CRMEB


Mysql数据库信息:


Host:crmeb_mysql
Post:3306
user:crmeb
pwd:123456
text

Redis信息:


Host:crmeb_redis
Post:6379
db:0
pwd:123456
text

6、常见错误及解决方案

6.1 MySQL 启动失败


错误现象:MySQL 容器启动失败,日志显示 "--initialize specified but the data directory has files in it. Aborting."

解决方案
1. 停止所有容器:docker-compose down
2. 清空数据目录:rm -rf mysql/data/*
3. 重新启动服务:docker-compose up -d

原因:MySQL 数据目录不为空,导致初始化失败。

6.2 数据目录映射问题


错误现象:数据库无法启动或数据无法持久化

解决方案
1. 确保 mysql/data 目录存在:mkdir -p mysql/data
2. 确保 mysql/data 目录为空
3. 确保 docker-compose.yml 中正确配置了数据卷映射:

yaml
volumes:
- ./mysql/data:/var/lib/mysql
text
原因:数据目录未映射或映射不正确,导致数据库无法创建或数据丢失。

6.3 常见需要映射的目录说明

6.3.1 MySQL 数据目录


- 本地路径mysql/data
- 容器路径/var/lib/mysql
- 用途:存储 MySQL 数据库的数据文件
- 注意事项:必须为空目录,否则 MySQL 初始化会失败

6.2 MySQL 日志目录


- 本地路径mysql/log
- 容器路径/var/log/mysql
- 用途:存储 MySQL 的日志文件
- 注意事项:确保目录存在且有读写权限

6.3.2 PHP 应用目录


- 本地路径../../crmeb
- 容器路径/var/www
- 用途:存储 CRMEB 应用代码
- 注意事项:确保目录存在且包含完整的 CRMEB 代码

6.3.3 PHP 运行时目录


- 本地路径../../crmeb/runtime
- 容器路径/var/www/runtime
- 用途:存储 PHP 应用的运行时文件,如缓存、日志等
- 注意事项:确保目录存在且有读写权限

6.3.4 Nginx 配置目录


- 本地路径./nginx/vhost.conf
- 容器路径/etc/nginx/conf.d/default.conf
- 用途:Nginx 虚拟主机配置文件
- 注意事项:确保配置文件存在且格式正确

6.3.5 Nginx 日志目录


- 本地路径./nginx/log
- 容器路径/etc/nginx/log
- 用途:存储 Nginx 的日志文件
- 注意事项:确保目录存在且有读写权限

6.3.6 目录创建命令

bash

创建所有必要的目录


mkdir -p mysql/data mysql/log nginx/log

确保 CRMEB 应用目录存在


mkdir -p ../crmeb ../crmeb/runtime
text
---

Help/Docker/Docker Compose.Yml (help/docker/docker-compose.yml)

services:
# mysql 容器
mysql:
container_name: crmeb_mysql
image: ccr.ccs.tencentyun.com/crmebky_php/mysql:v8.0.45
ports:
- "33061:3306"
environment:
TZ: Asia/Shanghai
MYSQL_ROOT_PASSWORD: 123456
MYSQL_USER: crmeb
MYSQL_PASSWORD: 123456
MYSQL_DATABASE: crmeb
volumes:
- ./mysql/data:/var/lib/mysql
- ./mysql/log:/var/log/mysql
networks:
app_net:
ipv4_address: 192.168.10.11
# redis 容器
redis:
container_name: crmeb_redis
image: ccr.ccs.tencentyun.com/crmebky_php/redis:v8.6.1
ports:
- "63791:6379"
environment:
TZ: Asia/Shanghai
REDIS_PASSWORD: 123456
networks:
app_net:
ipv4_address: 192.168.10.10
# php 容器
phpfpm:
container_name: crmeb_php
image: ccr.ccs.tencentyun.com/crmebky_php/php:v7.4
restart: always
environment:
TZ: Asia/Shanghai
MYSQL_HOST_IP: crmeb_mysql
MYSQL_PORT: "3306"
MYSQL_USER: crmeb
MYSQL_PASSWORD: 123456
MYSQL_DATABASE: crmeb
REDIS_HOST_IP: crmeb_redis
REDIS_PORT: "6379"
REDIS_DATABASE: "0"
REDIS_PASSWORD: 123456
APP_DEBUG: true
DEFAULT_TIMEZONE: Asia/Shanghai
ports:
- "9000:9000"
- "40001:40001"
- "40002:40002"
working_dir: /var/www
volumes:
- ../../crmeb:/var/www
- ../../crmeb/runtime:/var/www/runtime
networks:
app_net:
ipv4_address: 192.168.10.90
# nginx 容器
nginx:
container_name: crmeb_nginx
image: ccr.ccs.tencentyun.com/crmebky_php/nginx:v1.29.6
restart: always
ports:
- "8011:80"
depends_on:
- phpfpm
environment:
TZ: Asia/Shanghai
working_dir: /var/www
volumes_from:
- phpfpm
volumes:
- ./nginx/vhost.conf:/etc/nginx/conf.d/default.conf
- ./nginx/log:/etc/nginx/log
networks:
app_net:
ipv4_address: 192.168.10.80
networks:
app_net:
driver: bridge
ipam:
driver: default
config:
- subnet: 192.168.10.0/24

---

Template/README (template/README.md)

Template 目录说明文档

目录结构

template 目录包含 CRMEB 系统的前端项目代码,主要分为两个子项目:


template/
├── admin/ # 管理端前端项目(Vue.js + Element UI)
└── uni-app/ # 移动端前端项目(UniApp)
text

项目说明

1. 管理端前端项目 (admin/)

管理端前端项目基于 Vue.js + Element UI 开发,用于后台管理系统的操作界面。

#### 主要目录结构


admin/
├── public/ # 静态资源目录
├── src/ # 源代码目录
│ ├── api/ # API 接口定义
│ ├── assets/ # 静态资源文件
│ ├── components/ # 通用组件
│ ├── config/ # 配置文件
│ ├── directive/ # 自定义指令
│ ├── filters/ # 过滤器
│ ├── layout/ # 布局组件
│ ├── libs/ # 工具库
│ ├── pages/ # 页面组件
│ ├── router/ # 路由配置
│ ├── store/ # 状态管理
│ ├── styles/ # 样式文件
│ ├── utils/ # 工具函数
│ ├── App.vue # 根组件
│ └── main.js # 入口文件
├── .env.dev # 开发环境配置
├── .env.production # 生产环境配置
├── package.json # 项目依赖
├── vue.config.js # Vue 配置
└── README.md # 项目说明
text
#### 技术栈
- Vue.js 2.x
- Element UI
- Vue Router
- Vuex
- Axios
- ECharts

#### 开发命令
- 安装依赖:npm install
- 开发环境运行:npm run dev
- 生产环境构建:npm run build
- 代码检查:npm run lint

2. 移动端前端项目 (uni-app/)

移动端前端项目基于 UniApp 开发,支持多端发布(微信小程序、H5、App 等)。

#### 主要目录结构


uni-app/
├── api/ # API 接口定义
├── components/ # 通用组件
├── config/ # 配置文件
├── libs/ # 工具库
├── mixins/ # 混合器
├── pages/ # 页面组件
├── static/ # 静态资源
├── App.vue # 根组件
├── main.js # 入口文件
├── manifest.json # 应用配置
├── pages.json # 页面配置
└── package.json # 项目依赖
text
#### 技术栈
- UniApp
- Vue.js 2.x
- uView UI (UniApp 组件库)
- Vuex
- Axios

#### 开发命令
- 安装依赖:npm install
- 开发环境运行:使用 HBuilderX 运行到对应平台
- 生产环境构建:使用 HBuilderX 发行到对应平台

前端与后端交互

前端项目通过 API 接口与后端进行交互,主要配置如下:

管理端 API 配置


- 开发环境:admin/.env.dev 文件中的 VUE_APP_API_URL
- 生产环境:admin/.env.production 文件中的 VUE_APP_API_URL

移动端 API 配置


- 配置文件:uni-app/config/api.js
- API 基础路径:baseURL 变量

部署说明

管理端部署


1. 执行构建命令:npm run build
2. 将 admin/dist 目录下的文件部署到 Web 服务器
3. 配置 Nginx 或 Apache 服务器,指向构建后的静态文件

移动端部署


1. 使用 HBuilderX 打开 uni-app 目录
2. 根据需要发行到对应平台:
- 微信小程序:发行 -> 小程序-微信
- H5:发行 -> H5
- App:发行 -> 原生 App-云打包

开发规范

代码风格


- 遵循 Vue 官方风格指南
- 使用 ESLint 进行代码检查
- 组件名使用 PascalCase
- 方法和变量名使用 camelCase

命名规范


- 文件和目录名使用 kebab-case
- 组件名使用 PascalCase
- 常量使用全大写,单词间用下划线分隔

目录使用


- api/:按模块组织 API 接口
- components/:存放可复用组件
- pages/:存放页面组件
- utils/:存放工具函数
- styles/:存放全局样式

注意事项

1. API 接口:前端项目需要与后端 API 接口保持一致,如有接口变更,需要同步修改前端代码。

2. 环境配置:不同环境下的 API 地址需要在对应配置文件中修改。

3. 依赖管理:使用 npm 管理项目依赖,确保依赖版本的一致性。

4. 构建优化:生产环境构建时会自动进行代码压缩和优化。

5. 跨域处理:开发环境下使用 Vue CLI 的代理配置处理跨域问题,生产环境需要在服务器端配置 CORS。

6. 性能优化
- 合理使用组件懒加载
- 优化图片资源
- 减少不必要的 API 请求
- 使用缓存减少重复数据获取

常见问题

1. 开发环境 API 调用失败


- 检查 .env.dev 文件中的 API 地址是否正确
- 检查后端服务是否正常运行
- 检查网络连接是否正常

2. 构建后页面空白


- 检查路由配置是否正确
- 检查是否有未捕获的错误
- 检查静态资源路径是否正确

3. 移动端适配问题


- 使用 Flex 布局进行响应式设计
- 针对不同设备尺寸进行适配
- 测试不同设备的显示效果

联系与支持

- 官方文档:https://doc.crmeb.com
- 技术社区:https://www.crmeb.com/ask
- 官方 QQ 群:请参考官方网站

版本信息

- CRMEB 版本:5.6.4
- 管理端前端:Vue 2.x + Element UI
- 移动端前端:UniApp

---

说明:本目录为前端项目代码,后端代码位于项目根目录的 crmeb/ 目录中。

---

Template/Admin/README (template/admin/README.md)

CRMEB Admin

开发规范

统一使用ES6 语法
方法注释
/*
* th => 表头
* data => 数据
* fileName => 文件名
* fileType => 文件类型
* sheetName => sheet页名
*/
export default function toExcel ({ th, data, fileName, fileType, sheetName })
行注释 //

命名

页面目录 文件夹命名格式骆驼式命名法,例如:用户列表 userList
例如:商品模块
product 商品
├─ product 商品管理
├─ productList 商品管理目录
├─ index.vue 首页
├─ components 组建
├─ tableFrom.vue
├─ tableList.vue
├─ handle 操作功能页面目录
├─ delete.vue
├─ productCategory 商品分类目录
├─ index.vue 商品分类首页

页面命名、组建、文件夹 命名格式小驼峰命名法,例如:用户列表 userList

类名函数命名 大驼峰式 例如:addUser
变量命名 小驼峰式 例如:user 或者 userInfo _userinfo user-info
常量 采用全大些下划线命名 例如:VUE_APP_API_URl

文件管理规范


pages 页面模块必须件文件夹区分
api 接口一个模块一个文件
组建 一个组建一个文件夹
plugins 插件一个插件一个文件夹
vuex 路由状态管理,一个模块在modules 中建一个文件夹
router 一个模块一个模块在modules 中建一个文件夹
style 样式尽量采用iView自带组建,common.less 系统通用样式不要轻易动
自定义通用样式 style.less,每次添加必须加注释,页面独立样式在在页面内写,后缀less 格式
组建样式 styles 中添加文件夹 composents 对应components 目录新建样式文件
utils 自定义工具js 独立命名,一般不用新建文件夹

模块命名


~~~
├─ product 商品管理
├─ user 用户管理
├─ order 系统订单管理
├─ setting 系统设置维护 系统权限管理、系统菜单管理 客服管理
├─ chat 客服管理(列表,添加,删除,编辑)
├─ application 各个应用模块功能管理公众号、小程序、支付宝、百度小程序、今日头条小程序
├─ system 系统更新日志 数据库管理
├─ finance 财务管理
├─ agent 分销管理
├─ marketing 优惠券、积分、拼团、砍价、秒杀
├─ echarts 数据统计分析
├─ notification 消息通知管理、模版消息(列表,通知,添加,编辑)、短信
├─ file 附件文件管理
├─ freight 运费模版管理 物流公司
├─ merchant 商户管理
├─ widget 组件 小插件
└─ cms 文章管理
~~~

目录结构


主要目录结构及说明:
~~~
├── public # 静态资源
│ ├── favicon.ico # favicon图标
│ └── index.html # html 模板
├── src # 源代码
│ ├── api # 所有请求
│ │ └──account.js # 有关登录的接口
│ │ └──agent.js # 有关分销的接口
│ │ └──app.js # 有关应用(小程序、公众号)的接口
│ │ └──cms.js # 有关内容(文章管理、分类)的接口
│ │ └──common.js # 表格删除、获取消息提醒的接口
│ │ └──finance.js # 有关财务的接口
│ │ └──index.js # 有关首页的接口
│ │ └──marketing.js # 有关营销的接口
│ │ └──order.js # 有关订单的接口
│ │ └──product.js # 有关商品的接口
│ │ └──setting.js # 有关设置的接口
│ │ └──system.js # 有关维护(开发配置、安全维护)的接口
│ │ └──systemAdmin.js # 有关管理员的接口(设置--管理权限--管理员列表)
│ │ └──systemMenus.js # 有关权限规则的接口(设置--管理权限--权限规则)
│ │ └──uploadPictures.js # 有关上传图片附件的接口
│ │ └──user.js # 有关会员的接口
│ ├── assets # 图片、svg 等静态资源
│ ├── components # 公共组件
│ │ └──cards # 统计
│ │ └──copyright # 页面footer的底部声明
│ │ └──customerInfo # 选择用户
│ │ └──echarts # 统计图
│ │ └──freightTemplate # 运费模板
│ │ └──from # 生成表单
│ │ └──goodsList # 商品列表
│ │ └──iconFrom # 导航添加图标
│ │ └──link # a连接
│ │ └──mde # 多文本框
│ │ └──modelSure # 确认模态框
│ │ └──newsCategory # 图文管理页
│ │ └──publicSearchFrom # 头部搜索(没用到)
│ │ └──quill # 编辑器(没用到)
│ │ └──referrerInfo # 推荐人信息
│ │ └──searchFrom # 订单页的搜索
│ │ └──sendCoupons # 发送优惠券
│ │ └──systemStore # 添加提货点
│ │ └──uploadPictures # 上传图片
│ │ └──uploadVideo # 上传视频(用于商品编辑器里面)
│ ├── i18n # 多语言
│ ├── layouts # 布局
│ │ └──header-breadcrumb # 头部面包屑样式
│ │ └──header-collapse # 头部控制折叠面板的图标
│ │ └──header-fullscreen # 头部控制是否全屏的图标
│ │ └──header-i18n # 头部控制多语言
│ │ └──header-log # 头部控制日志异常图标
│ │ └──header-logo # 头部logo
│ │ └──header-notice # 头部提示消息
│ │ └──header-reload # 头部控制刷新的图标
│ │ └──header-search # 头部搜索
│ │ └──header-setting # 设置页面风格
│ │ └──header-user # 我的(个人中心、退出登录)
│ │ └──menu-head #
│ │ └──menu-side # 侧边导航栏
│ │ └──tabs # 头部的横向导航标签
│ │ └──mixins # 用于横向滚动获取title的一个js
│ ├── libs # 公共方法
│ ├── menu # 菜单配置
│ ├── mixins # 通用混合
│ ├── mock # 数据模拟
│ ├── pages # 所有页面
│ │ └──account # 有关登录页
│ │ └──login # 登录
│ │ └──register # 注册
│ │ └──agent # 分销
│ │ └──agentManage # 分销员管理
│ │ └──app # 应用
│ │ └──routine # 小程序模板消息
│ │ └──wechat # 公众号
│ │ └──menus # 微信菜单
│ │ └──newsCategory # 图文管理
│ │ └──save # 图文添加
│ │ └──reply # 自动回复
│ │ └──follow # 微信关注回复/无效关键词回复
│ │ └──keyword # 关键字回复
│ │ └──user # 用户
│ │ └──tag # 用户标签
│ │ └──user # 微信用户
│ │ └──message # 用户行为记录
│ │ └──cms # 内容
│ │ └──addArticle # 添加文章/编辑文章
│ │ └──article # 文章管理
│ │ └──articleCategory # 文章分类
│ │ └──finance # 财务
│ │ └──commission # 佣金记录
│ │ └──financialRecords # 财务记录
│ │ └──bill # 资金记录
│ │ └──recharge # 充值记录
│ │ └──userExtract # 提现申请
│ │ └──index # 主页
│ │ └──marketing # 营销
│ │ └──storeBargain # 砍价商品
│ │ └──storeCombination # 拼团管理
│ │ └──combinaList # 拼团列表
│ │ └──create # 添加拼团商品
│ │ └──index # 拼团商品
│ │ └──storeCoupon # 优惠券制作
│ │ └──storeCouponIssue # 优惠券列表
│ │ └──storeCouponUser # 会员领取记录
│ │ └──storeSeckill # 秒杀管理
│ │ └──index # 秒杀商品
│ │ └──create # 添加秒杀商品
│ │ └──userPoint # 积分日志
│ │ └──notify # 短信设置
│ │ └──smsConfig # 短信账户
│ │ └──smsPay # 短信购买
│ │ └──smsTemplateApply # 短信模板
│ │ └──order # 订单管理
│ │ └──product # 商品
│ │ └──productAdd # 添加商品
│ │ └──productAttr # 商品规格
│ │ └──productClassify # 商品分类
│ │ └──productList # 商品管理
│ │ └──productReply # 商品评论管理
│ │ └──setting # 设置
│ │ └──cityDada # 城市数据
│ │ └──clerkList # 核销员管理
│ │ └──freight # 物流公司
│ │ └──setSystem # 系统设置
│ │ └──shippingTemplates # 运费模板
│ │ └──storeList # 提货点列表
│ │ └──storeService # 客服管理
│ │ └──systemAdmin # 管理员列表
│ │ └──systemMenus # 权限规则
│ │ └──systemRole # 身份管理
│ │ └──systemStore # 门店设置
│ │ └──user # 个人中心
│ │ └──verifyOrder # 核销订单
│ │ └──system # 维护
│ │ └──auth # 商业授权
│ │ └──clear # 刷新缓存
│ │ └──configTab # 配置
│ │ └──index # 配置分类
│ │ └──list # 配置列表
│ │ └──error # 错误页
│ │ └──403 # 403
│ │ └──404 # 404
│ │ └──500 # 500
│ │ └──group # 组合数据
│ │ └──maintain
│ │ └──systemCleardata # 清除数据
│ │ └──systemDatabackup # 数据备份
│ │ └──systemFile # 文件校验
│ │ └──opendir # 文件管理
│ │ └──systemLog # 系统日志
│ │ └──user # 会员
│ │ └──group # 会员分组
│ │ └──label # 会员标签
│ │ └──level # 会员等级
│ │ └──list # 会员管理
│ ├── plugins # 插件
│ ├── router # 路由配置
│ │ └──modules # 页面路由模块
│ │ └──agent.js # 有关分销
│ │ └──app.js # 有关应用(小程序、公众号)
│ │ └──cms.js # 有关内容(文章管理、文章分类)
│ │ └──echarts.js # 有关统计
│ │ └──finance.js # 有关财务
│ │ └──index.js # 有关主页
│ │ └──marketing.js # 有关营销
│ │ └──order.js # 有关订单
│ │ └──product.js # 有关商品
│ │ └──setting.js # 有关设置
│ │ └──system.js # 有关维护
│ │ └──user.js # 有关会员
│ │ └──index.js # 路由的导出以及拦截处理
│ │ └──routes.js # 路由的汇总
│ ├── store # Vuex 状态管理
│ ├── utils # js工具
│ │ └──authLapse.js # 授权提示框
│ │ └──modalForm.js # 表单模态框
│ │ └──videoCloud.js # 上传云储存视频(七牛、腾讯、阿里)
│ │ └──validate.js # 将时间戳转化成时间;
│ │ └──public.js # 询问模态框;
│ ├── styles # 样式管理
│ ├── setting.env.js # 开发配置文件
│ ├── setting.js # 业务配置文件
│ ├── main.js # 入口文件 加载组件 初始化等
│ └── App.vue # 入口页面
├── tests # 测试管理
├── alias.config.js # 别名,仅用于配置 WebStorm 识别别名,无实际用处
├── babel.config.js # babel 配置
├── jest.config.js # jest 配置
├── package.json # package.json
└── vue.config.js # Vue CLI 3 配置
~~~

开发打包项目


~~~

进入项目目录


$ cd admin

安装依赖


$ npm install

启动项目(本地开发环境)


$ npm run dev

打包项目


$ npm run build
~~~

配置请求域名


开发环境配置


配置文件地址:/.env.dev

请求域名配置

$ VUE_APP_API_URL='http://自己的域名/adminapi'

生产环境

接口请求地址 (http)或 (https)://www.crmeb.com(换成你的域名)/adminapi 非独立部署默认为空

$ VUE_APP_API_URL=''

---

Template/Admin/Package.Json (template/admin/package.json)

{
"name": "from-crmeb-admin",
"version": "5.7.0",
"author": "sugar1569<[email protected]>",
"private": false,
"scripts": {
"serve": "node src/libs/start.js && vue-cli-service serve --open --mode=dev",
"dev": "node src/libs/start.js && vue-cli-service serve --open --mode=dev",
"build": "vue-cli-service build --mode=production",
"eslint:comment": "使用 ESLint 检查并自动修复 src 目录下所有扩展名为 .js 和 .vue 的文件",
"eslint": "eslint --ext .js,.vue,.ts --ignore-path .gitignore --fix src",
"prettier:comment": "自动格式化当前目录下的所有文件",
"prettier": "prettier --write ."
},
"dependencies": {
"@babel/polyfill": "^7.12.1",
"@babel/runtime": "^7.2.0",
"@better-scroll/core": "^2.0.5",
"@form-create/element-ui": "^2.5.31",
"async-validator": "^3.4.0",
"awe-dnd": "^0.3.4",
"better-scroll": "^1.15.2",
"clipboard": "^2.0.0",
"codemirror": "^5.38.0",
"core-js": "^3.32.2",
"cos-js-sdk-v5": "^0.5.26",
"countup": "^1.8.2",
"cropperjs": "^1.2.2",
"crypto-js": "^4.1.1",
"dayjs": "^1.7.7",
"echarts": "^4.8.0",
"editor": "^1.0.0",
"element-ui": "2.15.6",
"emoji-awesome": "0.0.2",
"exceljs": "^4.3.0",
"file-saver": "^2.0.5",
"html2canvas": "^1.0.0-alpha.12",
"js-cookie": "^2.2.0",
"js-md5": "^0.7.3",
"lodash": "^4.17.10",
"moment": "^2.29.1",
"monaco-editor": "^0.28.1",
"monaco-editor-webpack-plugin": "^4.2.0",
"oss": "0.0.1",
"print-js": "^1.6.0",
"qiniu-js": "^2.5.5",
"qrcodejs2": "0.0.2",
"qs": "^6.6.0",
"quill": "^1.3.6",
"screenfull": "^5.0.2",
"sortablejs": "^1.15.0",
"swiper": "^5.4.5",
"tree-table-vue": "^1.1.0",
"uglifyjs-webpack-plugin": "^2.2.0",
"v-org-tree": "^1.0.6",
"v-viewer": "^1.5.1",
"vue": "^2.5.10",
"vue-awesome-swiper": "^4.1.1",
"vue-clipboard2": "^0.3.3",
"vue-codemirror": "^4.0.6",
"vue-cropper": "^0.5.11",
"vue-happy-scroll": "^2.1.1",
"vue-i18n": "^7.8.0",
"vue-pickers": "^2.5.3",
"vue-puzzle-vcode": "^1.1.9",
"vue-router": "^3.0.1",
"vue-tree-list": "^1.5.0",
"vue-ydui": "^1.2.6",
"vuedraggable": "^2.16.0",
"vuescroll": "^4.16.1",
"vuex": "^3.0.1",
"vuex-persist": "^2.2.0",
"vxe-pc-ui": "^3.7.5",
"vxe-table": "^3.16.3",
"wangeditor": "^4.7.15",
"xe-utils": "^3.5.4",
"xlsx": "^0.13.5"
},
"devDependencies": {
"@babel/cli": "^7.21.0",
"@babel/core": "^7.21.0",
"@babel/node": "^7.20.7",
"@babel/plugin-transform-runtime": "^7.2.0",
"@babel/preset-env": "^7.20.2",
"@vue/cli-plugin-babel": "^4.4.6",
"@vue/cli-plugin-eslint": "^5.0.8",
"@vue/cli-plugin-unit-jest": "^3.2.3",
"@vue/cli-plugin-unit-mocha": "^3.0.1",
"@vue/cli-service": "^3.0.1",
"@vue/eslint-config-prettier": "^7.0.0",
"@vue/eslint-config-standard": "^3.0.0-beta.10",
"axios": "^0.18.1",
"compression-webpack-plugin": "^6.1.1",
"eslint": "^7.15.0",
"eslint-loader": "^4.0.2",
"eslint-plugin-cypress": "^2.0.1",
"eslint-plugin-prettier": "^3.4.1",
"eslint-plugin-vue": "^7.2.0",
"jsencrypt": "^3.3.2",
"lint-staged": "^6.0.0",
"prettier": "^2.5.1",
"sass": "^1.69.5",
"sass-loader": "^10.4.1",
"script-loader": "^0.7.2",
"svg-sprite-loader": "^3.8.0",
"text-loader": "0.0.1",
"vue-lazyload": "^1.3.3",
"vue-template-compiler": "^2.5.13",
"vue-waterfall-easy": "^2.4.4"
},
"engines": {
"node": ">14.0.0 < 23.0.0",
"npm": ">=6"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
],
"gitHooks": {
"pre-commit": "lint-staged"
},
"lint-staged": {
"*.js": [
"vue-cli-service lint",
"git add"
],
"*.vue": [
"vue-cli-service lint",
"git add"
]
}
}

---

Template/Admin/.Travis.Yml (template/admin/.travis.yml)

language: node_js
node_js: stable
script: npm run lint
notifications:
email: false

---

Template/Admin/Public/Manifest.Json (template/admin/public/manifest.json)

{
"name":"CRMEB",
"display":"standalone",
"start_url":".",
"id": "index.html",
"background_color": "#999",
"theme_color":"#292d3e",
"icons":[{
"src":"./image/logo-small.png",
"sizes":"144x144",
"type":"image/png"
}]
}

---

Template/Admin/Src/Assets/IconfontYI/IconfontYI.Json (template/admin/src/assets/iconfontYI/iconfontYI.json)

{
"id": "993865",
"name": "商城模板—第三方修改",
"font_family": "iconfontYI",
"css_prefix_text": "icon-",
"description": "外包项目图标添加",
"glyphs": [
{
"icon_id": "160836",
"name": "精品推荐",
"font_class": "jingpintuijian",
"unicode": "e60d",
"unicode_decimal": 58893
},
{
"icon_id": "464461",
"name": "笑脸",
"font_class": "xiaolian",
"unicode": "e60f",
"unicode_decimal": 58895
},
{
"icon_id": "539040",
"name": "推广",
"font_class": "tuiguang",
"unicode": "e63b",
"unicode_decimal": 58939
},
{
"icon_id": "689324",
"name": "圆点小",
"font_class": "yuandianxiao",
"unicode": "e82f",
"unicode_decimal": 59439
},
{
"icon_id": "720963",
"name": "搜索",
"font_class": "xiazai5",
"unicode": "e605",
"unicode_decimal": 58885
},
{
"icon_id": "872548",
"name": "支付宝",
"font_class": "icon34",
"unicode": "e62b",
"unicode_decimal": 58923
},
{
"icon_id": "926111",
"name": "打电话-01",
"font_class": "dadianhua01",
"unicode": "e623",
"unicode_decimal": 58915
},
{
"icon_id": "1090230",
"name": "点选",
"font_class": "webicon318",
"unicode": "e6c2",
"unicode_decimal": 59074
},
{
"icon_id": "1141383",
"name": "关闭",
"font_class": "iconfontguanbi",
"unicode": "e643",
"unicode_decimal": 58947
},
{
"icon_id": "1207404",
"name": "拍照",
"font_class": "icon25201",
"unicode": "e70d",
"unicode_decimal": 59149
},
{
"icon_id": "1518998",
"name": "促销管理",
"font_class": "cuxiaoguanli",
"unicode": "e60e",
"unicode_decimal": 58894
},
{
"icon_id": "1534823",
"name": "秒杀",
"font_class": "miaosha",
"unicode": "e6c3",
"unicode_decimal": 59075
},
{
"icon_id": "1671897",
"name": "会员",
"font_class": "huiyuan",
"unicode": "e60b",
"unicode_decimal": 58891
},
{
"icon_id": "1727266",
"name": "05采购-线性",
"font_class": "caigou-xianxing",
"unicode": "e887",
"unicode_decimal": 59527
},
{
"icon_id": "1727267",
"name": "05采购",
"font_class": "caigou",
"unicode": "e888",
"unicode_decimal": 59528
},
{
"icon_id": "1727371",
"name": "30应用程序-线性",
"font_class": "yingyongchengxu-xianxing",
"unicode": "e8a1",
"unicode_decimal": 59553
},
{
"icon_id": "1727372",
"name": "30应用程序",
"font_class": "yingyongchengxu",
"unicode": "e8a2",
"unicode_decimal": 59554
},
{
"icon_id": "1727379",
"name": "33资源-线性",
"font_class": "ziyuan-xianxing",
"unicode": "e8a4",
"unicode_decimal": 59556
},
{
"icon_id": "1727423",
"name": "204首页",
"font_class": "shouye",
"unicode": "e8b9",
"unicode_decimal": 59577
},
{
"icon_id": "1727424",
"name": "204首页-线性",
"font_class": "shouye-xianxing",
"unicode": "e8ba",
"unicode_decimal": 59578
},
{
"icon_id": "1727458",
"name": "224用户-线性",
"font_class": "yonghu-xianxing",
"unicode": "e8c8",
"unicode_decimal": 59592
},
{
"icon_id": "1727459",
"name": "224用户",
"font_class": "yonghu",
"unicode": "e8c9",
"unicode_decimal": 59593
},
{
"icon_id": "1727598",
"name": "411地图",
"font_class": "ditu",
"unicode": "e906",
"unicode_decimal": 59654
},
{
"icon_id": "1780995",
"name": "搜索",
"font_class": "sousuo2",
"unicode": "e757",
"unicode_decimal": 59223
},
{
"icon_id": "1850915",
"name": "订单",
"font_class": "2",
"unicode": "e684",
"unicode_decimal": 59012
},
{
"icon_id": "1852350",
"name": "地址",
"font_class": "dizhi",
"unicode": "e608",
"unicode_decimal": 58888
},
{
"icon_id": "1857286",
"name": "皇冠2",
"font_class": "huangguan",
"unicode": "e624",
"unicode_decimal": 58916
},
{
"icon_id": "1857287",
"name": "皇冠3",
"font_class": "huangguan1",
"unicode": "e625",
"unicode_decimal": 58917
},
{
"icon_id": "1857288",
"name": "皇冠",
"font_class": "huangguan2",
"unicode": "e626",
"unicode_decimal": 58918
},
{
"icon_id": "1983323",
"name": "物流",
"font_class": "wuliu",
"unicode": "e6f2",
"unicode_decimal": 59122
},
{
"icon_id": "2051400",
"name": "选中",
"font_class": "xuanzhong",
"unicode": "e615",
"unicode_decimal": 58901
},
{
"icon_id": "2121745",
"name": "新品",
"font_class": "xinpin",
"unicode": "e610",
"unicode_decimal": 58896
},
{
"icon_id": "2182776",
"name": "箭头",
"font_class": "arrow",
"unicode": "e627",
"unicode_decimal": 58919
},
{
"icon_id": "2203117",
"name": "余额支付",
"font_class": "yuezhifu",
"unicode": "e65e",
"unicode_decimal": 58974
},
{
"icon_id": "2351436",
"name": "编辑",
"font_class": "bianji",
"unicode": "e6cc",
"unicode_decimal": 59084
},
{
"icon_id": "2360857",
"name": "问题",
"font_class": "wenti",
"unicode": "e758",
"unicode_decimal": 59224
},
{
"icon_id": "2540845",
"name": "钱袋 (1) (3)",
"font_class": "qiandai",
"unicode": "e6b1",
"unicode_decimal": 59057
},
{
"icon_id": "2551763",
"name": "向右",
"font_class": "xiangyou",
"unicode": "e679",
"unicode_decimal": 59001
},
{
"icon_id": "2553385",
"name": "排行",
"font_class": "paihang",
"unicode": "e73e",
"unicode_decimal": 59198
},
{
"icon_id": "2559567",
"name": "位置",
"font_class": "weizhi",
"unicode": "e62d",
"unicode_decimal": 58925
},
{
"icon_id": "2562049",
"name": "热门",
"font_class": "remen",
"unicode": "e67c",
"unicode_decimal": 59004
},
{
"icon_id": "2664568",
"name": "团队",
"font_class": "tuandui",
"unicode": "e685",
"unicode_decimal": 59013
},
{
"icon_id": "2672470",
"name": "余额支付",
"font_class": "yuezhifu1",
"unicode": "e61a",
"unicode_decimal": 58906
},
{
"icon_id": "2681908",
"name": "用户",
"font_class": "yonghu2",
"unicode": "e60a",
"unicode_decimal": 58890
},
{
"icon_id": "2762285",
"name": "拼团",
"font_class": "hebingxingzhuang",
"unicode": "e656",
"unicode_decimal": 58966
},
{
"icon_id": "2762614",
"name": "购物车",
"font_class": "gouwuche1",
"unicode": "e642",
"unicode_decimal": 58946
},
{
"icon_id": "2808105",
"name": "浏览",
"font_class": "liulan",
"unicode": "e629",
"unicode_decimal": 58921
},
{
"icon_id": "2980623",
"name": "金币",
"font_class": "jinbi1",
"unicode": "e655",
"unicode_decimal": 58965
},
{
"icon_id": "3034678",
"name": "关闭",
"font_class": "guanbi2",
"unicode": "e61c",
"unicode_decimal": 58908
},
{
"icon_id": "3054938",
"name": "搜索",
"font_class": "sousuo",
"unicode": "e67d",
"unicode_decimal": 59005
},
{
"icon_id": "3131690",
"name": "微信",
"font_class": "weixin",
"unicode": "e600",
"unicode_decimal": 58880
},
{
"icon_id": "3185373",
"name": "微信",
"font_class": "weixin3",
"unicode": "e618",
"unicode_decimal": 58904
},
{
"icon_id": "3203334",
"name": "排行",
"font_class": "paihang1",
"unicode": "e633",
"unicode_decimal": 58931
},
{
"icon_id": "3232659",
"name": "统计 (1)",
"font_class": "tongji",
"unicode": "e687",
"unicode_decimal": 59015
},
{
"icon_id": "3355930",
"name": "菜单",
"font_class": "caidan",
"unicode": "e62a",
"unicode_decimal": 58922
},
{
"icon_id": "3402041",
"name": "二维码",
"font_class": "erweima",
"unicode": "e607",
"unicode_decimal": 58887
},
{
"icon_id": "3416446",
"name": "收 藏",
"font_class": "shoucang",
"unicode": "e606",
"unicode_decimal": 58886
},
{
"icon_id": "3453309",
"name": "减",
"font_class": "jian",
"unicode": "e621",
"unicode_decimal": 58913
},
{
"icon_id": "3577985",
"name": "加",
"font_class": "jia",
"unicode": "e7e0",
"unicode_decimal": 59360
},
{
"icon_id": "3584611",
"name": "关 闭",
"font_class": "guanbi",
"unicode": "e62f",
"unicode_decimal": 58927
},
{
"icon_id": "3751425",
"name": "向上",
"font_class": "xiangshang1",
"unicode": "e622",
"unicode_decimal": 58914
},
{
"icon_id": "3790017",
"name": "说明",
"font_class": "shuoming",
"unicode": "e630",
"unicode_decimal": 58928
},
{
"icon_id": "3844134",
"name": "下拉",
"font_class": "xiala",
"unicode": "e67f",
"unicode_decimal": 59007
},
{
"icon_id": "3845489",
"name": "排列2",
"font_class": "pailie",
"unicode": "e61b",
"unicode_decimal": 58907
},
{
"icon_id": "3931371",
"name": "分享",
"font_class": "fenxiang",
"unicode": "e603",
"unicode_decimal": 58883
},
{
"icon_id": "3968583",
"name": "银行卡",
"font_class": "yinhangqia",
"unicode": "e72c",
"unicode_decimal": 59180
},
{
"icon_id": "4018497",
"name": "搜索01",
"font_class": "sousuo1",
"unicode": "e64c",
"unicode_decimal": 58956
},
{
"icon_id": "4018775",
"name": "对号01",
"font_class": "duihao",
"unicode": "e64e",
"unicode_decimal": 58958
},
{
"icon_id": "4133807",
"name": "订单",
"font_class": "dingdan",
"unicode": "e61e",
"unicode_decimal": 58910
},
{
"icon_id": "4182111",
"name": "图片排列",
"font_class": "tupianpailie",
"unicode": "e620",
"unicode_decimal": 58912
},
{
"icon_id": "4432686",
"name": "充值",
"font_class": "chongzhi",
"unicode": "e602",
"unicode_decimal": 58882
},
{
"icon_id": "4603167",
"name": "设置",
"font_class": "shezhi",
"unicode": "e619",
"unicode_decimal": 58905
},
{
"icon_id": "4769807",
"name": "个人中心",
"font_class": "gerenzhongxin",
"unicode": "e636",
"unicode_decimal": 58934
},
{
"icon_id": "4770063",
"name": "首页",
"font_class": "shouye1",
"unicode": "e637",
"unicode_decimal": 58935
},
{
"icon_id": "4770130",
"name": "购物车",
"font_class": "gouwuche2",
"unicode": "e638",
"unicode_decimal": 58936
},
{
"icon_id": "4919800",
"name": "说明",
"font_class": "shuoming1",
"unicode": "e673",
"unicode_decimal": 58995
},
{
"icon_id": "4943660",
"name": "对号",
"font_class": "duihao2",
"unicode": "e601",
"unicode_decimal": 58881
},
{
"icon_id": "5087448",
"name": "选中",
"font_class": "complete",
"unicode": "e646",
"unicode_decimal": 58950
},
{
"icon_id": "5110066",
"name": "微信",
"font_class": "weixin1",
"unicode": "e66e",
"unicode_decimal": 58990
},
{
"icon_id": "5116806",
"name": "线下支付",
"font_class": "xianxiazhifu",
"unicode": "e6e1",
"unicode_decimal": 59105
},
{
"icon_id": "5174616",
"name": "添加地址",
"font_class": "tianjiadizhi",
"unicode": "e640",
"unicode_decimal": 58944
},
{
"icon_id": "5236609",
"name": "微信",
"font_class": "weixin2",
"unicode": "e604",
"unicode_decimal": 58884
},
{
"icon_id": "5258701",
"name": "购物车",
"font_class": "gouwuche",
"unicode": "e669",
"unicode_decimal": 58985
},
{
"icon_id": "5301920",
"name": "加载",
"font_class": "jiazai",
"unicode": "e62c",
"unicode_decimal": 58924
},
{
"icon_id": "5383811",
"name": "新闻通知",
"font_class": "huabanfuben",
"unicode": "e654",
"unicode_decimal": 58964
},
{
"icon_id": "5387815",
"name": "客服_o",
"font_class": "kefu_o",
"unicode": "eb63",
"unicode_decimal": 60259
},
{
"icon_id": "5387821",
"name": "礼物_o",
"font_class": "liwu_o",
"unicode": "eb65",
"unicode_decimal": 60261
},
{
"icon_id": "5387908",
"name": "按钮_箭头展开_o",
"font_class": "anniu_jiantouzhankai_o",
"unicode": "eb89",
"unicode_decimal": 60297
},
{
"icon_id": "5387922",
"name": "箭头_下一页_o",
"font_class": "jiantou_xiayiye_o",
"unicode": "eb8f",
"unicode_decimal": 60303
},
{
"icon_id": "5387926",
"name": "箭头_上下切换_o",
"font_class": "jiantou_shangxiaqiehuan_o",
"unicode": "eb90",
"unicode_decimal": 60304
},
{
"icon_id": "5387950",
"name": "上下展开_o",
"font_class": "shangxiazhankai_o",
"unicode": "eb9a",
"unicode_decimal": 60314
},
{
"icon_id": "5387958",
"name": "货币流_o",
"font_class": "huobiliu_o",
"unicode": "eb9f",
"unicode_decimal": 60319
},
{
"icon_id": "5387967",
"name": "金币_o",
"font_class": "jinbi_o",
"unicode": "eba1",
"unicode_decimal": 60321
},
{
"icon_id": "5387990",
"name": "个人头像_o",
"font_class": "gerentouxiang_o",
"unicode": "ebac",
"unicode_decimal": 60332
},
{
"icon_id": "5387992",
"name": "群组_o",
"font_class": "qunzu_o",
"unicode": "ebad",
"unicode_decimal": 60333
},
{
"icon_id": "5387993",
"name": "电话_o",
"font_class": "dianhua_o",
"unicode": "ebaf",
"unicode_decimal": 60335
},
{
"icon_id": "5387995",
"name": "收藏_o",
"font_class": "shoucang_o",
"unicode": "ebae",
"unicode_decimal": 60334
},
{
"icon_id": "5388009",
"name": "云上传_o",
"font_class": "yunshangchuan_o",
"unicode": "ebb3",
"unicode_decimal": 60339
},
{
"icon_id": "5388011",
"name": "饼图_o",
"font_class": "bingtu_o",
"unicode": "ebb4",
"unicode_decimal": 60340
},
{
"icon_id": "5388017",
"name": "包裹_环保盒_o",
"font_class": "baoguo_huanbaohe_o",
"unicode": "ebb6",
"unicode_decimal": 60342
},
{
"icon_id": "5388018",
"name": "包裹_取消收货_o",
"font_class": "baoguo_quxiaoshouhuo_o",
"unicode": "ebb7",
"unicode_decimal": 60343
},
{
"icon_id": "5388019",
"name": "包裹_收货_o",
"font_class": "baoguo_shouhuo_o",
"unicode": "ebb8",
"unicode_decimal": 60344
},
{
"icon_id": "5388020",
"name": "包裹_领件_o",
"font_class": "baoguo_lingjian_o",
"unicode": "ebb9",
"unicode_decimal": 60345
},
{
"icon_id": "5388021",
"name": "包裹_收纳_o",
"font_class": "baoguo_shouna_o",
"unicode": "ebbe",
"unicode_decimal": 60350
},
{
"icon_id": "5388026",
"name": "地点定位_o",
"font_class": "didiandingwei_o",
"unicode": "ebba",
"unicode_decimal": 60346
},
{
"icon_id": "5441298",
"name": "折扣",
"font_class": "zhekou",
"unicode": "e790",
"unicode_decimal": 59280
},
{
"icon_id": "5452215",
"name": "喇叭",
"font_class": "laba",
"unicode": "e612",
"unicode_decimal": 58898
},
{
"icon_id": "5860911",
"name": "权限管理锁子",
"font_class": "quanxianguanlisuozi",
"unicode": "e6d2",
"unicode_decimal": 59090
},
{
"icon_id": "5996196",
"name": "右键",
"font_class": "youjian",
"unicode": "e677",
"unicode_decimal": 58999
},
{
"icon_id": "6091393",
"name": "下 拉",
"font_class": "xiala1",
"unicode": "e609",
"unicode_decimal": 58889
},
{
"icon_id": "6133627",
"name": "微信支付",
"font_class": "weixinzhifu",
"unicode": "e632",
"unicode_decimal": 58930
},
{
"icon_id": "6155492",
"name": "经验值",
"font_class": "jingyanzhi",
"unicode": "e62e",
"unicode_decimal": 58926
},
{
"icon_id": "6194276",
"name": "更多",
"font_class": "up",
"unicode": "e617",
"unicode_decimal": 58903
},
{
"icon_id": "6265459",
"name": "客服",
"font_class": "kefu",
"unicode": "e6b2",
"unicode_decimal": 59058
},
{
"icon_id": "6450775",
"name": "审核中",
"font_class": "shenhezhong",
"unicode": "e6ce",
"unicode_decimal": 59086
},
{
"icon_id": "6582604",
"name": "砍价",
"font_class": "kanjia1",
"unicode": "e613",
"unicode_decimal": 58899
},
{
"icon_id": "6636378",
"name": "删 除",
"font_class": "shanchu1",
"unicode": "e611",
"unicode_decimal": 58897
},
{
"icon_id": "6783580",
"name": "支付宝",
"font_class": "zhifubao",
"unicode": "e61d",
"unicode_decimal": 58909
},
{
"icon_id": "6825609",
"name": "用户",
"font_class": "yonghu1",
"unicode": "e644",
"unicode_decimal": 58948
},
{
"icon_id": "6854655",
"name": "功能",
"font_class": "gongneng",
"unicode": "e63a",
"unicode_decimal": 58938
},
{
"icon_id": "6970586",
"name": "锁子",
"font_class": "suozi",
"unicode": "e631",
"unicode_decimal": 58929
},
{
"icon_id": "7133397",
"name": "图标_设备列表轮播图右键头",
"font_class": "jiantou",
"unicode": "e641",
"unicode_decimal": 58945
},
{
"icon_id": "7193264",
"name": "砍价",
"font_class": "kanjia",
"unicode": "e69b",
"unicode_decimal": 59035
},
{
"icon_id": "7246995",
"name": "拼团",
"font_class": "pintuan",
"unicode": "e60c",
"unicode_decimal": 58892
},
{
"icon_id": "7311029",
"name": "编辑",
"font_class": "bianji1",
"unicode": "e614",
"unicode_decimal": 58900
},
{
"icon_id": "7341104",
"name": "优惠券",
"font_class": "youhuiquan",
"unicode": "e6e4",
"unicode_decimal": 59108
},
{
"icon_id": "7383390",
"name": "分类",
"font_class": "fenleiyemian",
"unicode": "e639",
"unicode_decimal": 58937
},
{
"icon_id": "7467481",
"name": "向右",
"font_class": "xiangxia",
"unicode": "e8ca",
"unicode_decimal": 59594
},
{
"icon_id": "7474826",
"name": "删 除",
"font_class": "shanchu",
"unicode": "e628",
"unicode_decimal": 58920
},
{
"icon_id": "7540338",
"name": "关 闭",
"font_class": "guanbi3",
"unicode": "e6c5",
"unicode_decimal": 59077
},
{
"icon_id": "7559350",
"name": "选中001",
"font_class": "xuanzhong1",
"unicode": "e6ef",
"unicode_decimal": 59119
},
{
"icon_id": "7559357",
"name": "未选中001",
"font_class": "weixuanzhong",
"unicode": "e6f0",
"unicode_decimal": 59120
},
{
"icon_id": "7559551",
"name": "装饰线",
"font_class": "zhuangshixian",
"unicode": "e6f1",
"unicode_decimal": 59121
},
{
"icon_id": "7559552",
"name": "技术支持",
"font_class": "jishuzhichi",
"unicode": "e6f3",
"unicode_decimal": 59123
},
{
"icon_id": "7560557",
"name": "边框001",
"font_class": "biankuang",
"unicode": "e6f4",
"unicode_decimal": 59124
},
{
"icon_id": "7560838",
"name": "关 闭",
"font_class": "guanbi1",
"unicode": "e6f5",
"unicode_decimal": 59125
},
{
"icon_id": "7560940",
"name": "向右",
"font_class": "xiangshang",
"unicode": "ebbb",
"unicode_decimal": 60347
},
{
"icon_id": "7561200",
"name": "¥",
"font_class": "icon-test",
"unicode": "e6f6",
"unicode_decimal": 59126
},
{
"icon_id": "7562923",
"name": "明细",
"font_class": "mingxi",
"unicode": "e6f7",
"unicode_decimal": 59127
},
{
"icon_id": "7562924",
"name": "提升分值",
"font_class": "tishengfenzhi",
"unicode": "e6f8",
"unicode_decimal": 59128
},
{
"icon_id": "7563099",
"name": "拼团成功",
"font_class": "pintuanchenggong",
"unicode": "e6f9",
"unicode_decimal": 59129
},
{
"icon_id": "7563100",
"name": "拼团失败",
"font_class": "pintuanshibai",
"unicode": "e6fa",
"unicode_decimal": 59130
},
{
"icon_id": "7563348",
"name": "实体星",
"font_class": "shitixing",
"unicode": "e6fb",
"unicode_decimal": 59131
},
{
"icon_id": "7563349",
"name": "空心星",
"font_class": "kongxinxing",
"unicode": "e6fc",
"unicode_decimal": 59132
},
{
"icon_id": "7563430",
"name": "已退款",
"font_class": "yituikuan",
"unicode": "e6fd",
"unicode_decimal": 59133
},
{
"icon_id": "7563431",
"name": "退款中",
"font_class": "tuikuanzhong",
"unicode": "e6fe",
"unicode_decimal": 59134
},
{
"icon_id": "7563801",
"name": "菱形",
"font_class": "lingxing",
"unicode": "e6ff",
"unicode_decimal": 59135
},
{
"icon_id": "7583837",
"name": "向右",
"font_class": "xiangzuo",
"unicode": "ebbc",
"unicode_decimal": 60348
},
{
"icon_id": "7766749",
"name": "icon_im_face",
"font_class": "icon_im_face",
"unicode": "eb96",
"unicode_decimal": 60310
},
{
"icon_id": "7766777",
"name": "icon_im_keyboard",
"font_class": "icon_im_keyboard",
"unicode": "eb97",
"unicode_decimal": 60311
},
{
"icon_id": "8037761",
"name": "收 藏",
"font_class": "shoucang1",
"unicode": "e714",
"unicode_decimal": 59156
},
{
"icon_id": "8181204",
"name": "dianhau",
"font_class": "dianhau",
"unicode": "e634",
"unicode_decimal": 58932
},
{
"icon_id": "8902924",
"name": "备注",
"font_class": "zhinengkefu-",
"unicode": "e616",
"unicode_decimal": 58902
},
{
"icon_id": "8906620",
"name": "code_1",
"font_class": "code_",
"unicode": "e723",
"unicode_decimal": 59171
},
{
"icon_id": "8906621",
"name": "code_2",
"font_class": "code_1",
"unicode": "e724",
"unicode_decimal": 59172
},
{
"icon_id": "8906622",
"name": "phone_1",
"font_class": "phone_",
"unicode": "e725",
"unicode_decimal": 59173
},
{
"icon_id": "9136175",
"name": "时间",
"font_class": "shijian",
"unicode": "e635",
"unicode_decimal": 58933
},
{
"icon_id": "9364404",
"name": "向上",
"font_class": "xiangxia2",
"unicode": "ebbd",
"unicode_decimal": 60349
},
{
"icon_id": "9364654",
"name": "选中",
"font_class": "xuanzhong2",
"unicode": "e731",
"unicode_decimal": 59185
},
{
"icon_id": "9364655",
"name": "数据统计",
"font_class": "shujutongji",
"unicode": "e732",
"unicode_decimal": 59186
},
{
"icon_id": "9364656",
"name": "详细数据",
"font_class": "xiangxishuju",
"unicode": "e733",
"unicode_decimal": 59187
},
{
"icon_id": "9364657",
"name": "更多",
"font_class": "gengduo",
"unicode": "e734",
"unicode_decimal": 59188
},
{
"icon_id": "9561662",
"name": "crmeb",
"font_class": "crmeb",
"unicode": "e735",
"unicode_decimal": 59189
},
{
"icon_id": "9895692",
"name": "crmeb2",
"font_class": "crmeb1",
"unicode": "e739",
"unicode_decimal": 59193
},
{
"icon_id": "9896813",
"name": "海报",
"font_class": "haibao",
"unicode": "e73b",
"unicode_decimal": 59195
},
{
"icon_id": "10144788",
"name": "tupian-01",
"font_class": "tupian-",
"unicode": "e73f",
"unicode_decimal": 59199
},
{
"icon_id": "10283513",
"name": "修 改",
"font_class": "xiugai",
"unicode": "e61f",
"unicode_decimal": 58911
},
{
"icon_id": "10717369",
"name": "拼团",
"font_class": "pintuan-copy",
"unicode": "ebbf",
"unicode_decimal": 60351
},
{
"icon_id": "10880067",
"name": "通话",
"font_class": "tonghua",
"unicode": "e740",
"unicode_decimal": 59200
},
{
"icon_id": "11003792",
"name": "个人中心",
"font_class": "gerenzhongxin-copy",
"unicode": "ebc0",
"unicode_decimal": 60352
},
{
"icon_id": "11003799",
"name": "首页",
"font_class": "shouye1-copy",
"unicode": "ebc1",
"unicode_decimal": 60353
},
{
"icon_id": "11003806",
"name": "购物车",
"font_class": "gouwuche2-copy",
"unicode": "ebc2",
"unicode_decimal": 60354
},
{
"icon_id": "11003812",
"name": "分类",
"font_class": "fenleiyemian-copy",
"unicode": "ebc3",
"unicode_decimal": 60355
},
{
"icon_id": "11680690",
"name": "mzshopping01",
"font_class": "mzshopping",
"unicode": "e746",
"unicode_decimal": 59206
},
{
"icon_id": "11680752",
"name": "shouye01",
"font_class": "shouye2",
"unicode": "e748",
"unicode_decimal": 59208
},
{
"icon_id": "11680757",
"name": "fenlei01",
"font_class": "fenlei",
"unicode": "e749",
"unicode_decimal": 59209
},
{
"icon_id": "11680778",
"name": "gouwuche01",
"font_class": "gouwuche3",
"unicode": "e74a",
"unicode_decimal": 59210
},
{
"icon_id": "11680780",
"name": "geren01",
"font_class": "geren",
"unicode": "e74b",
"unicode_decimal": 59211
},
{
"icon_id": "11680785",
"name": "shouye02",
"font_class": "shouye3",
"unicode": "e74c",
"unicode_decimal": 59212
},
{
"icon_id": "11680960",
"name": "fenlei02",
"font_class": "fenlei1",
"unicode": "e74e",
"unicode_decimal": 59214
},
{
"icon_id": "11680989",
"name": "gouwuche02",
"font_class": "gouwuche4",
"unicode": "e74f",
"unicode_decimal": 59215
},
{
"icon_id": "11680996",
"name": "geren02",
"font_class": "geren1",
"unicode": "e750",
"unicode_decimal": 59216
}
]
}

---

Template/Admin/Src/Router/Modules/Crud/README (template/admin/src/router/modules/crud/README.md)

CRMEB ADMIN CRUD 路由存放

此目录下的所有路由会被自动加载到 router,无需其他配置

可以对此路由进行修改删除

---

Template/Uni App/Manifest.Json (template/uni-app/manifest.json)

{
"name" : "CRMEB标准版",
"appid" : "__UNI__A3F1ED4",
"description" : "CRMEB标准版",
"versionName" : "6.0.0",
"versionCode" : 600,
"transformPx" : false,
"sassImplementationName" : "node-sass",
/ 5+App特有相关 /
"app-plus" : {
"usingComponents" : true,
"nvueCompiler" : "uni-app",
"splashscreen" : {
"alwaysShowBeforeRender" : false,
"waiting" : false,
"autoclose" : true,
"delay" : 0
},
"screenOrientation" : [
"portrait-primary",
"portrait-secondary",
"landscape-primary",
"landscape-secondary"
],
/ 模块配置 /
"modules" : {
"Payment" : {},
"Share" : {},
"VideoPlayer" : {},
"OAuth" : {},
"Barcode" : {},
"Camera" : {}
},
"safearea" : {
"bottom" : {
"offset" : "none"
}
},
/ 应用发布信息 /
"distribute" : {
/ android打包配置 /
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
"<uses-permission android:name=\"android.permission.CAPTURE_AUDIO_OUTPUT\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.INTERNET\"/>",
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
],
"abiFilters" : [ "armeabi-v7a", "arm64-v8a" ],
"permissionExternalStorage" : {
"request" : "none",
"prompt" : "应用保存运行状态等信息,需要获取读写手机存储(系统提示为访问设备上的照片、媒体内容和文件)权限,请允许。"
},
"permissionPhoneState" : {
"request" : "none" //拨打电话权限关闭
},
"targetSdkVersion" : 30
},
/ ios打包配置 /
"ios" : {
"capabilities" : {
"entitlements" : {
"com.apple.developer.associated-domains" : [
"applinks:",
"applinks:",
"applinks:",
"applinks:static-679f0930-8f60-425c-9033-8c135f397ea5.bspapp.com"
]
}
},
"privacyDescription" : {
"NSLocationWhenInUseUsageDescription" : "根据客户地理位置推荐最近门店",
"NSPhotoLibraryUsageDescription" : "上传用户头像保存分享海报",
"NSPhotoLibraryAddUsageDescription" : "上传用户头像保存分享海报",
"NSLocationAlwaysAndWhenInUseUsageDescription" : "根据客户地理位置推荐最近门店",
"NSLocationAlwaysUsageDescription" : "根据客户地理位置推荐最近门店",
"NSCameraUsageDescription" : "上传用户头像保存分享海报"
},
"idfa" : false,
"dSYMs" : false
},
/ SDK配置 /
"sdkConfigs" : {
"payment" : {
"alipay" : {
"__platform__" : [ "ios", "android" ]
},
"weixin" : {
"__platform__" : [ "ios", "android" ],
"appid" : "wx277a269f3d736d67",
"UniversalLinks" : "https://bzapp.crmeb.net/uni-universallinks/__UNI__A3F1ED4/"
}
},
"share" : {
"weixin" : {
"appid" : "wx277a269f3d736d67",
"UniversalLinks" : "https://bzapp.crmeb.net/uni-universallinks/__UNI__A3F1ED4/"
}
},
"push" : {},
"maps" : {
"amap" : {
"appkey_ios" : "aeb768547b9d752891e37e1ca0a2b66d",
"appkey_android" : "41ec5c3f4d110ce02a326210fe147be8"
}
},
"oauth" : {
"apple" : {},
"weixin" : {
"appid" : "wx277a269f3d736d67",
"appsecret" : "bd08741a055c2ecac5826ff1c048464b",
"UniversalLinks" : "https://bzapp.crmeb.net/uni-universallinks/__UNI__A3F1ED4/"
}
},
"ad" : {},
"geolocation" : {
"amap" : {
"__platform__" : [ "ios", "android" ],
"appkey_ios" : "aeb768547b9d752891e37e1ca0a2b66d",
"appkey_android" : "41ec5c3f4d110ce02a326210fe147be8"
}
},
"statics" : {
"google" : {
"config_ios" : "",
"config_android" : ""
}
}
},
"splashscreen" : {
"androidStyle" : "common",
"iosStyle" : "common",
"useOriginalMsgbox" : true
},
"icons" : {
"android" : {
"hdpi" : "unpackage/res/icons/72x72.png",
"xhdpi" : "unpackage/res/icons/96x96.png",
"xxhdpi" : "unpackage/res/icons/144x144.png",
"xxxhdpi" : "unpackage/res/icons/192x192.png"
},
"ios" : {
"appstore" : "unpackage/res/icons/1024x1024.png",
"ipad" : {
"app" : "unpackage/res/icons/76x76.png",
"app@2x" : "unpackage/res/icons/152x152.png",
"notification" : "unpackage/res/icons/20x20.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"proapp@2x" : "unpackage/res/icons/167x167.png",
"settings" : "unpackage/res/icons/29x29.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"spotlight" : "unpackage/res/icons/40x40.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png"
},
"iphone" : {
"app@2x" : "unpackage/res/icons/120x120.png",
"app@3x" : "unpackage/res/icons/180x180.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"notification@3x" : "unpackage/res/icons/60x60.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"settings@3x" : "unpackage/res/icons/87x87.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png",
"spotlight@3x" : "unpackage/res/icons/120x120.png"
}
}
}
}
},
/ 快应用特有相关 /
"quickapp" : {},
/ 小程序特有相关 /
"mp-weixin" : {
"appid" : "wx3b82801238ca1b57",
"setting" : {
"urlCheck" : false,
"minified" : true,
"postcss" : true,
"es6" : true
},
"permission" : {
"scope.userLocation" : {
"desc" : "你的位置信息将用于查看与门店的距离"
}
},
"optimization" : {
"subPackages" : true
},
"usingComponents" : true,
"requiredPrivateInfos" : [
"getLocation",
"onLocationChange",
"startLocationUpdateBackground",
"chooseAddress"
],
"__usePrivacyCheck__" : true
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"h5" : {
"devServer" : {
"https" : false
},
"router" : {
"mode" : "history",
"base" : ""
},
"domain" : "",
"sdkConfigs" : {
"maps" : {
"qqmap" : {
"key" : "NO7BZ-APDKP-UCBD7-VT7CX-R5UZK-JBF2W"
}
}
},
"optimization" : {
"treeShaking" : {
"enable" : true
},
"subPackages" : true
},
"async" : {
"timeout" : 200000
},
"title" : "加载中"
},
"plus" : {
"statusbar" : {
"immersed" : true
}
},
"_spaceID" : "679f0930-8f60-425c-9033-8c135f397ea5",
"lazyCodeLoading" : "requiredComponents"
}
/ ios打包配置 /

---

Template/Uni App/Package.Json (template/uni-app/package.json)

{
"name": "uni-app",
"version": "1.0.0",
"dependencies": {
}
}

---

Template/Uni App/Pages.Json (template/uni-app/pages.json)

{
"easycom": {
"autoscan": true,
"custom": {}
},
"pages": [ //pages数组中第一项表示应用启动页
{
"path": "pages/guide/index",
"style": {
"app-plus": {
"titleNView": false //禁用原生导航栏
}
}
},
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom",
"navigationBarTextStyle": "black",
"app-plus": {
"scrollIndicator": "none"
},
"mp-weixin": {
"componentPlaceholder": {
"page-design": "view"
}
}
}
},
{
"path": "pages/order_addcart/order_addcart",
"style": {
"navigationBarTitleText": "购物车",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}

}
},
{
"path": "pages/user/index",
"style": {

"navigationBarTitleText": "个人中心",
"mp-weixin": {
"componentPlaceholder": {
"page-design": "view"
}
},
"enablePullDownRefresh": true
// #ifdef MP || APP-PLUS
,
"navigationStyle": "custom",
// "navigationBarBackgroundColor": "#e93323",
"navigationBarTextStyle": "black"
// #endif
}
},
{
"path": "pages/goods_cate/goods_cate",
"style": {
"navigationBarTitleText": "商品分类",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}

}
}

],
// 模块分包
"subPackages": [
{
"root": "pages/goods_details",
"name": "goods_details",
"pages": [{
"path": "index",
"style": {
"navigationStyle": "custom",
"transparentTitle": "auto",
"mp-weixin": {
"componentPlaceholder": {
"page-design": "view",
"product-bottom": "view"
}
}
}
}]
},
{
"root": "pages/extension",
"name": "extension",
"pages": [{
"path": "customer_list/chat",
"style": {
"navigationBarTitleText": "对话详情",
"navigationBarBackgroundColor": "#3875EA",
"navigationBarTextStyle": "white",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "news_list/index",
"style": {
"navigationBarTitleText": "资讯",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "news_details/index",
"style": {
"navigationBarTitleText": "资讯详情",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}
]
}, {
"root": "pages/goods",
"name": "goods",
"pages": [ {
"path": "goods_list/index",
"style": {
"navigationBarTitleText": "商品列表",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "goods_search/index",
"style": {
"navigationBarTitleText": "搜索商品",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "order_pay_status/index",
"style": {
"navigationBarTitleText": "支付成功",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "admin_order_detail/index",
"style": {
"navigationBarTitleText": "订单详情",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "goods_comment_con/index",
"style": {
"navigationBarTitleText": "商品评价",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "goods_comment_con/lottery_comment",
"style": {
"navigationBarTitleText": "订单评价",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "goods_comment_list/index",
"style": {
"navigationBarTitleText": "商品评分",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "goods_details_store/index",
"style": {
"navigationBarTitleText": "门店列表",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "goods_logistics/index",
"style": {
"navigationBarTitleText": "物流信息",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "goods_return/index",
"style": {
"navigationBarTitleText": "申请退货",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "goods_return_list/index",
"style": {
"navigationBarTitleText": "退货列表",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "lottery/grids/index",
"style": {
"navigationBarTitleText": "抽奖活动",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "lottery/grids/record",
"style": {
"navigationBarTitleText": "中奖记录",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "order_confirm/index",
"style": {
"navigationBarTitleText": "提交订单",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "order_details/index",
"style": {
"navigationBarTitleText": "订单详情",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "order_list/index",
"style": {
"navigationBarTitleText": "我的订单",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "order_refund_goods/index",
"style": {
"navigationBarTitleText": "退回商品",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "receive_gifts_status/index",
"style": {
"navigationBarTitleText": "领取结果",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "receive_gift/index",
"style": {
"navigationBarTitleText": "领取礼物",
"navigationBarBackgroundColor": "#e93323",
// #ifdef MP
"navigationBarTextStyle": "#fff",
// #endif
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "cashier/index",
"style": {
"navigationBarTitleText": "收银台",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}
]
}, {
"root": "pages/users",
"name": "users",
"pages": [{
"path": "user_vip_areer/index",
"style": {
"navigationBarTitleText": "经验记录",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "privacy/index",
"style": {
"navigationBarTitleText": "隐私协议",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "user_cancellation/index",
"style": {
"navigationBarTitleText": "注销协议",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "message_center/index",
"style": {
"navigationBarTitleText": "消息中心",
"enablePullDownRefresh": true,
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "message_center/messageDetail",
"style": {
"navigationBarTitleText": "消息详情",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "user_invoice_order/index",
"style": {
"navigationBarTitleText": "发票详情",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "scan_login/index",
"style": {
"navigationBarTitleText": "授权登录"
}
},
{
"path": "user_invoice_list/index",
"style": {
"navigationBarTitleText": "发票管理",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "user_invoice_form/index",
"style": {
"navigationBarTitleText": "添加新发票",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
//#ifdef H5
{
"path": "alipay_invoke/index",
"style": {
"navigationBarTitleText": "支付提示"
}
},
//#endif
{
"path": "wechat_login/index",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom",
"app-plus": {
"scrollIndicator": "none"
}
}
},
{
"path": "binding_phone/index",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom",
"app-plus": {
"scrollIndicator": "none"
}
}
},
{
"path": "retrievePassword/index",
"style": {
"navigationBarTitleText": "忘记密码",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "user_info/index",
"style": {
"navigationBarTitleText": "设置",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "user_get_coupon/index",
"style": {
"navigationBarTitleText": "领取优惠券",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "visit_list/index",
"style": {
"navigationBarTitleText": "浏览记录",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "user_goods_collection/index",
"style": {
"navigationBarTitleText": "收藏商品",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "user_sgin/index",
"style": {
"navigationBarTitleText": "签到",
// #ifdef MP
// "navigationBarTextStyle": "white",
// "navigationBarBackgroundColor": "#e93323"
// #endif
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "user_sgin_list/index",
"style": {
"navigationBarTitleText": "签到记录",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "user_money/index",
"style": {
"navigationBarTitleText": "我的账户",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "user_bill/index",
"style": {
"navigationBarTitleText": "账单明细",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "user_integral/index",
"style": {
"navigationBarTitleText": "积分详情"

// #ifdef MP
,
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#FFFFFF"
// #endif
,
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "user_coupon/index",
"style": {
"navigationBarTitleText": "我的优惠券",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "user_spread_user/index",
"style": {
"navigationBarTitleText": "我的推广"

// #ifdef MP
,
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#FFFFFF"
// #endif
,
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "user_spread_code/index",
"style": {
"navigationBarTitleText": "分销海报",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "user_spread_money/index",
"style": {
"navigationBarTitleText": "佣金记录"

// #ifdef MP
,
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#FFFFFF"
// #endif
,
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "user_spread_money/receiving",
"style": {
"navigationBarTitleText": "收款"
// #ifdef MP
,
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#FFFFFF"
// #endif
,
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "user_cash/index",
"style": {
"navigationBarTitleText": "提现",
"navigationBarBackgroundColor": "#FFFFFF"
// #ifdef MP || APP-PLUS
,
"navigationBarTextStyle": "black"
// #endif
,
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "user_vip/index",
"style": {
"navigationBarTitleText": "我的等级",
"navigationBarBackgroundColor": "#232323"
// #ifdef MP || APP-PLUS
,
"navigationBarTextStyle": "white"
// #endif
,
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "user_distribution_level/index",
"style": {
"navigationBarTitleText": "分销等级",
"navigationBarBackgroundColor": "#232323"
// #ifdef MP || APP-PLUS
,
"navigationBarTextStyle": "white"
// #endif
,
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "user_address_list/index",
"style": {
"navigationBarTitleText": "地址管理",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "user_address/index",
"style": {
"navigationBarTitleText": "添加地址",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "user_phone/index",
"style": {
"navigationBarTitleText": "绑定手机",

// #ifdef MP
// "navigationBarTextStyle": "white",
// "navigationBarBackgroundColor": "#e93323"
// #endif
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "user_payment/index",
"style": {
"navigationBarTitleText": "余额充值",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "user_pwd_edit/index",
"style": {
"navigationBarTitleText": "修改密码"

// #ifdef MP
// ,
// "navigationBarTextStyle": "white"
// "navigationBarBackgroundColor": "#e93323"
// #endif
,
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "promoter-list/index",
"style": {
"navigationBarTitleText": "推广人列表"
// #ifdef MP
,
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
// #endif
,
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "promoter-order/index",
"style": {
"navigationBarTitleText": "推广人订单"

// #ifdef MP
,
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#FFFFFF"
// #endif
,
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "promoter_rank/index",
"style": {
"navigationBarTitleText": "推广人排行"

// #ifdef MP
,
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#FFFFFF"
// #endif
,
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "commission_rank/index",
"style": {
"navigationBarTitleText": "佣金排行",
"navigationBarBackgroundColor": "#FFFFFF"
// #ifdef MP || APP-PLUS
,
"navigationBarTextStyle": "black"
// #endif
,
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "user_return_list/index",
"style": {
"navigationBarTitleText": "退货列表",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "login/index",
"style": {
"navigationBarTitleText": "登录",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "payment_on_behalf/index",
"style": {
"navigationBarTitleText": "好友代付",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "payment_on_behalf/pay_status",
"style": {
"navigationBarTitleText": "代付成功",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "staff_list/index",
"style": {
"navigationBarTitleText": "员工列表",
"navigationBarBackgroundColor": "#e93323"
// #ifdef MP
,
"navigationBarTextStyle": "#fff"
// #endif
}
}
// #ifdef H5
,
{
"path": "auth/index",
"style": {
"navigationBarTitleText": ""
}
}
// #endif
],
"plugins": {
"live-player-plugin": {
"version": "1.3.5",
"provider": "wx2b03c6e691cd7370"
}
}
},

{
"root": "pages/activity",
"name": "activity",
"pages": [{
"path": "goods_bargain/index",
"style": {
// #ifdef MP
// "navigationBarTextStyle": "white",
// "navigationBarBackgroundColor": "#E93323",
"navigationBarTitleText": "砍价列表",
// #endif
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "goods_bargain_details/index",
"style": {
// #ifdef MP
"navigationBarTitleText": "砍价活动",
// #endif
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "goods_combination/index",
"style": {
// #ifdef MP
// "navigationBarTextStyle": "white",
// "navigationBarBackgroundColor": "#E93323",
"navigationBarTitleText": "拼团活动",
// #endif
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "goods_combination_details/index",
"style": {
"navigationStyle": "custom",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"padding-left": "10px",
"padding-right": "10px",
"type": "transparent",
"buttons": [ //原生标题栏按钮配置,
{
"type": "menu" //原生标题栏增加分享按钮,点击事件可通过页面的 onNavigationBarButtonTap 函数进行监听
}
]
}
// #endif
}
}
},
{
"path": "goods_combination_status/index",
"style": {
"navigationBarTitleText": "拼团",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "goods_seckill/index",
"style": {
"navigationBarTitleText": "限时秒杀"
// #ifdef MP
// "navigationBarTextStyle": "white"
// "navigationBarBackgroundColor": "#e93323"
// #endif
,
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "goods_seckill_details/index",
"style": {
"navigationStyle": "custom"
// #ifdef MP
,
"navigationBarTextStyle": "white"
// #endif
,
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"padding-left": "10px",
"padding-right": "10px",
"type": "transparent",
"buttons": [ //原生标题栏按钮配置,
{
"type": "menu" //原生标题栏增加分享按钮,点击事件可通过页面的 onNavigationBarButtonTap 函数进行监听
}
]
}
// #endif
}
}
},
{
"path": "poster-poster/index",
"style": {
"navigationBarTitleText": "砍价海报"
// #ifdef MP
// "navigationBarTextStyle": "white"
// "navigationBarBackgroundColor": "#d22516"
// #endif
,
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "bargain/index",
"style": {
"navigationBarTitleText": "砍价记录",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "presell/index",
"style": {
"navigationBarTitleText": "预售列表",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}
]
},
{
"root": "pages/admin",
"name": "adminOrder",
"pages": [{
"path": "distribution/index",
"style": {
"navigationStyle": "custom",
"app-plus": {}
}
}, {
"path": "distribution/scanning/index",
"style": {
"navigationBarTitleText": "订单核销",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "distribution/scanning/detail/index",
"style": {
"navigationBarTitleText": "订单核销",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "distribution/orderDetail/index",
"style": {
"navigationStyle": "custom"
}
}, {
"path": "custom_date/index",
"style": {
"navigationBarTitleText": "选择日期"
}
},
{
"path": "order/index",
"style": {
"navigationBarTitleText": "订单统计",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "orderList/index",
"style": {
"navigationBarTitleText": "订单列表",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "orderDetail/index",
"style": {
"navigationBarTitleText": "订单详情",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "delivery/index",
"style": {
"navigationBarTitleText": "订单发货",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "refund/index",
"style": {
"navigationBarTitleText": "售后退款",
"navigationStyle": "custom"
}
},
{
"path": "logistics/index",
"style": {
"navigationBarTitleText": "物流信息",
"navigationStyle": "custom"
}
},
{
"path": "refund_order_list/index",
"style": {
"navigationBarTitleText": "售后订单列表",
"navigationStyle": "custom"
}
},
{
"path": "refund_order_detail/index",
"style": {
"navigationBarTitleText": "售后订单详情",
"navigationStyle": "custom"
}
},
{
"path": "goods/index",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "商品管理"
}
},
{
"path": "goods/specs",
"style": {
"navigationBarTitleText": "修改价格/库存",
"navigationBarBackgroundColor": "#F5F5F5",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "goods/addGoods",
"style": {
"navigationBarTitleText": "添加商品"
}
},
{
"path": "user/list",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "用户管理"
}
},
{
"path": "user/index",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "用户详情"
}
},
{
"path": "statistics/index",
"style": {
"navigationBarTitleText": "订单数据统计",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "order_cancellation/index",
"style": {
"navigationBarTitleText": "订单核销",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}
]
},
{
"root": "pages/columnGoods",
"name": "columnGoods",
"pages": [{
"path": "HotNewGoods/index",
"style": {
"navigationBarTitleText": "精品推荐",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "HotNewGoods/feedback",
"style": {
"navigationBarTitleText": "我的客服",
"navigationBarTextStyle": "white",
"navigationBarBackgroundColor": "#3A3A3A",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "live_list/index",
"style": {
"navigationBarTitleText": "精彩内容"
}
}
]
},
{
"root": "pages/annex",
"pages": [{
"path": "web_view/index",
"style": {
"navigationBarTitleText": "",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "vip_paid/index",
"style": {
"navigationBarTitleText": "SVIP会员",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "vip_coupon/index",
"style": {
"navigationBarTitleText": "会员优惠券",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "vip_clause/index",
"style": {
"navigationBarTitleText": "会员协议",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "vip_active/index",
"style": {
"navigationBarTitleText": "激活会员",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "offline_pay/index",
"style": {
"navigationBarTitleText": "支付",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "offline_result/index",
"style": {
"navigationBarTitleText": "支付结果",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "special/index",
"style": {
"navigationBarTextStyle": "white",
"navigationBarBackgroundColor": "#333333",
"navigationBarTitleText": "专题页",
"app-plus": {
"scrollIndicator": "none"
},
"mp-weixin": {
"componentPlaceholder": {
"page-design": "view"
}
}
}
},
{
"path": "settled/index",
"style": {
"navigationBarTitleText": "分销申请",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}
]
},
{
"root": "pages/points_mall",
"pages": [{
"path": "index",
"style": {
"navigationBarTextStyle": "white",
"navigationBarBackgroundColor": "#333333",
"navigationBarTitleText": "积分商城",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "integral_goods_list",
"style": {
"navigationBarTitleText": "商品列表",
// "navigationBarTextStyle": "white",
// "navigationBarBackgroundColor": "#E93323",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "integral_goods_details",
"style": {
"navigationStyle": "custom",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"padding-left": "10px",
"padding-right": "10px",
"type": "transparent",
"buttons": [ //原生标题栏按钮配置,
{
"type": "menu" //原生标题栏增加分享按钮,点击事件可通过页面的 onNavigationBarButtonTap 函数进行监听
}
]
}
// #endif
}
}
},
{
"path": "exchange_record",
"style": {
"navigationBarTitleText": "兑换记录",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "integral_order",
"style": {
"navigationBarTitleText": "积分订单",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "user_address",
"style": {
"navigationBarTitleText": "选择地址",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
},
{
"path": "integral_order_status",
"style": {
"navigationBarTitleText": "兑换成功",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "integral_order_details",
"style": {
"navigationBarTitleText": "兑换订单详情",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}, {
"path": "logistics_details",
"style": {
"navigationBarTitleText": "兑换物流详情",
"app-plus": {
// #ifdef APP-PLUS
"titleNView": {
"type": "default"
}
// #endif
}
}
}
]
},
{
"root": "subpackage/diyComponents",
"name": "diyComponents",
"pages": [{
"path": "pages/placeholder",
"style": {
"navigationBarTitleText": ""
}
}]
}

],
"tabBar": { // 底部菜单
"color": "#282828",
"selectedColor": "#ff3366",
"borderStyle": "white",
"backgroundColor": "#ffffff",
"list": [{
"pagePath": "pages/index/index",
"iconPath": "static/images/1-001.png",
"selectedIconPath": "static/images/1-002.png",
"text": "首页"
},
{
"pagePath": "pages/goods_cate/goods_cate",
"iconPath": "static/images/2-001.png",
"selectedIconPath": "static/images/2-002.png",
"text": "分类"
},
{
"pagePath": "pages/order_addcart/order_addcart",
"iconPath": "static/images/3-001.png",
"selectedIconPath": "static/images/3-002.png",
"text": "购物车"
},
{
"pagePath": "pages/user/index",
"iconPath": "static/images/4-001.png",
"selectedIconPath": "static/images/4-002.png",
"text": "我的"
}
]
},
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "加载中",
"navigationBarBackgroundColor": "#fff",
"backgroundColor": "#F8F8F8",
"titleNView": false,
"pageOrientation": "portrait" // 全局设置为竖屏
},
"condition": { //模式配置,仅开发期间生效
"current": 0, //当前激活的模式(list 的索引项)
"list": [{
"name": "", //模式名称
"path": "", //启动页面,必选
"query": "" //启动参数,在页面的onLoad函数里面得到
}]
},
"embeddedAppIdList": ["wxef277996acc166c3"] //通联支付appid
}

---

.Codebuddy/Agents/接口开发 (.codebuddy/agents/接口开发.md)

---
name: 接口开发
description: PHP接口开发智能体,专注于CRMEB电商系统的API接口开发、调试和维护
model: default
tools: list_dir, search_file, search_content, read_file, read_lints, replace_in_file, write_to_file, execute_command, create_rule, delete_file, preview_url, web_fetch, use_skill, web_search
agentMode: agentic
enabled: true
enabledAutoRun: true
---

你是一个专业的PHP接口开发智能体,专门服务于CRMEB电商系统。你的职责是帮助开发者快速理解项目架构、开发符合规范的API接口、调试和优化接口性能。

🎯 核心职责

1. 接口开发: 基于CRMEB架构快速开发符合规范的API接口
2. 代码生成: 按照项目规范生成Controller、Service、DAO、Model代码
3. 调试支持: 协助排查接口问题、分析错误日志
4. 性能优化: 提供接口性能优化建议
5. 规范检查: 确保代码符合CRMEB开发规范

🏗️ CRMEB技术栈架构

框架基础


- 核心框架: ThinkPHP 6.x
- 架构模式: 多应用架构 (Multi-App)
- 分层架构: MVC + Service + DAO
- PHP版本: 7.1-7.4
- 数据库: MySQL 5.7+
- 缓存: Redis (可选)

应用模块划分


app/
├── adminapi/ # 后台管理API (需要管理员权限)
├── api/ # 用户端API (需要用户登录)
├── kefuapi/ # 客服系统API
├── outapi/ # 外部API
├── dao/ # 数据访问层
├── model/ # 数据模型层
├── services/ # 业务逻辑层
├── jobs/ # 队列任务
└── listener/ # 事件监听器
text

认证机制


- 后台管理: AdminAuthTokenMiddleware (管理员Token)
- 用户端: AuthTokenMiddleware (用户Token)
- 公共接口: 无需认证

📋 分层架构说明

Controller层 (控制器)


职责:
- 处理HTTP请求
- 参数验证和获取
- 调用Service层
- 统一返回响应格式

规范要求:

php
<?php
namespace app\adminapi\controller\v1\user;

use app\Request;
use app\services\user\UserServices;
use crmeb\basic\BaseController;

/
* 用户管理控制器
*/
class UserController extends BaseController
{
protected $services;

public function __construct(UserServices $services)
{
$this->services = $services;
}

/
* 获取用户列表
*/
public function getList()
{
$where = $this->request->getMore([
['keywords', ''],
['status', ''],
['page', 1],
['limit', 15]
]);
$list = $this->services->getUserList($where);
return app('json')->success($list);
}

/
* 保存用户信息
*/
public function save()
{
$data = $this->request->postMore([
['nickname', ''],
['phone', ''],
['avatar', ''],
['status', 1]
]);
$this->services->saveUser($data);
return app('json')->success('保存成功');
}
}

text
命名规范:
- 控制器方法: 小写+下划线,如 get_list, save_data
- 参数获取: 使用 $this->request->getMore()$this->request->postMore()
- 返回响应: return app('json')->success($data)app('json')->fail('错误信息')

Service层 (服务层)


职责:
- 实现核心业务逻辑
- 事务管理
- 调用DAO层
- 缓存处理

规范要求:


/ Detailed source-code truncated for AI context efficiency. /
text
命名规范:
- 服务方法: 驼峰法,如 getUserList, saveUser
- 参数类型声明: 必须声明参数和返回值类型
- 异常处理: 使用项目异常类,如 AdminException, ApiException

DAO层 (数据访问层)


职责:
- 封装数据库操作
- 提供数据查询方法
- 处理复杂的SQL查询

规范要求:

php
<?php
namespace app\dao\user;

use crmeb\basic\BaseDao;
use app\model\user\User;

class UserDao extends BaseDao
{
/
* 设置模型
* @return string
*/
protected function setModel(): string
{
return User::class;
}

/
* 搜索条件
* @param array $where
* @return \think\Model
*/
public function search(array $where = [])
{
$query = $this->getModel()->where('is_del', 0);

// 关键词搜索
if (!empty($where['keywords'])) {
$query = $query->whereLike('nickname|phone', "%{$where['keywords']}%");
}

// 状态筛选
if ($where['status'] !== '') {
$query = $query->where('status', $where['status']);
}

return $query;
}

/
* 根据ID获取用户信息
* @param int $id
* @return array|null
*/
public function getById(int $id): ?array
{
return $this->getModel()->where('id', $id)->find();
}
}

text
命名规范:
- DAO方法: 数据库操作相关,如 search, getById, update, delete
- 查询构造: 必须返回 \think\Model 对象
- 模型绑定: 必须实现 setModel() 方法

Model层 (模型层)


职责:
- 定义数据模型
- 设置表名和主键
- 定义关联关系
- 定义访问器和修改器

规范要求:

php
<?php
namespace app\model\user;

use crmeb\basic\BaseModel;
use think\model\relation\HasMany;

class User extends BaseModel
{
protected $name = 'user';
protected $pk = 'id';

/
* 关联订单
* @return HasMany
*/
public function orders()
{
return $this->hasMany(Order::class, 'uid', 'id');
}

/
* 头像获取器
* @param $value
* @return string
*/
public function getAvatarAttr($value): string
{
return $value ? $value : '/static/default_avatar.png';
}

/
* 状态文本获取器
* @param $value
* @return string
*/
public function getStatusTextAttr($value, $data): string
{
$status = [0 => '禁用', 1 => '启用'];
return $status[$data['status']] ?? '';
}

/
* 自动时间戳
* @var bool
*/
protected $autoWriteTimestamp = true;
}

text

📝 接口开发流程

1. 创建新接口步骤

#### Step 1: 创建数据表

sql
CREATE TABLE eb_example (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL DEFAULT '' COMMENT '名称',
status tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态 0禁用 1启用',
create_time int(11) NOT NULL DEFAULT '0' COMMENT '创建时间',
update_time int(11) NOT NULL DEFAULT '0' COMMENT '更新时间',
is_del tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='示例表';
text
#### Step 2: 创建Model
bash

创建Model


php think make:model Example
text
#### Step 3: 创建DAO
php
// app/dao/ExampleDao.php
<?php
namespace app\dao;

use crmeb\basic\BaseDao;
use app\model\Example;

class ExampleDao extends BaseDao
{
protected function setModel(): string
{
return Example::class;
}

public function search(array $where = [])
{
$query = $this->getModel()->where('is_del', 0);

if (!empty($where['keywords'])) {
$query = $query->whereLike('name', "%{$where['keywords']}%");
}

if ($where['status'] !== '') {
$query = $query->where('status', $where['status']);
}

return $query;
}
}

text
#### Step 4: 创建Service
php
// app/services/ExampleServices.php
<?php
namespace app\services;

use crmeb\basic\BaseServices;
use app\dao\ExampleDao;

class ExampleServices extends BaseServices
{
public function __construct(ExampleDao $dao)
{
$this->dao = $dao;
}

public function getList(array $where): array
{
$query = $this->dao->search($where);
$count = $query->count();
$list = $query->page($where['page'], $where['limit'])
->order('id', 'desc')
->select()
->toArray();
return compact('list', 'count');
}

public function save(array $data): int
{
if (isset($data['id']) && $data['id']) {
$id = $data['id'];
unset($data['id']);
$this->dao->update($id, $data);
} else {
$id = $this->dao->save($data);
}
return $id;
}

public function delete(int $id): bool
{
return $this->dao->update($id, ['is_del' => 1]);
}
}

text
#### Step 5: 创建Controller
php
// app/adminapi/controller/v1/ExampleController.php
<?php
namespace app\adminapi\controller\v1;

use app\Request;
use app\services\ExampleServices;
use crmeb\basic\BaseController;

class ExampleController extends BaseController
{
protected $services;

public function __construct(ExampleServices $services)
{
$this->services = $services;
}

public function getList()
{
$where = $this->request->getMore([
['keywords', ''],
['status', ''],
['page', 1],
['limit', 15]
]);
$list = $this->services->getList($where);
return app('json')->success($list);
}

public function save()
{
$data = $this->request->postMore([
['id', 0],
['name', ''],
['status', 1]
]);
$this->services->save($data);
return app('json')->success('保存成功');
}

public function delete()
{
$id = $this->request->param('id');
$this->services->delete($id);
return app('json')->success('删除成功');
}
}

text
#### Step 6: 创建路由
php
// app/adminapi/route/example.php
<?php
use think\facade\Route;

Route::group(function () {
Route::get('example/list', 'v1.Example/getList');
Route::post('example/save', 'v1.Example/save');
Route::post('example/delete', 'v1.Example/delete');
});

text
#### Step 7: 创建验证器(可选)
php
// app/adminapi/validate/example/ExampleValidate.php
<?php
namespace app\adminapi\validate\example;

use think\Validate;

class ExampleValidate extends Validate
{
protected $rule = [
'name' => 'require|max:255',
'status' => 'require|in:0,1',
];

protected $message = [
'name.require' => '名称不能为空',
'name.max' => '名称最多255个字符',
'status.require' => '状态不能为空',
'status.in' => '状态值不正确',
];
}

text

2. 接口响应规范

#### 成功响应

json
{
"status": 200,
"msg": "success",
"data": {
"list": [],
"count": 100
},
"time": "2024-01-01 10:00:00"
}
text
#### 失败响应
json
{
"status": 400,
"msg": "错误信息",
"data": null,
"time": "2024-01-01 10:00:00"
}
text
#### 分页响应
json
{
"status": 200,
"msg": "success",
"data": {
"list": [...],
"count": 100,
"page": 1,
"limit": 15
}
}
text

3. 错误码规范

| 错误码 | 说明 |
|-------|------|
| 200 | 成功 |
| 400 | 参数错误 |
| 401 | 未授权(未登录) |
| 403 | 权限不足 |
| 404 | 资源不存在 |
| 422 | 验证失败 |
| 500 | 服务器错误 |

4. 异常处理

php
// 使用项目异常类
use crmeb\exceptions\AdminException;
use crmeb\exceptions\ApiException;

// 业务异常
if (empty($data)) {
throw new AdminException('数据不存在');
}

// 权限异常
if (!$hasPermission) {
throw new AdminException('无权访问', 403);
}

// 参数验证失败
if (!$validated) {
throw new ApiException('参数错误', 400);
}

text

🔧 常用开发工具类

1. 配置获取

php
// 获取系统配置
$configValue = \app\services\system\ConfigServices::get('config_key');

// 缓存配置
$cacheValue = Cache::get('cache_key');
Cache::set('cache_key', $value, 3600);

text

2. 文件上传

php
// 使用上传服务
use crmeb\services\upload\UploadService;

$uploadService = UploadService::instance();
$result = $uploadService->to('oss')->move($file);
$imageUrl = $result['url'];

text

3. 日志记录

php
// 记录日志
Log::info('操作日志', $data);
Log::error('错误信息', $error);
Log::debug('调试信息', $debug);
text

4. 队列任务

php
// 推送队列任务
use think\queue\Job;
use app\jobs\OrderJob;

// 异步执行
Queue::push(new OrderJob($orderData));

// 延迟执行(秒)
Queue::later(3600, new OrderJob($orderData));

text

📊 核心业务模块

1. 用户模块


- 用户管理: 用户信息、等级、分组、标签
- 认证登录: 账号密码、手机验证码、微信授权
- 余额积分: 充值、提现、账单记录
- 收货地址: 地址管理

2. 商品模块


- 商品管理: 商品信息、分类、属性、规格(SKU)
- 库存管理: 库存扣减、库存预警
- 商品评价: 评价管理、评分统计
- 商品导入: 淘宝商品采集

3. 订单模块


- 订单创建: 商品验证、价格计算、库存扣减
- 支付流程: 调起支付、支付回调、状态更新
- 订单发货: 物流信息、发货通知
- 订单售后: 退款、退货、换货

4. 营销模块


- 优惠券: 优惠券模板、用户优惠券、使用验证
- 拼团活动: 拼团商品、拼团记录、成团判断
- 砍价活动: 砍价商品、砍价进度、完成判断
- 秒杀活动: 秒杀商品、限购控制、库存管理

5. 支付模块


- 微信支付: 公众号支付、小程序支付、H5支付
- 支付宝支付: APP支付、网页支付、扫码支付
- 余额支付: 余额支付、密码验证
- 支付回调: 异步通知处理、签名验证

🚀 性能优化建议

1. 数据库优化


- 为常用查询字段添加索引
- 避免使用 SELECT *,只查询需要的字段
- 使用 EXPLAIN 分析SQL执行计划
- 合理使用缓存减少数据库查询

2. 缓存优化


- 使用Redis缓存热点数据
- 设置合理的缓存过期时间
- 使用缓存前缀防止冲突
- 缓存更新时注意一致性

3. 代码优化


- 减少循环嵌套
- 优化算法复杂度
- 使用队列处理耗时操作
- 异步处理非关键业务

4. 接口优化


- 合理使用分页
- 控制返回数据量
- 使用HTTP压缩
- 启用CDN加速

🐛 常见问题排查

1. 数据库连接失败

php
// 错误信息
SQLSTATE[HY000] [2002] Connection refused

// 排查步骤
1. 检查数据库服务是否启动
2. 检查 .env 配置文件中的数据库配置
3. 检查数据库用户权限
4. 检查防火墙设置

text

2. 队列任务不执行

bash

排查步骤


1. 检查队列消费者是否启动: php think queue:work
2. 检查队列配置: config/queue.php
3. 检查Redis连接: redis-cli ping
4. 查看队列日志: runtime/log/
text

3. Token认证失败

php
// 错误信息
401 Unauthorized

// 排查步骤
1. 检查Token是否正确传递
2. 检查Token是否过期
3. 检查中间件配置
4. 检查JWT配置

text

📚 常用命令

bash

生成控制器


php think make:controller UserController

生成模型


php think make:model User

生成验证器


php think make:validate UserValidate

清除缓存


php think clear

启动队列


php think queue:listen

启动定时任务


php think timer start

启动WebSocket


php think workerman start
text

🎯 开发检查清单

在提交代码前,请确保:

- [ ] 代码符合CRMEB命名规范
- [ ] 方法有完整的PHPDoc注释
- [ ] 参数验证完整
- [ ] 异常处理完善
- [ ] 返回格式统一
- [ ] 日志记录合理
- [ ] 数据库操作使用DAO层
- [ ] 业务逻辑在Service层
- [ ] SQL查询已优化
- [ ] 测试通过
- [ ] 无敏感信息泄露
- [ ] 权限验证正确

💡 最佳实践

1. 单一职责: 每个类和方法只做一件事
2. 依赖注入: 通过构造函数注入依赖
3. 接口隔离: Controller不直接操作数据库
4. 事务管理: Service层使用事务确保数据一致性
5. 异常处理: 使用项目异常类,统一错误处理
6. 日志记录: 记录关键操作和错误信息
7. 代码复用: 抽象公共逻辑到基类或工具类
8. 性能优化: 合理使用缓存和队列
9. 安全防护: 参数验证、SQL注入防护、XSS防护
10. 文档完善: 保持注释和文档的及时更新

📖 参考文档

- ThinkPHP 6 官方文档
- CRMEB 开发文档
- 数据库结构设计
- 开发规范说明
- API接口文档
- 业务流程说明

---

提示: 在开发过程中,始终遵循CRMEB的开发规范,确保代码质量和系统稳定性。

---

.Codebuddy/Skills/Admin Element/References/Api Flow (.codebuddy/skills/admin-element/references/api_flow.md)

Admin-Element 接口请求流程文档

1 API 请求流程概述

Admin-Element 项目的 API 请求流程遵循以下步骤:

1. 接口定义: 在 src/api/ 目录下按模块定义 API 接口
2. 请求封装: 使用 axios 封装网络请求,添加拦截器
3. 接口调用: 在组件或业务逻辑中调用 API 接口
4. 响应处理: 统一处理 API 响应,包括成功和失败情况
5. 错误处理: 统一处理网络错误、业务错误等异常情况
6. 数据管理: 将获取的数据存储到状态管理或组件中

2 网络请求封装

2.1 axios 实例创建

src/utils/request.js 中创建 axios 实例并配置:

javascript
import axios from 'axios'
import { Message, Loading } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'

// 创建 axios 实例
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // API 基础路径
timeout: 10000, // 请求超时时间
headers: {
'Content-Type': 'application/json;charset=utf-8'
}
})

text

2.2 请求拦截器

javascript
// 请求拦截器
service.interceptors.request.use(
config => {
// 显示加载动画
if (config.loading !== false) {
store.dispatch('app/showLoading')
}

// 自动添加 token
if (store.getters.token) {
config.headers['Authorization'] = Bearer ${getToken()}
}

return config
},
error => {
// 隐藏加载动画
store.dispatch('app/hideLoading')
console.error('请求错误:', error)
return Promise.reject(error)
}
)
text

2.3 响应拦截器


/ Detailed source-code truncated for AI context efficiency. /
text

3 API 接口定义

3.1 接口文件组织

API 接口按模块组织,存放在 src/api/ 目录下:


src/api/
├── index.js # API 入口文件
├── user.js # 用户相关接口
├── goods.js # 商品相关接口
├── order.js # 订单相关接口
└── ... # 其他模块接口
text

3.2 接口定义示例

src/api/user.js 中定义用户相关接口:

javascript
import request from '@/utils/request'

export default {
// 登录
login(data) {
return request({
url: '/admin/login',
method: 'post',
data
})
},

// 获取用户信息
getUserInfo() {
return request({
url: '/admin/user/info',
method: 'get'
})
},

// 获取用户列表
getUserList(params) {
return request({
url: '/admin/user/list',
method: 'get',
params
})
},

// 修改用户信息
updateUser(data) {
return request({
url: '/admin/user/update',
method: 'put',
data
})
},

// 删除用户
deleteUser(id) {
return request({
url: /admin/user/delete/${id},
method: 'delete'
})
}
}

text

3.3 API 入口文件

src/api/index.js 中导出所有 API 模块:

javascript
import user from './user'
import goods from './goods'
import order from './order'

// 导出 API 模块
export default {
user,
goods,
order
}

text

4 请求和响应处理

4.1 请求参数处理

#### 4.1.1 GET 请求

javascript
// 带查询参数的 GET 请求
api.user.getUserList({
page: 1,
limit: 10,
keyword: 'test'
})
text
#### 4.1.2 POST 请求
javascript
// 带请求体的 POST 请求
api.user.login({
username: 'admin',
password: '123456'
})
text
#### 4.1.3 PUT 请求
javascript
// 带请求体的 PUT 请求
api.user.updateUser({
id: 1,
username: 'newadmin',
nickname: '新管理员'
})
text
#### 4.1.4 DELETE 请求
javascript
// 路径参数的 DELETE 请求
api.user.deleteUser(1)
text

4.2 响应数据结构

后端 API 响应数据结构应遵循以下规范:

javascript
{
"code": 200, // 状态码,200 表示成功
"message": "操作成功", // 响应消息
"data": { ... } // 响应数据
}
text

4.3 响应处理示例

javascript
// 在组件中调用 API
import api from '@/api'

export default {
methods: {
async fetchUserList() {
try {
const res = await api.user.getUserList({
page: this.page,
limit: this.limit
})

// 处理成功响应
this.userList = res.data.list
this.total = res.data.total
} catch (error) {
// 错误已在拦截器中处理,这里可以做额外处理
console.error('获取用户列表失败:', error)
}
}
}
}

text

5 错误处理机制

5.1 网络错误

- 网络连接失败
- 请求超时
- 服务器无响应

5.2 业务错误

- 参数错误 (400)
- 未授权 (401)
- 拒绝访问 (403)
- 请求地址不存在 (404)
- 服务器内部错误 (500)

5.3 业务逻辑错误

- 状态码非 200 的响应
- 业务规则验证失败

5.4 错误处理最佳实践

1. 统一错误处理: 在响应拦截器中统一处理错误
2. 友好的错误提示: 向用户显示清晰的错误消息
3. 错误日志记录: 记录错误信息,便于排查问题
4. 特殊错误处理: 对 token 过期等特殊情况进行处理
5. 降级处理: 网络错误时提供合理的降级方案

6 接口调用最佳实践

6.1 使用 async/await

javascript
async fetchData() {
try {
const res = await api.goods.getGoodsList(this.queryParams)
this.goodsList = res.data.list
this.total = res.data.total
} catch (error) {
// 错误处理
}
}
text

6.2 加载状态管理

javascript
export default {
data() {
return {
loading: false,
goodsList: []
}
},
methods: {
async fetchData() {
this.loading = true
try {
const res = await api.goods.getGoodsList(this.queryParams)
this.goodsList = res.data.list
} catch (error) {
// 错误处理
} finally {
this.loading = false
}
}
}
}
text

6.3 防抖和节流

对于频繁触发的请求,使用防抖或节流优化:

javascript
import { debounce } from 'lodash'

export default {
methods: {
// 使用防抖优化搜索请求
search: debounce(async function(query) {
try {
const res = await api.goods.searchGoods({ keyword: query })
this.searchResults = res.data
} catch (error) {
// 错误处理
}
}, 300)
}
}

text

6.4 请求取消

对于可能重复触发的请求,使用取消令牌避免重复请求:

javascript
import axios from 'axios'

export default {
data() {
return {
cancelToken: null
}
},
methods: {
async fetchData() {
// 取消之前的请求
if (this.cancelToken) {
this.cancelToken.cancel('取消重复请求')
}

// 创建新的取消令牌
this.cancelToken = axios.CancelToken.source()

try {
const res = await api.goods.getGoodsList({
page: this.page,
limit: this.limit
}, {
cancelToken: this.cancelToken.token
})
this.goodsList = res.data.list
} catch (error) {
if (axios.isCancel(error)) {
console.log('请求已取消:', error.message)
} else {
// 错误处理
}
}
}
}
}

text

7 接口安全

7.1 认证与授权

- 使用 JWT 令牌进行身份认证
- 请求头中携带 Authorization 字段
- 定期刷新令牌,避免过期

7.2 数据加密

- 敏感数据传输加密
- 密码等敏感信息使用 HTTPS 传输

7.3 防止 CSRF 攻击

- 使用 CSRF Token
- 验证请求来源

7.4 接口速率限制

- 后端实现接口速率限制
- 前端避免频繁请求

8 性能优化

8.1 请求合并

对于多个相同类型的请求,合并为一个请求:

javascript
// 批量获取数据
api.goods.batchGetGoodsInfo(ids)
text

8.2 缓存策略

- 对不常变化的数据进行缓存
- 使用 localStorage 或 sessionStorage 缓存数据

8.3 懒加载

- 按需加载数据
- 滚动到底部加载更多数据

8.4 预加载

- 预加载可能需要的数据
- 提升用户体验

9 调试技巧

9.1 接口调试工具

- 使用 Chrome DevTools 的 Network 面板
- 使用 Postman 等 API 调试工具

9.2 日志记录

- 在开发环境下打印详细的请求和响应信息
- 在生产环境下只记录错误信息

9.3 模拟数据

- 使用 Mock 数据进行前端开发
- 减少对后端接口的依赖

10 总结

Admin-Element 项目的 API 请求流程采用了统一的封装和处理机制,通过 axios 拦截器实现了请求和响应的统一处理,提高了代码的可维护性和可扩展性。开发者应遵循接口定义规范和最佳实践,确保 API 调用的安全性、可靠性和性能。

---

.Codebuddy/Skills/Admin Element/References/Code Style (.codebuddy/skills/admin-element/references/code_style.md)

管理端前端代码规范文档

1. 概述

本文档描述了 CRMEB 项目中管理端前端的代码规范,包括命名规范、代码风格、文件结构、组件开发等方面的规范,旨在统一代码风格,提高代码质量和可维护性。

2. 命名规范

2.1 目录命名


- 目录名: 小写字母,单词之间用连字符分隔
- 示例: components/common/pages/user-management/utils/
- 规范: 简洁明了,反映目录的功能

2.2 文件命名


- 组件文件: 大写字母开头的 PascalCase 命名风格
- 示例: Button.vueUserList.vueNavbar.vue
- 页面文件: 小写字母,单词之间用连字符分隔
- 示例: login.vueuser-list.vuedashboard.vue
- JS 文件: 小写字母,单词之间用连字符分隔
- 示例: api.jsrequest.jsutil.js
- CSS/SCSS 文件: 小写字母,单词之间用连字符分隔
- 示例: common.scsstheme.scssvariables.scss

2.3 变量命名


- 普通变量: 驼峰命名法
- 示例: userInfogoodsListisLoading
- 常量: 全大写,单词之间用下划线分隔
- 示例: BASE_URLMAX_COUNTDEFAULT_PAGE_SIZE
- 布尔变量: 以 is 开头的驼峰命名法
- 示例: isShowisLoadingisLogin
- 数组变量: 以复数形式命名
- 示例: usersgoodsorders
- 对象变量: 以单数形式命名
- 示例: usergoodorder

2.4 函数命名


- 函数名: 驼峰命名法,动词开头
- 示例: getUserInfosubmitFormhandleClick
- 方法名: 驼峰命名法
- 示例: datamethodscomputedwatch
- 生命周期函数: 按照 Vue 规范命名
- 示例: createdmountedbeforeDestroy
- 事件处理函数: 以 handle 开头
- 示例: handleSubmithandleClickhandleChange

2.5 组件命名


- 组件名: PascalCase 命名风格
- 示例: ButtonUserListNavbar
- 组件标签: 小写字母,单词之间用连字符分隔
- 示例: <el-button><user-list><nav-bar>
- 组件文件名: 与组件名一致,PascalCase 命名
- 示例: Button.vueUserList.vueNavbar.vue

2.6 其他命名


- 路由命名: 小写字母,单词之间用连字符分隔
- 示例: /login/user/list/dashboard
- CSS 类名: 小写字母,单词之间用连字符分隔
- 示例: .user-info.goods-list.btn-primary
- ID 命名: 小写字母,单词之间用连字符分隔
- 示例: #app#header#footer
- Vuex 模块命名: 小写字母,单词之间用连字符分隔
- 示例: usergoodsorders

3. 代码风格

3.1 缩进


- 缩进方式: 4 个空格
- 示例:
vue
<template>
<div class="container">
<h1>{{ title }}</h1>
</div>
</template>
text

3.2 换行


- 标签换行: 多个属性的标签应该换行
- 示例:
vue
<el-button
type="primary"
size="medium"
@click="handleSubmit"
>
提交
</el-button>
text
- 代码块换行: 逻辑代码块应该换行
- 示例:
javascript
if (condition) {
// 代码块
} else {
// 代码块
}
text

3.3 空格


- 运算符空格: 运算符两侧应该有空格
- 示例: a + bx = yi < 10
- 逗号空格: 逗号后面应该有空格
- 示例: [1, 2, 3]{ name: '张三', age: 18 }
- 括号空格: 括号内侧不应该有空格
- 示例: if (condition)function (param)
- 冒号空格: 对象字面量中冒号后面应该有空格
- 示例: { name: '张三', age: 18 }

3.4 注释


- 单行注释: 使用 // 注释
- 示例: // 这是单行注释
- 多行注释: 使用 / / 注释
- 示例:
javascript
/*
* 这是多行注释
* 第二行
*/
text
- 文档注释: 使用 JSDoc 风格的注释
- 示例:
javascript
/
* 获取用户信息
* @param {number} id - 用户ID
* @returns {Promise} 用户信息
*/
async function getUserInfo(id) {
// 代码
}
text
- 组件注释: 组件使用文档注释
- 示例:
vue
/
* 用户列表组件
* @props {Array} users - 用户列表数据
* @props {Boolean} loading - 是否加载中
* @events {Function} select - 选择用户时触发
*/
text

3.5 引号


- 字符串: 使用单引号 ''
- 示例: const name = '张三'<span>Hello</span>
- 模板字符串: 使用反引号 ` `
- 示例:
const url = ${baseUrl}/api/user
- HTML 属性: 使用双引号
""
- 示例:
<div class="container"><img src="https://example.com/img.jpg">

3.6 分号


- 语句结束: 每个语句结束都应该加分号
- 示例:
const name = '张三';function() {};

3.7 空行


- 代码块之间: 代码块之间应该有空行
- 示例:
javascript
function first() {
// 代码
}

function second() {
// 代码
}

text
- 逻辑块之间: 逻辑块之间应该有空行
- 示例:
javascript
if (condition) {
// 代码
}

while (loop) {
// 代码
}

text

4. 文件结构

4.1 组件文件结构


/ Detailed source-code truncated for AI context efficiency. /
text

4.2 页面文件结构


/ Detailed source-code truncated for AI context efficiency. /
text

4.3 JS 文件结构

javascript
// 导入依赖
import axios from 'axios';
import { Message } from 'element-ui';

// 常量定义
const BASE_URL = process.env.VUE_APP_API_BASE_URL;
const TIMEOUT = 10000;

// 创建 axios 实例
const service = axios.create({
baseURL: BASE_URL,
timeout: TIMEOUT
});

// 请求拦截器
service.interceptors.request.use(
config => {
// 添加 token
const token = localStorage.getItem('token');
if (token) {
config.headers['Authorization'] =
Bearer ${token};
}
return config;
},
error => {
console.error('请求错误:', error);
return Promise.reject(error);
}
);

// 响应拦截器
service.interceptors.response.use(
response => {
const { data } = response;
if (data.code !== 200) {
Message.error(data.message || '请求失败');
return Promise.reject(data);
}
return data;
},
error => {
console.error('响应错误:', error);
Message.error('网络错误,请稍后重试');
return Promise.reject(error);
}
);

// 工具函数
function formatDate(date) {
const d = new Date(date);
return d.toLocaleString();
}

function deepClone(obj) {
return JSON.parse(JSON.stringify(obj));
}

// 导出
export {
service,
formatDate,
deepClone
};

// 默认导出
export default service;

text

5. 组件开发规范

5.1 组件设计


- 单一职责: 每个组件只负责一个功能
- 可复用性: 设计通用的、可复用的组件
- 可配置性: 通过 props 提供配置选项
- 事件通信: 通过事件与父组件通信
- 插槽支持: 提供插槽,增强组件灵活性

5.2 组件使用


- 组件导入: 使用 import 导入组件
- 示例:
import Button from '@/components/Button.vue'
- 组件注册: 在 components 中注册组件
- 示例:
javascript
components: {
Button
}
text
- 组件使用: 使用组件标签
- 示例:
<Button type="primary">点击</Button>
- 组件传值: 通过 props 传递数据
- 示例:
<UserList :users="userList" :loading="loading" />
- 事件监听: 监听组件事件
- 示例:
<UserList @select="handleSelect" />

5.3 组件通信


- props 向下传递: 父组件通过 props 向子组件传递数据
- events 向上传递: 子组件通过 events 向父组件传递事件
- refs 引用: 通过 refs 引用子组件实例
- provide/inject: 祖先组件向后代组件传递数据
- Vuex 全局状态: 使用 Vuex 管理全局状态
- EventBus: 组件间事件总线

5.4 组件生命周期


- created: 初始化数据,发送请求
- mounted: 操作 DOM,初始化第三方库
- beforeUpdate: 更新前的准备工作
- updated: 数据更新后的操作
- beforeDestroy: 清理定时器,取消订阅
- destroyed: 组件销毁后的清理工作

5.5 组件命名规范


- 组件名: PascalCase 命名风格
- 组件文件名: 与组件名一致
- 组件目录: 按功能分类存放
- 组件前缀: 通用组件使用统一前缀

6. 页面开发规范

6.1 页面结构


- 模板结构: 清晰明了,层次分明
- 脚本结构: 按照 Vue 规范组织代码
- 样式结构: 模块化,可维护
- 布局规范: 遵循统一的布局规范

6.2 数据管理


- 本地数据: 使用 data 管理组件内部数据
- 计算数据: 使用 computed 计算衍生数据
- 监听数据: 使用 watch 监听数据变化
- 全局数据: 使用 Vuex 管理全局数据

6.3 路由管理


- 路由配置: 在 router 目录中配置路由
- 路由跳转: 使用 router.push、router.replace 等方法
- 路由参数: 通过 $route.params 获取路由参数
- 路由守卫: 使用全局/局部路由守卫

6.4 API 调用


- API 封装: 统一封装 API 调用
- 异步处理: 使用 async/await 处理异步请求
- 错误处理: 使用 try/catch 捕获错误
- 加载状态: 显示加载状态,提升用户体验

6.5 用户体验


- 响应式设计: 适配不同屏幕尺寸
- 加载状态: 显示加载中提示
- 错误提示: 显示错误信息
- 成功提示: 显示操作成功提示
- 表单验证: 实时表单验证
- 防抖节流: 优化频繁触发的事件

7. 性能优化

7.1 代码优化


- 减少冗余代码: 避免重复的代码
- 使用计算属性: 对于复杂的计算,使用 computed
- 使用 v-if 和 v-show 合理: 根据场景选择合适的指令
- 使用 key: 在 v-for 中使用 key,提高渲染性能
- 避免频繁更新: 使用防抖和节流

7.2 网络优化


- 合理使用缓存: 缓存不经常变化的数据
- 减少请求次数: 合并请求,批量操作
- 使用 CDN: 静态资源使用 CDN
- 压缩传输: 使用 gzip 压缩传输数据

7.3 构建优化


- Tree Shaking: 移除未使用的代码
- 代码分割: 按路由分割代码
- 懒加载: 路由懒加载,组件懒加载
- 预加载: 预加载关键资源

7.4 其他优化


- 减少 DOM 节点: 简化 DOM 结构
- 优化图片: 使用合适的图片格式和大小
- 使用虚拟列表: 对于长列表,使用虚拟列表
- 避免内存泄漏: 及时清理定时器、事件监听器等

8. 常见问题

8.1 代码风格问题


- 问题: 代码风格不一致
- 解决方案: 使用 ESLint 和 Prettier 统一代码风格

8.2 性能问题


- 问题: 页面加载慢,卡顿
- 解决方案: 优化代码,减少 DOM 操作,使用虚拟列表等

8.3 兼容性问题


- 问题: 在不同浏览器上表现不一致
- 解决方案: 遵循 Web 标准,使用 polyfill

8.4 维护性问题


- 问题: 代码难以维护
- 解决方案: 模块化开发,添加注释,遵循代码规范

8.5 命名冲突问题


- 问题: 命名冲突
- 解决方案: 使用命名空间,避免全局变量

9. 参考资源

- Vue 官方风格指南
- Element UI 官方文档
- ESLint 官方文档
- Prettier 官方文档
- JavaScript 代码规范
- CSS 代码规范

10. 总结

本文档描述了 CRMEB 项目中管理端前端的代码规范,包括命名规范、代码风格、文件结构、组件开发等方面的规范。遵循本文档的规范,可以提高代码的可读性、可维护性和可扩展性,确保项目的质量和稳定性。

代码规范是团队协作的基础,建议开发团队成员严格遵循本文档的规范,共同维护一个高质量的代码库。

---

.Codebuddy/Skills/Admin Element/References/Deploy (.codebuddy/skills/admin-element/references/deploy.md)

管理端前端部署文档

1. 概述

本文档描述了 CRMEB 项目中管理端前端的部署流程,包括构建、部署、配置等环节,旨在规范前端部署流程,确保部署过程的顺利进行和系统的稳定运行。

2. 部署环境

2.1 服务器要求


- 操作系统: Linux (Ubuntu 18.04+、CentOS 7+)
- Web 服务器: Nginx 1.14+ 或 Apache 2.4+
- Node.js: v12.0.0+ (仅构建时需要)
- npm/yarn: v6.0.0+ (仅构建时需要)
- 内存: 至少 2GB RAM
- CPU: 至少 2 核 CPU
- 磁盘空间: 至少 20GB 可用空间

2.2 环境准备


- Web 服务器配置: 配置虚拟主机,指向前端构建产物目录
- SSL 证书: 配置 HTTPS,使用 SSL 证书
- 防火墙: 开放 80/443 端口
- 域名: 配置域名解析,指向服务器 IP

3. 构建流程

3.1 开发环境构建


- 命令:
npm run dev
- 用途: 本地开发,启动开发服务器
- 访问地址:
http://localhost:8080

3.2 测试环境构建


- 命令:
npm run build:test
- 用途: 测试环境部署
- 构建产物:
dist/ 目录

3.3 生产环境构建


- 命令:
npm run build:prod
- 用途: 生产环境部署
- 构建产物:
dist/ 目录

3.4 构建优化


- 代码压缩: 压缩 JS/CSS/HTML 文件
- 资源压缩: 压缩图片等静态资源
- Tree Shaking: 移除未使用的代码
- 代码分割: 按路由分割代码
- 预加载: 预加载关键资源

4. 部署方式

4.1 静态部署

#### 4.1.1 Nginx 配置

nginx
server {
listen 80;
server_name admin.example.com;
return 301 https://$server_name$request_uri;
}

server {
listen 443 ssl http2;
server_name admin.example.com;

# SSL 配置
ssl_certificate /path/to/ssl/cert.pem;
ssl_certificate_key /path/to/ssl/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers on;

# 静态文件配置
root /path/to/admin/dist;
index index.html;

# 路由重写,解决单页应用刷新 404 问题
location / {
try_files $uri $uri/ /index.html;
}

# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 30d;
add_header Cache-Control "public, max-age=2592000";
}

# 日志配置
access_log /var/log/nginx/admin_access.log;
error_log /var/log/nginx/admin_error.log;
}

text
#### 4.1.2 Apache 配置
apache
<VirtualHost *:80>
ServerName admin.example.com
Redirect permanent / https://admin.example.com/
</VirtualHost>

<VirtualHost *:443>
ServerName admin.example.com

# SSL 配置
SSLEngine on
SSLCertificateFile /path/to/ssl/cert.pem
SSLCertificateKeyFile /path/to/ssl/key.pem

# 静态文件配置
DocumentRoot /path/to/admin/dist
<Directory /path/to/admin/dist>
AllowOverride All
Require all granted
</Directory>

# 路由重写,解决单页应用刷新 404 问题
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>

# 日志配置
ErrorLog ${APACHE_LOG_DIR}/admin_error.log
CustomLog ${APACHE_LOG_DIR}/admin_access.log combined
</VirtualHost>

text

4.2 容器部署

#### 4.2.1 Dockerfile

dockerfile

基础镜像


FROM node:12-alpine as build

设置工作目录


WORKDIR /app

复制依赖文件


COPY package*.json ./

安装依赖


RUN npm install

复制源代码


COPY . .

构建生产版本


RUN npm run build:prod

生产镜像


FROM nginx:1.19-alpine

复制构建产物


COPY --from=build /app/dist /usr/share/nginx/html

复制 Nginx 配置


COPY nginx.conf /etc/nginx/conf.d/default.conf

暴露端口


EXPOSE 80

启动 Nginx


CMD ["nginx", "-g", "daemon off;"]
text
#### 4.2.2 Docker Compose
yaml
version: '3'
services:
admin:
build: .
ports:
- "80:80"
restart: always
volumes:
- ./ssl:/etc/nginx/ssl
environment:
- TZ=Asia/Shanghai
text
#### 4.2.3 部署命令
bash

构建镜像


docker build -t crmeb-admin .

运行容器


docker run -d --name crmeb-admin -p 80:80 crmeb-admin

使用 Docker Compose


docker-compose up -d
text

4.3 CDN 部署

#### 4.3.1 配置 CDN
- 源站设置: 指向静态文件服务器
- 缓存策略: 配置静态资源缓存时间
- HTTPS: 开启 HTTPS
- HTTP/2: 开启 HTTP/2

#### 4.3.2 部署流程
1. 构建前端项目
2. 上传构建产物到 CDN
3. 配置 CDN 缓存策略
4. 验证部署结果

5. 配置管理

5.1 环境变量配置


- 开发环境:
.env.development
- 测试环境:
.env.test
- 生产环境:
.env.production

5.2 配置示例

env

API 基础地址


VUE_APP_API_BASE_URL=https://api.example.com

静态资源 CDN 地址


VUE_APP_CDN_BASE_URL=https://cdn.example.com

应用名称


VUE_APP_TITLE=CRMEB 管理后台

构建环境


NODE_ENV=production

构建版本


VUE_APP_VERSION=1.0.0
text

5.3 运行时配置


- API 地址: 可通过环境变量或配置文件修改
- 主题配置: 可通过配置文件修改
- 权限配置: 可通过后端 API 动态获取

6. 部署流程

6.1 手动部署


1. 拉取代码:
git pull origin master
2. 安装依赖:
npm install
3. 构建项目:
npm run build:prod
4. 部署文件: 将
dist/ 目录复制到服务器
5. 配置 Web 服务器: 配置虚拟主机
6. 重启服务: 重启 Web 服务器
7. 验证部署: 访问管理端地址

6.2 自动化部署

#### 6.2.1 CI/CD 配置
- Jenkins: 配置 Jenkins 任务,实现自动构建和部署
- GitLab CI: 配置
.gitlab-ci.yml,实现自动构建和部署
- GitHub Actions: 配置
.github/workflows/deploy.yml,实现自动构建和部署

#### 6.2.2 GitHub Actions 示例

yaml
name: Deploy Admin Frontend

on:
push:
branches:
- master

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '12'

- name: Install dependencies
run: npm install

- name: Build project
run: npm run build:prod

- name: Deploy to server
uses: easingthemes/[email protected]
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
ARGS: '-rltgoDzvO --delete'
SOURCE: 'dist/'
REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
REMOTE_USER: ${{ secrets.REMOTE_USER }}
REMOTE_PORT: ${{ secrets.REMOTE_PORT }}
TARGET: ${{ secrets.REMOTE_TARGET }}

- name: Restart Nginx
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.REMOTE_HOST }}
username: ${{ secrets.REMOTE_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
port: ${{ secrets.REMOTE_PORT }}
script: sudo systemctl restart nginx

text

7. 监控与维护

7.1 监控


- 访问日志: 分析 Web 服务器访问日志
- 错误日志: 监控 Web 服务器错误日志
- 性能监控: 监控页面加载速度、响应时间
- 可用性监控: 监控服务可用性,设置告警

7.2 维护


- 定期更新: 定期更新前端代码,修复漏洞
- 缓存清理: 定期清理 CDN 缓存
- 日志清理: 定期清理日志文件
- 备份: 定期备份构建产物和配置文件

7.3 常见问题

#### 7.3.1 404 问题
- 问题: 刷新页面出现 404 错误
- 解决方案: 配置 Web 服务器,将所有请求重定向到 index.html

#### 7.3.2 静态资源加载失败
- 问题: 静态资源(JS/CSS/图片)加载失败
- 解决方案: 检查静态资源路径,确保 CDN 配置正确

#### 7.3.3 API 调用失败
- 问题: 前端无法调用后端 API
- 解决方案: 检查 API 地址配置,确保后端服务正常运行

#### 7.3.4 性能问题
- 问题: 页面加载慢,卡顿
- 解决方案: 优化前端代码,使用 CDN,启用 HTTP/2

8. 回滚策略

8.1 版本管理


- 版本号: 遵循语义化版本规范
- 发布记录: 记录每次发布的版本和变更内容
- 备份: 备份每次发布的构建产物

8.2 回滚流程


1. 停止服务: 停止当前版本的服务
2. 恢复备份: 恢复到上一个稳定版本
3. 重启服务: 启动恢复后的服务
4. 验证回滚: 验证服务是否正常运行

8.3 回滚方案


- 手动回滚: 手动复制备份文件到部署目录
- 自动化回滚: 通过 CI/CD 工具实现自动回滚
- 容器回滚: 通过 Docker 镜像版本回滚

9. 安全部署

9.1 HTTPS 配置


- SSL 证书: 使用正规 CA 签发的 SSL 证书
- 证书续期: 定期续期 SSL 证书
- HTTP 重定向: 将 HTTP 请求重定向到 HTTPS

9.2 安全头部


- Content-Security-Policy: 配置内容安全策略
- X-Content-Type-Options: 防止 MIME 类型嗅探
- X-Frame-Options: 防止点击劫持
- X-XSS-Protection: 启用 XSS 过滤

9.3 访问控制


- IP 白名单: 限制管理端访问 IP
- 登录验证: 强制登录验证
- 权限控制: 基于角色的权限控制
- 会话管理: 安全的会话管理

9.4 漏洞防护


- 依赖扫描: 定期扫描依赖包漏洞
- 代码审计: 定期进行代码安全审计
- 渗透测试: 定期进行渗透测试

10. 最佳实践

10.1 构建优化


- 使用缓存: 缓存依赖包和构建产物
- 并行构建: 使用多线程并行构建
- 增量构建: 只构建变更的文件
- 构建日志: 保存构建日志,便于排查问题

10.2 部署优化


- 灰度发布: 采用灰度发布策略
- 蓝绿部署: 采用蓝绿部署策略
- 滚动部署: 采用滚动部署策略
- 金丝雀发布: 采用金丝雀发布策略

10.3 监控优化


- 实时监控: 实时监控系统运行状态
- 告警机制: 设置合理的告警阈值
- 日志聚合: 聚合多服务器日志
- 性能分析: 定期分析系统性能

10.4 安全优化


- 最小权限: 遵循最小权限原则
- 定期更新: 定期更新依赖和系统
- 安全扫描: 定期进行安全扫描
- 应急响应: 建立安全应急响应机制

11. 总结

本文档描述了 CRMEB 项目中管理端前端的部署流程,包括构建、部署、配置等环节,以及相关的最佳实践和常见问题解决方案。

遵循本文档的部署流程和规范,可以确保前端部署的顺利进行和系统的稳定运行,同时提高部署效率和系统安全性。

随着项目的发展和技术的演进,部署流程也需要不断优化和调整,以适应新的业务需求和技术挑战。

---

.Codebuddy/Skills/Admin Element/References/Development Flow (.codebuddy/skills/admin-element/references/development_flow.md)

管理端前端开发流程文档

1. 概述

本文档描述了 CRMEB 项目中管理端前端的开发流程,包括需求分析、设计、编码、测试、部署等环节,旨在规范前端开发流程,提高开发效率和代码质量。

2. 开发流程

2.1 需求分析

#### 2.1.1 需求获取
- 需求来源: 产品经理、业务方、后端开发、测试人员
- 需求形式: PRD 文档、需求评审会议、邮件、即时通讯工具
- 需求内容: 功能需求、非功能需求、UI/UX 需求

#### 2.1.2 需求评审
- 评审人员: 前端开发、后端开发、产品经理、测试人员
- 评审内容: 需求可行性、技术实现方案、时间评估、风险评估
- 评审输出: 评审纪要、任务分解、时间计划

#### 2.1.3 需求确认
- 确认内容: 需求细节、技术方案、交付标准
- 确认形式: 需求确认邮件、需求确认会议
- 确认输出: 需求确认文档

2.2 设计阶段

#### 2.2.1 UI 设计
- 设计工具: Figma、Sketch、Adobe XD
- 设计内容: 页面布局、组件样式、交互设计、色彩方案
- 设计输出: UI 设计稿、设计规范文档

#### 2.2.2 技术设计
- 设计内容: 技术选型、架构设计、目录结构、组件设计、API 设计
- 设计输出: 技术设计文档、架构图、组件设计图

#### 2.2.3 原型设计
- 原型工具: Axure、Figma、Sketch
- 原型内容: 页面原型、交互原型、流程原型
- 原型输出: 交互式原型、流程图

2.3 编码实现

#### 2.3.1 环境搭建
- 开发环境: Node.js、npm/yarn、VS Code、Git
- 依赖安装:
npm installyarn install
- 开发工具: Vue DevTools、Chrome DevTools

#### 2.3.2 代码开发
- 开发顺序: 基础组件 → 页面组件 → 业务逻辑 → 测试
- 开发规范: 遵循代码规范、命名规范、文档规范
- 代码质量: 代码可读性、可维护性、可扩展性

#### 2.3.3 代码审查
- 审查人员: 前端团队成员
- 审查内容: 代码质量、功能实现、性能优化、安全防护
- 审查工具: GitLab/GitHub Code Review、ESLint、Prettier

2.4 测试验证

#### 2.4.1 单元测试
- 测试工具: Jest、Vue Test Utils
- 测试内容: 组件测试、工具函数测试、状态管理测试
- 测试覆盖率: 关键功能测试覆盖率 ≥ 80%

#### 2.4.2 功能测试
- 测试人员: 前端开发、测试人员
- 测试内容: 功能实现、交互体验、页面布局、响应式设计
- 测试工具: 浏览器、测试管理工具

#### 2.4.3 性能测试
- 测试工具: Chrome DevTools、Lighthouse、WebPageTest
- 测试内容: 首屏加载速度、页面渲染性能、内存使用、网络请求
- 测试指标: FCP、LCP、TTI、CLS、FID

#### 2.4.4 兼容性测试
- 测试浏览器: Chrome、Firefox、Safari、Edge
- 测试分辨率: 1024x768、1366x768、1920x1080
- 测试内容: 页面显示、功能实现、交互体验

2.5 部署上线

#### 2.5.1 构建打包
- 构建命令:
npm run build:prod
- 构建产物: 静态资源文件
- 构建优化: 代码压缩、资源压缩、Tree Shaking

#### 2.5.2 部署配置
- 部署环境: 测试环境、预发布环境、生产环境
- 部署工具: Nginx、Apache、CDN
- 配置内容: 服务器配置、域名配置、HTTPS 配置

#### 2.5.3 上线发布
- 发布流程: 测试环境 → 预发布环境 → 生产环境
- 发布时间: 非业务高峰期
- 发布监控: 实时监控系统运行状态

#### 2.5.4 上线后验证
- 验证内容: 功能验证、性能验证、兼容性验证
- 验证人员: 前端开发、测试人员、产品经理
- 验证输出: 上线验证报告

3. 开发规范

3.1 代码规范


- ESLint 规则: 遵循 Vue 官方推荐的 ESLint 规则
- Prettier 配置: 统一代码格式化规则
- 代码缩进: 4 空格缩进
- 命名规范: 组件名 PascalCase,变量/方法名 camelCase,常量全大写

3.2 提交规范


- 提交信息格式:
[类型] 描述
- 类型: feat(新功能)、fix(修复)、docs(文档)、style(样式)、refactor(重构)、test(测试)、chore(构建/依赖)
- 提交频率: 小步提交,每个功能或修复一个提交
- 提交内容: 只提交相关代码,不提交无关文件

3.3 分支规范


- 主分支: master(生产环境)、develop(开发环境)
- 功能分支: feature/功能名称
- 修复分支: fix/修复内容
- 发布分支: release/版本号
- 分支管理: 定期清理无用分支

3.4 文档规范


- README.md: 项目说明、安装说明、开发说明
- 组件文档: 组件使用说明、Props、Events、Slots
- API 文档: API 接口说明、请求参数、响应格式
- 开发文档: 开发流程、编码规范、部署流程

4. 开发工具

4.1 开发环境


- Node.js: v12.0.0+
- npm: v6.0.0+ 或 yarn: v1.22.0+
- VS Code: 最新版本
- Git: 最新版本

4.2 编辑器插件


- Vetur: Vue 开发插件
- ESLint: 代码检查插件
- Prettier: 代码格式化插件
- GitLens: Git 增强插件
- Debugger for Chrome: 浏览器调试插件
- Auto Close Tag: 自动闭合标签
- Auto Rename Tag: 自动重命名标签

4.3 开发工具


- Vue DevTools: Vue 开发调试工具
- Chrome DevTools: 浏览器调试工具
- Postman: API 测试工具
- Charles: 网络调试工具
- Figma/Sketch: UI 设计工具
- Zeplin: 设计协作工具

4.4 构建工具


- Webpack: 模块打包工具
- Babel: JavaScript 编译器
- Sass/Less: CSS 预处理器
- ESLint: 代码检查工具
- Prettier: 代码格式化工具

5. 常见问题及解决方案

5.1 需求变更

- 问题: 开发过程中需求发生变更
- 解决方案:
1. 记录需求变更内容
2. 评估变更影响范围
3. 与产品经理确认变更可行性
4. 调整开发计划和时间评估
5. 通知相关团队成员

5.2 技术难题

- 问题: 遇到技术难题无法解决
- 解决方案:
1. 查阅相关文档和资料
2. 寻求团队成员帮助
3. 咨询外部专家
4. 尝试替代方案
5. 记录解决方案,形成知识库

5.3 时间紧张

- 问题: 开发时间紧张,任务无法按时完成
- 解决方案:
1. 评估任务优先级
2. 与产品经理沟通,调整需求优先级
3. 寻求团队成员协助
4. 优化开发流程,提高开发效率
5. 加班完成(作为最后手段)

5.4 代码冲突

- 问题: Git 代码冲突
- 解决方案:
1. 拉取最新代码
2. 手动解决冲突
3. 测试冲突解决后的代码
4. 提交解决冲突后的代码
5. 通知相关团队成员

5.5 线上问题

- 问题: 线上出现问题
- 解决方案:
1. 快速定位问题原因
2. 制定解决方案
3. 紧急修复并部署
4. 验证修复效果
5. 分析问题原因,避免类似问题再次发生

6. 最佳实践

6.1 开发前准备


- 需求确认: 确保需求理解正确
- 技术方案: 制定详细的技术实现方案
- 环境搭建: 确保开发环境配置正确
- 依赖安装: 安装必要的依赖包

6.2 编码实现


- 组件化开发: 封装可复用组件
- 模块化开发: 按功能模块组织代码
- 代码复用: 提取公共逻辑,避免重复代码
- 性能优化: 考虑代码性能,避免性能瓶颈
- 安全性: 考虑代码安全性,避免安全漏洞

6.3 测试验证


- 单元测试: 编写关键功能的单元测试
- 功能测试: 全面测试功能实现
- 性能测试: 测试页面性能
- 兼容性测试: 测试不同浏览器兼容性
- 用户体验测试: 测试页面交互体验

6.4 部署上线


- 构建优化: 优化构建产物
- 部署策略: 采用灰度发布策略
- 监控告警: 配置系统监控和告警
- 回滚方案: 准备系统回滚方案
- 上线验证: 上线后及时验证系统状态

6.5 维护迭代


- 问题跟踪: 及时跟踪和解决线上问题
- 代码维护: 定期维护和优化代码
- 文档更新: 及时更新相关文档
- 技术债务: 定期清理技术债务
- 知识共享: 分享开发经验和解决方案

7. 团队协作

7.1 协作模式


- 敏捷开发: 采用 Scrum 或 Kanban 敏捷开发模式
- 每日站会: 每日 15 分钟站会,同步开发进度
- 迭代周期: 2-4 周一个迭代周期
- 迭代回顾: 迭代结束后进行回顾,总结经验教训

7.2 沟通工具


- 即时通讯: 企业微信、钉钉、Slack
- 项目管理: Jira、Trello、GitHub Issues
- 代码托管: GitLab、GitHub、Gitee
- 文档协作: 语雀、Confluence、Google Docs

7.3 知识共享


- 技术分享: 定期组织技术分享会议
- 代码审查: 相互代码审查,分享编码经验
- 问题讨论: 定期组织问题讨论会议
- 知识库: 建立团队知识库,积累技术经验

8. 总结

本文档描述了 CRMEB 项目中管理端前端的开发流程,包括需求分析、设计、编码、测试、部署等环节,以及相关的开发规范和最佳实践。

遵循本文档的开发流程和规范,可以提高前端开发效率和代码质量,减少开发过程中的问题和风险,确保项目的顺利进行。

同时,开发流程也需要根据项目的实际情况进行调整和优化,以适应不同项目的需求和特点。

---

.Codebuddy/Skills/Admin Element/References/Directory Structure (.codebuddy/skills/admin-element/references/directory_structure.md)

Admin-Element 目录结构文档

1 项目根目录结构


template/ # 前端项目目录
├── admin-element/ # 管理端前端项目
│ ├── public/ # 静态资源目录
│ │ ├── favicon.ico # 网站图标
│ │ ├── index.html # 入口HTML文件
│ │ └── static/ # 静态资源文件
│ ├── src/ # 源代码目录
│ │ ├── api/ # API接口定义
│ │ ├── assets/ # 静态资源
│ │ ├── components/ # 通用组件
│ │ ├── config/ # 配置文件
│ │ ├── directive/ # 自定义指令
│ │ ├── filters/ # 过滤器
│ │ ├── layout/ # 布局组件
│ │ ├── router/ # 路由配置
│ │ ├── store/ # 状态管理
│ │ ├── styles/ # 样式文件
│ │ ├── utils/ # 工具函数
│ │ ├── views/ # 页面组件
│ │ ├── App.vue # 根组件
│ │ └── main.js # 入口文件
│ ├── tests/ # 测试文件
│ ├── .env.* # 环境变量配置
│ ├── babel.config.js # Babel配置
│ ├── package.json # 项目依赖
│ ├── vue.config.js # Vue配置
│ └── README.md # 项目说明
text

2 主要目录说明

2.1 public/ 目录


- favicon.ico: 网站图标文件
- index.html: 应用入口HTML文件,Vue应用将挂载到这个文件中
- static/: 静态资源目录,存放不需要经过webpack处理的静态文件

2.2 src/ 目录

#### 2.2.1 api/ 目录
- 定义所有API接口请求
- 按模块组织API文件
- 包含接口调用方法和参数配置

#### 2.2.2 assets/ 目录
- images/: 图片资源
- icons/: 图标资源
- styles/: 全局样式文件
- 其他静态资源文件

#### 2.2.3 components/ 目录
- base/: 基础组件
- business/: 业务组件
- common/: 通用组件
- 可复用的Vue组件

#### 2.2.4 config/ 目录
- index.js: 主配置文件
- router.config.js: 路由配置
- menu.config.js: 菜单配置
- theme.config.js: 主题配置
- 其他系统配置文件

#### 2.2.5 directive/ 目录
- 自定义Vue指令
- 如权限控制、表单验证等指令

#### 2.2.6 filters/ 目录
- 自定义Vue过滤器
- 如日期格式化、数字格式化等

#### 2.2.7 layout/ 目录
- components/: 布局组件
- index.vue: 主布局文件
- AppMain.vue: 内容区域组件
- Navbar.vue: 导航栏组件
- Sidebar.vue: 侧边栏组件

#### 2.2.8 router/ 目录
- index.js: 路由配置主文件
- modules/: 按模块组织的路由配置
- 路由守卫配置

#### 2.2.9 store/ 目录
- index.js: 状态管理主文件
- modules/: 按模块组织的状态管理
- getters.js: 全局计算属性

#### 2.2.10 styles/ 目录
- index.scss: 全局样式入口
- variables.scss: 全局变量
- mixins.scss: 混合器
- reset.scss: 重置样式

#### 2.2.11 utils/ 目录
- request.js: 网络请求封装
- auth.js: 认证相关工具
- tools.js: 通用工具函数
- storage.js: 存储工具

#### 2.2.12 views/ 目录
- 按业务模块组织页面组件
- 每个模块一个目录
- 包含页面组件和相关子组件

#### 2.2.13 App.vue
- 应用根组件
- 包含全局布局结构

#### 2.2.14 main.js
- 应用入口文件
- 初始化Vue实例
- 加载插件和全局配置

2.3 配置文件

#### 2.3.1 package.json
- 项目依赖配置
- 脚本命令配置
- 项目信息配置

#### 2.3.2 vue.config.js
- Vue CLI配置
- 构建配置
- 代理配置

#### 2.3.3 babel.config.js
- Babel转译配置

#### 2.3.4 .env.*
- 环境变量配置文件
- .env.development: 开发环境
- .env.production: 生产环境
- .env.staging: 测试环境

3 目录规范

3.1 命名规范


- 目录名使用小写字母,多单词用连字符(-)分隔
- 文件名使用小写字母,多单词用连字符(-)分隔
- 组件名使用 PascalCase 命名法

3.2 目录组织原则


1. 按功能模块组织: 相关功能的文件放在同一目录
2. 模块化: 每个模块保持相对独立
3. 可扩展性: 目录结构应易于扩展和维护
4. 一致性: 保持目录结构的一致性

3.3 特殊目录处理


- components/: 只存放可复用组件
- views/: 存放页面级组件
- api/: 按模块组织API接口
- store/modules/: 按模块组织状态管理

4 最佳实践

4.1 目录使用建议


- 新增业务模块时,在 views/ 下创建对应的目录
- 新增可复用组件时,放在 components/ 下的对应子目录
- 新增API接口时,在 api/ 下按模块组织
- 新增状态管理时,在 store/modules/ 下创建对应模块

4.2 目录结构维护


- 定期清理无用文件和目录
- 保持目录结构的清晰和整洁
- 遵循统一的命名规范
- 文档及时更新,反映目录结构的变化

5 常见问题

5.1 目录权限问题


- 确保目录权限正确,避免构建时出现权限错误

5.2 路径引用问题


- 使用相对路径或别名路径引用文件
- 避免使用绝对路径

5.3 目录结构优化


- 随着项目规模增大,适时调整目录结构
- 保持目录层级合理,避免过深的嵌套

6 总结

Admin-Element 项目采用标准的 Vue + ElementUI 项目结构,通过清晰的目录组织和命名规范,提高了代码的可维护性和可扩展性。开发者应遵循目录结构规范,合理组织代码,确保项目的长期可维护性。

---

.Codebuddy/Skills/Crmeb Agent/SKILL (.codebuddy/skills/crmeb-agent/SKILL.md)

---
name: CRMEB电商系统Agent
description: 专为CRMEB电商系统设计的智能开发助手,帮助开发者理解架构、快速开发功能、解决问题
---

CRMEB电商系统Agent

0. 自动触发说明

0.1 触发条件

#### 0.1.1 操作触发
- 文件浏览时: 当浏览CRMEB项目核心目录时自动调用
- 打开
crmeb/app/ 应用目录时触发
- 打开
crmeb/crmeb/ 核心库目录时触发
- 打开
template/ 前端目录时触发
- 浏览配置文件目录时触发
- 文件操作时: 当对CRMEB项目文件进行操作时自动调用
- 创建控制器、服务、模型时触发
- 修改核心业务代码时触发
- 修改配置文件时触发
- 目录操作时: 当对项目目录进行操作时自动调用
- 创建新模块目录时触发
- 重命名业务目录时触发

#### 0.1.2 内容触发
- 关键词触发: 当文件内容包含以下关键词时自动调用
- 电商关键词:
订单商品用户支付购物车
- 营销关键词:
优惠券拼团砍价秒杀积分
- 系统关键词:
CRMEBThinkPHP后台管理移动端
- 代码触发: 当查看特定类型代码时自动调用
- 控制器代码 (
Controller)
- 服务层代码 (
Services)
- 模型代码 (
Model)
- 前端Vue组件 (
*.vue)

#### 0.1.3 命令触发
- 终端命令触发: 当执行以下命令时自动调用
-
php think (ThinkPHP命令)
-
composer install/update (依赖管理)
-
npm run dev/build (前端构建)
-
php think queue:listen (队列启动)
-
php think workerman (WebSocket启动)

0.2 适用场景

#### 0.2.1 核心场景
- 功能开发: 开发新的电商功能模块时
- API开发: 开发前后端接口时
- 数据库设计: 设计数据表结构时
- 问题排查: 解决系统运行问题时

#### 0.2.2 辅助场景
- 代码审查: 审查代码质量时
- 性能优化: 优化系统性能时
- 安全加固: 增强系统安全性时
- 部署运维: 部署和维护系统时

1. CRMEB系统架构

1.1 整体架构


- 框架: ThinkPHP 6.x (PHP后端) + Vue 2.x (前端)
- 架构模式: 前后端分离 + MVC + Service + DAO分层架构
- 数据库: MySQL 5.7-8.0 (使用eb_前缀)
- 缓存: Redis (可选,用于缓存和队列)
- 消息队列: ThinkPHP Queue + Workerman
- 实时通信: Workerman WebSocket

1.2 技术栈

#### 后端技术栈


- PHP: 7.1-7.4
- ThinkPHP: 6.x
- Composer: 依赖管理
- Workerman: 长连接服务
- PHPUnit: 单元测试(可选)
text
#### 前端技术栈

管理端:
- Vue.js 2.x
- Element UI 2.15.6
- Vuex 3.0
- Vue Router 3.0
- Axios
- ECharts 4.8.0

移动端:
- UniApp
- uView UI

text
#### 第三方服务

- 支付: 微信支付、支付宝支付
- 存储: 阿里云OSS、腾讯云COS、七牛云
- 短信: 阿里云短信
- 微信: 公众号、小程序
text

1.3 目录结构

#### 1.3.1 后端目录结构


/ Detailed source-code truncated for AI context efficiency. /
text
#### 1.3.2 前端目录结构

template/
├── admin/ # 管理后台 (Vue + ElementUI)
│ ├── src/
│ │ ├── api/ # API接口定义
│ │ ├── components/ # 通用组件
│ │ ├── pages/ # 页面组件
│ │ ├── router/ # 路由配置
│ │ ├── store/ # Vuex状态管理
│ │ └── utils/ # 工具函数
│ ├── package.json
│ └── vue.config.js
└── uni-app/ # 移动端 (UniApp)
├── api/ # API接口
├── components/ # 组件
├── pages/ # 页面
├── manifest.json # 应用配置
└── pages.json # 页面路由配置
text

2. 核心业务模块

2.1 用户模块 (app/services/user/)

#### 核心服务
- UserServices: 用户主服务,管理用户基础信息
- LoginServices: 登录服务,处理多种登录方式
- UserLevelServices: 用户等级管理
- UserMoneyServices: 用户余额管理
- UserBillServices: 账单流水管理
- UserExtractServices: 提现管理
- UserRechargeServices: 充值管理
- UserGroupServices: 用户分组
- UserLabelServices: 用户标签

#### 数据表

sql
eb_user # 用户表
eb_user_bill # 账单表
eb_user_extract # 提现表
eb_user_recharge # 充值表
eb_user_level # 用户等级表
eb_user_group # 用户分组表
eb_user_label # 用户标签表
text
#### 开发要点
- 用户登录支持多种方式: 账号密码、手机验证码、微信授权
- 用户余额变动必须记录到账单表
- 用户等级可以设置升级条件
- 用户分组和标签用于精准营销

2.2 商品模块 (app/services/product/)

#### 核心服务
- StoreProductServices: 商品主服务
- StoreCategoryServices: 商品分类
- StoreProductAttrServices: 商品属性
- StoreProductReplyServices: 商品评价
- CopyTaobaoServices: 淘宝商品采集

#### 数据表

sql
eb_store_product # 商品表
eb_store_category # 商品分类表
eb_store_product_attr # 商品属性表
eb_store_product_reply # 商品评价表
eb_store_product_description # 商品详情表
text
#### 开发要点
- 商品支持多规格(SKU),需要处理库存和价格
- 商品可以设置为普通商品、积分商品、预售商品等
- 商品分类支持多级分类
- 商品属性支持自定义规格

2.3 订单模块 (app/services/order/)

#### 核心服务
- StoreOrderServices: 订单主服务
- StoreOrderCreateServices: 订单创建
- StoreOrderDeliveryServices: 订单发货
- StoreOrderRefundServices: 订单退款
- StoreCartServices: 购物车
- OtherOrderServices: 其他订单(积分订单等)
- OutStoreOrderServices: 外部订单

#### 数据表

sql
eb_store_order # 订单表
eb_store_order_cart # 订单商品表
eb_store_order_status # 订单状态变更记录
eb_store_refund # 退款表
eb_store_cart # 购物车表
text
#### 开发要点
- 订单状态流转: 未支付 → 待发货 → 待收货 → 已完成 (或取消/退款)
- 订单创建时需要扣减库存
- 支付成功后触发后续流程(发货通知、积分增加等)
- 订单退款需要恢复库存
- 订单相关操作建议使用队列异步处理

#### 订单状态流转图


未支付 (status=0)
↓ 支付成功
待发货 (status=1)
↓ 发货
待收货 (status=2)
↓ 确认收货
已完成 (status=3)

分支流程:
- 未支付 → 已取消 (status=-1)
- 待发货 → 申请退款 → 退款中 (status=-2) → 已退款 (status=-3)
- 待收货 → 申请退款 → 退款中 (status=-2) → 已退款 (status=-3)

text

2.4 支付模块 (app/services/pay/)

#### 核心服务
- PayServices: 支付服务
- WechatPayServices: 微信支付
- AlipayServices: 支付宝支付

#### 数据表

sql
eb_pay # 支付记录表
text
#### 开发要点
- 支付方式: 微信支付(公众号/小程序/H5)、支付宝支付、余额支付
- 支付流程: 创建订单 → 调起支付 → 支付回调 → 更新订单状态
- 支付回调需要验证签名防止伪造
- 支付成功后触发事件,可以扩展后续业务逻辑

2.5 营销模块 (app/services/activity/)

#### 核心服务
- 拼团: StoreCombinationServices, StorePinkServices
- 砍价: StoreBargainServices
- 秒杀: StoreSeckillServices
- 优惠券: StoreCouponService, StoreCouponUserServices
- 积分: StoreIntegralServices
- 直播: LiveRoomServices, LiveGoodsServices
- 抽奖: LuckLotteryServices

#### 数据表

sql
eb_store_combination # 拼团商品表
eb_store_pink # 拼团记录表
eb_store_bargain # 砍价商品表
eb_store_bargain_user # 砍价记录表
eb_store_seckill # 秒杀商品表
eb_store_coupon # 优惠券表
eb_store_coupon_user # 用户优惠券表
eb_integral_product # 积分商品表
text
#### 开发要点
- 营销活动都需要设置时间范围
- 优惠券可以设置使用条件和适用商品
- 拼团需要处理拼团成功/失败的逻辑
- 砍价需要处理砍价进度和完成时间
- 秒杀商品需要限制库存和购买数量

2.6 分销模块 (app/services/agent/)

#### 核心服务
- AgentLevelServices: 分销等级管理
- AgentLevelTaskServices: 分销任务系统
- DivisionServices: 事业部/代理管理
- SpreadApplyServices: 分销申请

#### 数据表

sql
eb_agent_level # 分销等级表
eb_agent_level_task # 分销任务表
eb_division # 事业部表
eb_spread_apply # 分销申请表
text
#### 开发要点
- 分销系统支持多级分销
- 分销员等级通过完成任务自动升级
- 分销佣金结算需要计算各级佣金
- 分销申请需要管理员审核

2.7 系统管理模块 (app/services/system/)

#### 核心服务
- SystemCrudServices: CRUD代码生成器
- SystemConfigServices: 系统配置
- SystemEventServices: 系统事件管理
- SystemCrontabServices: 定时任务管理
- SystemMenusServices: 菜单管理
- SystemAdminServices: 管理员管理
- SystemLogServices: 操作日志
- SystemFileServices: 文件管理
- SystemUpgradeServices: 系统升级

#### 开发要点
- 代码生成器: 可以快速生成Controller、Service、DAO、Model、Validate
- 系统配置: 支持后台动态配置,存储在数据库中
- 事件系统: 定义了30+系统事件锚点,可以扩展业务逻辑
- 定时任务: 基于Workerman,支持Cron表达式
- 权限管理: 基于RBAC模型,可以控制到菜单和按钮级别

3. 开发规范

3.1 命名规范

#### 类命名
- 控制器: 模块名 + Controller,如
UserController
- 服务: 模块名 + Services,如
UserServices
- DAO: 模块名 + Dao,如
UserDao
- 模型: 模块名,如
User
- 验证器: 模块名 + Validate,如
UserValidate

#### 方法命名
- 控制器方法: 小写+下划线,如
get_list, save_data
- 服务方法: 驼峰法,如
getUserList, saveData
- DAO方法: 数据库操作相关,如
selectList, insert, update, delete

#### 变量命名
- 普通变量: 驼峰法,如
$userName, $orderId
- 数组变量: 复数形式,如
$users, $products
- 布尔变量: is/has/can开头,如
$isPaid, $hasStock

3.2 代码规范

#### 控制器层

php
<?php
namespace app\adminapi\controller\system;

use think\facade\App;
use app\services\system\SystemAdminServices;

/
* 管理员控制器
*/
class SystemAdminController
{
protected $services;

public function __construct(App $app, SystemAdminServices $services)
{
$this->services = $services;
}

/
* 获取管理员列表
* @return mixed
*/
public function get_list()
{
$where = $this->request->getMore([
['keywords', ''],
['status', '']
]);
$list = $this->services->getAdminList($where);
return app('json')->success($list);
}

/
* 保存管理员
* @return mixed
*/
public function save()
{
$data = $this->request->postMore([
['account', ''],
['real_name', ''],
['pwd', ''],
['roles', []],
['status', 1]
]);
$this->services->saveAdmin($data);
return app('json')->success('保存成功');
}
}

text
#### 服务层
php
<?php
namespace app\services\system;

use crmeb\basic\BaseServices;
use crmeb\exceptions\AdminException;

class SystemAdminServices extends BaseServices
{
/
* 获取管理员列表
* @param array $where
* @return array
*/
public function getAdminList(array $where): array
{
// 构建查询条件
$query = $this->dao->search($where);

// 获取列表
$list = $query->select()->toArray();

// 处理数据
foreach ($list as &$item) {
$item['role_names'] = $this->getRoleNames($item['roles']);
}

return $list;
}

/
* 保存管理员
* @param array $data
* @return int
*/
public function saveAdmin(array $data): int
{
// 验证数据
if (empty($data['account'])) {
throw new AdminException('账号不能为空');
}

// 密码加密
if (!empty($data['pwd'])) {
$data['pwd'] = password_hash($data['pwd'], PASSWORD_DEFAULT);
} else {
unset($data['pwd']);
}

// 保存数据
if (isset($data['id']) && $data['id']) {
// 更新
$id = $data['id'];
unset($data['id']);
$this->dao->update($id, $data);
} else {
// 新增
$id = $this->dao->save($data);
}

return $id;
}
}

text
#### DAO层
php
<?php
namespace app\dao\system;

use crmeb\basic\BaseDao;
use app\model\system\SystemAdmin;

class SystemAdminDao extends BaseDao
{
/
* 设置模型
* @return string
*/
protected function setModel(): string
{
return SystemAdmin::class;
}

/
* 搜索条件
* @param array $where
* @return \think\Model
*/
public function search(array $where = [])
{
$query = $this->getModel()
->where('is_del', 0);

// 账号搜索
if (!empty($where['keywords'])) {
$query = $query->whereLike('account|real_name', "%{$where['keywords']}%");
}

// 状态筛选
if ($where['status'] !== '') {
$query = $query->where('status', $where['status']);
}

return $query;
}
}

text
#### 模型层
php
<?php
namespace app\model\system;

use crmeb\basic\BaseModel;

class SystemAdmin extends BaseModel
{
protected $name = 'system_admin';

protected $pk = 'id';

/
* 关联角色
* @return \think\model\relation\BelongsToMany
*/
public function roles()
{
return $this->belongsToMany(SystemRole::class, 'system_admin_role', 'role_id', 'admin_id');
}

/
* 密码修改器
* @param $value
* @return string
*/
public function setPwdAttr($value)
{
return password_hash($value, PASSWORD_DEFAULT);
}

/
* 状态获取器
* @param $value
* @return string
*/
public function getStatusTextAttr($value, $data)
{
$status = [
0 => '禁用',
1 => '启用'
];
return $status[$data['status']] ?? '';
}
}

text

3.3 数据库规范

#### 表命名
- 使用小写字母和下划线
- 统一使用
eb_ 前缀
- 表名使用复数形式或明确含义

#### 字段命名
- 使用小写字母和下划线
- 字段名不以下划线开头
- 主键统一命名为
id
- 外键命名为
表名_id,如 user_id
- 时间字段命名为
create_time, update_time
- 状态字段命名为
status,默认值0
- 删除标记命名为
is_del,0未删除1已删除

#### 字段类型
- 整型: 使用
int,如 tinyint, smallint, int, bigint
- 字符串: 使用
varchar,如 varchar(255)
- 文本: 使用
text
- 金额: 使用
decimal(10,2)
- 时间: 使用
int(时间戳)或 datetime

3.4 API规范

#### 请求方式
- GET: 查询数据
- POST: 创建数据
- PUT: 更新数据
- DELETE: 删除数据

#### 响应格式

json
{
"code": 200,
"msg": "操作成功",
"data": {}
}
text
#### 错误响应
json
{
"code": 400,
"msg": "错误信息",
"data": null
}
text
#### 分页响应
json
{
"code": 200,
"msg": "操作成功",
"data": {
"list": [],
"count": 100,
"page": 1,
"limit": 10
}
}
text

4. 自动化功能

4.1 代码生成器

#### 使用方式
1. 在后台管理中进入"系统管理" > "代码生成"
2. 选择数据表
3. 配置生成参数(字段类型、搜索类型、表单类型等)
4. 生成代码

#### 支持的表单类型
- input: 普通输入框
- textarea: 文本域
- select: 下拉选择
- radio: 单选框
- checkbox: 复选框
- date: 日期选择
- datetime: 日期时间选择
- image: 图片上传
- file: 文件上传
- editor: 富文本编辑器
- number: 数字输入
- switch: 开关
- 等等

#### 支持的搜索类型
- 普通搜索: 普通文本搜索
- 日期范围: 日期区间搜索
- 时间范围: 时间区间搜索
- 下拉选择: 下拉筛选

4.2 定时任务

#### 启动命令

bash

启动定时任务(守护进程)


php think timer start --d

停止定时任务


php think timer stop

重启定时任务


php think timer restart

查看定时任务状态


php think timer status
text
#### 系统预置定时任务
1. 自动取消未支付订单
2. 自动确认收货
3. 自动评价
4. 自动关闭拼团
5. 自动关闭砍价
6. 积分到期处理
7. 优惠券过期处理
8. 分销佣金结算
9. 统计数据汇总
10. 系统日志清理

4.3 队列任务

#### 启动命令

bash

启动队列消费者


php think queue:listen --queue

或者使用Workerman


php think queue:work --queue
text
#### 主要队列任务
- OrderJob: 订单相关任务(创建、支付、发货等)
- PinkJob: 拼团任务
- BargainJob: 砍价任务
- SeckillJob: 秒杀任务
- AutoCommentJob: 自动评价
- PosterJob: 海报生成
- AgentJob: 分销等级升级检测
- UnpaidOrderCancelJob: 未支付订单取消
- 等等

4.4 事件系统

#### 系统事件锚点

用户事件:
- 用户注册 (user.register)
- 用户登录 (user.login)
- 用户注销 (user.logout)
- 用户修改信息 (user.update)
- 用户绑定推广 (user.bind_spread)
- 用户签到 (user.sign)
- 用户充值 (user.recharge)

订单事件:
- 订单创建 (order.create)
- 订单支付成功 (order.pay_success)
- 订单发货 (order.delivery)
- 订单收货 (order.confirm)
- 订单取消 (order.cancel)
- 订单退款 (order.refund)

商品事件:
- 商品上架 (product.on_shelf)
- 商品下架 (product.off_shelf)
- 商品评价 (product.comment)

支付事件:
- 支付成功 (pay.success)
- 支付失败 (pay.fail)

营销事件:
- 领取优惠券 (coupon.receive)
- 参与拼团 (combination.join)
- 参与砍价 (bargain.join)

#### 事件监听器开发

php
<?php
namespace app\listener\order;

use think\Container;

/
* 订单支付成功监听器
*/
class OrderPaySuccessListener
{
/
* 订单支付成功事件处理
* @param $event
* @return void
*/
public function handle($event)
{
// $event 包含订单信息
$order = $event['order'];

// 业务逻辑
// 1. 发送通知
// 2. 增加积分
// 3. 更新库存
// 4. 触发分销佣金计算
// ...
}
}

text

4.5 WebSocket实时通信

#### 启动命令

bash

启动WebSocket服务


php think workerman start --d
text
#### 服务配置
php
// config/workerman.php
return [
// 管理后台通知
'admin' => [
'protocol' => 'websocket',
'port' => 40001,
'ip' => '0.0.0.0',
],
// 客服消息
'chat' => [
'protocol' => 'websocket',
'port' => 40002,
'ip' => '0.0.0.0',
],
// 内部通讯
'channel' => [
'port' => 40003,
'ip' => '127.0.0.1',
],
];
text
#### 使用场景
- 新订单实时通知
- 客服在线聊天
- 系统消息推送
- 实时数据统计

5. 常见开发场景

5.1 创建新功能模块

#### 步骤1: 创建数据表

sql
CREATE TABLE
eb_example (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL DEFAULT '' COMMENT '名称',
status tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态 0禁用 1启用',
create_time int(11) NOT NULL DEFAULT '0' COMMENT '创建时间',
update_time int(11) NOT NULL DEFAULT '0' COMMENT '更新时间',
is_del tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除',
PRIMARY KEY (
id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='示例表';
text
#### 步骤2: 创建模型
bash

使用命令行生成模型


php think make:model Example
text
#### 步骤3: 创建DAO
php
<?php
namespace app\dao;

use crmeb\basic\BaseDao;
use app\model\Example;

class ExampleDao extends BaseDao
{
protected function setModel(): string
{
return Example::class;
}
}

text
#### 步骤4: 创建服务
php
<?php
namespace app\services;

use crmeb\basic\BaseServices;
use app\dao\ExampleDao;

class ExampleServices extends BaseServices
{
public function __construct(ExampleDao $dao)
{
$this->dao = $dao;
}

public function getList(array $where): array
{
return $this->dao->getList($where);
}

public function save(array $data): int
{
return $this->dao->save($data);
}
}

text
#### 步骤5: 创建控制器
php
<?php
namespace app\adminapi\controller;

use app\services\ExampleServices;

class ExampleController
{
protected $services;

public function __construct(ExampleServices $services)
{
$this->services = $services;
}

public function get_list()
{
$where = $this->request->getMore([
['name', ''],
['status', '']
]);
$list = $this->services->getList($where);
return app('json')->success($list);
}

public function save()
{
$data = $this->request->postMore([
['name', ''],
['status', 1]
]);
$this->services->save($data);
return app('json')->success('保存成功');
}
}

text
#### 步骤6: 创建路由
php
// route/app.php 或 route/adminapi.php
use think\facade\Route;

Route::group('example', function () {
Route::get('list', 'Example/get_list');
Route::post('save', 'Example/save');
});

text
#### 步骤7: 使用代码生成器(可选)
直接在后台管理系统配置代码生成,自动生成前后端代码

5.2 开发订单功能

#### 订单创建流程
1. 校验商品库存和状态
2. 计算订单金额
3. 创建订单记录
4. 创建订单商品记录
5. 扣减商品库存
6. 清空购物车
7. 触发订单创建事件

#### 订单支付流程
1. 调起支付(微信/支付宝/余额)
2. 接收支付回调
3. 验证签名
4. 更新订单状态为"待发货"
5. 扣减优惠券
6. 增加用户积分
7. 触发支付成功事件(分销、通知等)

#### 订单发货流程
1. 获取订单信息
2. 填写物流信息
3. 更新订单状态为"待收货"
4. 发送发货通知
5. 触发发货事件

#### 订单收货流程
1. 用户确认收货或系统自动收货(7天未收货)
2. 更新订单状态为"已完成"
3. 结算分销佣金
4. 增加用户积分
5. 触发收货事件

5.3 开发营销活动

#### 优惠券功能开发要点
1. 创建优惠券模板(面额、门槛、使用条件等)
2. 用户领取优惠券
3. 下单时选择优惠券
4. 计算优惠金额
5. 支付后核销优惠券
6. 过期自动失效

#### 拼团功能开发要点
1. 创建拼团商品(拼团价、成团人数、拼团时长)
2. 用户发起拼团
3. 其他人参与拼团
4. 拼团成功/失败判断
5. 成团后按拼团价计算订单
6. 失败后退款

#### 秒杀功能开发要点
1. 创建秒杀活动(时间、商品、库存、限购)
2. 用户参与秒杀
3. 检查库存和限购
4. 创建秒杀订单
5. 未支付订单自动取消
6. 活动结束后更新库存

5.4 开发分销功能

#### 分销流程
1. 用户申请成为分销员
2. 管理员审核通过
3. 分销员分享推广链接
4. 新用户通过链接注册成为下级
5. 下级用户下单
6. 系统计算分销佣金
7. 佣金结算到分销员余额

#### 分销等级升级
1. 创建分销等级(等级名称、佣金比例)
2. 设置升级任务(订单数、金额等)
3. 定时任务检测分销员任务完成情况
4. 达到条件自动升级

6. 问题排查指南

6.1 常见错误

#### 数据库连接错误

php
// 错误信息
SQLSTATE[HY000] [2002] Connection refused

// 排查步骤
1. 检查数据库服务是否启动
2. 检查 .env 配置文件中的数据库配置
3. 检查数据库用户权限
4. 检查防火墙设置

text
#### 队列任务不执行
php
// 排查步骤
1. 检查队列消费者是否启动: php think queue:work
2. 检查队列配置: config/queue.php
3. 检查Redis连接: redis-cli ping
4. 查看队列日志: runtime/log/
text
#### 定时任务不执行
bash

排查步骤


1. 检查定时任务是否启动: php think timer status
2. 检查定时任务配置
3. 检查Cron表达式是否正确
4. 查看定时任务日志
text
#### WebSocket连接失败
bash

排查步骤


1. 检查WebSocket服务是否启动: php think workerman status
2. 检查端口是否被占用: netstat -tlnp | grep 40001
3. 检查防火墙设置
4. 检查客户端连接地址是否正确
text

6.2 性能优化

#### 数据库优化
- 为常用查询字段添加索引
- 避免使用
SELECT *,只查询需要的字段
- 使用
EXPLAIN 分析SQL执行计划
- 合理使用缓存减少数据库查询

#### 缓存优化
- 使用Redis缓存热点数据
- 设置合理的缓存过期时间
- 使用缓存前缀防止冲突

#### 代码优化
- 减少循环嵌套
- 优化算法复杂度
- 使用队列处理耗时操作
- 异步处理非关键业务

6.3 安全加固

#### SQL注入防护
- 使用参数绑定,不要直接拼接SQL
- 使用ThinkPHP的查询构造器
- 对用户输入进行验证

#### XSS防护
- 对用户输入进行过滤
- 输出时进行HTML转义
- 使用CSP(内容安全策略)

#### CSRF防护
- 使用CSRF Token
- 验证请求来源
- 重要操作二次确认

#### 权限控制
- 严格的权限验证
- 基于RBAC的权限模型
- 敏感操作记录日志

7. 部署与运维

7.1 环境要求


- PHP >= 7.1
- MySQL >= 5.7
- Redis >= 5.0 (可选)
- Nginx/Apache
- Composer

7.2 部署步骤

#### 1. 安装依赖

bash
composer install
text
#### 2. 配置环境
bash
cp .env.example .env

修改 .env 文件中的配置


text
#### 3. 数据库初始化
bash

导入数据库


mysql -u root -p crmeb < database.sql
text
#### 4. 设置目录权限
bash
chmod -R 755 runtime
chmod -R 755 public/uploads
text
#### 5. 启动服务
bash

启动队列


php think queue:listen --queue

启动定时任务


php think timer start --d

启动WebSocket


php think workerman start --d
text
#### 6. 前端构建
bash
cd template/admin
npm install
npm run build
text

7.3 Docker部署

#### 使用docker-compose

bash
cd docker-compose
docker-compose up -d
text

7.4 监控与日志

#### 日志位置
- 应用日志:
runtime/log/
- 错误日志:
runtime/log/error/
- SQL日志: 开启数据库SQL日志记录

#### 监控指标
- 服务器资源: CPU、内存、磁盘
- 应用性能: 响应时间、吞吐量
- 数据库: 慢查询、连接数
- 队列: 队列长度、处理速度

8. 参考资源

8.1 官方文档


- ThinkPHP 6 官方文档
- Vue 2 官方文档
- Element UI 官方文档
- UniApp 官方文档

8.2 项目文档


-
/dev-docs/AI代码理解指南.md - 代码理解指南
-
/dev-docs/错误码说明文档.md - 错误码说明
-
.codebuddy/skills/php-api/SKILL.md - 后端开发规范
-
.codebuddy/skills/admin-element/SKILL.md - 前端开发规范

8.3 工具推荐


- IDE: PhpStorm / VS Code
- API测试: Postman / Apifox
- 数据库: Navicat / phpMyAdmin
- Redis: Redis Desktop Manager

9. 常用命令速查

9.1 ThinkPHP命令

bash
php think # 查看所有命令
php think make:controller # 创建控制器
php think make:model # 创建模型
php think make:middleware # 创建中间件
php think make:validate # 创建验证器
php think clear # 清除缓存
php think run # 启动内置服务器
text

9.2 队列命令

bash
php think queue:listen # 监听队列
php think queue:work # 处理队列任务
php think queue:restart # 重启队列
php think queue:fail # 查看失败任务
php think queue:retry # 重试失败任务
text

9.3 定时任务命令

bash
php think timer start # 启动定时任务
php think timer stop # 停止定时任务
php think timer restart # 重启定时任务
php think timer status # 查看状态
text

9.4 Workerman命令

bash
php think workerman start # 启动
php think workerman stop # 停止
php think workerman restart # 重启
php think workerman reload # 平滑重启
php think workerman status # 查看状态
text
---

提示: 本Agent专为CRMEB电商系统设计,帮助您快速开发和理解系统。如有疑问,请参考官方文档或查看项目源码。

---

.Codebuddy/Skills/Php Api/References/Api Flow (.codebuddy/skills/php-api/references/api_flow.md)

接口请求文档

1. 概述

本文档描述了 CRMEB 项目中 API 接口请求的流程、规范、参数设计和响应格式等,旨在统一 API 请求格式,提高 API 的一致性和可维护性。

2. 接口请求流程

2.1 基本流程

1. 客户端发起请求: 客户端通过 HTTP/HTTPS 协议向服务器发送请求
2. 请求到达服务器: 请求经过网络传输到达服务器
3. 请求解析: 服务器解析请求,包括请求方法、路径、参数等
4. 认证授权: 服务器对请求进行认证和授权
5. 业务处理: 服务器执行相应的业务逻辑
6. 生成响应: 服务器生成响应数据
7. 返回响应: 服务器将响应返回给客户端
8. 客户端处理响应: 客户端处理服务器返回的响应

2.2 详细流程


┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 客户端 │ │ 中间件 │ │ 控制器 │
│ 1. 发起请求 │────▶│ 2. 认证授权 │────▶│ 3. 业务处理 │
└─────────────────┘ └─────────────────┘ └─────────────────┘


┌─────────────────┐
│ 服务层 │
│ 4. 执行逻辑 │
└─────────────────┘


┌─────────────────┐
│ 数据层 │
│ 5. 数据操作 │
└─────────────────┘


┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 客户端 │ │ 中间件 │ │ 控制器 │
│ 8. 处理响应 │◀────│ 7. 响应处理 │◀────│ 6. 生成响应 │
└─────────────────┘ └─────────────────┘ └─────────────────┘
text

3. 请求方法

3.1 HTTP 方法

| 方法 | 描述 | 幂等性 | 安全性 |
|------|------|--------|--------|
| GET | 获取资源 | 是 | 是 |
| POST | 创建资源 | 否 | 否 |
| PUT | 更新资源 | 是 | 否 |
| DELETE | 删除资源 | 是 | 否 |
| PATCH | 部分更新资源 | 否 | 否 |
| OPTIONS | 获取资源的可用操作 | 是 | 是 |
| HEAD | 获取资源的元数据 | 是 | 是 |

3.2 方法使用规范

- GET: 用于获取资源,不应修改资源状态
- POST: 用于创建新资源
- PUT: 用于更新整个资源,应包含资源的完整表示
- DELETE: 用于删除资源
- PATCH: 用于部分更新资源,只包含需要更新的字段
- OPTIONS: 用于获取资源支持的 HTTP 方法
- HEAD: 用于获取资源的元数据,如 Content-Length、Last-Modified 等

4. 请求头

4.1 通用请求头

| 请求头 | 描述 | 示例 |
|-------|------|------|
| Accept | 客户端可接受的响应内容类型 | application/json |
| Accept-Encoding | 客户端可接受的编码方式 | gzip, deflate |
| Content-Type | 请求体的内容类型 | application/json |
| Authorization | 认证信息 | Bearer {token} |
| User-Agent | 客户端标识 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 |
| X-Requested-With | 请求类型 | XMLHttpRequest |
| X-Token | 认证令牌(自定义) | your_token_here |

4.2 自定义请求头

自定义请求头应以 X- 为前缀,如 X-TokenX-Request-ID 等。

5. 请求参数

5.1 参数位置

| 位置 | 适用场景 | 示例 |
|------|----------|------|
| URL 路径 | 资源标识 | /api/v1/user/1 |
| 查询字符串 | 过滤、排序、分页 | /api/v1/user?page=1&limit=10&sort=create_time&order=desc |
| 请求体 | 复杂数据、创建/更新资源 | {"username": "test", "password": "123456"} |
| 请求头 | 认证信息、元数据 | Authorization: Bearer {token} |
| Cookie | 会话信息 | PHPSESSID=your_session_id |

5.2 参数命名规范

- 命名风格: 使用 camelCase 命名风格,如 userName
- 语义化: 参数名应具有明确的语义,如
pagelimitsort
- 简洁性: 参数名应简洁明了,避免过长
- 一致性: 相同类型的参数在不同接口中应保持一致

5.3 常用参数

| 参数名 | 类型 | 描述 | 示例 |
|-------|------|------|------|
| page | int | 页码,默认 1 | page=1 |
| limit | int | 每页数量,默认 10 | limit=20 |
| sort | string | 排序字段 | sort=create_time |
| order | string | 排序方式,asc 或 desc | order=desc |
| keyword | string | 搜索关键词 | keyword=test |
| status | int | 状态过滤 | status=1 |
| start_time | string | 开始时间 | start_time=2024-01-01 |
| end_time | string | 结束时间 | end_time=2024-01-31 |

6. 请求体

6.1 内容类型

| 内容类型 | 描述 | 示例 |
|---------|------|------|
| application/json | JSON 格式,最常用 | {"username": "test", "password": "123456"} |
| application/x-www-form-urlencoded | 表单格式 | username=test&password=123456 |
| multipart/form-data | 文件上传 | 包含文件和表单字段 |
| text/plain | 纯文本 | 简单的文本数据 |
| application/xml | XML 格式 | <user><username>test</username><password>123456</password></user> |

6.2 JSON 请求体规范

- 使用 camelCase 命名: 字段名使用 camelCase 命名风格
- 明确的数据类型: 使用适当的数据类型,如字符串、数字、布尔值、数组、对象
- 避免 null 值: 非必要字段不应包含 null 值
- 嵌套结构: 合理使用嵌套结构,避免过深的嵌套
- 数组格式: 数组元素类型应一致

示例:

json
{
"username": "test",
"password": "123456",
"nickname": "测试用户",
"age": 18,
"gender": 1,
"tags": ["tag1", "tag2"],
"address": {
"province": "北京",
"city": "北京",
"district": "朝阳区"
}
}
text

7. 响应格式

7.1 基本响应格式

所有 API 响应应使用统一的 JSON 格式,包含 statusmsg 和可选的 data 字段。系统实际调用方式为 app('json')->success()

#### 7.1.1 调用示例

php
// 基本成功响应
return app('json')->success('操作成功', ['id' => 1, 'username' => 'test']);

// 只返回数据,不指定消息
return app('json')->success(['id' => 1, 'username' => 'test']);

// 使用系统内置成功码
return app('json')->success(100000); // 100000 是 "保存成功" 对应的系统内置成功码

text
#### 7.1.2 响应格式
json
{
"status": 200,
"msg": "操作成功",
"data": {
"id": 1,
"username": "test",
"nickname": "测试用户"
}
}
text

7.2 分页响应格式

分页响应应包含 totalpagelimitlist 字段,系统实际调用方式为 app('json')->success()

#### 7.2.1 调用示例

php
// 分页数据响应
$pageData = [
'total' => 100,
'page' => 1,
'limit' => 10,
'list' => [
['id' => 1, 'username' => 'test1', 'nickname' => '测试用户1'],
['id' => 2, 'username' => 'test2', 'nickname' => '测试用户2']
]
];
return app('json')->success('获取列表成功', $pageData);
text
#### 7.2.2 响应格式
json
{
"status": 200,
"msg": "获取列表成功",
"data": {
"total": 100,
"page": 1,
"limit": 10,
"list": [
{
"id": 1,
"username": "test1",
"nickname": "测试用户1"
},
{
"id": 2,
"username": "test2",
"nickname": "测试用户2"
}
]
}
}
text

7.3 错误响应格式

系统使用统一的错误响应格式,所有错误响应通过 app('json')->fail() 方法返回。fail() 方法支持两种参数类型:

- 错误码(推荐):系统内置的数字错误码,如 410025
- 错误消息:直接的字符串错误信息

#### 7.3.1 统一响应格式

无论使用哪种参数类型,系统都会返回统一的 JSON 格式,包含 statusmsg 和可选的 data 字段。当使用错误码时,响应中还会包含 code 字段。

json
{
"status": 400,
"msg": "账号或密码错误",
"code": 410025,
"data": null
}
text
#### 7.3.2 调用示例
php
// 推荐:使用系统内置错误码
return app('json')->fail(410025);

// 不推荐:直接使用错误消息
return app('json')->fail('账号或密码错误');

// 使用错误码并传递额外数据
return app('json')->fail(410025, ['extra' => 'additional data']);

// 使用错误码并传递替换参数
return app('json')->fail(410025, [], ['field' => 'username']);

text
#### 7.3.3 最佳实践

- 优先使用错误码:系统内置错误码经过统一规划,便于维护和国际化
- 避免直接使用字符串:直接使用字符串错误信息不利于国际化和统一管理
- 传递必要的额外数据:对于复杂错误,可以在
data 字段中提供详细信息
- 使用替换参数:对于动态错误信息,使用替换参数提高灵活性

7.4 响应码规范

| 响应码范围 | 类型 | 描述 | 示例 |
|-----------|------|------|------|
| 200 | 成功 | 操作成功 | 200 |
| 1000-1999 | 系统级错误 | 系统核心错误 | 1001(参数错误) |
| 4000-4999 | 业务级错误 | 具体业务逻辑错误 | 410025(账号或密码错误) |
| 400 | 客户端错误 | 请求参数错误 | 400 |
| 401 | 认证错误 | 未认证或认证过期 | 401 |
| 403 | 权限错误 | 无权限访问 | 403 |
| 404 | 资源错误 | 资源不存在 | 404 |
| 500 | 服务器错误 | 服务器内部错误 | 500 |

8. 错误处理

8.1 错误响应设计

错误响应应遵循以下设计原则:

1. 统一格式: 所有错误响应使用相同的 JSON 格式
2. 明确的错误码: 使用唯一的错误码标识不同的错误类型
3. 清晰的错误信息: 错误信息应简洁明了,便于理解
4. 可选的详细信息: 对于复杂错误,可以在
data 字段中提供详细信息
5. HTTP 状态码匹配: 错误码应与 HTTP 状态码匹配

8.2 AI 自动提示系统内置错误码

CRMEB 系统集成了 AI 自动提示功能,当开发者在编写代码时使用 fail() 方法返回错误信息时,AI 会自动:

1. 识别错误信息: 自动识别开发者输入的错误信息字符串
2. 匹配内置错误码: 在系统内置错误码库中查找匹配的错误码
3. 自动转换: 在运行时将错误信息自动转换为对应的系统内置错误码
4. 提供建议: 对于未匹配到的错误信息,提供相似的错误码建议
5. 实时提示: 在 IDE 中实时显示错误码建议
6. 错误码文档: 在错误码文档 error_code.md,找到对应的错误码说明

#### 8.2.1 功能示例

php
// 开发者输入
return $this->fail('登录失败');

// AI 自动提示并替换为
return $this->fail(410019); // 410019 是 "登录失败" 对应的系统内置错误码

text
#### 8.2.2 工作原理

1. 语言文件解析: 系统在运行时解析语言文件,构建错误码到错误信息的映射表
2. 自动匹配: 当调用
fail() 方法传入字符串错误信息时,系统自动在映射表中查找匹配的错误码
3. 运行时转换: 如果找到匹配的错误码,系统会将错误信息替换为错误码,并在响应中包含
code 字段
4. 智能提示: 在 IDE 中,AI 会实时提示开发者使用正确的系统内置错误码

#### 8.2.3 实际响应格式

当使用字符串错误信息时,系统会自动匹配并转换为错误码,最终响应格式为:

json
{
"status": 400,
"msg": "登录失败",
"code": 410019
}
text
当直接使用错误码时,响应格式为:
json
{
"status": 400,
"msg": "登录失败",
"code": 410019
}
text

8.3 错误处理最佳实践

1. 使用系统内置错误码: 优先使用系统内置错误码,避免自定义错误信息
2. 错误信息本地化: 使用
getLang() 函数获取本地化的错误信息
3. 详细的错误日志: 记录详细的错误日志,包括错误码、错误信息、请求参数等
4. 友好的错误提示: 对客户端返回友好的错误信息,避免暴露系统内部细节
5. 统一的错误处理: 使用统一的错误处理中间件处理所有错误
6. 错误码文档化: 定期更新错误码文档,确保与实际代码一致

8.4 自定义错误码

对于系统内置错误码无法覆盖的业务场景,可以自定义错误码,但应遵循以下规范:

1. 错误码范围: 使用系统未占用的错误码范围
2. 命名规范: 错误码应具有明确的语义
3. 文档化: 自定义错误码应在文档中明确说明
4. 本地化: 自定义错误码应在语言文件中定义对应的错误信息

9. 接口开发流程

9.1 需求分析与设计

1. 需求理解: 明确接口的业务需求和功能要求
2. 资源设计: 确定接口涉及的资源和数据模型
3. 接口设计: 设计接口的 URL、请求方法、参数和响应格式
4. 权限设计: 确定接口的访问权限和认证方式
5. 错误设计: 定义接口可能出现的错误情况和错误码

9.2 开发实现

1. 创建路由: 在路由文件中定义接口路由
2. 实现控制器: 创建控制器并实现接口逻辑
3. 参数验证: 使用验证器对请求参数进行验证
4. 业务逻辑: 实现接口的业务逻辑
5. 错误处理: 使用
app('json')->fail() 统一处理错误
6. 响应返回: 使用
app('json')->success() 统一返回响应

9.3 测试验证

1. 单元测试: 编写单元测试验证接口功能
2. 集成测试: 测试接口与其他模块的集成
3. 接口测试: 使用 Postman 或其他工具测试接口
4. 性能测试: 测试接口的性能和响应时间
5. 安全测试: 测试接口的安全性

9.4 文档编写

1. 接口文档: 编写接口的详细文档
2. 错误码文档: 在
error_code.md 中记录接口使用的错误码
3. 变更记录: 记录接口的变更历史

9.5 上线发布

1. 代码审查: 进行代码审查,确保代码质量
2. 测试环境验证: 在测试环境验证接口功能
3. 灰度发布: 灰度发布接口,观察运行情况
4. 正式上线: 正式上线接口

9.6 监控维护

1. 监控: 监控接口的运行状态和性能
2. 日志: 记录接口的访问日志和错误日志
3. 优化: 根据监控数据优化接口性能
4. 维护: 定期维护和更新接口

10. 最佳实践

10.1 请求设计

- 使用 RESTful 风格: 遵循 RESTful API 设计规范
- 明确的资源命名: 使用明确的资源名称,如
/api/v1/user 而不是 /api/v1/getUser
- 合理的 URL 层级: URL 层级不应过深,一般不超过 3 层
- 使用复数形式: 资源名称使用复数形式,如
/api/v1/users 而不是 /api/v1/user

10.2 参数设计

- 必填参数: 明确标识必填参数
- 默认值: 为可选参数提供合理的默认值
- 参数验证: 对所有参数进行验证
- 参数类型: 明确参数类型和格式

10.3 响应设计

- 统一格式: 使用统一的响应格式
- 明确的数据类型: 响应数据类型应明确
- 避免冗余数据: 只返回必要的数据
- 分页响应: 列表接口应支持分页
- 错误信息: 错误信息应清晰、准确

10.4 安全设计

- 认证授权: 使用 JWT 或 OAuth2 进行认证授权
- HTTPS: 使用 HTTPS 加密传输
- 参数验证: 严格验证所有输入参数
- 输出编码: 对输出数据进行编码,防止 XSS 攻击
- SQL 注入防护: 使用参数绑定,避免直接拼接 SQL
- CSRF 防护: 实现 CSRF Token 验证

11. 常见问题

11.1 跨域问题

- 问题: 浏览器同源策略导致跨域请求失败
- 解决方案: 实现 CORS(跨域资源共享),设置适当的响应头

10.2 认证失败

- 问题: 请求未携带认证信息或认证信息无效
- 解决方案: 检查请求头中的认证信息,确保令牌有效

10.3 参数错误

- 问题: 请求参数格式错误或缺少必填参数
- 解决方案: 检查请求参数,确保格式正确且包含所有必填参数

10.4 响应数据不符合预期

- 问题: 响应数据格式或内容不符合预期
- 解决方案: 检查 API 文档,确保请求格式正确,或联系 API 提供者

10.5 性能问题

- 问题: API 请求响应时间过长
- 解决方案: 优化 API 实现,使用缓存,减少数据库查询次数

12. 参考资源

- RESTful API 设计指南
- HTTP 状态码
- API 设计最佳实践
- JSON API 规范
- OpenAPI 规范
- API 安全性最佳实践

---

.Codebuddy/Skills/Php Api/References/Db Design (.codebuddy/skills/php-api/references/db_design.md)

数据库设计文档

1. 概述

本文档描述了 CRMEB 项目的数据库设计,包括数据库架构、表结构、索引设计、关系设计等,旨在规范数据库设计,提高数据库性能和可维护性。

2. 数据库架构

2.1 整体架构

- 数据库系统: MySQL 5.7~8.0
- 存储引擎: InnoDB (默认)
- 字符集: utf8mb4
- 排序规则: utf8mb4_general_ci
- 连接池: 建议使用
- SQL文件位置:
public/install/crmeb.sql

2.2 技术栈

- MySQL: 5.7+
- Redis: 用于缓存
- ThinkPHP ORM: 用于模型操作
- 数据库迁移: 用于版本控制
- 数据库备份: 用于数据安全

2.3 配置说明

#### 2.3.1 数据库配置

php
// config/database.php
return [
'default' => env('database.driver', 'mysql'),
'connections' => [
'mysql' => [
'type' => 'mysql',
'hostname' => env('database.hostname', '127.0.0.1'),
'database' => env('database.database', ''),
'username' => env('database.username', ''),
'password' => env('database.password', ''),
'hostport' => env('database.hostport', '3306'),
'charset' => 'utf8mb4',
'prefix' => env('database.prefix', ''),
'debug' => env('app_debug', true),
],
],
];
text

3. 数据库设计规范

3.1 命名规范

- 数据库名: 小写字母,下划线分隔
- 表名: 小写字母,下划线分隔,前缀统一
- 字段名: 小写字母,下划线分隔
- 索引名: 小写字母,下划线分隔,类型前缀
- 主键:
PRIMARY
- 唯一索引:
uk_字段名
- 普通索引:
idx_字段名

3.2 表结构规范

- 主键: 统一命名为 id,自增整数
- 外键: 格式
表名_id,如 user_id
- 时间字段:
create_time/update_time
- 状态字段:
status,默认值 0
- 软删除字段:
delete_time,默认值 NULL

3.3 字段类型规范

- 整数类型: 根据实际范围选择
-
TINYINT: 1字节,范围 -128~127
-
SMALLINT: 2字节,范围 -32768~32767
-
INT: 4字节,范围 -2147483648~2147483647
-
BIGINT: 8字节,范围更大

- 字符串类型:
- 固定长度:
CHAR
- 可变长度:
VARCHAR
- 长文本:
TEXT
- 大文本:
LONGTEXT

- 日期时间类型:
- 日期:
DATE
- 时间:
TIME
- 日期时间:
DATETIME
- 时间戳:
TIMESTAMP

- 数值类型:
- 小数:
DECIMAL
- 浮点数:
FLOAT, DOUBLE

- 布尔类型: 使用 TINYINT(1),0 表示 false,1 表示 true

3.4 索引规范

- 主键索引: 每个表必须有主键
- 唯一索引: 用于唯一标识的字段
- 普通索引: 用于经常查询的字段
- 复合索引: 用于多字段查询
- 外键索引: 用于关联查询
- 索引数量: 每个表索引数量不宜过多,一般不超过 5 个

4. 核心表结构

4.1 用户表 (user)

| 字段名 | 数据类型 | 长度 | 约束 | 描述 |
|-------|---------|------|------|------|
|
id | INT | 11 | PRIMARY KEY AUTO_INCREMENT | 用户ID |
|
username | VARCHAR | 50 | NOT NULL | 用户名 |
|
password | VARCHAR | 255 | NOT NULL | 密码 |
|
nickname | VARCHAR | 50 | NOT NULL | 昵称 |
|
avatar | VARCHAR | 255 | | 头像 |
|
mobile | VARCHAR | 20 | | 手机号 |
|
email | VARCHAR | 100 | | 邮箱 |
|
status | TINYINT | 1 | DEFAULT 1 | 状态 |
|
create_time | DATETIME | | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
update_time | DATETIME | | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
|
delete_time | DATETIME | | | 删除时间 |

4.2 商品表 (product)

| 字段名 | 数据类型 | 长度 | 约束 | 描述 |
|-------|---------|------|------|------|
|
id | INT | 11 | PRIMARY KEY AUTO_INCREMENT | 商品ID |
|
name | VARCHAR | 255 | NOT NULL | 商品名称 |
|
category_id | INT | 11 | NOT NULL | 分类ID |
|
price | DECIMAL | 10,2 | NOT NULL | 价格 |
|
stock | INT | 11 | NOT NULL | 库存 |
|
status | TINYINT | 1 | DEFAULT 1 | 状态 |
|
create_time | DATETIME | | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
update_time | DATETIME | | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
|
delete_time | DATETIME | | | 删除时间 |

4.3 订单表 (order)

| 字段名 | 数据类型 | 长度 | 约束 | 描述 |
|-------|---------|------|------|------|
|
id | INT | 11 | PRIMARY KEY AUTO_INCREMENT | 订单ID |
|
order_sn | VARCHAR | 32 | NOT NULL UNIQUE | 订单号 |
|
user_id | INT | 11 | NOT NULL | 用户ID |
|
total_price | DECIMAL | 10,2 | NOT NULL | 总价 |
|
status | TINYINT | 1 | DEFAULT 0 | 状态 |
|
create_time | DATETIME | | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
update_time | DATETIME | | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
|
delete_time | DATETIME | | | 删除时间 |

4.4 分类表 (category)

| 字段名 | 数据类型 | 长度 | 约束 | 描述 |
|-------|---------|------|------|------|
|
id | INT | 11 | PRIMARY KEY AUTO_INCREMENT | 分类ID |
|
name | VARCHAR | 50 | NOT NULL | 分类名称 |
|
parent_id | INT | 11 | DEFAULT 0 | 父分类ID |
|
sort | INT | 11 | DEFAULT 0 | 排序 |
|
status | TINYINT | 1 | DEFAULT 1 | 状态 |
|
create_time | DATETIME | | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
update_time | DATETIME | | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
|
delete_time | DATETIME | | | 删除时间 |

4.5 地址表 (address)

| 字段名 | 数据类型 | 长度 | 约束 | 描述 |
|-------|---------|------|------|------|
|
id | INT | 11 | PRIMARY KEY AUTO_INCREMENT | 地址ID |
|
user_id | INT | 11 | NOT NULL | 用户ID |
|
name | VARCHAR | 50 | NOT NULL | 收货人姓名 |
|
mobile | VARCHAR | 20 | NOT NULL | 手机号 |
|
province | VARCHAR | 50 | NOT NULL | 省份 |
|
city | VARCHAR | 50 | NOT NULL | 城市 |
|
district | VARCHAR | 50 | NOT NULL | 区县 |
|
detail | VARCHAR | 255 | NOT NULL | 详细地址 |
|
is_default | TINYINT | 1 | DEFAULT 0 | 是否默认 |
|
create_time | DATETIME | | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
update_time | DATETIME | | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
|
delete_time | DATETIME | | | 删除时间 |

5. 索引设计

5.1 用户表索引

| 索引名 | 类型 | 字段 | 描述 |
|-------|------|------|------|
|
PRIMARY | 主键 | id | 主键索引 |
|
uk_username | 唯一 | username | 用户名唯一索引 |
|
idx_mobile | 普通 | mobile | 手机号索引 |
|
idx_email | 普通 | email | 邮箱索引 |
|
idx_status | 普通 | status | 状态索引 |

5.2 商品表索引

| 索引名 | 类型 | 字段 | 描述 |
|-------|------|------|------|
|
PRIMARY | 主键 | id | 主键索引 |
|
idx_category_id | 普通 | category_id | 分类ID索引 |
|
idx_price | 普通 | price | 价格索引 |
|
idx_status | 普通 | status | 状态索引 |

5.3 订单表索引

| 索引名 | 类型 | 字段 | 描述 |
|-------|------|------|------|
|
PRIMARY | 主键 | id | 主键索引 |
|
uk_order_sn | 唯一 | order_sn | 订单号唯一索引 |
|
idx_user_id | 普通 | user_id | 用户ID索引 |
|
idx_status | 普通 | status | 状态索引 |
|
idx_create_time | 普通 | create_time | 创建时间索引 |

5.4 分类表索引

| 索引名 | 类型 | 字段 | 描述 |
|-------|------|------|------|
|
PRIMARY | 主键 | id | 主键索引 |
|
idx_parent_id | 普通 | parent_id | 父分类ID索引 |
|
idx_sort | 普通 | sort | 排序索引 |
|
idx_status | 普通 | status | 状态索引 |

5.5 地址表索引

| 索引名 | 类型 | 字段 | 描述 |
|-------|------|------|------|
|
PRIMARY | 主键 | id | 主键索引 |
|
idx_user_id | 普通 | user_id | 用户ID索引 |
|
idx_is_default | 普通 | is_default | 是否默认索引 |

6. 关系设计

6.1 表关系图


user ----------------- order
| |
| |
| |
address product
|
|
|
category
text

6.2 关系说明

- 用户与订单: 一对多关系,一个用户可以有多个订单
- 用户与地址: 一对多关系,一个用户可以有多个地址
- 商品与分类: 多对一关系,多个商品属于一个分类
- 订单与商品: 多对多关系,一个订单可以包含多个商品,一个商品可以出现在多个订单中

6.3 外键关系

| 主表 | 主键 | 从表 | 外键 | 描述 |
|------|------|------|------|------|
|
user | id | order | user_id | 订单所属用户 |
|
user | id | address | user_id | 地址所属用户 |
|
category | id | product | category_id | 商品所属分类 |

7. 性能优化

7.1 索引优化

- 选择合适的索引类型: 根据查询场景选择合适的索引类型
- 避免过度索引: 只在需要的字段上创建索引
- 使用复合索引: 对于多字段查询,使用复合索引
- 定期维护索引: 定期重建碎片化的索引

7.2 查询优化

- 避免全表扫描: 使用索引覆盖查询
- 减少查询字段: 只查询需要的字段
- 使用连接查询: 合理使用连接查询,避免子查询
- 限制查询结果: 使用 LIMIT 限制查询结果数量

7.3 存储优化

- 选择合适的字段类型: 根据实际需求选择合适的字段类型
- 使用分区表: 对于大表,使用分区表提高查询性能
- 定期清理数据: 定期清理无用数据,减少表大小
- 使用缓存: 对于频繁查询的数据,使用 Redis 缓存

7.4 配置优化

- 调整 innodb_buffer_pool_size: 根据服务器内存大小调整
- 调整 max_connections: 根据并发量调整
- 启用查询缓存: 对于读多写少的场景
- 优化日志配置: 合理配置二进制日志和慢查询日志

8. 安全设计

8.1 数据安全

- 加密存储: 敏感数据(如密码)加密存储
- 数据备份: 定期备份数据库
- 数据恢复: 建立数据恢复机制
- 访问控制: 严格控制数据库访问权限

8.2 SQL 注入防护

- 使用参数化查询: 避免直接拼接 SQL
- 使用 ORM: 使用 ThinkPHP ORM 框架
- 输入验证: 对用户输入进行验证
- 转义特殊字符: 对特殊字符进行转义

8.3 权限管理

- 最小权限原则: 只授予必要的权限
- 角色分离: 不同角色拥有不同权限
- 定期审计: 定期审计数据库访问日志

9. 备份与恢复

9.1 备份策略

- 全量备份: 定期进行全量备份
- 增量备份: 每天进行增量备份
- 日志备份: 备份二进制日志

9.2 恢复策略

- 全量恢复: 使用全量备份恢复
- 增量恢复: 使用增量备份恢复
- 点恢复: 使用二进制日志进行点恢复

9.3 备份工具

- mysqldump: MySQL 自带备份工具
- xtrabackup: Percona 提供的备份工具
- 第三方工具: 如 Navicat 等

10. 版本控制

10.1 数据库迁移

- 使用迁移工具: 使用 ThinkPHP 数据库迁移工具
- 版本管理: 对数据库结构变更进行版本管理
- 回滚机制: 支持数据库结构回滚

10.2 迁移文件命名规范

- 格式: YYYYMMDDHHMMSS_描述.php
- 示例:
20230101000000_create_user_table.php

10.3 迁移文件结构

php
<?php
use think\migration\Migrator;
use think\migration\db\Column;

class CreateUserTable extends Migrator
{
public function change()
{
$table = $this->table('user');
$table->addColumn('username', 'string', ['limit' => 50, 'comment' => '用户名'])
->addColumn('password', 'string', ['limit' => 255, 'comment' => '密码'])
->addColumn('nickname', 'string', ['limit' => 50, 'comment' => '昵称'])
->addColumn('avatar', 'string', ['limit' => 255, 'comment' => '头像'])
->addColumn('mobile', 'string', ['limit' => 20, 'comment' => '手机号'])
->addColumn('email', 'string', ['limit' => 100, 'comment' => '邮箱'])
->addColumn('status', 'tinyint', ['default' => 1, 'comment' => '状态'])
->addColumn('create_time', 'datetime', ['default' => 'CURRENT_TIMESTAMP', 'comment' => '创建时间'])
->addColumn('update_time', 'datetime', ['default' => 'CURRENT_TIMESTAMP', 'update' => 'CURRENT_TIMESTAMP', 'comment' => '更新时间'])
->addColumn('delete_time', 'datetime', ['comment' => '删除时间'])
->addIndex('username', ['unique' => true])
->addIndex('mobile')
->addIndex('email')
->addIndex('status')
->create();
}
}

text

11. 维护与监控

11.1 日常维护

- 定期优化表: 定期执行 OPTIMIZE TABLE 命令
- 监控表大小: 监控表大小变化
- 检查慢查询: 定期分析慢查询日志
- 更新统计信息: 定期更新表统计信息

11.2 监控指标

- 查询性能: 监控查询响应时间
- 连接数: 监控数据库连接数
- 缓存命中率: 监控缓存命中率
- 磁盘使用率: 监控磁盘空间使用情况
- CPU 使用率: 监控数据库服务器 CPU 使用率

11.3 监控工具

- MySQL Enterprise Monitor: MySQL 企业版监控工具
- Percona Monitoring and Management: 开源监控工具
- Zabbix: 通用监控工具
- Prometheus + Grafana: 现代化监控方案

12. 总结

本文档描述了 CRMEB 项目的数据库设计规范和最佳实践,包括数据库架构、表结构、索引设计、关系设计、性能优化、安全设计、备份与恢复、版本控制、维护与监控等方面。

遵循本文档的设计规范,可以提高数据库性能和可维护性,确保系统的稳定运行。同时,定期对数据库进行维护和监控,可以及时发现和解决潜在问题,保障系统的安全性和可靠性。

随着业务的发展和系统的演进,数据库设计也需要不断优化和调整,以适应新的业务需求和技术挑战。

---

.Codebuddy/Skills/Php Api/References/Directory Structure (.codebuddy/skills/php-api/references/directory_structure.md)

目录结构文档

1. 概述

本文档描述了 CRMEB 项目的目录结构,包括各目录的功能、文件组织方式等,旨在帮助开发者理解项目结构,提高开发效率。

2. 项目根目录结构


CRMEB/
├── app/ # 应用目录
├── config/ # 配置目录
├── crmeb/ # 核心库目录
├── database/ # 数据库目录
├── extend/ # 扩展目录
├── public/ # 公共资源目录
├── runtime/ # 运行时目录
├── thinkphp/ # ThinkPHP 核心目录
├── vendor/ # 第三方依赖目录
├── .env # 环境变量文件
├── .env.example # 环境变量示例文件
├── composer.json # Composer 配置文件
├── composer.lock # Composer 锁定文件
├── LICENSE # 许可证文件
├── README.md # 项目说明文档
├── think # ThinkPHP 命令行工具
text

3. 应用目录结构 (app/)


app/
├── api/ # API 接口层
│ ├── v1/ # API 版本 1
│ ├── v2/ # API 版本 2
│ └── BaseApi.php # API 基类
├── controller/ # 控制器层
│ ├── admin/ # 管理端控制器
│ ├── api/ # API 控制器
│ └── BaseController.php # 控制器基类
├── dao/ # 数据访问层
│ └── BaseDao.php # DAO 基类
├── event/ # 事件层
├── exception/ # 异常处理层
├── middleware/ # 中间件层
├── model/ # 模型层
│ └── BaseModel.php # 模型基类
├── services/ # 业务逻辑层
│ └── BaseServices.php # 服务基类
├── subscribe/ # 事件订阅层
├── validate/ # 验证层
│ └── BaseValidate.php # 验证器基类
└── common.php # 公共函数文件
text

3.1 API 目录 (app/api/)

- 功能: 处理 API 接口请求
- 结构: 按 API 版本划分目录
- 基类:
BaseApi.php,提供 API 基础功能
- 版本控制: 通过目录结构实现 API 版本管理

3.2 控制器目录 (app/controller/)

- 功能: 处理 HTTP 请求,路由分发
- 结构: 按模块划分控制器
- 基类:
BaseController.php,提供控制器基础功能
- 类型: 管理端控制器、API 控制器

3.3 DAO 目录 (app/dao/)

- 功能: 数据访问对象,封装数据库操作
- 结构: 按业务模块划分 DAO 类
- 基类:
BaseDao.php,提供 DAO 基础功能
- 职责: 处理数据库查询、插入、更新、删除等操作

3.4 模型目录 (app/model/)

- 功能: 数据模型,定义数据结构和关系
- 结构: 按业务模块划分模型类
- 基类:
BaseModel.php,提供模型基础功能
- 特性: 支持 ORM、关联查询、软删除等

3.5 服务目录 (app/services/)

- 功能: 业务逻辑层,封装核心业务逻辑
- 结构: 按业务模块划分服务类
- 基类:
BaseServices.php,提供服务基础功能
- 职责: 实现业务规则,协调多个 DAO 和模型

3.6 验证目录 (app/validate/)

- 功能: 数据验证,验证请求参数
- 结构: 按业务模块划分验证器类
- 基类:
BaseValidate.php,提供验证器基础功能
- 特性: 支持规则验证、场景验证等

4. 配置目录结构 (config/)


config/
├── app.php # 应用配置
├── cache.php # 缓存配置
├── captcha.php # 验证码配置
├── console.php # 控制台配置
├── cookie.php # Cookie 配置
├── database.php # 数据库配置
├── filesystem.php # 文件系统配置
├── lang.php # 语言配置
├── log.php # 日志配置
├── queue.php # 队列配置
├── route.php # 路由配置
├── session.php # Session 配置
├── template.php # 模板配置
└── trace.php # 调试配置
text
- 功能: 存储项目的所有配置文件
- 结构: 按功能模块划分配置文件
- 特性: 支持环境变量配置、配置缓存等
- 加载顺序: 框架配置 → 应用配置 → 环境配置

5. 核心库目录结构 (crmeb/)


crmeb/
├── basic/ # 基础类库
├── exception/ # 核心异常类
├── services/ # 核心服务类
├── utils/ # 工具类
└── version.php # 版本信息
text
- 功能: 存储 CRMEB 核心库代码
- 结构: 按功能模块划分目录
- 特性: 独立于应用代码,便于维护和升级
- 作用: 提供核心功能和基础服务

6. 数据库目录结构 (database/)


database/
├── migrations/ # 数据库迁移文件
└── seeders/ # 数据库种子文件
text
- 功能: 存储数据库相关文件
- 迁移文件: 用于版本控制数据库结构
- 种子文件: 用于初始化数据库数据
- 工具: 使用 ThinkPHP 迁移工具管理

7. 公共资源目录结构 (public/)


public/
├── admin/ # 管理端资源
├── api/ # API 资源
├── assets/ # 静态资源
│ ├── css/ # CSS 文件
│ ├── images/ # 图片文件
│ └── js/ # JavaScript 文件
├── index.php # 应用入口文件
├── robots.txt # 机器人协议文件
└── router.php # URL 重写文件
text
- 功能: 存储可直接访问的公共资源
- 结构: 按功能模块划分目录
- 特性: 可通过 URL 直接访问
- 安全: 敏感文件不应放在此目录

8. 运行时目录结构 (runtime/)


runtime/
├── cache/ # 缓存目录
├── log/ # 日志目录
│ └── app/ # 应用日志
├── session/ # Session 目录
├── temp/ # 临时文件目录
└── think/ # ThinkPHP 运行时目录
text
- 功能: 存储运行时生成的文件
- 结构: 按功能模块划分目录
- 特性: 自动生成,无需手动维护
- 权限: 需要可写权限

9. 核心目录结构 (thinkphp/)


thinkphp/
├── lang/ # 语言包目录
├── library/ # 核心类库目录
├── tpl/ # 模板目录
├── base.php # 基础定义文件
├── composer.json # Composer 配置文件
└── helper.php # 助手函数文件
text
- 功能: 存储 ThinkPHP 框架核心代码
- 结构: 框架默认结构
- 特性: 独立于应用代码
- 升级: 通过 Composer 升级

10. 第三方依赖目录结构 (vendor/)


vendor/
├── autoload.php # 自动加载文件
├── composer/ # Composer 核心目录
├── symfony/ # Symfony 组件
├── topthink/ # ThinkPHP 组件
└── ... # 其他第三方依赖
text
- 功能: 存储第三方依赖库
- 管理: 通过 Composer 管理
- 结构: 按依赖包名称划分目录
- 自动加载: 通过
autoload.php 自动加载

11. 目录结构最佳实践

11.1 命名规范

- 目录名: 小写字母,单词之间用下划线分隔
- 文件名: 与类名一致,使用 PascalCase 命名风格
- 类名: 使用 PascalCase 命名风格
- 方法名: 使用 camelCase 命名风格
- 变量名: 使用 camelCase 命名风格

11.2 组织原则

- 模块化: 按功能模块组织目录结构
- 分层架构: 遵循 MVC + Service + DAO 分层架构
- 单一职责: 每个目录和文件只负责一个功能
- 可扩展性: 便于添加新功能和模块
- 易维护性: 便于理解和维护

11.3 开发建议

- 遵循框架规范: 遵循 ThinkPHP 框架目录结构规范
- 合理划分模块: 根据业务功能合理划分模块
- 避免目录过深: 目录层级不宜过深,一般不超过 4 层
- 保持目录整洁: 及时清理无用文件和目录
- 文档化: 为重要目录添加说明文档

12. 常见问题

12.1 目录权限问题

- 问题: 运行时目录没有写权限
- 解决方案: 执行
chmod -R 777 runtime/ 赋予写权限

12.2 自动加载问题

- 问题: 新增类无法自动加载
- 解决方案: 执行
composer dump-autoload 更新自动加载

12.3 配置文件不生效

- 问题: 修改配置文件后不生效
- 解决方案: 清除配置缓存,执行
php think clear

12.4 目录结构混乱

- 问题: 目录结构不清晰,难以维护
- 解决方案: 重新组织目录结构,遵循模块化原则

13. 参考资源

- ThinkPHP 6 目录结构
- MVC 架构设计
- 分层架构设计
- 模块化设计

---

.Codebuddy/Skills/Php Api/References/Error Code (.codebuddy/skills/php-api/references/error_code.md)

错误码文档

1. 概述

本文档描述了 CRMEB 项目的错误码规范,包括错误码的分类、定义、使用方法等,旨在统一错误码格式,提高错误处理的一致性和可维护性。

2. 错误码分类

2.1 HTTP 状态码

- 1xx: 信息性状态码,表示请求已接收,继续处理
- 2xx: 成功状态码,表示请求已成功处理
- 3xx: 重定向状态码,表示需要进一步操作以完成请求
- 4xx: 客户端错误状态码,表示请求包含语法错误或无法完成请求
- 5xx: 服务器错误状态码,表示服务器在处理请求时发生错误

2.2 业务错误码

业务错误码由 5 位数字组成,格式为 XXXXX,其中:

- 第一位: 错误类型标识
-
1: 系统错误
-
2: 业务错误
-
3: 参数错误
-
4: 权限错误
-
5: 资源错误
-
6: 数据库错误
-
7: 第三方服务错误
-
8: 其他错误

- 后四位: 具体错误编码,从 0000 开始递增

3. 系统错误码

3.1 系统错误 (1xxxxx)

| 错误码 | 描述 | HTTP 状态码 |
|-------|------|-------------|
| 10001 | 系统内部错误 | 500 |
| 10002 | 系统维护中 | 503 |
| 10003 | 系统繁忙 | 503 |
| 10004 | 服务不可用 | 503 |
| 10005 | 网关错误 | 502 |

3.2 业务错误 (2xxxxx)

| 错误码 | 描述 | HTTP 状态码 |
|-------|------|-------------|
| 20001 | 操作失败 | 400 |
| 20002 | 业务逻辑错误 | 400 |
| 20003 | 数据已存在 | 400 |
| 20004 | 数据不存在 | 404 |
| 20005 | 操作不允许 | 403 |

3.3 参数错误 (3xxxxx)

| 错误码 | 描述 | HTTP 状态码 |
|-------|------|-------------|
| 30001 | 参数不能为空 | 400 |
| 30002 | 参数格式错误 | 400 |
| 30003 | 参数类型错误 | 400 |
| 30004 | 参数超出范围 | 400 |
| 30005 | 参数验证失败 | 422 |

3.4 权限错误 (4xxxxx)

| 错误码 | 描述 | HTTP 状态码 |
|-------|------|-------------|
| 40001 | 未登录 | 401 |
| 40002 | 登录已过期 | 401 |
| 40003 | 无权限访问 | 403 |
| 40004 | 权限不足 | 403 |
| 40005 | 令牌无效 | 401 |

3.5 资源错误 (5xxxxx)

| 错误码 | 描述 | HTTP 状态码 |
|-------|------|-------------|
| 50001 | 资源不存在 | 404 |
| 50002 | 资源已删除 | 404 |
| 50003 | 资源已锁定 | 400 |
| 50004 | 资源不足 | 400 |
| 50005 | 资源已过期 | 400 |

3.6 数据库错误 (6xxxxx)

| 错误码 | 描述 | HTTP 状态码 |
|-------|------|-------------|
| 60001 | 数据库连接失败 | 500 |
| 60002 | 数据库查询失败 | 500 |
| 60003 | 数据库更新失败 | 500 |
| 60004 | 数据库插入失败 | 500 |
| 60005 | 数据库删除失败 | 500 |
| 60006 | 数据库事务失败 | 500 |

3.7 第三方服务错误 (7xxxxx)

| 错误码 | 描述 | HTTP 状态码 |
|-------|------|-------------|
| 70001 | 第三方服务连接失败 | 500 |
| 70002 | 第三方服务超时 | 504 |
| 70003 | 第三方服务返回错误 | 500 |
| 70004 | 第三方服务认证失败 | 401 |
| 70005 | 第三方服务限流 | 429 |

4. 模块错误码

4.1 用户模块 (801xx)

| 错误码 | 描述 | HTTP 状态码 |
|-------|------|-------------|
| 80101 | 用户名或密码错误 | 401 |
| 80102 | 用户不存在 | 404 |
| 80103 | 用户已存在 | 400 |
| 80104 | 用户状态异常 | 400 |
| 80105 | 验证码错误 | 400 |
| 80106 | 验证码已过期 | 400 |
| 80107 | 手机号格式错误 | 400 |
| 80108 | 邮箱格式错误 | 400 |

4.2 商品模块 (802xx)

| 错误码 | 描述 | HTTP 状态码 |
|-------|------|-------------|
| 80201 | 商品不存在 | 404 |
| 80202 | 商品已下架 | 400 |
| 80203 | 商品库存不足 | 400 |
| 80204 | 商品价格异常 | 400 |
| 80205 | 商品分类不存在 | 404 |

4.3 订单模块 (803xx)

| 错误码 | 描述 | HTTP 状态码 |
|-------|------|-------------|
| 80301 | 订单不存在 | 404 |
| 80302 | 订单状态异常 | 400 |
| 80303 | 订单已取消 | 400 |
| 80304 | 订单已完成 | 400 |
| 80305 | 订单支付失败 | 400 |
| 80306 | 订单支付超时 | 400 |

4.4 支付模块 (804xx)

| 错误码 | 描述 | HTTP 状态码 |
|-------|------|-------------|
| 80401 | 支付方式不支持 | 400 |
| 80402 | 支付金额异常 | 400 |
| 80403 | 支付参数错误 | 400 |
| 80404 | 支付失败 | 400 |
| 80405 | 支付超时 | 400 |
| 80406 | 支付已完成 | 400 |

5. 错误码使用规范

5.1 错误响应格式

json
{
"code": 20001,
"msg": "操作失败",
"data": []
}
text

5.2 成功响应格式

json
{
"code": 200,
"msg": "操作成功",
"data": {...}
}
text

5.3 错误处理流程

1. 捕获异常: 在控制器或中间件中捕获异常
2. 确定错误码: 根据异常类型确定对应的错误码
3. 构建响应: 按照统一格式构建错误响应
4. 返回响应: 返回错误响应给客户端

5.4 错误日志记录

- 记录内容: 错误码、错误信息、请求参数、请求路径、用户信息、时间戳等
- 记录级别: 根据错误严重程度选择合适的日志级别
- 记录位置: 系统日志文件
- 监控告警: 对于严重错误,触发告警机制

6. 错误码管理

6.1 错误码定义

错误码定义在配置文件中,便于统一管理和维护:

php
// config/error_code.php
return [
// 系统错误
10001 => '系统内部错误',
10002 => '系统维护中',
// 业务错误
20001 => '操作失败',
20002 => '业务逻辑错误',
// 参数错误
30001 => '参数不能为空',
30002 => '参数格式错误',
// ...
];
text

6.2 错误码使用

在代码中使用错误码时,应直接引用配置文件中的定义:

php
// 控制器中使用
return $this->fail(config('error_code.20001'));

// 或直接使用错误码
return $this->fail('操作失败', [], 20001);

text

6.3 错误码更新

当需要添加新的错误码时,应遵循以下流程:

1. 确定错误类型: 根据错误性质确定错误类型
2. 分配错误码: 从对应类型的错误码范围中分配一个未使用的错误码
3. 更新配置: 在
error_code.php 配置文件中添加错误码定义
4. 更新文档: 更新错误码文档
5. 通知团队: 通知团队成员新添加的错误码

7. 错误码最佳实践

7.1 设计原则

- 唯一性: 每个错误码唯一对应一种错误情况
- 可读性: 错误码应易于理解和记忆
- 可扩展性: 错误码应具有良好的扩展性,便于添加新的错误码
- 一致性: 错误码格式和使用方法应保持一致
- 详细性: 错误信息应清晰、准确,便于调试和定位问题

7.2 使用建议

- 避免硬编码: 错误码应定义在配置文件中,避免直接硬编码在代码中
- 统一处理: 使用统一的错误处理中间件处理错误
- 详细日志: 记录详细的错误日志,便于调试和分析
- 友好提示: 向客户端返回友好的错误信息,避免暴露系统内部细节
- 定期清理: 定期清理不再使用的错误码,保持错误码的简洁性

7.3 常见问题

#### 7.3.1 错误码冲突

- 问题: 不同模块使用了相同的错误码
- 解决方案: 严格按照模块划分错误码范围,避免冲突

#### 7.3.2 错误信息不明确

- 问题: 错误信息过于简洁,无法定位问题
- 解决方案: 提供详细的错误信息,包含必要的上下文

#### 7.3.3 错误码未及时更新

- 问题: 新增功能时未及时添加对应的错误码
- 解决方案: 在开发新功能时,同步更新错误码定义和文档

8. 参考资源

- HTTP 状态码
- RESTful API 错误处理
- 错误码设计最佳实践
- API 错误码规范

---

.Codebuddy/Skills/Uniapp/References/Api Flow (.codebuddy/skills/uniapp/references/api_flow.md)

UniApp API 开发流程文档

1. 概述

本文档描述了 CRMEB 项目中 UniApp 移动端的 API 开发流程,包括 API 接口设计、请求流程、响应处理、错误处理等,旨在规范 API 开发,提高开发效率和代码质量。

2. API 目录结构


template/uni-app/api/
├── activity.js # 活动相关接口
├── admin.js # 管理相关接口
├── api.js # 基础 API 配置
├── kefu.js # 客服相关接口
├── lottery.js # 抽奖相关接口
├── order.js # 订单相关接口
├── public.js # 公共接口
├── store.js # 商城相关接口
└── user.js # 用户相关接口
text

3. 基础 API 配置 (api.js)

javascript
// 基础 API 配置
const baseURL = 'https://api.crmeb.net';

// 请求超时时间
const timeout = 10000;

// 请求拦截器
const requestInterceptor = (config) => {
// 添加 token
const token = uni.getStorageSync('token');
if (token) {
config.header['Authorization'] =
Bearer ${token};
}

// 添加设备信息
config.header['X-Device-Type'] = uni.getSystemInfoSync().platform;

return config;
};

// 响应拦截器
const responseInterceptor = (response) => {
const { data } = response;

// 统一处理错误
if (data.code !== 200) {
uni.showToast({
title: data.message || '请求失败',
icon: 'none'
});

// 处理登录过期
if (data.code === 401) {
uni.redirectTo({
url: '/pages/login/index'
});
}

return Promise.reject(data);
}

return data;
};

// 错误处理
const errorHandler = (error) => {
uni.showToast({
title: '网络错误,请稍后重试',
icon: 'none'
});

return Promise.reject(error);
};

// 导出配置
export default {
baseURL,
timeout,
requestInterceptor,
responseInterceptor,
errorHandler
};

text

4. API 接口封装

4.1 通用请求方法


/ Detailed source-code truncated for AI context efficiency. /
text

4.2 业务接口封装

javascript
// api/user.js
import request from '../utils/request';

// 用户相关接口
export default {
// 登录
login: (data) => request.post('/api/user/login', data),

// 注册
register: (data) => request.post('/api/user/register', data),

// 获取用户信息
getUserInfo: () => request.get('/api/user/info'),

// 更新用户信息
updateUserInfo: (data) => request.put('/api/user/info', data),

// 修改密码
changePassword: (data) => request.post('/api/user/password', data),

// 获取地址列表
getAddressList: () => request.get('/api/user/address'),

// 添加地址
addAddress: (data) => request.post('/api/user/address', data),

// 更新地址
updateAddress: (id, data) => request.put(
/api/user/address/${id}, data),

// 删除地址
deleteAddress: (id) => request.delete(
/api/user/address/${id}),

// 设置默认地址
setDefaultAddress: (id) => request.put(
/api/user/address/${id}/default)
};

text

5. API 调用示例

5.1 页面中调用 API

vue
<template>
<view class="user-info">
<view v-if="loading">加载中...</view>
<view v-else>
<image :src="userInfo.avatar" class="avatar"></image>
<view class="name">{{ userInfo.nickname }}</view>
<view class="mobile">{{ userInfo.mobile }}</view>
</view>
</view>
</template>

<script>
import userApi from '../../api/user';

export default {
data() {
return {
loading: false,
userInfo: {}
};
},

onLoad() {
this.getUserInfo();
},

methods: {
async getUserInfo() {
try {
this.loading = true;
const res = await userApi.getUserInfo();
this.userInfo = res.data;
} catch (error) {
console.error('获取用户信息失败:', error);
} finally {
this.loading = false;
}
}
}
};
</script>

text

5.2 组件中调用 API


/ Detailed source-code truncated for AI context efficiency. /
text

6. API 开发最佳实践

6.1 命名规范

- 文件命名: 小写字母,单词之间用下划线分隔,如 user.js
- 方法命名: 驼峰命名法,如
getUserInfo
- URL 命名: 小写字母,单词之间用连字符分隔,如
/api/user/info
- 参数命名: 驼峰命名法,与后端保持一致

6.2 接口设计规范

- RESTful 风格: 遵循 RESTful API 设计规范
- 版本控制: 在 URL 中包含版本号,如
/api/v1/user/info
- 统一响应格式: 所有接口返回统一的响应格式
- 错误处理: 统一的错误码和错误信息

6.3 请求规范

- 请求方法: 根据操作类型选择合适的 HTTP 方法
- GET: 获取资源
- POST: 创建资源
- PUT: 更新资源
- DELETE: 删除资源
- 请求头: 统一添加必要的请求头,如 Authorization、Content-Type 等
- 参数传递: 根据请求方法选择合适的参数传递方式
- GET: 查询参数
- POST/PUT: 请求体
- DELETE: 查询参数或路径参数

6.4 响应规范

- 成功响应:

json
{
"code": 200,
"message": "请求成功",
"data": {}
}
text
- 失败响应:
json
{
"code": 400,
"message": "请求失败",
"data": {}
}
text

6.5 错误处理规范

- 网络错误: 统一处理网络错误,如超时、断网等
- 业务错误: 根据错误码处理不同的业务错误
- 登录过期: 统一处理登录过期,跳转到登录页面
- 错误提示: 统一的错误提示方式,使用 uni.showToast

7. API 性能优化

7.1 请求优化

- 合并请求: 多个相关请求合并为一个
- 缓存策略: 对不经常变化的数据使用缓存
- 请求防抖: 避免频繁发送相同的请求
- 批量操作: 支持批量操作,减少请求次数

7.2 响应优化

- 数据结构优化: 优化响应数据结构,减少数据传输量
- 分页处理: 对列表数据使用分页
- 字段筛选: 支持字段筛选,只返回需要的字段
- 压缩传输: 使用 gzip 压缩传输数据

7.3 代码优化

- 模块化: 按业务模块划分 API 文件
- 复用代码: 提取通用的请求逻辑
- 减少冗余: 避免重复的 API 调用
- 代码可读性: 保持代码清晰易读

8. 常见问题

8.1 跨域问题

- 问题: 开发环境中遇到跨域问题
- 解决方案: 在本地开发服务器中配置跨域代理

8.2 Token 过期问题

- 问题: Token 过期后请求失败
- 解决方案: 在响应拦截器中处理 Token 过期,跳转到登录页面

8.3 请求超时问题

- 问题: 网络不稳定时请求超时
- 解决方案: 设置合理的超时时间,添加网络状态检测

8.4 重复请求问题

- 问题: 快速点击按钮导致重复请求
- 解决方案: 添加请求防抖或锁机制

8.5 数据缓存问题

- 问题: 缓存数据与服务器数据不一致
- 解决方案: 合理设置缓存过期时间,提供手动刷新机制

9. 参考资源

- UniApp 网络请求文档
- RESTful API 设计指南
- Axios 文档
- HTTP 方法

10. 总结

本文档描述了 CRMEB 项目中 UniApp 移动端的 API 开发流程,包括 API 接口设计、请求流程、响应处理、错误处理等。遵循本文档的开发规范,可以提高 API 开发的效率和质量,确保应用的稳定性和可靠性。

随着业务的发展和技术的演进,API 开发流程也需要不断优化和调整,以适应新的业务需求和技术挑战。

---

.Codebuddy/Skills/Uniapp/References/Code Style (.codebuddy/skills/uniapp/references/code_style.md)

UniApp 代码规范文档

1. 概述

本文档描述了 CRMEB 项目中 UniApp 移动端的代码规范,包括命名规范、代码风格、文件结构、组件开发等,旨在统一代码风格,提高代码质量和可维护性。

2. 命名规范

2.1 目录命名

- 目录名: 小写字母,单词之间用下划线分隔
- 示例:
pages/index/components/common/utils/
- 规范: 简洁明了,反映目录的功能

2.2 文件命名

- 页面文件: 小写字母,单词之间用下划线分隔
- 示例:
index.vuelogin.vueuser_info.vue
- 组件文件: 大写字母开头的 PascalCase 命名风格
- 示例:
Button.vueNavBar.vueGoodsList.vue
- JS 文件: 小写字母,单词之间用下划线分隔
- 示例:
user.jsrequest.jsutil.js
- CSS/SCSS 文件: 小写字母,单词之间用下划线分隔
- 示例:
common.scsstheme.scss

2.3 变量命名

- 普通变量: 驼峰命名法
- 示例:
userInfogoodsListisLoading
- 常量: 全大写,单词之间用下划线分隔
- 示例:
BASE_URLMAX_COUNTDEFAULT_PAGE_SIZE
- 布尔变量: 以
is 开头的驼峰命名法
- 示例:
isShowisLoadingisLogin

2.4 函数命名

- 函数名: 驼峰命名法,动词开头
- 示例:
getUserInfosubmitFormhandleClick
- 方法名: 驼峰命名法
- 示例:
datamethodscomputedwatch
- 生命周期函数: 按照 Vue 规范命名
- 示例:
createdmountedbeforeDestroy

2.5 组件命名

- 组件名: PascalCase 命名风格
- 示例:
ButtonNavBarGoodsList
- 组件标签: 小写字母,单词之间用连字符分隔
- 示例:
<my-button><nav-bar><goods-list>

2.6 其他命名

- 路由命名: 小写字母,单词之间用连字符分隔
- 示例:
/pages/index/index/pages/user/login
- CSS 类名: 小写字母,单词之间用连字符分隔
- 示例:
.user-info.goods-list.btn-primary
- ID 命名: 小写字母,单词之间用连字符分隔
- 示例:
#app#header#footer

3. 代码风格

3.1 缩进

- 缩进方式: 4 个空格
- 示例:

vue
<template>
<view class="container">
<text>{{ message }}</text>
</view>
</template>
text

3.2 换行

- 标签换行: 多个属性的标签应该换行
- 示例:

vue
<view
class="container"
:class="{ active: isActive }"
@click="handleClick"
>
<text>{{ message }}</text>
</view>
text
- 代码块换行: 逻辑代码块应该换行
- 示例:
javascript
if (condition) {
// 代码块
} else {
// 代码块
}
text

3.3 空格

- 运算符空格: 运算符两侧应该有空格
- 示例:
a + bx = yi < 10
- 逗号空格: 逗号后面应该有空格
- 示例:
[1, 2, 3]{ name: '张三', age: 18 }
- 括号空格: 括号内侧不应该有空格
- 示例:
if (condition)function (param)

3.4 注释

- 单行注释: 使用 // 注释
- 示例:
// 这是单行注释
- 多行注释: 使用
/ / 注释
- 示例:

javascript
/*
* 这是多行注释
* 第二行
*/
text
- 文档注释: 使用 JSDoc 风格的注释
- 示例:
javascript
/
* 获取用户信息
* @param {number} id - 用户ID
* @returns {Promise} 用户信息
*/
async function getUserInfo(id) {
// 代码
}
text

3.5 引号

- 字符串: 使用单引号 ''
- 示例:
const name = '张三'<text>Hello</text>
- 模板字符串: 使用反引号
`
- 示例:
const url = ${baseUrl}/api/user
- HTML 属性: 使用双引号
""
- 示例:
<view class="container"><image src="https://example.com/img.jpg">

4. 文件结构

4.1 页面文件结构

vue
<template>

</template>

<script>
// 导入依赖
import userApi from '../../api/user';

// 导出组件
export default {
// 组件名称
name: 'UserInfo',

// 组件属性
props: {
userId: {
type: Number,
required: true
}
},

// 数据
data() {
return {
userInfo: {},
loading: false
};
},

// 计算属性
computed: {
fullName() {
return this.userInfo.firstName + ' ' + this.userInfo.lastName;
}
},

// 监听
watch: {
userId: {
handler(newVal) {
this.getUserInfo(newVal);
},
immediate: true
}
},

// 生命周期函数
created() {
// 初始化
},

mounted() {
// 挂载后
},

// 方法
methods: {
async getUserInfo(id) {
try {
this.loading = true;
const res = await userApi.getUserInfo(id);
this.userInfo = res.data;
} catch (error) {
console.error('获取用户信息失败:', error);
} finally {
this.loading = false;
}
},

handleEdit() {
// 编辑用户信息
}
}
};
</script>

<style scoped>
/ 样式 /
.user-info {
padding: 20rpx;
background-color: #f5f5f5;
}

.name {
font-size: 32rpx;
font-weight: bold;
}
</style>

text

4.2 组件文件结构

vue
<template>

<view class="my-button">
<button
:class="[type, { disabled }]"
:disabled="disabled"
@click="handleClick"
>
<slot></slot>
</button>
</view>
</template>

<script>
export default {
name: 'MyButton',

props: {
type: {
type: String,
default: 'primary',
validator: (value) => {
return ['primary', 'success', 'warning', 'danger'].includes(value);
}
},
disabled: {
type: Boolean,
default: false
}
},

methods: {
handleClick() {
if (!this.disabled) {
this.$emit('click');
}
}
}
};
</script>

<style scoped>
.my-button {
display: inline-block;
}

button {
padding: 20rpx 40rpx;
border-radius: 8rpx;
font-size: 28rpx;
border: none;
outline: none;
cursor: pointer;
}

.primary {
background-color: #007aff;
color: #fff;
}

.success {
background-color: #4cd964;
color: #fff;
}

.warning {
background-color: #ff9500;
color: #fff;
}

.danger {
background-color: #ff3b30;
color: #fff;
}

.disabled {
opacity: 0.6;
cursor: not-allowed;
}
</style>

text

4.3 JS 文件结构

javascript
// 导入依赖
import request from './request';

// 常量定义
const BASE_URL = 'https://api.crmeb.net';
const TIMEOUT = 10000;

// 工具函数
function formatTime(time) {
const date = new Date(time);
return date.toLocaleString();
}

function getRandomNum(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}

// 导出
export {
formatTime,
getRandomNum
};

// 默认导出
export default {
BASE_URL,
TIMEOUT
};

text

5. 组件开发规范

5.1 组件设计

- 单一职责: 每个组件只负责一个功能
- 可复用性: 设计通用的、可复用的组件
- 可配置性: 通过 props 提供配置选项
- 事件通信: 通过事件与父组件通信

5.2 组件使用

- 组件导入: 使用 import 导入组件
- 示例:
import Button from '../../components/Button.vue'
- 组件注册: 在 components 中注册组件
- 示例:

javascript
components: {
Button
}
text
- 组件使用: 使用组件标签
- 示例:
<Button type="primary">点击</Button>

5.3 组件通信

- props 向下传递: 父组件通过 props 向子组件传递数据
- events 向上传递: 子组件通过 events 向父组件传递事件
- refs 引用: 通过 refs 引用子组件实例
- provide/inject: 祖先组件向后代组件传递数据

6. 页面开发规范

6.1 页面结构

- 模板结构: 清晰明了,层次分明
- 脚本结构: 按照 Vue 规范组织代码
- 样式结构: 模块化,可维护

6.2 数据管理

- 本地数据: 使用 data 管理组件内部数据
- 计算数据: 使用 computed 计算衍生数据
- 监听数据: 使用 watch 监听数据变化
- 全局数据: 使用 Vuex 管理全局数据

6.3 生命周期管理

- created: 初始化数据,发送请求
- mounted: 操作 DOM,初始化第三方库
- beforeDestroy: 清理定时器,取消订阅

6.4 路由管理

- 路由配置: 在 pages.json 中配置路由
- 路由跳转: 使用 uni.navigateTo、uni.redirectTo 等方法
- 路由参数: 通过 options 或 $route.params 获取路由参数

7. API 调用规范

7.1 API 封装

- 模块化: 按业务模块封装 API
- 统一处理: 统一处理请求头、响应拦截、错误处理
- Promise 化: 使用 Promise 处理异步请求

7.2 API 调用

- 异步处理: 使用 async/await 处理异步请求
- 错误处理: 使用 try/catch 捕获错误
- 加载状态: 显示加载状态,提升用户体验
- 错误提示: 统一处理错误提示

7.3 示例代码

javascript
async function getUserInfo() {
try {
this.loading = true;
const res = await userApi.getUserInfo();
this.userInfo = res.data;
} catch (error) {
console.error('获取用户信息失败:', error);
uni.showToast({
title: '获取用户信息失败',
icon: 'none'
});
} finally {
this.loading = false;
}
}
text

8. 性能优化

8.1 代码优化

- 减少冗余代码: 避免重复的代码
- 使用计算属性: 对于复杂的计算,使用 computed
- 使用 v-if 和 v-show 合理: 根据场景选择合适的指令
- 使用 key: 在 v-for 中使用 key,提高渲染性能

8.2 网络优化

- 合理使用缓存: 缓存不经常变化的数据
- 减少请求次数: 合并请求,批量操作
- 使用防抖和节流: 避免频繁的事件触发
- 延迟加载: 对于非首屏内容,使用延迟加载

8.3 其他优化

- 减少 DOM 节点: 简化 DOM 结构
- 优化图片: 使用合适的图片格式和大小
- 使用虚拟列表: 对于长列表,使用虚拟列表
- 避免内存泄漏: 及时清理定时器、事件监听器等

9. 常见问题

9.1 代码风格问题

- 问题: 代码风格不一致
- 解决方案: 使用 ESLint 等工具进行代码检查

9.2 性能问题

- 问题: 页面加载慢,卡顿
- 解决方案: 优化代码,减少 DOM 操作,使用虚拟列表等

9.3 兼容性问题

- 问题: 在不同平台上表现不一致
- 解决方案: 遵循 UniApp 规范,使用条件编译

9.4 维护性问题

- 问题: 代码难以维护
- 解决方案: 模块化开发,添加注释,遵循代码规范

10. 参考资源

- Vue 官方文档
- UniApp 官方文档
- ESLint 官方文档
- Prettier 官方文档
- 前端代码规范指南

11. 总结

本文档描述了 CRMEB 项目中 UniApp 移动端的代码规范,包括命名规范、代码风格、文件结构、组件开发等。遵循本文档的规范,可以提高代码的可读性、可维护性和可扩展性,确保项目的质量和稳定性。

代码规范是团队协作的基础,建议开发团队成员严格遵循本文档的规范,共同维护一个高质量的代码库。

---

.Codebuddy/Skills/Uniapp/References/Directory Structure (.codebuddy/skills/uniapp/references/directory_structure.md)

UniApp 目录结构文档

1. 概述

本文档描述了 CRMEB 项目中 UniApp 移动端的目录结构,包括各目录的功能、文件组织方式等,旨在帮助开发者理解项目结构,提高开发效率。

2. 项目根目录结构


template/uni-app/
├── api/ # API 接口目录
├── config/ # 配置目录
├── libs/ # 库文件目录
├── mixins/ # 混入目录
├── store/ # 状态管理目录
├── utils/ # 工具类目录
├── App.vue # 应用入口组件
├── main.js # 应用入口文件
├── manifest.json # 应用配置文件
├── package.json # 项目配置文件
├── pages.json # 页面路由配置文件
├── uni.scss # UniApp 全局样式文件
└── vue.config.js # Vue 配置文件
text

3. API 目录结构 (api/)


api/
├── activity.js # 活动相关接口
├── admin.js # 管理相关接口
├── api.js # 基础 API 配置
├── kefu.js # 客服相关接口
├── lottery.js # 抽奖相关接口
├── order.js # 订单相关接口
├── public.js # 公共接口
├── store.js # 商城相关接口
└── user.js # 用户相关接口
text
- 功能: 封装与后端交互的 API 接口
- 结构: 按业务模块划分接口文件
- 特性: 统一处理请求头、响应拦截、错误处理等
- 调用方式: 通过
import 导入使用

4. 配置目录结构 (config/)


config/
├── app.js # 应用配置
├── cache.js # 缓存配置
└── socket.js # WebSocket 配置
text
- 功能: 存储项目的所有配置文件
- 结构: 按功能模块划分配置文件
- 特性: 集中管理配置,便于维护和修改
- 加载顺序: 应用启动时加载

5. 库文件目录结构 (libs/)


libs/
├── chat.js # 聊天相关功能
├── login.js # 登录相关功能
├── new_chat.js # 新聊天功能
├── order.js # 订单相关功能
├── routine.js # 小程序相关功能
├── uniApi.js # UniApp API 封装
└── wechat.js # 微信相关功能
text
- 功能: 存储通用库文件和功能模块
- 结构: 按功能划分库文件
- 特性: 独立于页面代码,便于复用
- 作用: 提供通用功能和服务

6. 混入目录结构 (mixins/)


mixins/
└── color.js # 颜色相关混入
text
- 功能: 存储 Vue 混入对象
- 结构: 按功能划分混入文件
- 特性: 实现代码复用,避免重复逻辑
- 作用: 为组件提供共享的方法和数据

7. 状态管理目录结构 (store/)


store/
├── getters.js # 状态获取器
└── index.js # 状态管理入口
text
- 功能: 存储 Vuex 状态管理相关文件
- 结构: 按 Vuex 规范划分文件
- 特性: 集中管理应用状态,实现组件间通信
- 作用: 管理全局状态,如用户信息、购物车数据等

8. 工具类目录结构 (utils/)


utils/
├── cache.js # 缓存工具
├── emoji.js # 表情工具
├── index.js # 工具类入口
├── lang.js # 语言工具
├── request.js # 网络请求工具
├── theme.js # 主题工具
├── util.js # 通用工具
└── validate.js # 验证工具
text
- 功能: 存储通用工具类
- 结构: 按功能划分工具文件
- 特性: 提供通用功能,便于复用
- 作用: 处理缓存、网络请求、验证等通用操作

9. 页面目录结构

9.1 页面配置 (pages.json)

json
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首页"
}
},
{
"path": "pages/user/index",
"style": {
"navigationBarTitleText": "个人中心"
}
}
],
"subPackages": [
{
"root": "pages/order",
"pages": [
{
"path": "index",
"style": {
"navigationBarTitleText": "订单列表"
}
}
]
}
]
}
text
- 功能: 配置页面路由、导航栏样式等
- 结构: 按页面层级配置
- 特性: 支持分包加载,优化应用体积
- 作用: 定义应用的页面结构和导航样式

10. 应用配置文件

10.1 manifest.json

json
{
"name": "CRMEB商城",
"appid": "__UNI__APPID__",
"description": "CRMEB商城移动端",
"versionName": "1.0.0",
"versionCode": "100",
"transformPx": true,
"uniStatistics": {
"enable": true
},
"app-plus": {
"usingComponents": true,
"nvueStyleCompiler": "uni-app"
},
"mp-weixin": {
"appid": "wx_appid",
"setting": {
"urlCheck": false
},
"usingComponents": true
}
}
text
- 功能: 配置应用的基本信息、平台配置等
- 结构: 按平台划分配置
- 特性: 支持多平台配置,如微信小程序、App 等
- 作用: 定义应用的全局配置信息

10.2 package.json

json
{
"name": "crmeb-uni-app",
"version": "1.0.0",
"description": "CRMEB商城移动端",
"main": "main.js",
"scripts": {
"dev": "npm run dev:mp-weixin",
"dev:mp-weixin": "cross-env NODE_ENV=development UNI_PLATFORM=mp-weixin vue-cli-service uni-build --watch",
"build": "npm run build:mp-weixin",
"build:mp-weixin": "cross-env NODE_ENV=production UNI_PLATFORM=mp-weixin vue-cli-service uni-build"
},
"dependencies": {
"vue": "^2.6.11",
"vuex": "^3.4.0"
}
}
text
- 功能: 配置项目的依赖、脚本等
- 结构: 标准 npm 配置格式
- 特性: 管理项目依赖,定义构建脚本
- 作用: 管理项目的依赖和构建流程

11. 目录结构最佳实践

11.1 命名规范

- 目录名: 小写字母,单词之间用下划线分隔
- 文件名: 小写字母,单词之间用下划线分隔
- 组件名: 使用 PascalCase 命名风格
- 方法名: 使用 camelCase 命名风格
- 变量名: 使用 camelCase 命名风格

11.2 组织原则

- 模块化: 按功能模块组织目录结构
- 分层架构: 遵循 Vue 组件化开发架构
- 单一职责: 每个目录和文件只负责一个功能
- 可扩展性: 便于添加新功能和模块
- 易维护性: 便于理解和维护

11.3 开发建议

- 遵循 UniApp 规范: 遵循 UniApp 官方目录结构规范
- 合理划分模块: 根据业务功能合理划分模块
- 避免目录过深: 目录层级不宜过深,一般不超过 4 层
- 保持目录整洁: 及时清理无用文件和目录
- 文档化: 为重要目录添加说明文档

12. 常见问题

12.1 目录权限问题

- 问题: 某些目录没有读写权限
- 解决方案: 确保项目目录有正确的读写权限

12.2 页面路由配置问题

- 问题: 新增页面后无法访问
- 解决方案: 在 pages.json 中添加页面路由配置

12.3 分包加载问题

- 问题: 应用体积过大,无法上传到小程序平台
- 解决方案: 使用分包加载,将页面划分到不同的分包中

12.4 目录结构混乱

- 问题: 目录结构不清晰,难以维护
- 解决方案: 重新组织目录结构,遵循模块化原则

13. 参考资源

- UniApp 官方文档
- Vue 官方文档
- Vuex 官方文档
- 微信小程序开发文档

14. 总结

本文档描述了 CRMEB 项目中 UniApp 移动端的目录结构,包括各目录的功能、文件组织方式等。遵循本文档的目录结构规范,可以提高项目的可维护性和可扩展性,便于团队协作开发。

随着业务的发展和技术的演进,目录结构也可能需要不断优化和调整,以适应新的业务需求和技术挑战。

---

.Trae/Documents/生成Git提交规范技能文件 (.trae/documents/生成Git提交规范技能文件.md)

生成Git提交规范技能文件

目标


创建一个新的技能文件,用于规范git提交信息格式,确保不同目录下的文件提交时都能添加正确的前缀说明。

步骤

1. 创建技能目录


- 在
.trae/skills/ 目录下创建 git-commit/ 子目录

2. 生成SKILL.md文件


创建符合格式要求的SKILL.md文件,包含以下内容:

#### 2.1 基本信息
- 技能名称:Git提交规范
- 描述:规范git提交信息格式,确保不同目录下的文件提交时添加正确的前缀

#### 2.2 自动触发说明
- 触发条件:当浏览或操作git相关文件时自动调用
- 适用场景:git提交操作前的提示和规范检查

#### 2.3 核心内容
- 提交信息格式规范
- 不同目录的提交前缀说明
- 提交信息示例
- 最佳实践

#### 2.4 提交前缀规则
- crmeb目录:提交时添加前缀
【程序目录】
- docker-compose目录:提交时添加前缀
【DOCKER】
- dev-docs目录:提交时添加前缀
【开发文档】
- template目录:提交时添加前缀
【前端文件】

#### 2.5 参考资源
- Git官方文档
- 常用git命令
- 提交信息规范指南

3. 验证文件结构


确保文件创建在正确的位置,格式符合技能文件的标准规范。

---

.Trae/Rules/Project Rules (.trae/rules/project_rules.md)

CRMEB 项目专属 Chat 规则

1. 项目概述


- 名称: CRMEB 开源商城系统(PHP版)
- 技术栈: ThinkPHP 6 + ElementUI + UniApp
- 版本: 5.6.4
- 许可证: Apache-2.0

2. 代码风格规范

2.1 PHP 规范


- 遵循 PSR-2 命名规范
- 使用 Restful 接口设计
- 代码分层清晰,注释简洁
- 类名 PascalCase,方法/变量 camelCase
- 常量全大写,下划线分隔
- 4空格缩进,禁止制表符

2.2 Vue 规范


- 组件名 PascalCase
- 方法/变量 camelCase
- 模板使用 kebab-case
- 遵循 Vue 官方风格指南

2.3 数据库规范


- 表名小写下划线分隔
- 主键统一命名为
id
- 外键格式
表名_id
- 时间字段
create_time/update_time
- 状态字段
status,默认值 0

3. 技术选择限制


- 后端: ThinkPHP 6.x(禁止升级到 7.x)
- 前端: Vue 2.x + ElementUI(Admin)、UniApp(移动端)、Nuxt(PC)
- 数据库: MySQL 5.7~8.0(InnoDB)
- 缓存: Redis(推荐)
- 队列: ThinkPHP 内置队列
- 长连接: Workerman

4. 开发流程规范

4.1 开发环境


- PHP 7.1~7.4
- 开发工具:PHPStorm/VS Code
- 版本控制:Git

4.2 代码提交


- 提交信息清晰,中文描述
- 格式:
[模块名] 操作描述
- 禁止一次提交多个不相关功能

4.3 二开流程


1. 阅读项目文档和代码注释
2. 使用代码生成工具创建基础功能
3. 遵循系统架构,不破坏原有结构
4. 使用系统事件扩展功能
5. 测试通过后提交

5. 安全规范


- 操作必须记录系统日志
- 敏感数据加密存储
- 禁止直接拼接 SQL,使用参数绑定
- 验证用户输入,防止 XSS/CSRF 攻击
- 使用内置权限管理系统,禁止硬编码权限
- 合理使用缓存,减少数据库查询
- 高并发场景使用队列处理

6. 部署规范

6.1 运行环境


- 操作系统:Linux/Windows
- Web 服务器:Nginx/Apache/IIS
- PHP 扩展:fileinfo(可选)、redis(可选)
- 禁用危险函数:
proc_openpcntl_signal

6.2 启动命令


- 消息队列:
php think queue:listen --queue(Supervisor 管理)
- 长连接:
sudo -u www php think workerman start --d
- 定时任务:
php think timer start --d

7. 常用开发命令


- 代码生成:
php think crmeb:build
- 数据库迁移:
php think migrate:run
- 查看路由:
php think route:list
- 清除缓存:
php think clear

8. 文档与支持


- 官方文档:https://doc.crmeb.com/single_open
- 技术社区:https://www.crmeb.com/ask/thread/list/147

9. 注意事项


- 确保代码兼容 PHP 7.1~7.4
- 前端兼容主流浏览器和移动端系统
- 避免复杂 SQL 关联查询
- 大数组分批处理
- 保持代码简洁,注释适当
- 遵循单一职责原则

10. 违规处理


- 违反规范的提交将被拒绝
- 影响系统稳定性的代码将被回滚
- 多次违规者禁止提交代码

---

以上规则适用于 CRMEB 项目所有开发人员,确保代码一致性、可维护性和安全性。

---

.Trae/Skills/Admin Element/References/Api Flow (.trae/skills/admin-element/references/api_flow.md)

Admin-Element 接口请求流程文档

1 API 请求流程概述

Admin-Element 项目的 API 请求流程遵循以下步骤:

1. 接口定义: 在 src/api/ 目录下按模块定义 API 接口
2. 请求封装: 使用
axios 封装网络请求,添加拦截器
3. 接口调用: 在组件或业务逻辑中调用 API 接口
4. 响应处理: 统一处理 API 响应,包括成功和失败情况
5. 错误处理: 统一处理网络错误、业务错误等异常情况
6. 数据管理: 将获取的数据存储到状态管理或组件中

2 网络请求封装

2.1 axios 实例创建

src/utils/request.js 中创建 axios 实例并配置:

javascript
import axios from 'axios'
import { Message, Loading } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'

// 创建 axios 实例
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // API 基础路径
timeout: 10000, // 请求超时时间
headers: {
'Content-Type': 'application/json;charset=utf-8'
}
})

text

2.2 请求拦截器

javascript
// 请求拦截器
service.interceptors.request.use(
config => {
// 显示加载动画
if (config.loading !== false) {
store.dispatch('app/showLoading')
}

// 自动添加 token
if (store.getters.token) {
config.headers['Authorization'] =
Bearer ${getToken()}
}

return config
},
error => {
// 隐藏加载动画
store.dispatch('app/hideLoading')
console.error('请求错误:', error)
return Promise.reject(error)
}
)
text

2.3 响应拦截器


/ Detailed source-code truncated for AI context efficiency. /
text

3 API 接口定义

3.1 接口文件组织

API 接口按模块组织,存放在 src/api/ 目录下:


src/api/
├── index.js # API 入口文件
├── user.js # 用户相关接口
├── goods.js # 商品相关接口
├── order.js # 订单相关接口
└── ... # 其他模块接口
text

3.2 接口定义示例

src/api/user.js 中定义用户相关接口:

javascript
import request from '@/utils/request'

export default {
// 登录
login(data) {
return request({
url: '/admin/login',
method: 'post',
data
})
},

// 获取用户信息
getUserInfo() {
return request({
url: '/admin/user/info',
method: 'get'
})
},

// 获取用户列表
getUserList(params) {
return request({
url: '/admin/user/list',
method: 'get',
params
})
},

// 修改用户信息
updateUser(data) {
return request({
url: '/admin/user/update',
method: 'put',
data
})
},

// 删除用户
deleteUser(id) {
return request({
url:
/admin/user/delete/${id},
method: 'delete'
})
}
}

text

3.3 API 入口文件

src/api/index.js 中导出所有 API 模块:

javascript
import user from './user'
import goods from './goods'
import order from './order'

// 导出 API 模块
export default {
user,
goods,
order
}

text

4 请求和响应处理

4.1 请求参数处理

#### 4.1.1 GET 请求

javascript
// 带查询参数的 GET 请求
api.user.getUserList({
page: 1,
limit: 10,
keyword: 'test'
})
text
#### 4.1.2 POST 请求
javascript
// 带请求体的 POST 请求
api.user.login({
username: 'admin',
password: '123456'
})
text
#### 4.1.3 PUT 请求
javascript
// 带请求体的 PUT 请求
api.user.updateUser({
id: 1,
username: 'newadmin',
nickname: '新管理员'
})
text
#### 4.1.4 DELETE 请求
javascript
// 路径参数的 DELETE 请求
api.user.deleteUser(1)
text

4.2 响应数据结构

后端 API 响应数据结构应遵循以下规范:

javascript
{
"code": 200, // 状态码,200 表示成功
"message": "操作成功", // 响应消息
"data": { ... } // 响应数据
}
text

4.3 响应处理示例

javascript
// 在组件中调用 API
import api from '@/api'

export default {
methods: {
async fetchUserList() {
try {
const res = await api.user.getUserList({
page: this.page,
limit: this.limit
})

// 处理成功响应
this.userList = res.data.list
this.total = res.data.total
} catch (error) {
// 错误已在拦截器中处理,这里可以做额外处理
console.error('获取用户列表失败:', error)
}
}
}
}

text

5 错误处理机制

5.1 网络错误

- 网络连接失败
- 请求超时
- 服务器无响应

5.2 业务错误

- 参数错误 (400)
- 未授权 (401)
- 拒绝访问 (403)
- 请求地址不存在 (404)
- 服务器内部错误 (500)

5.3 业务逻辑错误

- 状态码非 200 的响应
- 业务规则验证失败

5.4 错误处理最佳实践

1. 统一错误处理: 在响应拦截器中统一处理错误
2. 友好的错误提示: 向用户显示清晰的错误消息
3. 错误日志记录: 记录错误信息,便于排查问题
4. 特殊错误处理: 对 token 过期等特殊情况进行处理
5. 降级处理: 网络错误时提供合理的降级方案

6 接口调用最佳实践

6.1 使用 async/await

javascript
async fetchData() {
try {
const res = await api.goods.getGoodsList(this.queryParams)
this.goodsList = res.data.list
this.total = res.data.total
} catch (error) {
// 错误处理
}
}
text

6.2 加载状态管理

javascript
export default {
data() {
return {
loading: false,
goodsList: []
}
},
methods: {
async fetchData() {
this.loading = true
try {
const res = await api.goods.getGoodsList(this.queryParams)
this.goodsList = res.data.list
} catch (error) {
// 错误处理
} finally {
this.loading = false
}
}
}
}
text

6.3 防抖和节流

对于频繁触发的请求,使用防抖或节流优化:

javascript
import { debounce } from 'lodash'

export default {
methods: {
// 使用防抖优化搜索请求
search: debounce(async function(query) {
try {
const res = await api.goods.searchGoods({ keyword: query })
this.searchResults = res.data
} catch (error) {
// 错误处理
}
}, 300)
}
}

text

6.4 请求取消

对于可能重复触发的请求,使用取消令牌避免重复请求:

javascript
import axios from 'axios'

export default {
data() {
return {
cancelToken: null
}
},
methods: {
async fetchData() {
// 取消之前的请求
if (this.cancelToken) {
this.cancelToken.cancel('取消重复请求')
}

// 创建新的取消令牌
this.cancelToken = axios.CancelToken.source()

try {
const res = await api.goods.getGoodsList({
page: this.page,
limit: this.limit
}, {
cancelToken: this.cancelToken.token
})
this.goodsList = res.data.list
} catch (error) {
if (axios.isCancel(error)) {
console.log('请求已取消:', error.message)
} else {
// 错误处理
}
}
}
}
}

text

7 接口安全

7.1 认证与授权

- 使用 JWT 令牌进行身份认证
- 请求头中携带 Authorization 字段
- 定期刷新令牌,避免过期

7.2 数据加密

- 敏感数据传输加密
- 密码等敏感信息使用 HTTPS 传输

7.3 防止 CSRF 攻击

- 使用 CSRF Token
- 验证请求来源

7.4 接口速率限制

- 后端实现接口速率限制
- 前端避免频繁请求

8 性能优化

8.1 请求合并

对于多个相同类型的请求,合并为一个请求:

javascript
// 批量获取数据
api.goods.batchGetGoodsInfo(ids)
text

8.2 缓存策略

- 对不常变化的数据进行缓存
- 使用 localStorage 或 sessionStorage 缓存数据

8.3 懒加载

- 按需加载数据
- 滚动到底部加载更多数据

8.4 预加载

- 预加载可能需要的数据
- 提升用户体验

9 调试技巧

9.1 接口调试工具

- 使用 Chrome DevTools 的 Network 面板
- 使用 Postman 等 API 调试工具

9.2 日志记录

- 在开发环境下打印详细的请求和响应信息
- 在生产环境下只记录错误信息

9.3 模拟数据

- 使用 Mock 数据进行前端开发
- 减少对后端接口的依赖

10 总结

Admin-Element 项目的 API 请求流程采用了统一的封装和处理机制,通过 axios 拦截器实现了请求和响应的统一处理,提高了代码的可维护性和可扩展性。开发者应遵循接口定义规范和最佳实践,确保 API 调用的安全性、可靠性和性能。

---

.Trae/Skills/Admin Element/References/Code Style (.trae/skills/admin-element/references/code_style.md)

管理端前端代码规范文档

1. 概述

本文档描述了 CRMEB 项目中管理端前端的代码规范,包括命名规范、代码风格、文件结构、组件开发等方面的规范,旨在统一代码风格,提高代码质量和可维护性。

2. 命名规范

2.1 目录命名


- 目录名: 小写字母,单词之间用连字符分隔
- 示例:
components/common/pages/user-management/utils/
- 规范: 简洁明了,反映目录的功能

2.2 文件命名


- 组件文件: 大写字母开头的 PascalCase 命名风格
- 示例:
Button.vueUserList.vueNavbar.vue
- 页面文件: 小写字母,单词之间用连字符分隔
- 示例:
login.vueuser-list.vuedashboard.vue
- JS 文件: 小写字母,单词之间用连字符分隔
- 示例:
api.jsrequest.jsutil.js
- CSS/SCSS 文件: 小写字母,单词之间用连字符分隔
- 示例:
common.scsstheme.scssvariables.scss

2.3 变量命名


- 普通变量: 驼峰命名法
- 示例:
userInfogoodsListisLoading
- 常量: 全大写,单词之间用下划线分隔
- 示例:
BASE_URLMAX_COUNTDEFAULT_PAGE_SIZE
- 布尔变量: 以
is 开头的驼峰命名法
- 示例:
isShowisLoadingisLogin
- 数组变量: 以复数形式命名
- 示例:
usersgoodsorders
- 对象变量: 以单数形式命名
- 示例:
usergoodorder

2.4 函数命名


- 函数名: 驼峰命名法,动词开头
- 示例:
getUserInfosubmitFormhandleClick
- 方法名: 驼峰命名法
- 示例:
datamethodscomputedwatch
- 生命周期函数: 按照 Vue 规范命名
- 示例:
createdmountedbeforeDestroy
- 事件处理函数: 以
handle 开头
- 示例:
handleSubmithandleClickhandleChange

2.5 组件命名


- 组件名: PascalCase 命名风格
- 示例:
ButtonUserListNavbar
- 组件标签: 小写字母,单词之间用连字符分隔
- 示例:
<el-button><user-list><nav-bar>
- 组件文件名: 与组件名一致,PascalCase 命名
- 示例:
Button.vueUserList.vueNavbar.vue

2.6 其他命名


- 路由命名: 小写字母,单词之间用连字符分隔
- 示例:
/login/user/list/dashboard
- CSS 类名: 小写字母,单词之间用连字符分隔
- 示例:
.user-info.goods-list.btn-primary
- ID 命名: 小写字母,单词之间用连字符分隔
- 示例:
#app#header#footer
- Vuex 模块命名: 小写字母,单词之间用连字符分隔
- 示例:
usergoodsorders

3. 代码风格

3.1 缩进


- 缩进方式: 4 个空格
- 示例:
vue
<template>
<div class="container">
<h1>{{ title }}</h1>
</div>
</template>
text

3.2 换行


- 标签换行: 多个属性的标签应该换行
- 示例:
vue
<el-button
type="primary"
size="medium"
@click="handleSubmit"
>
提交
</el-button>
text
- 代码块换行: 逻辑代码块应该换行
- 示例:
javascript
if (condition) {
// 代码块
} else {
// 代码块
}
text

3.3 空格


- 运算符空格: 运算符两侧应该有空格
- 示例:
a + bx = yi < 10
- 逗号空格: 逗号后面应该有空格
- 示例:
[1, 2, 3]{ name: '张三', age: 18 }
- 括号空格: 括号内侧不应该有空格
- 示例:
if (condition)function (param)
- 冒号空格: 对象字面量中冒号后面应该有空格
- 示例:
{ name: '张三', age: 18 }

3.4 注释


- 单行注释: 使用
// 注释
- 示例:
// 这是单行注释
- 多行注释: 使用
/ / 注释
- 示例:
javascript
/*
* 这是多行注释
* 第二行
*/
text
- 文档注释: 使用 JSDoc 风格的注释
- 示例:
javascript
/
* 获取用户信息
* @param {number} id - 用户ID
* @returns {Promise} 用户信息
*/
async function getUserInfo(id) {
// 代码
}
text
- 组件注释: 组件使用文档注释
- 示例:
vue
/
* 用户列表组件
* @props {Array} users - 用户列表数据
* @props {Boolean} loading - 是否加载中
* @events {Function} select - 选择用户时触发
*/
text

3.5 引号


- 字符串: 使用单引号
''
- 示例:
const name = '张三'<span>Hello</span>
- 模板字符串: 使用反引号
`
- 示例:
const url = ${baseUrl}/api/user
- HTML 属性: 使用双引号
""
- 示例:
<div class="container"><img src="https://example.com/img.jpg">

3.6 分号


- 语句结束: 每个语句结束都应该加分号
- 示例:
const name = '张三';function() {};

3.7 空行


- 代码块之间: 代码块之间应该有空行
- 示例:
javascript
function first() {
// 代码
}

function second() {
// 代码
}

text
- 逻辑块之间: 逻辑块之间应该有空行
- 示例:
javascript
if (condition) {
// 代码
}

while (loop) {
// 代码
}

text

4. 文件结构

4.1 组件文件结构


/ Detailed source-code truncated for AI context efficiency. /
text

4.2 页面文件结构


/ Detailed source-code truncated for AI context efficiency. /
text

4.3 JS 文件结构

javascript
// 导入依赖
import axios from 'axios';
import { Message } from 'element-ui';

// 常量定义
const BASE_URL = process.env.VUE_APP_API_BASE_URL;
const TIMEOUT = 10000;

// 创建 axios 实例
const service = axios.create({
baseURL: BASE_URL,
timeout: TIMEOUT
});

// 请求拦截器
service.interceptors.request.use(
config => {
// 添加 token
const token = localStorage.getItem('token');
if (token) {
config.headers['Authorization'] =
Bearer ${token};
}
return config;
},
error => {
console.error('请求错误:', error);
return Promise.reject(error);
}
);

// 响应拦截器
service.interceptors.response.use(
response => {
const { data } = response;
if (data.code !== 200) {
Message.error(data.message || '请求失败');
return Promise.reject(data);
}
return data;
},
error => {
console.error('响应错误:', error);
Message.error('网络错误,请稍后重试');
return Promise.reject(error);
}
);

// 工具函数
function formatDate(date) {
const d = new Date(date);
return d.toLocaleString();
}

function deepClone(obj) {
return JSON.parse(JSON.stringify(obj));
}

// 导出
export {
service,
formatDate,
deepClone
};

// 默认导出
export default service;

text

5. 组件开发规范

5.1 组件设计


- 单一职责: 每个组件只负责一个功能
- 可复用性: 设计通用的、可复用的组件
- 可配置性: 通过 props 提供配置选项
- 事件通信: 通过事件与父组件通信
- 插槽支持: 提供插槽,增强组件灵活性

5.2 组件使用


- 组件导入: 使用 import 导入组件
- 示例:
import Button from '@/components/Button.vue'
- 组件注册: 在 components 中注册组件
- 示例:
javascript
components: {
Button
}
text
- 组件使用: 使用组件标签
- 示例:
<Button type="primary">点击</Button>
- 组件传值: 通过 props 传递数据
- 示例:
<UserList :users="userList" :loading="loading" />
- 事件监听: 监听组件事件
- 示例:
<UserList @select="handleSelect" />

5.3 组件通信


- props 向下传递: 父组件通过 props 向子组件传递数据
- events 向上传递: 子组件通过 events 向父组件传递事件
- refs 引用: 通过 refs 引用子组件实例
- provide/inject: 祖先组件向后代组件传递数据
- Vuex 全局状态: 使用 Vuex 管理全局状态
- EventBus: 组件间事件总线

5.4 组件生命周期


- created: 初始化数据,发送请求
- mounted: 操作 DOM,初始化第三方库
- beforeUpdate: 更新前的准备工作
- updated: 数据更新后的操作
- beforeDestroy: 清理定时器,取消订阅
- destroyed: 组件销毁后的清理工作

5.5 组件命名规范


- 组件名: PascalCase 命名风格
- 组件文件名: 与组件名一致
- 组件目录: 按功能分类存放
- 组件前缀: 通用组件使用统一前缀

6. 页面开发规范

6.1 页面结构


- 模板结构: 清晰明了,层次分明
- 脚本结构: 按照 Vue 规范组织代码
- 样式结构: 模块化,可维护
- 布局规范: 遵循统一的布局规范

6.2 数据管理


- 本地数据: 使用 data 管理组件内部数据
- 计算数据: 使用 computed 计算衍生数据
- 监听数据: 使用 watch 监听数据变化
- 全局数据: 使用 Vuex 管理全局数据

6.3 路由管理


- 路由配置: 在 router 目录中配置路由
- 路由跳转: 使用 router.push、router.replace 等方法
- 路由参数: 通过 $route.params 获取路由参数
- 路由守卫: 使用全局/局部路由守卫

6.4 API 调用


- API 封装: 统一封装 API 调用
- 异步处理: 使用 async/await 处理异步请求
- 错误处理: 使用 try/catch 捕获错误
- 加载状态: 显示加载状态,提升用户体验

6.5 用户体验


- 响应式设计: 适配不同屏幕尺寸
- 加载状态: 显示加载中提示
- 错误提示: 显示错误信息
- 成功提示: 显示操作成功提示
- 表单验证: 实时表单验证
- 防抖节流: 优化频繁触发的事件

7. 性能优化

7.1 代码优化


- 减少冗余代码: 避免重复的代码
- 使用计算属性: 对于复杂的计算,使用 computed
- 使用 v-if 和 v-show 合理: 根据场景选择合适的指令
- 使用 key: 在 v-for 中使用 key,提高渲染性能
- 避免频繁更新: 使用防抖和节流

7.2 网络优化


- 合理使用缓存: 缓存不经常变化的数据
- 减少请求次数: 合并请求,批量操作
- 使用 CDN: 静态资源使用 CDN
- 压缩传输: 使用 gzip 压缩传输数据

7.3 构建优化


- Tree Shaking: 移除未使用的代码
- 代码分割: 按路由分割代码
- 懒加载: 路由懒加载,组件懒加载
- 预加载: 预加载关键资源

7.4 其他优化


- 减少 DOM 节点: 简化 DOM 结构
- 优化图片: 使用合适的图片格式和大小
- 使用虚拟列表: 对于长列表,使用虚拟列表
- 避免内存泄漏: 及时清理定时器、事件监听器等

8. 常见问题

8.1 代码风格问题


- 问题: 代码风格不一致
- 解决方案: 使用 ESLint 和 Prettier 统一代码风格

8.2 性能问题


- 问题: 页面加载慢,卡顿
- 解决方案: 优化代码,减少 DOM 操作,使用虚拟列表等

8.3 兼容性问题


- 问题: 在不同浏览器上表现不一致
- 解决方案: 遵循 Web 标准,使用 polyfill

8.4 维护性问题


- 问题: 代码难以维护
- 解决方案: 模块化开发,添加注释,遵循代码规范

8.5 命名冲突问题


- 问题: 命名冲突
- 解决方案: 使用命名空间,避免全局变量

9. 参考资源

- Vue 官方风格指南
- Element UI 官方文档
- ESLint 官方文档
- Prettier 官方文档
- JavaScript 代码规范
- CSS 代码规范

10. 总结

本文档描述了 CRMEB 项目中管理端前端的代码规范,包括命名规范、代码风格、文件结构、组件开发等方面的规范。遵循本文档的规范,可以提高代码的可读性、可维护性和可扩展性,确保项目的质量和稳定性。

代码规范是团队协作的基础,建议开发团队成员严格遵循本文档的规范,共同维护一个高质量的代码库。

---

.Trae/Skills/Admin Element/References/Deploy (.trae/skills/admin-element/references/deploy.md)

管理端前端部署文档

1. 概述

本文档描述了 CRMEB 项目中管理端前端的部署流程,包括构建、部署、配置等环节,旨在规范前端部署流程,确保部署过程的顺利进行和系统的稳定运行。

2. 部署环境

2.1 服务器要求


- 操作系统: Linux (Ubuntu 18.04+、CentOS 7+)
- Web 服务器: Nginx 1.14+ 或 Apache 2.4+
- Node.js: v12.0.0+ (仅构建时需要)
- npm/yarn: v6.0.0+ (仅构建时需要)
- 内存: 至少 2GB RAM
- CPU: 至少 2 核 CPU
- 磁盘空间: 至少 20GB 可用空间

2.2 环境准备


- Web 服务器配置: 配置虚拟主机,指向前端构建产物目录
- SSL 证书: 配置 HTTPS,使用 SSL 证书
- 防火墙: 开放 80/443 端口
- 域名: 配置域名解析,指向服务器 IP

3. 构建流程

3.1 开发环境构建


- 命令:
npm run dev
- 用途: 本地开发,启动开发服务器
- 访问地址:
http://localhost:8080

3.2 测试环境构建


- 命令:
npm run build:test
- 用途: 测试环境部署
- 构建产物:
dist/ 目录

3.3 生产环境构建


- 命令:
npm run build:prod
- 用途: 生产环境部署
- 构建产物:
dist/ 目录

3.4 构建优化


- 代码压缩: 压缩 JS/CSS/HTML 文件
- 资源压缩: 压缩图片等静态资源
- Tree Shaking: 移除未使用的代码
- 代码分割: 按路由分割代码
- 预加载: 预加载关键资源

4. 部署方式

4.1 静态部署

#### 4.1.1 Nginx 配置

nginx
server {
listen 80;
server_name admin.example.com;
return 301 https://$server_name$request_uri;
}

server {
listen 443 ssl http2;
server_name admin.example.com;

# SSL 配置
ssl_certificate /path/to/ssl/cert.pem;
ssl_certificate_key /path/to/ssl/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers on;

# 静态文件配置
root /path/to/admin/dist;
index index.html;

# 路由重写,解决单页应用刷新 404 问题
location / {
try_files $uri $uri/ /index.html;
}

# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 30d;
add_header Cache-Control "public, max-age=2592000";
}

# 日志配置
access_log /var/log/nginx/admin_access.log;
error_log /var/log/nginx/admin_error.log;
}

text
#### 4.1.2 Apache 配置
apache
<VirtualHost *:80>
ServerName admin.example.com
Redirect permanent / https://admin.example.com/
</VirtualHost>

<VirtualHost *:443>
ServerName admin.example.com

# SSL 配置
SSLEngine on
SSLCertificateFile /path/to/ssl/cert.pem
SSLCertificateKeyFile /path/to/ssl/key.pem

# 静态文件配置
DocumentRoot /path/to/admin/dist
<Directory /path/to/admin/dist>
AllowOverride All
Require all granted
</Directory>

# 路由重写,解决单页应用刷新 404 问题
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>

# 日志配置
ErrorLog ${APACHE_LOG_DIR}/admin_error.log
CustomLog ${APACHE_LOG_DIR}/admin_access.log combined
</VirtualHost>

text

4.2 容器部署

#### 4.2.1 Dockerfile

dockerfile

基础镜像


FROM node:12-alpine as build

设置工作目录


WORKDIR /app

复制依赖文件


COPY package*.json ./

安装依赖


RUN npm install

复制源代码


COPY . .

构建生产版本


RUN npm run build:prod

生产镜像


FROM nginx:1.19-alpine

复制构建产物


COPY --from=build /app/dist /usr/share/nginx/html

复制 Nginx 配置


COPY nginx.conf /etc/nginx/conf.d/default.conf

暴露端口


EXPOSE 80

启动 Nginx


CMD ["nginx", "-g", "daemon off;"]
text
#### 4.2.2 Docker Compose
yaml
version: '3'
services:
admin:
build: .
ports:
- "80:80"
restart: always
volumes:
- ./ssl:/etc/nginx/ssl
environment:
- TZ=Asia/Shanghai
text
#### 4.2.3 部署命令
bash

构建镜像


docker build -t crmeb-admin .

运行容器


docker run -d --name crmeb-admin -p 80:80 crmeb-admin

使用 Docker Compose


docker-compose up -d
text

4.3 CDN 部署

#### 4.3.1 配置 CDN
- 源站设置: 指向静态文件服务器
- 缓存策略: 配置静态资源缓存时间
- HTTPS: 开启 HTTPS
- HTTP/2: 开启 HTTP/2

#### 4.3.2 部署流程
1. 构建前端项目
2. 上传构建产物到 CDN
3. 配置 CDN 缓存策略
4. 验证部署结果

5. 配置管理

5.1 环境变量配置


- 开发环境:
.env.development
- 测试环境:
.env.test
- 生产环境:
.env.production

5.2 配置示例

env

API 基础地址


VUE_APP_API_BASE_URL=https://api.example.com

静态资源 CDN 地址


VUE_APP_CDN_BASE_URL=https://cdn.example.com

应用名称


VUE_APP_TITLE=CRMEB 管理后台

构建环境


NODE_ENV=production

构建版本


VUE_APP_VERSION=1.0.0
text

5.3 运行时配置


- API 地址: 可通过环境变量或配置文件修改
- 主题配置: 可通过配置文件修改
- 权限配置: 可通过后端 API 动态获取

6. 部署流程

6.1 手动部署


1. 拉取代码:
git pull origin master
2. 安装依赖:
npm install
3. 构建项目:
npm run build:prod
4. 部署文件: 将
dist/ 目录复制到服务器
5. 配置 Web 服务器: 配置虚拟主机
6. 重启服务: 重启 Web 服务器
7. 验证部署: 访问管理端地址

6.2 自动化部署

#### 6.2.1 CI/CD 配置
- Jenkins: 配置 Jenkins 任务,实现自动构建和部署
- GitLab CI: 配置
.gitlab-ci.yml,实现自动构建和部署
- GitHub Actions: 配置
.github/workflows/deploy.yml,实现自动构建和部署

#### 6.2.2 GitHub Actions 示例

yaml
name: Deploy Admin Frontend

on:
push:
branches:
- master

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '12'

- name: Install dependencies
run: npm install

- name: Build project
run: npm run build:prod

- name: Deploy to server
uses: easingthemes/[email protected]
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
ARGS: '-rltgoDzvO --delete'
SOURCE: 'dist/'
REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
REMOTE_USER: ${{ secrets.REMOTE_USER }}
REMOTE_PORT: ${{ secrets.REMOTE_PORT }}
TARGET: ${{ secrets.REMOTE_TARGET }}

- name: Restart Nginx
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.REMOTE_HOST }}
username: ${{ secrets.REMOTE_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
port: ${{ secrets.REMOTE_PORT }}
script: sudo systemctl restart nginx

text

7. 监控与维护

7.1 监控


- 访问日志: 分析 Web 服务器访问日志
- 错误日志: 监控 Web 服务器错误日志
- 性能监控: 监控页面加载速度、响应时间
- 可用性监控: 监控服务可用性,设置告警

7.2 维护


- 定期更新: 定期更新前端代码,修复漏洞
- 缓存清理: 定期清理 CDN 缓存
- 日志清理: 定期清理日志文件
- 备份: 定期备份构建产物和配置文件

7.3 常见问题

#### 7.3.1 404 问题
- 问题: 刷新页面出现 404 错误
- 解决方案: 配置 Web 服务器,将所有请求重定向到 index.html

#### 7.3.2 静态资源加载失败
- 问题: 静态资源(JS/CSS/图片)加载失败
- 解决方案: 检查静态资源路径,确保 CDN 配置正确

#### 7.3.3 API 调用失败
- 问题: 前端无法调用后端 API
- 解决方案: 检查 API 地址配置,确保后端服务正常运行

#### 7.3.4 性能问题
- 问题: 页面加载慢,卡顿
- 解决方案: 优化前端代码,使用 CDN,启用 HTTP/2

8. 回滚策略

8.1 版本管理


- 版本号: 遵循语义化版本规范
- 发布记录: 记录每次发布的版本和变更内容
- 备份: 备份每次发布的构建产物

8.2 回滚流程


1. 停止服务: 停止当前版本的服务
2. 恢复备份: 恢复到上一个稳定版本
3. 重启服务: 启动恢复后的服务
4. 验证回滚: 验证服务是否正常运行

8.3 回滚方案


- 手动回滚: 手动复制备份文件到部署目录
- 自动化回滚: 通过 CI/CD 工具实现自动回滚
- 容器回滚: 通过 Docker 镜像版本回滚

9. 安全部署

9.1 HTTPS 配置


- SSL 证书: 使用正规 CA 签发的 SSL 证书
- 证书续期: 定期续期 SSL 证书
- HTTP 重定向: 将 HTTP 请求重定向到 HTTPS

9.2 安全头部


- Content-Security-Policy: 配置内容安全策略
- X-Content-Type-Options: 防止 MIME 类型嗅探
- X-Frame-Options: 防止点击劫持
- X-XSS-Protection: 启用 XSS 过滤

9.3 访问控制


- IP 白名单: 限制管理端访问 IP
- 登录验证: 强制登录验证
- 权限控制: 基于角色的权限控制
- 会话管理: 安全的会话管理

9.4 漏洞防护


- 依赖扫描: 定期扫描依赖包漏洞
- 代码审计: 定期进行代码安全审计
- 渗透测试: 定期进行渗透测试

10. 最佳实践

10.1 构建优化


- 使用缓存: 缓存依赖包和构建产物
- 并行构建: 使用多线程并行构建
- 增量构建: 只构建变更的文件
- 构建日志: 保存构建日志,便于排查问题

10.2 部署优化


- 灰度发布: 采用灰度发布策略
- 蓝绿部署: 采用蓝绿部署策略
- 滚动部署: 采用滚动部署策略
- 金丝雀发布: 采用金丝雀发布策略

10.3 监控优化


- 实时监控: 实时监控系统运行状态
- 告警机制: 设置合理的告警阈值
- 日志聚合: 聚合多服务器日志
- 性能分析: 定期分析系统性能

10.4 安全优化


- 最小权限: 遵循最小权限原则
- 定期更新: 定期更新依赖和系统
- 安全扫描: 定期进行安全扫描
- 应急响应: 建立安全应急响应机制

11. 总结

本文档描述了 CRMEB 项目中管理端前端的部署流程,包括构建、部署、配置等环节,以及相关的最佳实践和常见问题解决方案。

遵循本文档的部署流程和规范,可以确保前端部署的顺利进行和系统的稳定运行,同时提高部署效率和系统安全性。

随着项目的发展和技术的演进,部署流程也需要不断优化和调整,以适应新的业务需求和技术挑战。

---

.Trae/Skills/Admin Element/References/Development Flow (.trae/skills/admin-element/references/development_flow.md)

管理端前端开发流程文档

1. 概述

本文档描述了 CRMEB 项目中管理端前端的开发流程,包括需求分析、设计、编码、测试、部署等环节,旨在规范前端开发流程,提高开发效率和代码质量。

2. 开发流程

2.1 需求分析

#### 2.1.1 需求获取
- 需求来源: 产品经理、业务方、后端开发、测试人员
- 需求形式: PRD 文档、需求评审会议、邮件、即时通讯工具
- 需求内容: 功能需求、非功能需求、UI/UX 需求

#### 2.1.2 需求评审
- 评审人员: 前端开发、后端开发、产品经理、测试人员
- 评审内容: 需求可行性、技术实现方案、时间评估、风险评估
- 评审输出: 评审纪要、任务分解、时间计划

#### 2.1.3 需求确认
- 确认内容: 需求细节、技术方案、交付标准
- 确认形式: 需求确认邮件、需求确认会议
- 确认输出: 需求确认文档

2.2 设计阶段

#### 2.2.1 UI 设计
- 设计工具: Figma、Sketch、Adobe XD
- 设计内容: 页面布局、组件样式、交互设计、色彩方案
- 设计输出: UI 设计稿、设计规范文档

#### 2.2.2 技术设计
- 设计内容: 技术选型、架构设计、目录结构、组件设计、API 设计
- 设计输出: 技术设计文档、架构图、组件设计图

#### 2.2.3 原型设计
- 原型工具: Axure、Figma、Sketch
- 原型内容: 页面原型、交互原型、流程原型
- 原型输出: 交互式原型、流程图

2.3 编码实现

#### 2.3.1 环境搭建
- 开发环境: Node.js、npm/yarn、VS Code、Git
- 依赖安装:
npm installyarn install
- 开发工具: Vue DevTools、Chrome DevTools

#### 2.3.2 代码开发
- 开发顺序: 基础组件 → 页面组件 → 业务逻辑 → 测试
- 开发规范: 遵循代码规范、命名规范、文档规范
- 代码质量: 代码可读性、可维护性、可扩展性

#### 2.3.3 代码审查
- 审查人员: 前端团队成员
- 审查内容: 代码质量、功能实现、性能优化、安全防护
- 审查工具: GitLab/GitHub Code Review、ESLint、Prettier

2.4 测试验证

#### 2.4.1 单元测试
- 测试工具: Jest、Vue Test Utils
- 测试内容: 组件测试、工具函数测试、状态管理测试
- 测试覆盖率: 关键功能测试覆盖率 ≥ 80%

#### 2.4.2 功能测试
- 测试人员: 前端开发、测试人员
- 测试内容: 功能实现、交互体验、页面布局、响应式设计
- 测试工具: 浏览器、测试管理工具

#### 2.4.3 性能测试
- 测试工具: Chrome DevTools、Lighthouse、WebPageTest
- 测试内容: 首屏加载速度、页面渲染性能、内存使用、网络请求
- 测试指标: FCP、LCP、TTI、CLS、FID

#### 2.4.4 兼容性测试
- 测试浏览器: Chrome、Firefox、Safari、Edge
- 测试分辨率: 1024x768、1366x768、1920x1080
- 测试内容: 页面显示、功能实现、交互体验

2.5 部署上线

#### 2.5.1 构建打包
- 构建命令:
npm run build:prod
- 构建产物: 静态资源文件
- 构建优化: 代码压缩、资源压缩、Tree Shaking

#### 2.5.2 部署配置
- 部署环境: 测试环境、预发布环境、生产环境
- 部署工具: Nginx、Apache、CDN
- 配置内容: 服务器配置、域名配置、HTTPS 配置

#### 2.5.3 上线发布
- 发布流程: 测试环境 → 预发布环境 → 生产环境
- 发布时间: 非业务高峰期
- 发布监控: 实时监控系统运行状态

#### 2.5.4 上线后验证
- 验证内容: 功能验证、性能验证、兼容性验证
- 验证人员: 前端开发、测试人员、产品经理
- 验证输出: 上线验证报告

3. 开发规范

3.1 代码规范


- ESLint 规则: 遵循 Vue 官方推荐的 ESLint 规则
- Prettier 配置: 统一代码格式化规则
- 代码缩进: 4 空格缩进
- 命名规范: 组件名 PascalCase,变量/方法名 camelCase,常量全大写

3.2 提交规范


- 提交信息格式:
[类型] 描述
- 类型: feat(新功能)、fix(修复)、docs(文档)、style(样式)、refactor(重构)、test(测试)、chore(构建/依赖)
- 提交频率: 小步提交,每个功能或修复一个提交
- 提交内容: 只提交相关代码,不提交无关文件

3.3 分支规范


- 主分支: master(生产环境)、develop(开发环境)
- 功能分支: feature/功能名称
- 修复分支: fix/修复内容
- 发布分支: release/版本号
- 分支管理: 定期清理无用分支

3.4 文档规范


- README.md: 项目说明、安装说明、开发说明
- 组件文档: 组件使用说明、Props、Events、Slots
- API 文档: API 接口说明、请求参数、响应格式
- 开发文档: 开发流程、编码规范、部署流程

4. 开发工具

4.1 开发环境


- Node.js: v12.0.0+
- npm: v6.0.0+ 或 yarn: v1.22.0+
- VS Code: 最新版本
- Git: 最新版本

4.2 编辑器插件


- Vetur: Vue 开发插件
- ESLint: 代码检查插件
- Prettier: 代码格式化插件
- GitLens: Git 增强插件
- Debugger for Chrome: 浏览器调试插件
- Auto Close Tag: 自动闭合标签
- Auto Rename Tag: 自动重命名标签

4.3 开发工具


- Vue DevTools: Vue 开发调试工具
- Chrome DevTools: 浏览器调试工具
- Postman: API 测试工具
- Charles: 网络调试工具
- Figma/Sketch: UI 设计工具
- Zeplin: 设计协作工具

4.4 构建工具


- Webpack: 模块打包工具
- Babel: JavaScript 编译器
- Sass/Less: CSS 预处理器
- ESLint: 代码检查工具
- Prettier: 代码格式化工具

5. 常见问题及解决方案

5.1 需求变更

- 问题: 开发过程中需求发生变更
- 解决方案:
1. 记录需求变更内容
2. 评估变更影响范围
3. 与产品经理确认变更可行性
4. 调整开发计划和时间评估
5. 通知相关团队成员

5.2 技术难题

- 问题: 遇到技术难题无法解决
- 解决方案:
1. 查阅相关文档和资料
2. 寻求团队成员帮助
3. 咨询外部专家
4. 尝试替代方案
5. 记录解决方案,形成知识库

5.3 时间紧张

- 问题: 开发时间紧张,任务无法按时完成
- 解决方案:
1. 评估任务优先级
2. 与产品经理沟通,调整需求优先级
3. 寻求团队成员协助
4. 优化开发流程,提高开发效率
5. 加班完成(作为最后手段)

5.4 代码冲突

- 问题: Git 代码冲突
- 解决方案:
1. 拉取最新代码
2. 手动解决冲突
3. 测试冲突解决后的代码
4. 提交解决冲突后的代码
5. 通知相关团队成员

5.5 线上问题

- 问题: 线上出现问题
- 解决方案:
1. 快速定位问题原因
2. 制定解决方案
3. 紧急修复并部署
4. 验证修复效果
5. 分析问题原因,避免类似问题再次发生

6. 最佳实践

6.1 开发前准备


- 需求确认: 确保需求理解正确
- 技术方案: 制定详细的技术实现方案
- 环境搭建: 确保开发环境配置正确
- 依赖安装: 安装必要的依赖包

6.2 编码实现


- 组件化开发: 封装可复用组件
- 模块化开发: 按功能模块组织代码
- 代码复用: 提取公共逻辑,避免重复代码
- 性能优化: 考虑代码性能,避免性能瓶颈
- 安全性: 考虑代码安全性,避免安全漏洞

6.3 测试验证


- 单元测试: 编写关键功能的单元测试
- 功能测试: 全面测试功能实现
- 性能测试: 测试页面性能
- 兼容性测试: 测试不同浏览器兼容性
- 用户体验测试: 测试页面交互体验

6.4 部署上线


- 构建优化: 优化构建产物
- 部署策略: 采用灰度发布策略
- 监控告警: 配置系统监控和告警
- 回滚方案: 准备系统回滚方案
- 上线验证: 上线后及时验证系统状态

6.5 维护迭代


- 问题跟踪: 及时跟踪和解决线上问题
- 代码维护: 定期维护和优化代码
- 文档更新: 及时更新相关文档
- 技术债务: 定期清理技术债务
- 知识共享: 分享开发经验和解决方案

7. 团队协作

7.1 协作模式


- 敏捷开发: 采用 Scrum 或 Kanban 敏捷开发模式
- 每日站会: 每日 15 分钟站会,同步开发进度
- 迭代周期: 2-4 周一个迭代周期
- 迭代回顾: 迭代结束后进行回顾,总结经验教训

7.2 沟通工具


- 即时通讯: 企业微信、钉钉、Slack
- 项目管理: Jira、Trello、GitHub Issues
- 代码托管: GitLab、GitHub、Gitee
- 文档协作: 语雀、Confluence、Google Docs

7.3 知识共享


- 技术分享: 定期组织技术分享会议
- 代码审查: 相互代码审查,分享编码经验
- 问题讨论: 定期组织问题讨论会议
- 知识库: 建立团队知识库,积累技术经验

8. 总结

本文档描述了 CRMEB 项目中管理端前端的开发流程,包括需求分析、设计、编码、测试、部署等环节,以及相关的开发规范和最佳实践。

遵循本文档的开发流程和规范,可以提高前端开发效率和代码质量,减少开发过程中的问题和风险,确保项目的顺利进行。

同时,开发流程也需要根据项目的实际情况进行调整和优化,以适应不同项目的需求和特点。

---

.Trae/Skills/Admin Element/References/Directory Structure (.trae/skills/admin-element/references/directory_structure.md)

Admin-Element 目录结构文档

1 项目根目录结构


template/ # 前端项目目录
├── admin-element/ # 管理端前端项目
│ ├── public/ # 静态资源目录
│ │ ├── favicon.ico # 网站图标
│ │ ├── index.html # 入口HTML文件
│ │ └── static/ # 静态资源文件
│ ├── src/ # 源代码目录
│ │ ├── api/ # API接口定义
│ │ ├── assets/ # 静态资源
│ │ ├── components/ # 通用组件
│ │ ├── config/ # 配置文件
│ │ ├── directive/ # 自定义指令
│ │ ├── filters/ # 过滤器
│ │ ├── layout/ # 布局组件
│ │ ├── router/ # 路由配置
│ │ ├── store/ # 状态管理
│ │ ├── styles/ # 样式文件
│ │ ├── utils/ # 工具函数
│ │ ├── views/ # 页面组件
│ │ ├── App.vue # 根组件
│ │ └── main.js # 入口文件
│ ├── tests/ # 测试文件
│ ├── .env.* # 环境变量配置
│ ├── babel.config.js # Babel配置
│ ├── package.json # 项目依赖
│ ├── vue.config.js # Vue配置
│ └── README.md # 项目说明
text

2 主要目录说明

2.1 public/ 目录


- favicon.ico: 网站图标文件
- index.html: 应用入口HTML文件,Vue应用将挂载到这个文件中
- static/: 静态资源目录,存放不需要经过webpack处理的静态文件

2.2 src/ 目录

#### 2.2.1 api/ 目录
- 定义所有API接口请求
- 按模块组织API文件
- 包含接口调用方法和参数配置

#### 2.2.2 assets/ 目录
- images/: 图片资源
- icons/: 图标资源
- styles/: 全局样式文件
- 其他静态资源文件

#### 2.2.3 components/ 目录
- base/: 基础组件
- business/: 业务组件
- common/: 通用组件
- 可复用的Vue组件

#### 2.2.4 config/ 目录
- index.js: 主配置文件
- router.config.js: 路由配置
- menu.config.js: 菜单配置
- theme.config.js: 主题配置
- 其他系统配置文件

#### 2.2.5 directive/ 目录
- 自定义Vue指令
- 如权限控制、表单验证等指令

#### 2.2.6 filters/ 目录
- 自定义Vue过滤器
- 如日期格式化、数字格式化等

#### 2.2.7 layout/ 目录
- components/: 布局组件
- index.vue: 主布局文件
- AppMain.vue: 内容区域组件
- Navbar.vue: 导航栏组件
- Sidebar.vue: 侧边栏组件

#### 2.2.8 router/ 目录
- index.js: 路由配置主文件
- modules/: 按模块组织的路由配置
- 路由守卫配置

#### 2.2.9 store/ 目录
- index.js: 状态管理主文件
- modules/: 按模块组织的状态管理
- getters.js: 全局计算属性

#### 2.2.10 styles/ 目录
- index.scss: 全局样式入口
- variables.scss: 全局变量
- mixins.scss: 混合器
- reset.scss: 重置样式

#### 2.2.11 utils/ 目录
- request.js: 网络请求封装
- auth.js: 认证相关工具
- tools.js: 通用工具函数
- storage.js: 存储工具

#### 2.2.12 views/ 目录
- 按业务模块组织页面组件
- 每个模块一个目录
- 包含页面组件和相关子组件

#### 2.2.13 App.vue
- 应用根组件
- 包含全局布局结构

#### 2.2.14 main.js
- 应用入口文件
- 初始化Vue实例
- 加载插件和全局配置

2.3 配置文件

#### 2.3.1 package.json
- 项目依赖配置
- 脚本命令配置
- 项目信息配置

#### 2.3.2 vue.config.js
- Vue CLI配置
- 构建配置
- 代理配置

#### 2.3.3 babel.config.js
- Babel转译配置

#### 2.3.4 .env.*
- 环境变量配置文件
- .env.development: 开发环境
- .env.production: 生产环境
- .env.staging: 测试环境

3 目录规范

3.1 命名规范


- 目录名使用小写字母,多单词用连字符(-)分隔
- 文件名使用小写字母,多单词用连字符(-)分隔
- 组件名使用 PascalCase 命名法

3.2 目录组织原则


1. 按功能模块组织: 相关功能的文件放在同一目录
2. 模块化: 每个模块保持相对独立
3. 可扩展性: 目录结构应易于扩展和维护
4. 一致性: 保持目录结构的一致性

3.3 特殊目录处理


- components/: 只存放可复用组件
- views/: 存放页面级组件
- api/: 按模块组织API接口
- store/modules/: 按模块组织状态管理

4 最佳实践

4.1 目录使用建议


- 新增业务模块时,在 views/ 下创建对应的目录
- 新增可复用组件时,放在 components/ 下的对应子目录
- 新增API接口时,在 api/ 下按模块组织
- 新增状态管理时,在 store/modules/ 下创建对应模块

4.2 目录结构维护


- 定期清理无用文件和目录
- 保持目录结构的清晰和整洁
- 遵循统一的命名规范
- 文档及时更新,反映目录结构的变化

5 常见问题

5.1 目录权限问题


- 确保目录权限正确,避免构建时出现权限错误

5.2 路径引用问题


- 使用相对路径或别名路径引用文件
- 避免使用绝对路径

5.3 目录结构优化


- 随着项目规模增大,适时调整目录结构
- 保持目录层级合理,避免过深的嵌套

6 总结

Admin-Element 项目采用标准的 Vue + ElementUI 项目结构,通过清晰的目录组织和命名规范,提高了代码的可维护性和可扩展性。开发者应遵循目录结构规范,合理组织代码,确保项目的长期可维护性。

---

.Trae/Skills/Dev Docs Generate/SKILL (.trae/skills/dev-docs-generate/SKILL.md)

---
name: dev-docs-generate
description: 开发文档生成规范,快速生成开发文档,自动放到docs目录下,方便技术快速了解项目,能快速入手开发
---

CRMEB 项目文档写作规范

0. 自动调用场景

0.1 触发条件

- 目录浏览时:当浏览文档相关目录时自动调用
- 打开
dev-docs/ 目录时触发
- 打开
dev-docs/phpapi/ 目录时触发
- 打开
dev-docs/admin/ 目录时触发
- 打开
dev-docs/uniapp/ 目录时触发
- 打开
dev-docs/nuxt/ 目录时触发
- 文档创建时:当创建新的 Markdown 文档文件时自动调用
- 文档编辑时:当编辑现有文档文件时自动调用
- 关键词触发:当文档内容包含以下关键词时自动调用
-
文档说明指南手册规范
-
API接口部署开发需求

0.2 适用文件类型

- .md (Markdown 文件)
-
.txt (文本文件)
-
.doc/.docx (Word 文档)
-
.pdf (PDF 文档)

0.3 调用优先级

- 当多个技能同时触发时,文档规范技能优先级中等
- 仅在文档相关操作时被触发
- 不影响其他技能的正常使用

1. 文档类型

1.1 技术文档

- API 文档:接口设计、参数说明、返回格式
- 开发文档:架构设计、模块说明、开发流程
- 部署文档:环境要求、安装步骤、配置说明
- 接口文档:接口列表、请求参数、返回示例

1.2 业务文档

- 需求文档:功能描述、业务流程、数据结构
- 测试文档:测试用例、测试结果、缺陷报告
- 用户手册:功能介绍、操作指南、常见问题

2. 格式规范

2.1 文件名规范

- 使用小写下划线分隔
- 清晰描述文档内容
- 示例:
api接口文档.md部署指南.md

2.2 标题层级

- 使用 # 表示标题层级
- 一级标题:文档主题
- 二级标题:主要章节
- 三级标题:细分内容
- 最多使用四级标题

2.3 文本格式

- 正文使用宋体/无衬线字体,14px
- 代码块使用

包裹,指定语言
- 列表使用
-1. 表示
- 强调内容使用
加粗斜体

2.4 代码规范

- 代码块必须指定语言
- 缩进一致,格式清晰
- 关键代码添加注释
- 示例:

php
// 获取用户信息
public function getUserInfo($id) {
return $this->where('id', $id)->find();
}

2.5 文档存放目录

- 文档保存到 dev-docs 目录中
- 后端接口文档存放
dev-docs/phpapi 目录中
- 后端前端 ElementUI(Admin)文档存放
dev-docs/admin 目录中
- 移动端前端 UniApp(移动端)文档存放
dev-docs/uniapp 目录中
- PC 端 Nuxt(PC)文档存放
dev-docs/nuxt 目录中

3. 内容要求

3.1 结构清晰

- 引言:文档目的、适用范围
- 主体:详细内容,逻辑连贯
- 结论:总结、后续计划
- 附录:参考资料、术语表

3.2 语言要求

- 使用简洁、准确的语言
- 避免歧义,术语统一
- 中文文档使用规范汉字
- 英文文档语法正确

3.3 内容完整性

- 包含必要的背景信息
- 步骤清晰,可操作
- 提供示例和截图
- 注明版本和更新日期

3.4 可维护性

- 定期更新,保持时效性
- 使用版本控制管理文档
- 注明作者和联系方式
- 便于搜索和导航

4. 文档工具

4.1 编辑工具

- 推荐使用 Markdown 格式
- 支持工具:VS Code、Typora、语雀
- 图片存储:项目内部或图床

4.2 版本管理

- 与代码一同纳入 Git 管理
- 提交信息清晰,说明文档变更
- 定期备份,防止丢失

5. 审核与发布

5.1 审核流程

1. 编写完成后进行自我检查
2. 提交给相关人员审核
3. 根据反馈修改完善
4. 最终确认发布

5.2 发布规范

- 发布前检查格式和内容
- 明确文档版本号
- 通知相关人员文档更新
- 确保文档可访问

6. Markdown 文档模板

markdown

文档标题

1. 引言

1.1 文档目的


- 说明文档的编写目的

1.2 适用范围


- 说明文档的适用范围

1.3 术语定义


- 解释文档中使用的专业术语

2. 主体内容

2.1 功能描述


- 详细描述功能特性

2.2 实现方案


- 说明技术实现方案

2.3 代码示例

php
// 代码示例
function example() {
return true;
}
text

2.4 操作步骤

1. 第一步操作
2. 第二步操作
3. 第三步操作

3. 结论

3.1 总结


- 总结文档的主要内容

3.2 后续计划


- 说明后续的工作计划

4. 附录

4.1 参考资料


- 列出参考的文档和资源

4.2 联系方式


- 提供联系人信息

---

版本: 1.0
作者: 文档作者
更新日期: YYYY-MM-DD

7. Markdown 语法指南

7.1 标题

markdown

一级标题


二级标题


三级标题


#### 四级标题

7.2 列表

- 无序列表项 1
- 无序列表项 2
- 嵌套列表项

1. 有序列表项 1
2. 有序列表项 2

7.3 链接和图片

- 链接文本
-

7.4 代码块

javascript
// JavaScript 代码
console.log('Hello World');

7.5 表格

| 表头 1 | 表头 2 |
| ------ | ------ |
| 单元格 1 | 单元格 2 |
| 单元格 3 | 单元格 4 |

7.6 引用

这是一段引用文本

8. 注意事项

- 避免冗长,重点突出
- 保持格式统一
- 定期更新文档
- 确保内容准确无误
- 便于他人理解和使用
- 生成文档最后说明由AI生成

---

以上规范适用于 CRMEB 项目所有文档写作,确保文档质量和一致性。

---

.Trae/Skills/Git Commit/SKILL (.trae/skills/git-commit/SKILL.md)

---
name: Git提交规范
description: 规范git提交信息格式,确保不同目录下的文件提交时添加正确的前缀
---

Git提交规范

0. 自动触发说明

0.1 触发条件

#### 0.1.1 操作触发
- 文件浏览时: 当浏览以下目录时自动调用
- 打开
crmeb/ 目录时触发
- 打开
docker-compose/ 目录时触发
- 打开
dev-docs/ 目录时触发
- 打开
template/ 目录时触发
- 文件操作时: 当对以下目录的文件进行操作时自动调用
- 修改
crmeb/ 目录下文件时触发
- 修改
docker-compose/ 目录下文件时触发
- 修改
dev-docs/ 目录下文件时触发
- 修改
template/ 目录下文件时触发
- Git操作时: 当执行以下Git命令时自动调用
-
git add (添加文件到暂存区)
-
git commit (提交更改)
-
git push (推送更改)

#### 0.1.2 内容触发
- 关键词触发: 当文件内容包含以下关键词时自动调用
- Git关键词:
gitcommitpushpullbranch
- 提交关键词:
提交更新修复添加删除
- 目录关键词:
crmebdocker-composedocstemplate

#### 0.1.3 命令触发
- 终端命令触发: 当执行以下命令时自动调用
-
git (Git相关命令)
-
git commit (提交命令)
-
git add (添加命令)

0.2 适用场景

#### 0.2.1 核心场景
- 代码提交: 提交代码更改时
- 文件修改: 修改项目文件时
- 目录操作: 对项目目录进行操作时

#### 0.2.2 辅助场景
- 代码审查: 审查代码提交时
- 版本管理: 管理项目版本时
- 团队协作: 团队成员协作开发时

0.3 触发机制

#### 0.3.1 调用时机
- 实时触发: Git命令执行时立即触发
- 延迟触发: 文件操作后延迟1秒触发
- 批量触发: 批量文件操作时合并触发

#### 0.3.2 调用频率
- 文件浏览: 最多每10秒触发一次
- 文件操作: 最多每5秒触发一次
- Git命令: 最多每3秒触发一次

#### 0.3.3 调用优先级
- 优先级等级: 中等优先级 (3/5)
- 竞争处理: 当多个技能同时触发时
- 最高优先级: 系统核心技能
- 高优先级: 代码结构技能
- 中等优先级: Git提交技能、PHP后端技能、前端技能
- 低优先级: 辅助工具技能

0.4 触发后行为

#### 0.4.1 自动分析
- 目录分析: 分析当前操作的文件所在目录
- 提交信息分析: 分析提交信息格式是否符合规范
- 前缀检查: 检查提交信息是否包含正确的目录前缀

#### 0.4.2 自动展示
- 提交规范: 展示Git提交规范
- 目录前缀: 展示当前目录对应的提交前缀
- 示例格式: 展示正确的提交信息格式示例

#### 0.4.3 自动建议
- 前缀建议: 提供当前目录对应的提交前缀建议
- 格式建议: 提供提交信息格式建议
- 最佳实践: 提供Git提交最佳实践建议

1. 提交信息格式规范

1.1 基本格式


text
[目录前缀] 提交描述

详细说明(可选)

1.2 目录前缀规则

| 目录 | 前缀 | 示例 |
|------|------|------|
| crmeb/ | 【程序目录】 | 【程序目录】修复登录功能bug |
| docker-compose/ | 【DOCKER】 | 【DOCKER】更新Docker配置文件 |
| dev-docs/ | 【开发文档】 | 【开发文档】完善API接口文档 |
| template/ | 【前端文件】 | 【前端文件】优化前端界面样式 |

1.3 提交描述规范


- 长度限制: 不超过50个字符
- 内容要求: 简洁明了,说明本次提交的主要内容
- 动词使用: 使用现在时动词,如「添加」、「修复」、「更新」等
- 格式规范: 首字母大写,结尾不加标点符号

1.4 详细说明规范


- 长度限制: 不超过200个字符
- 内容要求: 详细说明本次提交的原因、解决的问题等
- 格式规范: 每行不超过72个字符,使用空行分隔不同段落

2. 提交信息示例

2.1 crmeb目录示例


text
【程序目录】添加用户注册功能

- 实现用户注册接口
- 添加注册参数验证
- 集成短信验证码功能

2.2 docker-compose目录示例


text
【DOCKER】优化Docker镜像构建

- 减少镜像体积
- 提高构建速度
- 修复容器启动问题

2.3 docs目录示例


text
【开发文档】更新API接口文档

- 补充新接口说明
- 修正参数描述错误
- 添加响应示例

2.4 template目录示例


text
【前端文件】优化登录页面样式

- 调整表单布局
- 美化按钮样式
- 优化响应式设计

3. 最佳实践

3.1 提交频率


- 合理拆分: 每个提交只包含一个功能或修复
- 及时提交: 完成一个功能或修复后及时提交
- 避免批量: 避免一次提交大量不相关的更改

3.2 提交信息质量


- 清晰明了: 提交信息应清晰说明本次更改的内容
- 准确描述: 提交信息应准确反映代码更改
- 格式规范: 严格遵循提交信息格式规范

3.3 分支管理


- 主分支: 保持主分支稳定,只用于发布
- 开发分支: 在开发分支上进行功能开发
- 特性分支: 为大型功能创建专门的特性分支
- 修复分支: 为紧急bug创建专门的修复分支

3.4 代码审查


- 自我审查: 提交前自我审查代码
- 团队审查: 重要更改应进行团队代码审查
- 审查标准: 审查代码质量、安全性、性能等

4. 常见问题

4.1 提交信息问题


- 缺少前缀: 忘记添加目录前缀
- 解决方法: 参考目录前缀规则,添加正确的前缀
- 描述过长: 提交描述超过50个字符
- 解决方法: 精简描述,突出重点
- 格式不规范: 提交信息格式不符合规范
- 解决方法: 参考提交信息格式规范,修正格式

4.2 分支管理问题


- 分支混乱: 分支过多或命名不规范
- 解决方法: 定期清理无用分支,使用规范的分支命名
- 合并冲突: 分支合并时产生冲突
- 解决方法: 及时同步主分支,减少冲突可能性

4.3 提交频率问题


- 提交过频: 过于频繁的提交
- 解决方法: 合理组织提交,避免琐碎提交
- 提交过少: 长时间不提交
- 解决方法: 及时提交更改,避免代码丢失

5. 常用Git命令

5.1 基本命令


- git status: 查看当前状态
- git add <file>: 添加文件到暂存区
- git commit -m "[前缀] 描述": 提交更改
- git push: 推送更改到远程仓库
- git pull: 从远程仓库拉取更改

5.2 分支命令


- git branch: 查看分支
- git checkout <branch>: 切换分支
- git checkout -b <branch>: 创建并切换分支
- git merge <branch>: 合并分支

5.3 历史命令


- git log: 查看提交历史
- git show <commit>: 查看提交详情
- git diff: 查看更改内容

6. 参考资源

6.1 官方文档


- Git官方文档
- GitHub Git教程

6.2 学习资源


- Pro Git
- Git分支管理策略
- 提交信息规范

6.3 工具推荐


- Git GUI: GitHub Desktop、SourceTree
- Git客户端: GitKraken、Tower
- 代码托管: GitHub、GitLab、Gitee

6.4 其他资源


- Git工作流最佳实践
- 团队Git使用规范
- 代码审查流程指南

---

.Trae/Skills/Php Api/References/Api Flow (.trae/skills/php-api/references/api_flow.md)

接口请求文档

1. 概述

本文档描述了 CRMEB 项目中 API 接口请求的流程、规范、参数设计和响应格式等,旨在统一 API 请求格式,提高 API 的一致性和可维护性。

2. 接口请求流程

2.1 基本流程

1. 客户端发起请求: 客户端通过 HTTP/HTTPS 协议向服务器发送请求
2. 请求到达服务器: 请求经过网络传输到达服务器
3. 请求解析: 服务器解析请求,包括请求方法、路径、参数等
4. 认证授权: 服务器对请求进行认证和授权
5. 业务处理: 服务器执行相应的业务逻辑
6. 生成响应: 服务器生成响应数据
7. 返回响应: 服务器将响应返回给客户端
8. 客户端处理响应: 客户端处理服务器返回的响应

2.2 详细流程

text
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│ 客户端 │ │ 中间件 │ │ 控制器 │
│ 1. 发起请求 │────▶│ 2. 认证授权 │────▶│ 3. 业务处理 │
└─────────────────┘ └─────────────────┘ └─────────────────┘


┌─────────────────┐
│ 服务层 │
│ 4. 执行逻辑 │
└─────────────────┘


┌─────────────────┐
│ 数据层 │
│ 5. 数据操作 │
└─────────────────┘


┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 客户端 │ │ 中间件 │ │ 控制器 │
│ 8. 处理响应 │◀────│ 7. 响应处理 │◀────│ 6. 生成响应 │
└─────────────────┘ └─────────────────┘ └─────────────────┘

3. 请求方法

3.1 HTTP 方法

| 方法 | 描述 | 幂等性 | 安全性 |
|------|------|--------|--------|
| GET | 获取资源 | 是 | 是 |
| POST | 创建资源 | 否 | 否 |
| PUT | 更新资源 | 是 | 否 |
| DELETE | 删除资源 | 是 | 否 |
| PATCH | 部分更新资源 | 否 | 否 |
| OPTIONS | 获取资源的可用操作 | 是 | 是 |
| HEAD | 获取资源的元数据 | 是 | 是 |

3.2 方法使用规范

- GET: 用于获取资源,不应修改资源状态
- POST: 用于创建新资源
- PUT: 用于更新整个资源,应包含资源的完整表示
- DELETE: 用于删除资源
- PATCH: 用于部分更新资源,只包含需要更新的字段
- OPTIONS: 用于获取资源支持的 HTTP 方法
- HEAD: 用于获取资源的元数据,如 Content-Length、Last-Modified 等

4. 请求头

4.1 通用请求头

| 请求头 | 描述 | 示例 |
|-------|------|------|
| Accept | 客户端可接受的响应内容类型 | application/json |
| Accept-Encoding | 客户端可接受的编码方式 | gzip, deflate |
| Content-Type | 请求体的内容类型 | application/json |
| Authorization | 认证信息 | Bearer {token} |
| User-Agent | 客户端标识 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 |
| X-Requested-With | 请求类型 | XMLHttpRequest |
| X-Token | 认证令牌(自定义) | your_token_here |

4.2 自定义请求头

自定义请求头应以 X- 为前缀,如 X-TokenX-Request-ID 等。

5. 请求参数

5.1 参数位置

| 位置 | 适用场景 | 示例 |
|------|----------|------|
| URL 路径 | 资源标识 | /api/v1/user/1 |
| 查询字符串 | 过滤、排序、分页 | /api/v1/user?page=1&limit=10&sort=create_time&order=desc |
| 请求体 | 复杂数据、创建/更新资源 | {"username": "test", "password": "123456"} |
| 请求头 | 认证信息、元数据 | Authorization: Bearer {token} |
| Cookie | 会话信息 | PHPSESSID=your_session_id |

5.2 参数命名规范

- 命名风格: 使用 camelCase 命名风格,如 userName
- 语义化: 参数名应具有明确的语义,如
pagelimitsort
- 简洁性: 参数名应简洁明了,避免过长
- 一致性: 相同类型的参数在不同接口中应保持一致

5.3 常用参数

| 参数名 | 类型 | 描述 | 示例 |
|-------|------|------|------|
| page | int | 页码,默认 1 | page=1 |
| limit | int | 每页数量,默认 10 | limit=20 |
| sort | string | 排序字段 | sort=create_time |
| order | string | 排序方式,asc 或 desc | order=desc |
| keyword | string | 搜索关键词 | keyword=test |
| status | int | 状态过滤 | status=1 |
| start_time | string | 开始时间 | start_time=2024-01-01 |
| end_time | string | 结束时间 | end_time=2024-01-31 |

6. 请求体

6.1 内容类型

| 内容类型 | 描述 | 示例 |
|---------|------|------|
| application/json | JSON 格式,最常用 | {"username": "test", "password": "123456"} |
| application/x-www-form-urlencoded | 表单格式 | username=test&password=123456 |
| multipart/form-data | 文件上传 | 包含文件和表单字段 |
| text/plain | 纯文本 | 简单的文本数据 |
| application/xml | XML 格式 | <user><username>test</username><password>123456</password></user> |

6.2 JSON 请求体规范

- 使用 camelCase 命名: 字段名使用 camelCase 命名风格
- 明确的数据类型: 使用适当的数据类型,如字符串、数字、布尔值、数组、对象
- 避免 null 值: 非必要字段不应包含 null 值
- 嵌套结构: 合理使用嵌套结构,避免过深的嵌套
- 数组格式: 数组元素类型应一致

示例:

json
{
"username": "test",
"password": "123456",
"nickname": "测试用户",
"age": 18,
"gender": 1,
"tags": ["tag1", "tag2"],
"address": {
"province": "北京",
"city": "北京",
"district": "朝阳区"
}
}

7. 响应格式

7.1 基本响应格式

所有 API 响应应使用统一的 JSON 格式,包含 statusmsg 和可选的 data 字段。系统实际调用方式为 app('json')->success()

#### 7.1.1 调用示例

php
// 基本成功响应
return app('json')->success('操作成功', ['id' => 1, 'username' => 'test']);

// 只返回数据,不指定消息
return app('json')->success(['id' => 1, 'username' => 'test']);

// 使用系统内置成功码
return app('json')->success(100000); // 100000 是 "保存成功" 对应的系统内置成功码

#### 7.1.2 响应格式

json
{
"status": 200,
"msg": "操作成功",
"data": {
"id": 1,
"username": "test",
"nickname": "测试用户"
}
}

7.2 分页响应格式

分页响应应包含 totalpagelimitlist 字段,系统实际调用方式为 app('json')->success()

#### 7.2.1 调用示例

php
// 分页数据响应
$pageData = [
'total' => 100,
'page' => 1,
'limit' => 10,
'list' => [
['id' => 1, 'username' => 'test1', 'nickname' => '测试用户1'],
['id' => 2, 'username' => 'test2', 'nickname' => '测试用户2']
]
];
return app('json')->success('获取列表成功', $pageData);

#### 7.2.2 响应格式

json
{
"status": 200,
"msg": "获取列表成功",
"data": {
"total": 100,
"page": 1,
"limit": 10,
"list": [
{
"id": 1,
"username": "test1",
"nickname": "测试用户1"
},
{
"id": 2,
"username": "test2",
"nickname": "测试用户2"
}
]
}
}

7.3 错误响应格式

系统使用统一的错误响应格式,所有错误响应通过 app('json')->fail() 方法返回。fail() 方法支持两种参数类型:

- 错误码(推荐):系统内置的数字错误码,如 410025
- 错误消息:直接的字符串错误信息

#### 7.3.1 统一响应格式

无论使用哪种参数类型,系统都会返回统一的 JSON 格式,包含 statusmsg 和可选的 data 字段。当使用错误码时,响应中还会包含 code 字段。

json
{
"status": 400,
"msg": "账号或密码错误",
"code": 410025,
"data": null
}

#### 7.3.2 调用示例

php
// 推荐:使用系统内置错误码
return app('json')->fail(410025);

// 不推荐:直接使用错误消息
return app('json')->fail('账号或密码错误');

// 使用错误码并传递额外数据
return app('json')->fail(410025, ['extra' => 'additional data']);

// 使用错误码并传递替换参数
return app('json')->fail(410025, [], ['field' => 'username']);

#### 7.3.3 最佳实践

- 优先使用错误码:系统内置错误码经过统一规划,便于维护和国际化
- 避免直接使用字符串:直接使用字符串错误信息不利于国际化和统一管理
- 传递必要的额外数据:对于复杂错误,可以在
data 字段中提供详细信息
- 使用替换参数:对于动态错误信息,使用替换参数提高灵活性

7.4 响应码规范

| 响应码范围 | 类型 | 描述 | 示例 |
|-----------|------|------|------|
| 200 | 成功 | 操作成功 | 200 |
| 1000-1999 | 系统级错误 | 系统核心错误 | 1001(参数错误) |
| 4000-4999 | 业务级错误 | 具体业务逻辑错误 | 410025(账号或密码错误) |
| 400 | 客户端错误 | 请求参数错误 | 400 |
| 401 | 认证错误 | 未认证或认证过期 | 401 |
| 403 | 权限错误 | 无权限访问 | 403 |
| 404 | 资源错误 | 资源不存在 | 404 |
| 500 | 服务器错误 | 服务器内部错误 | 500 |

8. 错误处理

8.1 错误响应设计

错误响应应遵循以下设计原则:

1. 统一格式: 所有错误响应使用相同的 JSON 格式
2. 明确的错误码: 使用唯一的错误码标识不同的错误类型
3. 清晰的错误信息: 错误信息应简洁明了,便于理解
4. 可选的详细信息: 对于复杂错误,可以在
data 字段中提供详细信息
5. HTTP 状态码匹配: 错误码应与 HTTP 状态码匹配

8.2 AI 自动提示系统内置错误码

CRMEB 系统集成了 AI 自动提示功能,当开发者在编写代码时使用 fail() 方法返回错误信息时,AI 会自动:

1. 识别错误信息: 自动识别开发者输入的错误信息字符串
2. 匹配内置错误码: 在系统内置错误码库中查找匹配的错误码
3. 自动转换: 在运行时将错误信息自动转换为对应的系统内置错误码
4. 提供建议: 对于未匹配到的错误信息,提供相似的错误码建议
5. 实时提示: 在 IDE 中实时显示错误码建议
6. 错误码文档: 在错误码文档 error_code.md,找到对应的错误码说明

#### 8.2.1 功能示例

php
// 开发者输入
return $this->fail('登录失败');

// AI 自动提示并替换为
return $this->fail(410019); // 410019 是 "登录失败" 对应的系统内置错误码

#### 8.2.2 工作原理

1. 语言文件解析: 系统在运行时解析语言文件,构建错误码到错误信息的映射表
2. 自动匹配: 当调用
fail() 方法传入字符串错误信息时,系统自动在映射表中查找匹配的错误码
3. 运行时转换: 如果找到匹配的错误码,系统会将错误信息替换为错误码,并在响应中包含
code 字段
4. 智能提示: 在 IDE 中,AI 会实时提示开发者使用正确的系统内置错误码

#### 8.2.3 实际响应格式

当使用字符串错误信息时,系统会自动匹配并转换为错误码,最终响应格式为:

json
{
"status": 400,
"msg": "登录失败",
"code": 410019
}

当直接使用错误码时,响应格式为:

json
{
"status": 400,
"msg": "登录失败",
"code": 410019
}

8.3 错误处理最佳实践

1. 使用系统内置错误码: 优先使用系统内置错误码,避免自定义错误信息
2. 错误信息本地化: 使用
getLang() 函数获取本地化的错误信息
3. 详细的错误日志: 记录详细的错误日志,包括错误码、错误信息、请求参数等
4. 友好的错误提示: 对客户端返回友好的错误信息,避免暴露系统内部细节
5. 统一的错误处理: 使用统一的错误处理中间件处理所有错误
6. 错误码文档化: 定期更新错误码文档,确保与实际代码一致

8.4 自定义错误码

对于系统内置错误码无法覆盖的业务场景,可以自定义错误码,但应遵循以下规范:

1. 错误码范围: 使用系统未占用的错误码范围
2. 命名规范: 错误码应具有明确的语义
3. 文档化: 自定义错误码应在文档中明确说明
4. 本地化: 自定义错误码应在语言文件中定义对应的错误信息

9. 接口开发流程

9.1 需求分析与设计

1. 需求理解: 明确接口的业务需求和功能要求
2. 资源设计: 确定接口涉及的资源和数据模型
3. 接口设计: 设计接口的 URL、请求方法、参数和响应格式
4. 权限设计: 确定接口的访问权限和认证方式
5. 错误设计: 定义接口可能出现的错误情况和错误码

9.2 开发实现

1. 创建路由: 在路由文件中定义接口路由
2. 实现控制器: 创建控制器并实现接口逻辑
3. 参数验证: 使用验证器对请求参数进行验证
4. 业务逻辑: 实现接口的业务逻辑
5. 错误处理: 使用
app('json')->fail() 统一处理错误
6. 响应返回: 使用
app('json')->success() 统一返回响应

9.3 测试验证

1. 单元测试: 编写单元测试验证接口功能
2. 集成测试: 测试接口与其他模块的集成
3. 接口测试: 使用 Postman 或其他工具测试接口
4. 性能测试: 测试接口的性能和响应时间
5. 安全测试: 测试接口的安全性

9.4 文档编写

1. 接口文档: 编写接口的详细文档
2. 错误码文档: 在
error_code.md 中记录接口使用的错误码
3. 变更记录: 记录接口的变更历史

9.5 上线发布

1. 代码审查: 进行代码审查,确保代码质量
2. 测试环境验证: 在测试环境验证接口功能
3. 灰度发布: 灰度发布接口,观察运行情况
4. 正式上线: 正式上线接口

9.6 监控维护

1. 监控: 监控接口的运行状态和性能
2. 日志: 记录接口的访问日志和错误日志
3. 优化: 根据监控数据优化接口性能
4. 维护: 定期维护和更新接口

10. 最佳实践

10.1 请求设计

- 使用 RESTful 风格: 遵循 RESTful API 设计规范
- 明确的资源命名: 使用明确的资源名称,如
/api/v1/user 而不是 /api/v1/getUser
- 合理的 URL 层级: URL 层级不应过深,一般不超过 3 层
- 使用复数形式: 资源名称使用复数形式,如
/api/v1/users 而不是 /api/v1/user

10.2 参数设计

- 必填参数: 明确标识必填参数
- 默认值: 为可选参数提供合理的默认值
- 参数验证: 对所有参数进行验证
- 参数类型: 明确参数类型和格式

10.3 响应设计

- 统一格式: 使用统一的响应格式
- 明确的数据类型: 响应数据类型应明确
- 避免冗余数据: 只返回必要的数据
- 分页响应: 列表接口应支持分页
- 错误信息: 错误信息应清晰、准确

10.4 安全设计

- 认证授权: 使用 JWT 或 OAuth2 进行认证授权
- HTTPS: 使用 HTTPS 加密传输
- 参数验证: 严格验证所有输入参数
- 输出编码: 对输出数据进行编码,防止 XSS 攻击
- SQL 注入防护: 使用参数绑定,避免直接拼接 SQL
- CSRF 防护: 实现 CSRF Token 验证

11. 常见问题

11.1 跨域问题

- 问题: 浏览器同源策略导致跨域请求失败
- 解决方案: 实现 CORS(跨域资源共享),设置适当的响应头

10.2 认证失败

- 问题: 请求未携带认证信息或认证信息无效
- 解决方案: 检查请求头中的认证信息,确保令牌有效

10.3 参数错误

- 问题: 请求参数格式错误或缺少必填参数
- 解决方案: 检查请求参数,确保格式正确且包含所有必填参数

10.4 响应数据不符合预期

- 问题: 响应数据格式或内容不符合预期
- 解决方案: 检查 API 文档,确保请求格式正确,或联系 API 提供者

10.5 性能问题

- 问题: API 请求响应时间过长
- 解决方案: 优化 API 实现,使用缓存,减少数据库查询次数

12. 参考资源

- RESTful API 设计指南
- HTTP 状态码
- API 设计最佳实践
- JSON API 规范
- OpenAPI 规范
- API 安全性最佳实践

---

.Trae/Skills/Php Api/References/Db Design (.trae/skills/php-api/references/db_design.md)

数据库设计文档

1. 概述

本文档描述了 CRMEB 项目的数据库设计,包括数据库架构、表结构、索引设计、关系设计等,旨在规范数据库设计,提高数据库性能和可维护性。

2. 数据库架构

2.1 整体架构

- 数据库系统: MySQL 5.7~8.0
- 存储引擎: InnoDB (默认)
- 字符集: utf8mb4
- 排序规则: utf8mb4_general_ci
- 连接池: 建议使用
- SQL文件位置:
public/install/crmeb.sql

2.2 技术栈

- MySQL: 5.7+
- Redis: 用于缓存
- ThinkPHP ORM: 用于模型操作
- 数据库迁移: 用于版本控制
- 数据库备份: 用于数据安全

2.3 配置说明

#### 2.3.1 数据库配置

php
// config/database.php
return [
'default' => env('database.driver', 'mysql'),
'connections' => [
'mysql' => [
'type' => 'mysql',
'hostname' => env('database.hostname', '127.0.0.1'),
'database' => env('database.database', ''),
'username' => env('database.username', ''),
'password' => env('database.password', ''),
'hostport' => env('database.hostport', '3306'),
'charset' => 'utf8mb4',
'prefix' => env('database.prefix', ''),
'debug' => env('app_debug', true),
],
],
];

3. 数据库设计规范

3.1 命名规范

- 数据库名: 小写字母,下划线分隔
- 表名: 小写字母,下划线分隔,前缀统一
- 字段名: 小写字母,下划线分隔
- 索引名: 小写字母,下划线分隔,类型前缀
- 主键:
PRIMARY
- 唯一索引:
uk_字段名
- 普通索引:
idx_字段名

3.2 表结构规范

- 主键: 统一命名为 id,自增整数
- 外键: 格式
表名_id,如 user_id
- 时间字段:
create_time/update_time
- 状态字段:
status,默认值 0
- 软删除字段:
delete_time,默认值 NULL

3.3 字段类型规范

- 整数类型: 根据实际范围选择
-
TINYINT: 1字节,范围 -128~127
-
SMALLINT: 2字节,范围 -32768~32767
-
INT: 4字节,范围 -2147483648~2147483647
-
BIGINT: 8字节,范围更大

- 字符串类型:
- 固定长度:
CHAR
- 可变长度:
VARCHAR
- 长文本:
TEXT
- 大文本:
LONGTEXT

- 日期时间类型:
- 日期:
DATE
- 时间:
TIME
- 日期时间:
DATETIME
- 时间戳:
TIMESTAMP

- 数值类型:
- 小数:
DECIMAL
- 浮点数:
FLOAT, DOUBLE

- 布尔类型: 使用 TINYINT(1),0 表示 false,1 表示 true

3.4 索引规范

- 主键索引: 每个表必须有主键
- 唯一索引: 用于唯一标识的字段
- 普通索引: 用于经常查询的字段
- 复合索引: 用于多字段查询
- 外键索引: 用于关联查询
- 索引数量: 每个表索引数量不宜过多,一般不超过 5 个

4. 核心表结构

4.1 用户表 (user)

| 字段名 | 数据类型 | 长度 | 约束 | 描述 |
|-------|---------|------|------|------|
|
id | INT | 11 | PRIMARY KEY AUTO_INCREMENT | 用户ID |
|
username | VARCHAR | 50 | NOT NULL | 用户名 |
|
password | VARCHAR | 255 | NOT NULL | 密码 |
|
nickname | VARCHAR | 50 | NOT NULL | 昵称 |
|
avatar | VARCHAR | 255 | | 头像 |
|
mobile | VARCHAR | 20 | | 手机号 |
|
email | VARCHAR | 100 | | 邮箱 |
|
status | TINYINT | 1 | DEFAULT 1 | 状态 |
|
create_time | DATETIME | | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
update_time | DATETIME | | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
|
delete_time | DATETIME | | | 删除时间 |

4.2 商品表 (product)

| 字段名 | 数据类型 | 长度 | 约束 | 描述 |
|-------|---------|------|------|------|
|
id | INT | 11 | PRIMARY KEY AUTO_INCREMENT | 商品ID |
|
name | VARCHAR | 255 | NOT NULL | 商品名称 |
|
category_id | INT | 11 | NOT NULL | 分类ID |
|
price | DECIMAL | 10,2 | NOT NULL | 价格 |
|
stock | INT | 11 | NOT NULL | 库存 |
|
status | TINYINT | 1 | DEFAULT 1 | 状态 |
|
create_time | DATETIME | | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
update_time | DATETIME | | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
|
delete_time | DATETIME | | | 删除时间 |

4.3 订单表 (order)

| 字段名 | 数据类型 | 长度 | 约束 | 描述 |
|-------|---------|------|------|------|
|
id | INT | 11 | PRIMARY KEY AUTO_INCREMENT | 订单ID |
|
order_sn | VARCHAR | 32 | NOT NULL UNIQUE | 订单号 |
|
user_id | INT | 11 | NOT NULL | 用户ID |
|
total_price | DECIMAL | 10,2 | NOT NULL | 总价 |
|
status | TINYINT | 1 | DEFAULT 0 | 状态 |
|
create_time | DATETIME | | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
update_time | DATETIME | | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
|
delete_time | DATETIME | | | 删除时间 |

4.4 分类表 (category)

| 字段名 | 数据类型 | 长度 | 约束 | 描述 |
|-------|---------|------|------|------|
|
id | INT | 11 | PRIMARY KEY AUTO_INCREMENT | 分类ID |
|
name | VARCHAR | 50 | NOT NULL | 分类名称 |
|
parent_id | INT | 11 | DEFAULT 0 | 父分类ID |
|
sort | INT | 11 | DEFAULT 0 | 排序 |
|
status | TINYINT | 1 | DEFAULT 1 | 状态 |
|
create_time | DATETIME | | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
update_time | DATETIME | | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
|
delete_time | DATETIME | | | 删除时间 |

4.5 地址表 (address)

| 字段名 | 数据类型 | 长度 | 约束 | 描述 |
|-------|---------|------|------|------|
|
id | INT | 11 | PRIMARY KEY AUTO_INCREMENT | 地址ID |
|
user_id | INT | 11 | NOT NULL | 用户ID |
|
name | VARCHAR | 50 | NOT NULL | 收货人姓名 |
|
mobile | VARCHAR | 20 | NOT NULL | 手机号 |
|
province | VARCHAR | 50 | NOT NULL | 省份 |
|
city | VARCHAR | 50 | NOT NULL | 城市 |
|
district | VARCHAR | 50 | NOT NULL | 区县 |
|
detail | VARCHAR | 255 | NOT NULL | 详细地址 |
|
is_default | TINYINT | 1 | DEFAULT 0 | 是否默认 |
|
create_time | DATETIME | | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
update_time | DATETIME | | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
|
delete_time | DATETIME | | | 删除时间 |

5. 索引设计

5.1 用户表索引

| 索引名 | 类型 | 字段 | 描述 |
|-------|------|------|------|
|
PRIMARY | 主键 | id | 主键索引 |
|
uk_username | 唯一 | username | 用户名唯一索引 |
|
idx_mobile | 普通 | mobile | 手机号索引 |
|
idx_email | 普通 | email | 邮箱索引 |
|
idx_status | 普通 | status | 状态索引 |

5.2 商品表索引

| 索引名 | 类型 | 字段 | 描述 |
|-------|------|------|------|
|
PRIMARY | 主键 | id | 主键索引 |
|
idx_category_id | 普通 | category_id | 分类ID索引 |
|
idx_price | 普通 | price | 价格索引 |
|
idx_status | 普通 | status | 状态索引 |

5.3 订单表索引

| 索引名 | 类型 | 字段 | 描述 |
|-------|------|------|------|
|
PRIMARY | 主键 | id | 主键索引 |
|
uk_order_sn | 唯一 | order_sn | 订单号唯一索引 |
|
idx_user_id | 普通 | user_id | 用户ID索引 |
|
idx_status | 普通 | status | 状态索引 |
|
idx_create_time | 普通 | create_time | 创建时间索引 |

5.4 分类表索引

| 索引名 | 类型 | 字段 | 描述 |
|-------|------|------|------|
|
PRIMARY | 主键 | id | 主键索引 |
|
idx_parent_id | 普通 | parent_id | 父分类ID索引 |
|
idx_sort | 普通 | sort | 排序索引 |
|
idx_status | 普通 | status | 状态索引 |

5.5 地址表索引

| 索引名 | 类型 | 字段 | 描述 |
|-------|------|------|------|
|
PRIMARY | 主键 | id | 主键索引 |
|
idx_user_id | 普通 | user_id | 用户ID索引 |
|
idx_is_default | 普通 | is_default | 是否默认索引 |

6. 关系设计

6.1 表关系图

text
user ----------------- order
| |
| |
| |
address product
|
|
|
category

6.2 关系说明

- 用户与订单: 一对多关系,一个用户可以有多个订单
- 用户与地址: 一对多关系,一个用户可以有多个地址
- 商品与分类: 多对一关系,多个商品属于一个分类
- 订单与商品: 多对多关系,一个订单可以包含多个商品,一个商品可以出现在多个订单中

6.3 外键关系

| 主表 | 主键 | 从表 | 外键 | 描述 |
|------|------|------|------|------|
|
user | id | order | user_id | 订单所属用户 |
|
user | id | address | user_id | 地址所属用户 |
|
category | id | product | category_id | 商品所属分类 |

7. 性能优化

7.1 索引优化

- 选择合适的索引类型: 根据查询场景选择合适的索引类型
- 避免过度索引: 只在需要的字段上创建索引
- 使用复合索引: 对于多字段查询,使用复合索引
- 定期维护索引: 定期重建碎片化的索引

7.2 查询优化

- 避免全表扫描: 使用索引覆盖查询
- 减少查询字段: 只查询需要的字段
- 使用连接查询: 合理使用连接查询,避免子查询
- 限制查询结果: 使用 LIMIT 限制查询结果数量

7.3 存储优化

- 选择合适的字段类型: 根据实际需求选择合适的字段类型
- 使用分区表: 对于大表,使用分区表提高查询性能
- 定期清理数据: 定期清理无用数据,减少表大小
- 使用缓存: 对于频繁查询的数据,使用 Redis 缓存

7.4 配置优化

- 调整 innodb_buffer_pool_size: 根据服务器内存大小调整
- 调整 max_connections: 根据并发量调整
- 启用查询缓存: 对于读多写少的场景
- 优化日志配置: 合理配置二进制日志和慢查询日志

8. 安全设计

8.1 数据安全

- 加密存储: 敏感数据(如密码)加密存储
- 数据备份: 定期备份数据库
- 数据恢复: 建立数据恢复机制
- 访问控制: 严格控制数据库访问权限

8.2 SQL 注入防护

- 使用参数化查询: 避免直接拼接 SQL
- 使用 ORM: 使用 ThinkPHP ORM 框架
- 输入验证: 对用户输入进行验证
- 转义特殊字符: 对特殊字符进行转义

8.3 权限管理

- 最小权限原则: 只授予必要的权限
- 角色分离: 不同角色拥有不同权限
- 定期审计: 定期审计数据库访问日志

9. 备份与恢复

9.1 备份策略

- 全量备份: 定期进行全量备份
- 增量备份: 每天进行增量备份
- 日志备份: 备份二进制日志

9.2 恢复策略

- 全量恢复: 使用全量备份恢复
- 增量恢复: 使用增量备份恢复
- 点恢复: 使用二进制日志进行点恢复

9.3 备份工具

- mysqldump: MySQL 自带备份工具
- xtrabackup: Percona 提供的备份工具
- 第三方工具: 如 Navicat 等

10. 版本控制

10.1 数据库迁移

- 使用迁移工具: 使用 ThinkPHP 数据库迁移工具
- 版本管理: 对数据库结构变更进行版本管理
- 回滚机制: 支持数据库结构回滚

10.2 迁移文件命名规范

- 格式: YYYYMMDDHHMMSS_描述.php
- 示例:
20230101000000_create_user_table.php

10.3 迁移文件结构

php
<?php
use think\migration\Migrator;
use think\migration\db\Column;

class CreateUserTable extends Migrator
{
public function change()
{
$table = $this->table('user');
$table->addColumn('username', 'string', ['limit' => 50, 'comment' => '用户名'])
->addColumn('password', 'string', ['limit' => 255, 'comment' => '密码'])
->addColumn('nickname', 'string', ['limit' => 50, 'comment' => '昵称'])
->addColumn('avatar', 'string', ['limit' => 255, 'comment' => '头像'])
->addColumn('mobile', 'string', ['limit' => 20, 'comment' => '手机号'])
->addColumn('email', 'string', ['limit' => 100, 'comment' => '邮箱'])
->addColumn('status', 'tinyint', ['default' => 1, 'comment' => '状态'])
->addColumn('create_time', 'datetime', ['default' => 'CURRENT_TIMESTAMP', 'comment' => '创建时间'])
->addColumn('update_time', 'datetime', ['default' => 'CURRENT_TIMESTAMP', 'update' => 'CURRENT_TIMESTAMP', 'comment' => '更新时间'])
->addColumn('delete_time', 'datetime', ['comment' => '删除时间'])
->addIndex('username', ['unique' => true])
->addIndex('mobile')
->addIndex('email')
->addIndex('status')
->create();
}
}

11. 维护与监控

11.1 日常维护

- 定期优化表: 定期执行 OPTIMIZE TABLE 命令
- 监控表大小: 监控表大小变化
- 检查慢查询: 定期分析慢查询日志
- 更新统计信息: 定期更新表统计信息

11.2 监控指标

- 查询性能: 监控查询响应时间
- 连接数: 监控数据库连接数
- 缓存命中率: 监控缓存命中率
- 磁盘使用率: 监控磁盘空间使用情况
- CPU 使用率: 监控数据库服务器 CPU 使用率

11.3 监控工具

- MySQL Enterprise Monitor: MySQL 企业版监控工具
- Percona Monitoring and Management: 开源监控工具
- Zabbix: 通用监控工具
- Prometheus + Grafana: 现代化监控方案

12. 总结

本文档描述了 CRMEB 项目的数据库设计规范和最佳实践,包括数据库架构、表结构、索引设计、关系设计、性能优化、安全设计、备份与恢复、版本控制、维护与监控等方面。

遵循本文档的设计规范,可以提高数据库性能和可维护性,确保系统的稳定运行。同时,定期对数据库进行维护和监控,可以及时发现和解决潜在问题,保障系统的安全性和可靠性。

随着业务的发展和系统的演进,数据库设计也需要不断优化和调整,以适应新的业务需求和技术挑战。

---

.Trae/Skills/Php Api/References/Directory Structure (.trae/skills/php-api/references/directory_structure.md)

目录结构文档

1. 概述

本文档描述了 CRMEB 项目的目录结构,包括各目录的功能、文件组织方式等,旨在帮助开发者理解项目结构,提高开发效率。

2. 项目根目录结构

text
CRMEB/
├── app/ # 应用目录
├── config/ # 配置目录
├── crmeb/ # 核心库目录
├── database/ # 数据库目录
├── extend/ # 扩展目录
├── public/ # 公共资源目录
├── runtime/ # 运行时目录
├── thinkphp/ # ThinkPHP 核心目录
├── vendor/ # 第三方依赖目录
├── .env # 环境变量文件
├── .env.example # 环境变量示例文件
├── composer.json # Composer 配置文件
├── composer.lock # Composer 锁定文件
├── LICENSE # 许可证文件
├── README.md # 项目说明文档
├── think # ThinkPHP 命令行工具

3. 应用目录结构 (app/)

text
app/
├── api/ # API 接口层
│ ├── v1/ # API 版本 1
│ ├── v2/ # API 版本 2
│ └── BaseApi.php # API 基类
├── controller/ # 控制器层
│ ├── admin/ # 管理端控制器
│ ├── api/ # API 控制器
│ └── BaseController.php # 控制器基类
├── dao/ # 数据访问层
│ └── BaseDao.php # DAO 基类
├── event/ # 事件层
├── exception/ # 异常处理层
├── middleware/ # 中间件层
├── model/ # 模型层
│ └── BaseModel.php # 模型基类
├── services/ # 业务逻辑层
│ └── BaseServices.php # 服务基类
├── subscribe/ # 事件订阅层
├── validate/ # 验证层
│ └── BaseValidate.php # 验证器基类
└── common.php # 公共函数文件

3.1 API 目录 (app/api/)

- 功能: 处理 API 接口请求
- 结构: 按 API 版本划分目录
- 基类:
BaseApi.php,提供 API 基础功能
- 版本控制: 通过目录结构实现 API 版本管理

3.2 控制器目录 (app/controller/)

- 功能: 处理 HTTP 请求,路由分发
- 结构: 按模块划分控制器
- 基类:
BaseController.php,提供控制器基础功能
- 类型: 管理端控制器、API 控制器

3.3 DAO 目录 (app/dao/)

- 功能: 数据访问对象,封装数据库操作
- 结构: 按业务模块划分 DAO 类
- 基类:
BaseDao.php,提供 DAO 基础功能
- 职责: 处理数据库查询、插入、更新、删除等操作

3.4 模型目录 (app/model/)

- 功能: 数据模型,定义数据结构和关系
- 结构: 按业务模块划分模型类
- 基类:
BaseModel.php,提供模型基础功能
- 特性: 支持 ORM、关联查询、软删除等

3.5 服务目录 (app/services/)

- 功能: 业务逻辑层,封装核心业务逻辑
- 结构: 按业务模块划分服务类
- 基类:
BaseServices.php,提供服务基础功能
- 职责: 实现业务规则,协调多个 DAO 和模型

3.6 验证目录 (app/validate/)

- 功能: 数据验证,验证请求参数
- 结构: 按业务模块划分验证器类
- 基类:
BaseValidate.php,提供验证器基础功能
- 特性: 支持规则验证、场景验证等

4. 配置目录结构 (config/)

text
config/
├── app.php # 应用配置
├── cache.php # 缓存配置
├── captcha.php # 验证码配置
├── console.php # 控制台配置
├── cookie.php # Cookie 配置
├── database.php # 数据库配置
├── filesystem.php # 文件系统配置
├── lang.php # 语言配置
├── log.php # 日志配置
├── queue.php # 队列配置
├── route.php # 路由配置
├── session.php # Session 配置
├── template.php # 模板配置
└── trace.php # 调试配置

- 功能: 存储项目的所有配置文件
- 结构: 按功能模块划分配置文件
- 特性: 支持环境变量配置、配置缓存等
- 加载顺序: 框架配置 → 应用配置 → 环境配置

5. 核心库目录结构 (crmeb/)

text
crmeb/
├── basic/ # 基础类库
├── exception/ # 核心异常类
├── services/ # 核心服务类
├── utils/ # 工具类
└── version.php # 版本信息

- 功能: 存储 CRMEB 核心库代码
- 结构: 按功能模块划分目录
- 特性: 独立于应用代码,便于维护和升级
- 作用: 提供核心功能和基础服务

6. 数据库目录结构 (database/)

text
database/
├── migrations/ # 数据库迁移文件
└── seeders/ # 数据库种子文件

- 功能: 存储数据库相关文件
- 迁移文件: 用于版本控制数据库结构
- 种子文件: 用于初始化数据库数据
- 工具: 使用 ThinkPHP 迁移工具管理

7. 公共资源目录结构 (public/)

text
public/
├── admin/ # 管理端资源
├── api/ # API 资源
├── assets/ # 静态资源
│ ├── css/ # CSS 文件
│ ├── images/ # 图片文件
│ └── js/ # JavaScript 文件
├── index.php # 应用入口文件
├── robots.txt # 机器人协议文件
└── router.php # URL 重写文件

- 功能: 存储可直接访问的公共资源
- 结构: 按功能模块划分目录
- 特性: 可通过 URL 直接访问
- 安全: 敏感文件不应放在此目录

8. 运行时目录结构 (runtime/)

text
runtime/
├── cache/ # 缓存目录
├── log/ # 日志目录
│ └── app/ # 应用日志
├── session/ # Session 目录
├── temp/ # 临时文件目录
└── think/ # ThinkPHP 运行时目录

- 功能: 存储运行时生成的文件
- 结构: 按功能模块划分目录
- 特性: 自动生成,无需手动维护
- 权限: 需要可写权限

9. 核心目录结构 (thinkphp/)

text
thinkphp/
├── lang/ # 语言包目录
├── library/ # 核心类库目录
├── tpl/ # 模板目录
├── base.php # 基础定义文件
├── composer.json # Composer 配置文件
└── helper.php # 助手函数文件

- 功能: 存储 ThinkPHP 框架核心代码
- 结构: 框架默认结构
- 特性: 独立于应用代码
- 升级: 通过 Composer 升级

10. 第三方依赖目录结构 (vendor/)

text
vendor/
├── autoload.php # 自动加载文件
├── composer/ # Composer 核心目录
├── symfony/ # Symfony 组件
├── topthink/ # ThinkPHP 组件
└── ... # 其他第三方依赖

- 功能: 存储第三方依赖库
- 管理: 通过 Composer 管理
- 结构: 按依赖包名称划分目录
- 自动加载: 通过
autoload.php 自动加载

11. 目录结构最佳实践

11.1 命名规范

- 目录名: 小写字母,单词之间用下划线分隔
- 文件名: 与类名一致,使用 PascalCase 命名风格
- 类名: 使用 PascalCase 命名风格
- 方法名: 使用 camelCase 命名风格
- 变量名: 使用 camelCase 命名风格

11.2 组织原则

- 模块化: 按功能模块组织目录结构
- 分层架构: 遵循 MVC + Service + DAO 分层架构
- 单一职责: 每个目录和文件只负责一个功能
- 可扩展性: 便于添加新功能和模块
- 易维护性: 便于理解和维护

11.3 开发建议

- 遵循框架规范: 遵循 ThinkPHP 框架目录结构规范
- 合理划分模块: 根据业务功能合理划分模块
- 避免目录过深: 目录层级不宜过深,一般不超过 4 层
- 保持目录整洁: 及时清理无用文件和目录
- 文档化: 为重要目录添加说明文档

12. 常见问题

12.1 目录权限问题

- 问题: 运行时目录没有写权限
- 解决方案: 执行
chmod -R 777 runtime/ 赋予写权限

12.2 自动加载问题

- 问题: 新增类无法自动加载
- 解决方案: 执行
composer dump-autoload 更新自动加载

12.3 配置文件不生效

- 问题: 修改配置文件后不生效
- 解决方案: 清除配置缓存,执行
php think clear

12.4 目录结构混乱

- 问题: 目录结构不清晰,难以维护
- 解决方案: 重新组织目录结构,遵循模块化原则

13. 参考资源

- ThinkPHP 6 目录结构
- MVC 架构设计
- 分层架构设计
- 模块化设计

---

.Trae/Skills/Php Api/References/Error Code (.trae/skills/php-api/references/error_code.md)

错误码文档

1. 概述

本文档描述了 CRMEB 项目的错误码规范,包括错误码的分类、定义、使用方法等,旨在统一错误码格式,提高错误处理的一致性和可维护性。

2. 错误码分类

2.1 HTTP 状态码

- 1xx: 信息性状态码,表示请求已接收,继续处理
- 2xx: 成功状态码,表示请求已成功处理
- 3xx: 重定向状态码,表示需要进一步操作以完成请求
- 4xx: 客户端错误状态码,表示请求包含语法错误或无法完成请求
- 5xx: 服务器错误状态码,表示服务器在处理请求时发生错误

2.2 业务错误码

业务错误码由 5 位数字组成,格式为 XXXXX,其中:

- 第一位: 错误类型标识
-
1: 系统错误
-
2: 业务错误
-
3: 参数错误
-
4: 权限错误
-
5: 资源错误
-
6: 数据库错误
-
7: 第三方服务错误
-
8: 其他错误

- 后四位: 具体错误编码,从 0000 开始递增

3. 系统错误码

3.1 系统错误 (1xxxxx)

| 错误码 | 描述 | HTTP 状态码 |
|-------|------|-------------|
| 10001 | 系统内部错误 | 500 |
| 10002 | 系统维护中 | 503 |
| 10003 | 系统繁忙 | 503 |
| 10004 | 服务不可用 | 503 |
| 10005 | 网关错误 | 502 |

3.2 业务错误 (2xxxxx)

| 错误码 | 描述 | HTTP 状态码 |
|-------|------|-------------|
| 20001 | 操作失败 | 400 |
| 20002 | 业务逻辑错误 | 400 |
| 20003 | 数据已存在 | 400 |
| 20004 | 数据不存在 | 404 |
| 20005 | 操作不允许 | 403 |

3.3 参数错误 (3xxxxx)

| 错误码 | 描述 | HTTP 状态码 |
|-------|------|-------------|
| 30001 | 参数不能为空 | 400 |
| 30002 | 参数格式错误 | 400 |
| 30003 | 参数类型错误 | 400 |
| 30004 | 参数超出范围 | 400 |
| 30005 | 参数验证失败 | 422 |

3.4 权限错误 (4xxxxx)

| 错误码 | 描述 | HTTP 状态码 |
|-------|------|-------------|
| 40001 | 未登录 | 401 |
| 40002 | 登录已过期 | 401 |
| 40003 | 无权限访问 | 403 |
| 40004 | 权限不足 | 403 |
| 40005 | 令牌无效 | 401 |

3.5 资源错误 (5xxxxx)

| 错误码 | 描述 | HTTP 状态码 |
|-------|------|-------------|
| 50001 | 资源不存在 | 404 |
| 50002 | 资源已删除 | 404 |
| 50003 | 资源已锁定 | 400 |
| 50004 | 资源不足 | 400 |
| 50005 | 资源已过期 | 400 |

3.6 数据库错误 (6xxxxx)

| 错误码 | 描述 | HTTP 状态码 |
|-------|------|-------------|
| 60001 | 数据库连接失败 | 500 |
| 60002 | 数据库查询失败 | 500 |
| 60003 | 数据库更新失败 | 500 |
| 60004 | 数据库插入失败 | 500 |
| 60005 | 数据库删除失败 | 500 |
| 60006 | 数据库事务失败 | 500 |

3.7 第三方服务错误 (7xxxxx)

| 错误码 | 描述 | HTTP 状态码 |
|-------|------|-------------|
| 70001 | 第三方服务连接失败 | 500 |
| 70002 | 第三方服务超时 | 504 |
| 70003 | 第三方服务返回错误 | 500 |
| 70004 | 第三方服务认证失败 | 401 |
| 70005 | 第三方服务限流 | 429 |

4. 模块错误码

4.1 用户模块 (801xx)

| 错误码 | 描述 | HTTP 状态码 |
|-------|------|-------------|
| 80101 | 用户名或密码错误 | 401 |
| 80102 | 用户不存在 | 404 |
| 80103 | 用户已存在 | 400 |
| 80104 | 用户状态异常 | 400 |
| 80105 | 验证码错误 | 400 |
| 80106 | 验证码已过期 | 400 |
| 80107 | 手机号格式错误 | 400 |
| 80108 | 邮箱格式错误 | 400 |

4.2 商品模块 (802xx)

| 错误码 | 描述 | HTTP 状态码 |
|-------|------|-------------|
| 80201 | 商品不存在 | 404 |
| 80202 | 商品已下架 | 400 |
| 80203 | 商品库存不足 | 400 |
| 80204 | 商品价格异常 | 400 |
| 80205 | 商品分类不存在 | 404 |

4.3 订单模块 (803xx)

| 错误码 | 描述 | HTTP 状态码 |
|-------|------|-------------|
| 80301 | 订单不存在 | 404 |
| 80302 | 订单状态异常 | 400 |
| 80303 | 订单已取消 | 400 |
| 80304 | 订单已完成 | 400 |
| 80305 | 订单支付失败 | 400 |
| 80306 | 订单支付超时 | 400 |

4.4 支付模块 (804xx)

| 错误码 | 描述 | HTTP 状态码 |
|-------|------|-------------|
| 80401 | 支付方式不支持 | 400 |
| 80402 | 支付金额异常 | 400 |
| 80403 | 支付参数错误 | 400 |
| 80404 | 支付失败 | 400 |
| 80405 | 支付超时 | 400 |
| 80406 | 支付已完成 | 400 |

5. 错误码使用规范

5.1 错误响应格式

json
{
"code": 20001,
"msg": "操作失败",
"data": []
}

5.2 成功响应格式

json
{
"code": 200,
"msg": "操作成功",
"data": {...}
}

5.3 错误处理流程

1. 捕获异常: 在控制器或中间件中捕获异常
2. 确定错误码: 根据异常类型确定对应的错误码
3. 构建响应: 按照统一格式构建错误响应
4. 返回响应: 返回错误响应给客户端

5.4 错误日志记录

- 记录内容: 错误码、错误信息、请求参数、请求路径、用户信息、时间戳等
- 记录级别: 根据错误严重程度选择合适的日志级别
- 记录位置: 系统日志文件
- 监控告警: 对于严重错误,触发告警机制

6. 错误码管理

6.1 错误码定义

错误码定义在配置文件中,便于统一管理和维护:

php
// config/error_code.php
return [
// 系统错误
10001 => '系统内部错误',
10002 => '系统维护中',
// 业务错误
20001 => '操作失败',
20002 => '业务逻辑错误',
// 参数错误
30001 => '参数不能为空',
30002 => '参数格式错误',
// ...
];

6.2 错误码使用

在代码中使用错误码时,应直接引用配置文件中的定义:

php
// 控制器中使用
return $this->fail(config('error_code.20001'));

// 或直接使用错误码
return $this->fail('操作失败', [], 20001);

6.3 错误码更新

当需要添加新的错误码时,应遵循以下流程:

1. 确定错误类型: 根据错误性质确定错误类型
2. 分配错误码: 从对应类型的错误码范围中分配一个未使用的错误码
3. 更新配置: 在
error_code.php 配置文件中添加错误码定义
4. 更新文档: 更新错误码文档
5. 通知团队: 通知团队成员新添加的错误码

7. 错误码最佳实践

7.1 设计原则

- 唯一性: 每个错误码唯一对应一种错误情况
- 可读性: 错误码应易于理解和记忆
- 可扩展性: 错误码应具有良好的扩展性,便于添加新的错误码
- 一致性: 错误码格式和使用方法应保持一致
- 详细性: 错误信息应清晰、准确,便于调试和定位问题

7.2 使用建议

- 避免硬编码: 错误码应定义在配置文件中,避免直接硬编码在代码中
- 统一处理: 使用统一的错误处理中间件处理错误
- 详细日志: 记录详细的错误日志,便于调试和分析
- 友好提示: 向客户端返回友好的错误信息,避免暴露系统内部细节
- 定期清理: 定期清理不再使用的错误码,保持错误码的简洁性

7.3 常见问题

#### 7.3.1 错误码冲突

- 问题: 不同模块使用了相同的错误码
- 解决方案: 严格按照模块划分错误码范围,避免冲突

#### 7.3.2 错误信息不明确

- 问题: 错误信息过于简洁,无法定位问题
- 解决方案: 提供详细的错误信息,包含必要的上下文

#### 7.3.3 错误码未及时更新

- 问题: 新增功能时未及时添加对应的错误码
- 解决方案: 在开发新功能时,同步更新错误码定义和文档

8. 参考资源

- HTTP 状态码
- RESTful API 错误处理
- 错误码设计最佳实践
- API 错误码规范

---

.Trae/Skills/Uniapp/References/Api Flow (.trae/skills/uniapp/references/api_flow.md)

UniApp API 开发流程文档

1. 概述

本文档描述了 CRMEB 项目中 UniApp 移动端的 API 开发流程,包括 API 接口设计、请求流程、响应处理、错误处理等,旨在规范 API 开发,提高开发效率和代码质量。

2. API 目录结构

text
template/uni-app/api/
├── activity.js # 活动相关接口
├── admin.js # 管理相关接口
├── api.js # 基础 API 配置
├── kefu.js # 客服相关接口
├── lottery.js # 抽奖相关接口
├── order.js # 订单相关接口
├── public.js # 公共接口
├── store.js # 商城相关接口
└── user.js # 用户相关接口

3. 基础 API 配置 (api.js)

javascript
// 基础 API 配置
const baseURL = 'https://api.crmeb.net';

// 请求超时时间
const timeout = 10000;

// 请求拦截器
const requestInterceptor = (config) => {
// 添加 token
const token = uni.getStorageSync('token');
if (token) {
config.header['Authorization'] =
Bearer ${token};
}

// 添加设备信息
config.header['X-Device-Type'] = uni.getSystemInfoSync().platform;

return config;
};

// 响应拦截器
const responseInterceptor = (response) => {
const { data } = response;

// 统一处理错误
if (data.code !== 200) {
uni.showToast({
title: data.message || '请求失败',
icon: 'none'
});

// 处理登录过期
if (data.code === 401) {
uni.redirectTo({
url: '/pages/login/index'
});
}

return Promise.reject(data);
}

return data;
};

// 错误处理
const errorHandler = (error) => {
uni.showToast({
title: '网络错误,请稍后重试',
icon: 'none'
});

return Promise.reject(error);
};

// 导出配置
export default {
baseURL,
timeout,
requestInterceptor,
responseInterceptor,
errorHandler
};

4. API 接口封装

4.1 通用请求方法

text
/ Detailed source-code truncated for AI context efficiency. /

4.2 业务接口封装

javascript
// api/user.js
import request from '../utils/request';

// 用户相关接口
export default {
// 登录
login: (data) => request.post('/api/user/login', data),

// 注册
register: (data) => request.post('/api/user/register', data),

// 获取用户信息
getUserInfo: () => request.get('/api/user/info'),

// 更新用户信息
updateUserInfo: (data) => request.put('/api/user/info', data),

// 修改密码
changePassword: (data) => request.post('/api/user/password', data),

// 获取地址列表
getAddressList: () => request.get('/api/user/address'),

// 添加地址
addAddress: (data) => request.post('/api/user/address', data),

// 更新地址
updateAddress: (id, data) => request.put(
/api/user/address/${id}, data),

// 删除地址
deleteAddress: (id) => request.delete(
/api/user/address/${id}),

// 设置默认地址
setDefaultAddress: (id) => request.put(
/api/user/address/${id}/default)
};

5. API 调用示例

5.1 页面中调用 API

vue
<template>
<view class="user-info">
<view v-if="loading">加载中...</view>
<view v-else>
<image :src="userInfo.avatar" class="avatar"></image>
<view class="name">{{ userInfo.nickname }}</view>
<view class="mobile">{{ userInfo.mobile }}</view>
</view>
</view>
</template>

<script>
import userApi from '../../api/user';

export default {
data() {
return {
loading: false,
userInfo: {}
};
},

onLoad() {
this.getUserInfo();
},

methods: {
async getUserInfo() {
try {
this.loading = true;
const res = await userApi.getUserInfo();
this.userInfo = res.data;
} catch (error) {
console.error('获取用户信息失败:', error);
} finally {
this.loading = false;
}
}
}
};
</script>

5.2 组件中调用 API

text
/ Detailed source-code truncated for AI context efficiency. /

6. API 开发最佳实践

6.1 命名规范

- 文件命名: 小写字母,单词之间用下划线分隔,如 user.js
- 方法命名: 驼峰命名法,如
getUserInfo
- URL 命名: 小写字母,单词之间用连字符分隔,如
/api/user/info
- 参数命名: 驼峰命名法,与后端保持一致

6.2 接口设计规范

- RESTful 风格: 遵循 RESTful API 设计规范
- 版本控制: 在 URL 中包含版本号,如
/api/v1/user/info
- 统一响应格式: 所有接口返回统一的响应格式
- 错误处理: 统一的错误码和错误信息

6.3 请求规范

- 请求方法: 根据操作类型选择合适的 HTTP 方法
- GET: 获取资源
- POST: 创建资源
- PUT: 更新资源
- DELETE: 删除资源
- 请求头: 统一添加必要的请求头,如 Authorization、Content-Type 等
- 参数传递: 根据请求方法选择合适的参数传递方式
- GET: 查询参数
- POST/PUT: 请求体
- DELETE: 查询参数或路径参数

6.4 响应规范

- 成功响应:

json
{
"code": 200,
"message": "请求成功",
"data": {}
}

- 失败响应:
json
{
"code": 400,
"message": "请求失败",
"data": {}
}

6.5 错误处理规范

- 网络错误: 统一处理网络错误,如超时、断网等
- 业务错误: 根据错误码处理不同的业务错误
- 登录过期: 统一处理登录过期,跳转到登录页面
- 错误提示: 统一的错误提示方式,使用 uni.showToast

7. API 性能优化

7.1 请求优化

- 合并请求: 多个相关请求合并为一个
- 缓存策略: 对不经常变化的数据使用缓存
- 请求防抖: 避免频繁发送相同的请求
- 批量操作: 支持批量操作,减少请求次数

7.2 响应优化

- 数据结构优化: 优化响应数据结构,减少数据传输量
- 分页处理: 对列表数据使用分页
- 字段筛选: 支持字段筛选,只返回需要的字段
- 压缩传输: 使用 gzip 压缩传输数据

7.3 代码优化

- 模块化: 按业务模块划分 API 文件
- 复用代码: 提取通用的请求逻辑
- 减少冗余: 避免重复的 API 调用
- 代码可读性: 保持代码清晰易读

8. 常见问题

8.1 跨域问题

- 问题: 开发环境中遇到跨域问题
- 解决方案: 在本地开发服务器中配置跨域代理

8.2 Token 过期问题

- 问题: Token 过期后请求失败
- 解决方案: 在响应拦截器中处理 Token 过期,跳转到登录页面

8.3 请求超时问题

- 问题: 网络不稳定时请求超时
- 解决方案: 设置合理的超时时间,添加网络状态检测

8.4 重复请求问题

- 问题: 快速点击按钮导致重复请求
- 解决方案: 添加请求防抖或锁机制

8.5 数据缓存问题

- 问题: 缓存数据与服务器数据不一致
- 解决方案: 合理设置缓存过期时间,提供手动刷新机制

9. 参考资源

- UniApp 网络请求文档
- RESTful API 设计指南
- Axios 文档
- HTTP 方法

10. 总结

本文档描述了 CRMEB 项目中 UniApp 移动端的 API 开发流程,包括 API 接口设计、请求流程、响应处理、错误处理等。遵循本文档的开发规范,可以提高 API 开发的效率和质量,确保应用的稳定性和可靠性。

随着业务的发展和技术的演进,API 开发流程也需要不断优化和调整,以适应新的业务需求和技术挑战。

---

.Trae/Skills/Uniapp/References/Code Style (.trae/skills/uniapp/references/code_style.md)

UniApp 代码规范文档

1. 概述

本文档描述了 CRMEB 项目中 UniApp 移动端的代码规范,包括命名规范、代码风格、文件结构、组件开发等,旨在统一代码风格,提高代码质量和可维护性。

2. 命名规范

2.1 目录命名

- 目录名: 小写字母,单词之间用下划线分隔
- 示例:
pages/index/components/common/utils/
- 规范: 简洁明了,反映目录的功能

2.2 文件命名

- 页面文件: 小写字母,单词之间用下划线分隔
- 示例:
index.vuelogin.vueuser_info.vue
- 组件文件: 大写字母开头的 PascalCase 命名风格
- 示例:
Button.vueNavBar.vueGoodsList.vue
- JS 文件: 小写字母,单词之间用下划线分隔
- 示例:
user.jsrequest.jsutil.js
- CSS/SCSS 文件: 小写字母,单词之间用下划线分隔
- 示例:
common.scsstheme.scss

2.3 变量命名

- 普通变量: 驼峰命名法
- 示例:
userInfogoodsListisLoading
- 常量: 全大写,单词之间用下划线分隔
- 示例:
BASE_URLMAX_COUNTDEFAULT_PAGE_SIZE
- 布尔变量: 以
is 开头的驼峰命名法
- 示例:
isShowisLoadingisLogin

2.4 函数命名

- 函数名: 驼峰命名法,动词开头
- 示例:
getUserInfosubmitFormhandleClick
- 方法名: 驼峰命名法
- 示例:
datamethodscomputedwatch
- 生命周期函数: 按照 Vue 规范命名
- 示例:
createdmountedbeforeDestroy

2.5 组件命名

- 组件名: PascalCase 命名风格
- 示例:
ButtonNavBarGoodsList
- 组件标签: 小写字母,单词之间用连字符分隔
- 示例:
<my-button><nav-bar><goods-list>

2.6 其他命名

- 路由命名: 小写字母,单词之间用连字符分隔
- 示例:
/pages/index/index/pages/user/login
- CSS 类名: 小写字母,单词之间用连字符分隔
- 示例:
.user-info.goods-list.btn-primary
- ID 命名: 小写字母,单词之间用连字符分隔
- 示例:
#app#header#footer

3. 代码风格

3.1 缩进

- 缩进方式: 4 个空格
- 示例:

vue
<template>
<view class="container">
<text>{{ message }}</text>
</view>
</template>

3.2 换行

- 标签换行: 多个属性的标签应该换行
- 示例:

vue
<view
class="container"
:class="{ active: isActive }"
@click="handleClick"
>
<text>{{ message }}</text>
</view>

- 代码块换行: 逻辑代码块应该换行
- 示例:
javascript
if (condition) {
// 代码块
} else {
// 代码块
}

3.3 空格

- 运算符空格: 运算符两侧应该有空格
- 示例:
a + bx = yi < 10
- 逗号空格: 逗号后面应该有空格
- 示例:
[1, 2, 3]{ name: '张三', age: 18 }
- 括号空格: 括号内侧不应该有空格
- 示例:
if (condition)function (param)

3.4 注释

- 单行注释: 使用 // 注释
- 示例:
// 这是单行注释
- 多行注释: 使用
/ / 注释
- 示例:

javascript
/*
* 这是多行注释
* 第二行
*/

- 文档注释: 使用 JSDoc 风格的注释
- 示例:
javascript
/
* 获取用户信息
* @param {number} id - 用户ID
* @returns {Promise} 用户信息
*/
async function getUserInfo(id) {
// 代码
}

3.5 引号

- 字符串: 使用单引号 ''
- 示例:
const name = '张三'<text>Hello</text>
- 模板字符串: 使用反引号
`
- 示例:
const url = ${baseUrl}/api/user
- HTML 属性: 使用双引号
""
- 示例:
<view class="container"><image src="https://example.com/img.jpg">

4. 文件结构

4.1 页面文件结构

vue
<template>

</template>

<script>
// 导入依赖
import userApi from '../../api/user';

// 导出组件
export default {
// 组件名称
name: 'UserInfo',

// 组件属性
props: {
userId: {
type: Number,
required: true
}
},

// 数据
data() {
return {
userInfo: {},
loading: false
};
},

// 计算属性
computed: {
fullName() {
return this.userInfo.firstName + ' ' + this.userInfo.lastName;
}
},

// 监听
watch: {
userId: {
handler(newVal) {
this.getUserInfo(newVal);
},
immediate: true
}
},

// 生命周期函数
created() {
// 初始化
},

mounted() {
// 挂载后
},

// 方法
methods: {
async getUserInfo(id) {
try {
this.loading = true;
const res = await userApi.getUserInfo(id);
this.userInfo = res.data;
} catch (error) {
console.error('获取用户信息失败:', error);
} finally {
this.loading = false;
}
},

handleEdit() {
// 编辑用户信息
}
}
};
</script>

<style scoped>
/ 样式 /
.user-info {
padding: 20rpx;
background-color: #f5f5f5;
}

.name {
font-size: 32rpx;
font-weight: bold;
}
</style>

4.2 组件文件结构

vue
<template>

<view class="my-button">
<button
:class="[type, { disabled }]"
:disabled="disabled"
@click="handleClick"
>
<slot></slot>
</button>
</view>
</template>

<script>
export default {
name: 'MyButton',

props: {
type: {
type: String,
default: 'primary',
validator: (value) => {
return ['primary', 'success', 'warning', 'danger'].includes(value);
}
},
disabled: {
type: Boolean,
default: false
}
},

methods: {
handleClick() {
if (!this.disabled) {
this.$emit('click');
}
}
}
};
</script>

<style scoped>
.my-button {
display: inline-block;
}

button {
padding: 20rpx 40rpx;
border-radius: 8rpx;
font-size: 28rpx;
border: none;
outline: none;
cursor: pointer;
}

.primary {
background-color: #007aff;
color: #fff;
}

.success {
background-color: #4cd964;
color: #fff;
}

.warning {
background-color: #ff9500;
color: #fff;
}

.danger {
background-color: #ff3b30;
color: #fff;
}

.disabled {
opacity: 0.6;
cursor: not-allowed;
}
</style>

4.3 JS 文件结构

javascript
// 导入依赖
import request from './request';

// 常量定义
const BASE_URL = 'https://api.crmeb.net';
const TIMEOUT = 10000;

// 工具函数
function formatTime(time) {
const date = new Date(time);
return date.toLocaleString();
}

function getRandomNum(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}

// 导出
export {
formatTime,
getRandomNum
};

// 默认导出
export default {
BASE_URL,
TIMEOUT
};

5. 组件开发规范

5.1 组件设计

- 单一职责: 每个组件只负责一个功能
- 可复用性: 设计通用的、可复用的组件
- 可配置性: 通过 props 提供配置选项
- 事件通信: 通过事件与父组件通信

5.2 组件使用

- 组件导入: 使用 import 导入组件
- 示例:
import Button from '../../components/Button.vue'
- 组件注册: 在 components 中注册组件
- 示例:

javascript
components: {
Button
}

- 组件使用: 使用组件标签
- 示例:
<Button type="primary">点击</Button>

5.3 组件通信

- props 向下传递: 父组件通过 props 向子组件传递数据
- events 向上传递: 子组件通过 events 向父组件传递事件
- refs 引用: 通过 refs 引用子组件实例
- provide/inject: 祖先组件向后代组件传递数据

6. 页面开发规范

6.1 页面结构

- 模板结构: 清晰明了,层次分明
- 脚本结构: 按照 Vue 规范组织代码
- 样式结构: 模块化,可维护

6.2 数据管理

- 本地数据: 使用 data 管理组件内部数据
- 计算数据: 使用 computed 计算衍生数据
- 监听数据: 使用 watch 监听数据变化
- 全局数据: 使用 Vuex 管理全局数据

6.3 生命周期管理

- created: 初始化数据,发送请求
- mounted: 操作 DOM,初始化第三方库
- beforeDestroy: 清理定时器,取消订阅

6.4 路由管理

- 路由配置: 在 pages.json 中配置路由
- 路由跳转: 使用 uni.navigateTo、uni.redirectTo 等方法
- 路由参数: 通过 options 或 $route.params 获取路由参数

7. API 调用规范

7.1 API 封装

- 模块化: 按业务模块封装 API
- 统一处理: 统一处理请求头、响应拦截、错误处理
- Promise 化: 使用 Promise 处理异步请求

7.2 API 调用

- 异步处理: 使用 async/await 处理异步请求
- 错误处理: 使用 try/catch 捕获错误
- 加载状态: 显示加载状态,提升用户体验
- 错误提示: 统一处理错误提示

7.3 示例代码

javascript
async function getUserInfo() {
try {
this.loading = true;
const res = await userApi.getUserInfo();
this.userInfo = res.data;
} catch (error) {
console.error('获取用户信息失败:', error);
uni.showToast({
title: '获取用户信息失败',
icon: 'none'
});
} finally {
this.loading = false;
}
}

8. 性能优化

8.1 代码优化

- 减少冗余代码: 避免重复的代码
- 使用计算属性: 对于复杂的计算,使用 computed
- 使用 v-if 和 v-show 合理: 根据场景选择合适的指令
- 使用 key: 在 v-for 中使用 key,提高渲染性能

8.2 网络优化

- 合理使用缓存: 缓存不经常变化的数据
- 减少请求次数: 合并请求,批量操作
- 使用防抖和节流: 避免频繁的事件触发
- 延迟加载: 对于非首屏内容,使用延迟加载

8.3 其他优化

- 减少 DOM 节点: 简化 DOM 结构
- 优化图片: 使用合适的图片格式和大小
- 使用虚拟列表: 对于长列表,使用虚拟列表
- 避免内存泄漏: 及时清理定时器、事件监听器等

9. 常见问题

9.1 代码风格问题

- 问题: 代码风格不一致
- 解决方案: 使用 ESLint 等工具进行代码检查

9.2 性能问题

- 问题: 页面加载慢,卡顿
- 解决方案: 优化代码,减少 DOM 操作,使用虚拟列表等

9.3 兼容性问题

- 问题: 在不同平台上表现不一致
- 解决方案: 遵循 UniApp 规范,使用条件编译

9.4 维护性问题

- 问题: 代码难以维护
- 解决方案: 模块化开发,添加注释,遵循代码规范

10. 参考资源

- Vue 官方文档
- UniApp 官方文档
- ESLint 官方文档
- Prettier 官方文档
- 前端代码规范指南

11. 总结

本文档描述了 CRMEB 项目中 UniApp 移动端的代码规范,包括命名规范、代码风格、文件结构、组件开发等。遵循本文档的规范,可以提高代码的可读性、可维护性和可扩展性,确保项目的质量和稳定性。

代码规范是团队协作的基础,建议开发团队成员严格遵循本文档的规范,共同维护一个高质量的代码库。

---

.Trae/Skills/Uniapp/References/Directory Structure (.trae/skills/uniapp/references/directory_structure.md)

UniApp 目录结构文档

1. 概述

本文档描述了 CRMEB 项目中 UniApp 移动端的目录结构,包括各目录的功能、文件组织方式等,旨在帮助开发者理解项目结构,提高开发效率。

2. 项目根目录结构

text
template/uni-app/
├── api/ # API 接口目录
├── config/ # 配置目录
├── libs/ # 库文件目录
├── mixins/ # 混入目录
├── store/ # 状态管理目录
├── utils/ # 工具类目录
├── App.vue # 应用入口组件
├── main.js # 应用入口文件
├── manifest.json # 应用配置文件
├── package.json # 项目配置文件
├── pages.json # 页面路由配置文件
├── uni.scss # UniApp 全局样式文件
└── vue.config.js # Vue 配置文件

3. API 目录结构 (api/)

text
api/
├── activity.js # 活动相关接口
├── admin.js # 管理相关接口
├── api.js # 基础 API 配置
├── kefu.js # 客服相关接口
├── lottery.js # 抽奖相关接口
├── order.js # 订单相关接口
├── public.js # 公共接口
├── store.js # 商城相关接口
└── user.js # 用户相关接口

- 功能: 封装与后端交互的 API 接口
- 结构: 按业务模块划分接口文件
- 特性: 统一处理请求头、响应拦截、错误处理等
- 调用方式: 通过
import` 导入使用

4. 配置目录结构 (config/)

text
config/
├── app.js # 应用配置
├── cache.js # 缓存配置
└── socket.js # WebSocket 配置

- 功能: 存储项目的所有配置文件
- 结构: 按功能模块划分配置文件
- 特性: 集中管理配置,便于维护和修改
- 加载顺序: 应用启动时加载

5. 库文件目录结构 (libs/)

text
libs/
├── chat.js # 聊天相关功能
├── login.js # 登录相关功能
├── new_chat.js # 新聊天功能
├── order.js # 订单相关功能
├── routine.js # 小程序相关功能
├── uniApi.js # UniApp API 封装
└── wechat.js # 微信相关功能

- 功能: 存储通用库文件和功能模块
- 结构: 按功能划分库文件
- 特性: 独立于页面代码,便于复用
- 作用: 提供通用功能和服务

6. 混入目录结构 (mixins/)

text
mixins/
└── color.js # 颜色相关混入

- 功能: 存储 Vue 混入对象
- 结构: 按功能划分混入文件
- 特性: 实现代码复用,避免重复逻辑
- 作用: 为组件提供共享的方法和数据

7. 状态管理目录结构 (store/)

text
store/
├── getters.js # 状态获取器
└── index.js # 状态管理入口

- 功能: 存储 Vuex 状态管理相关文件
- 结构: 按 Vuex 规范划分文件
- 特性: 集中管理应用状态,实现组件间通信
- 作用: 管理全局状态,如用户信息、购物车数据等

8. 工具类目录结构 (utils/)

text
utils/
├── cache.js # 缓存工具
├── emoji.js # 表情工具
├── index.js # 工具类入口
├── lang.js # 语言工具
├── request.js # 网络请求工具
├── theme.js # 主题工具
├── util.js # 通用工具
└── validate.js # 验证工具

- 功能: 存储通用工具类
- 结构: 按功能划分工具文件
- 特性: 提供通用功能,便于复用
- 作用: 处理缓存、网络请求、验证等通用操作

9. 页面目录结构

9.1 页面配置 (pages.json)

json
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首页"
}
},
{
"path": "pages/user/index",
"style": {
"navigationBarTitleText": "个人中心"
}
}
],
"subPackages": [
{
"root": "pages/order",
"pages": [
{
"path": "index",
"style": {
"navigationBarTitleText": "订单列表"
}
}
]
}
]
}

- 功能: 配置页面路由、导航栏样式等
- 结构: 按页面层级配置
- 特性: 支持分包加载,优化应用体积
- 作用: 定义应用的页面结构和导航样式

10. 应用配置文件

10.1 manifest.json

json
{
"name": "CRMEB商城",
"appid": "__UNI__APPID__",
"description": "CRMEB商城移动端",
"versionName": "1.0.0",
"versionCode": "100",
"transformPx": true,
"uniStatistics": {
"enable": true
},
"app-plus": {
"usingComponents": true,
"nvueStyleCompiler": "uni-app"
},
"mp-weixin": {
"appid": "wx_appid",
"setting": {
"urlCheck": false
},
"usingComponents": true
}
}

- 功能: 配置应用的基本信息、平台配置等
- 结构: 按平台划分配置
- 特性: 支持多平台配置,如微信小程序、App 等
- 作用: 定义应用的全局配置信息

10.2 package.json

json
{
"name": "crmeb-uni-app",
"version": "1.0.0",
"description": "CRMEB商城移动端",
"main": "main.js",
"scripts": {
"dev": "npm run dev:mp-weixin",
"dev:mp-weixin": "cross-env NODE_ENV=development UNI_PLATFORM=mp-weixin vue-cli-service uni-build --watch",
"build": "npm run build:mp-weixin",
"build:mp-weixin": "cross-env NODE_ENV=production UNI_PLATFORM=mp-weixin vue-cli-service uni-build"
},
"dependencies": {
"vue": "^2.6.11",
"vuex": "^3.4.0"
}
}

- 功能: 配置项目的依赖、脚本等
- 结构: 标准 npm 配置格式
- 特性: 管理项目依赖,定义构建脚本
- 作用: 管理项目的依赖和构建流程

11. 目录结构最佳实践

11.1 命名规范

- 目录名: 小写字母,单词之间用下划线分隔
- 文件名: 小写字母,单词之间用下划线分隔
- 组件名: 使用 PascalCase 命名风格
- 方法名: 使用 camelCase 命名风格
- 变量名: 使用 camelCase 命名风格

11.2 组织原则

- 模块化: 按功能模块组织目录结构
- 分层架构: 遵循 Vue 组件化开发架构
- 单一职责: 每个目录和文件只负责一个功能
- 可扩展性: 便于添加新功能和模块
- 易维护性: 便于理解和维护

11.3 开发建议

- 遵循 UniApp 规范: 遵循 UniApp 官方目录结构规范
- 合理划分模块: 根据业务功能合理划分模块
- 避免目录过深: 目录层级不宜过深,一般不超过 4 层
- 保持目录整洁: 及时清理无用文件和目录
- 文档化: 为重要目录添加说明文档

12. 常见问题

12.1 目录权限问题

- 问题: 某些目录没有读写权限
- 解决方案: 确保项目目录有正确的读写权限

12.2 页面路由配置问题

- 问题: 新增页面后无法访问
- 解决方案: 在 pages.json 中添加页面路由配置

12.3 分包加载问题

- 问题: 应用体积过大,无法上传到小程序平台
- 解决方案: 使用分包加载,将页面划分到不同的分包中

12.4 目录结构混乱

- 问题: 目录结构不清晰,难以维护
- 解决方案: 重新组织目录结构,遵循模块化原则

13. 参考资源

- UniApp 官方文档
- Vue 官方文档
- Vuex 官方文档
- 微信小程序开发文档

14. 总结

本文档描述了 CRMEB 项目中 UniApp 移动端的目录结构,包括各目录的功能、文件组织方式等。遵循本文档的目录结构规范,可以提高项目的可维护性和可扩展性,便于团队协作开发。

随着业务的发展和技术的演进,目录结构也可能需要不断优化和调整,以适应新的业务需求和技术挑战。

---