docs: complete developer documentation (5 guides + index)
- 01-快速开始: local setup for all 3 modules, common issues - 02-配置说明: all env vars, WeChat/Pay/DB/COS config details - 03-架构说明: system overview, directory structure, data flows - 04-部署指南: Tencent Cloud SCF/COS deployment, launch checklist - 05-API接口文档: all 42 endpoints with params and response format - README index with audience guide and quick links
这个提交包含在:
+232
@@ -0,0 +1,232 @@
|
|||||||
|
# 快速开始
|
||||||
|
|
||||||
|
## 项目概述
|
||||||
|
|
||||||
|
jw-beauty 是一款光子美容仪配套系统,包含三个子项目:
|
||||||
|
|
||||||
|
- **微信小程序** (`miniprogram/`) — 用户端,蓝牙连接设备、护理流程、订阅管理
|
||||||
|
- **后端服务** (`server/`) — Express.js API,部署为腾讯云 SCF HTTP 函数
|
||||||
|
- **H5 管理后台** (`admin-console/`) — Vue 3 + uni-app H5,管理设备/用户/订阅/固件
|
||||||
|
|
||||||
|
## 前置要求
|
||||||
|
|
||||||
|
| 工具 | 版本要求 | 说明 |
|
||||||
|
|------|---------|------|
|
||||||
|
| Node.js | >= 18 | 后端使用 Express 5,管理后台使用 Vite 5 |
|
||||||
|
| npm | >= 8 | 随 Node.js 一起安装 |
|
||||||
|
| MySQL | >= 5.7 | 本地开发用,推荐 8.0;也可用 Docker |
|
||||||
|
| 微信开发者工具 | 最新稳定版 | 小程序调试用 |
|
||||||
|
| Git | 任意 | 版本管理 |
|
||||||
|
|
||||||
|
## 获取代码
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone <仓库地址>
|
||||||
|
cd jw-beauty
|
||||||
|
```
|
||||||
|
|
||||||
|
## 后端启动
|
||||||
|
|
||||||
|
### 1. 安装依赖
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd server
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 配置环境变量
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
编辑 `.env`,至少填写数据库连接信息:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
NODE_ENV=development
|
||||||
|
PORT=3000
|
||||||
|
|
||||||
|
# 数据库(必填)
|
||||||
|
DB_HOST=127.0.0.1
|
||||||
|
DB_PORT=3306
|
||||||
|
DB_USER=root
|
||||||
|
DB_PASSWORD=你的MySQL密码
|
||||||
|
DB_NAME=jw_beauty
|
||||||
|
|
||||||
|
# 微信登录(本地开发可暂不填,有 mock 登录)
|
||||||
|
WECHAT_APPID=
|
||||||
|
WECHAT_SECRET=
|
||||||
|
|
||||||
|
# JWT 密钥(开发环境用默认值即可,会自动 fallback)
|
||||||
|
JWT_SECRET=replace-with-a-long-random-secret
|
||||||
|
ADMIN_JWT_SECRET=replace-with-a-different-long-random-secret
|
||||||
|
|
||||||
|
# 管理员账号(开发环境默认 admin/admin)
|
||||||
|
ADMIN_USERNAME=admin
|
||||||
|
ADMIN_PASSWORD=admin
|
||||||
|
|
||||||
|
# 腾讯云(头像上传/COS 功能需要,本地开发可暂不填)
|
||||||
|
TENCENT_SECRET_ID=
|
||||||
|
TENCENT_SECRET_KEY=
|
||||||
|
TENCENT_REGION=ap-guangzhou
|
||||||
|
COS_BUCKET=jw-bucket-1426323813
|
||||||
|
COS_REGION=ap-guangzhou
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 创建数据库
|
||||||
|
|
||||||
|
先手动创建数据库:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mysql -u root -p -e "CREATE DATABASE IF NOT EXISTS jw_beauty DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;"
|
||||||
|
```
|
||||||
|
|
||||||
|
然后运行初始化脚本(建表 + 插入默认设置 + 创建管理员账号):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run db:init
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 启动服务
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
看到以下输出说明启动成功:
|
||||||
|
|
||||||
|
```
|
||||||
|
Server listening on http://localhost:3000
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 验证
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://localhost:3000/health
|
||||||
|
```
|
||||||
|
|
||||||
|
期望返回:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"code":0,"data":{"status":"ok"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 小程序启动
|
||||||
|
|
||||||
|
### 1. 打开项目
|
||||||
|
|
||||||
|
用微信开发者工具打开 `miniprogram/` 目录。
|
||||||
|
|
||||||
|
项目的 AppID 已在 `project.config.json` 中配置为 `wxc4045074ef298510`。如果你没有该 AppID 的权限,可以用测试号或在开发者工具中选择"测试号"。
|
||||||
|
|
||||||
|
### 2. 指向本地后端
|
||||||
|
|
||||||
|
编辑 `miniprogram/config/env.js`,将 `ENV` 改为 `local`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var ENV = 'local' // 改为 local,API 请求会发到 http://localhost:3000
|
||||||
|
|
||||||
|
var API_BASES = {
|
||||||
|
local: 'http://localhost:3000',
|
||||||
|
test: 'https://api.vsai.net.cn',
|
||||||
|
prod: 'https://api.vsai.net.cn'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 注意事项
|
||||||
|
|
||||||
|
- **不校验合法域名**:在开发者工具「详情 > 本地设置」中勾选「不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书」,否则 localhost 请求会被拦截
|
||||||
|
- **BLE 蓝牙功能需要真机调试**:模拟器无法使用蓝牙,设备连接/护理流程必须在真机上测试
|
||||||
|
- **`__DEV__` 标志**:当 `ENV` 不是 `prod` 时,`__DEV__` 为 `true`,会启用 mock 绑定、mock 购买等开发便捷功能
|
||||||
|
- **权限**:小程序使用了蓝牙、位置(蓝牙依赖)、相机(扫码)权限,真机调试时需要授权
|
||||||
|
|
||||||
|
## 管理后台启动
|
||||||
|
|
||||||
|
### 1. 安装依赖
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd admin-console
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 指向本地后端
|
||||||
|
|
||||||
|
编辑 `admin-console/src/config/env.js`,将 `ENV` 改为 `local`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const ENV = 'local' // 改为 local
|
||||||
|
|
||||||
|
const API_BASES = {
|
||||||
|
local: 'http://localhost:3000',
|
||||||
|
test: 'https://api.vsai.net.cn',
|
||||||
|
prod: 'https://api.vsai.net.cn'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 启动开发服务器
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
启动后访问终端输出的地址,通常是 `http://localhost:5173/admin/`。
|
||||||
|
|
||||||
|
> 注意路径末尾的 `/admin/`,这是 `vite.config.js` 中配置的 `base` 路径。
|
||||||
|
|
||||||
|
### 4. 登录
|
||||||
|
|
||||||
|
使用默认管理员账号登录:
|
||||||
|
|
||||||
|
- 用户名:`admin`
|
||||||
|
- 密码:`admin`
|
||||||
|
|
||||||
|
(与 `.env` 中 `ADMIN_USERNAME` / `ADMIN_PASSWORD` 一致)
|
||||||
|
|
||||||
|
### 5. 构建生产版本
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run build:h5
|
||||||
|
```
|
||||||
|
|
||||||
|
构建产物在 `dist/build/h5/` 目录,部署到 COS:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run deploy:cos
|
||||||
|
```
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### 端口 3000 被占用
|
||||||
|
|
||||||
|
修改 `.env` 中的 `PORT`,同时更新小程序和管理后台的 `env.js` 中 `local` 对应的地址。
|
||||||
|
|
||||||
|
### 数据库连接失败
|
||||||
|
|
||||||
|
1. 确认 MySQL 服务已启动
|
||||||
|
2. 确认 `.env` 中 `DB_HOST`、`DB_PORT`、`DB_USER`、`DB_PASSWORD` 正确
|
||||||
|
3. 确认已创建 `jw_beauty` 数据库
|
||||||
|
4. 如果用 Docker 跑 MySQL,注意 host 应为 `127.0.0.1` 而非 `localhost`(避免 socket 连接问题)
|
||||||
|
|
||||||
|
### 微信登录在开发环境怎么测试
|
||||||
|
|
||||||
|
开发环境(`NODE_ENV=development`)下,服务端提供了 mock 端点:
|
||||||
|
|
||||||
|
- **mock 绑定设备**:不需要真实蓝牙握手
|
||||||
|
- **mock 购买订阅**:不需要真实微信支付
|
||||||
|
|
||||||
|
小程序端 `__DEV__` 为 `true` 时会显示对应的开发快捷入口。
|
||||||
|
|
||||||
|
如果需要测试真实微信登录,需要在 `.env` 中填写 `WECHAT_APPID` 和 `WECHAT_SECRET`(从微信公众平台获取)。
|
||||||
|
|
||||||
|
### 管理后台页面空白
|
||||||
|
|
||||||
|
确认访问地址包含 `/admin/` 路径前缀。直接访问 `http://localhost:5173/` 会 404。
|
||||||
|
|
||||||
|
### npm install 报错
|
||||||
|
|
||||||
|
确认 Node.js 版本 >= 18。可以使用 nvm 管理多版本:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nvm install 18
|
||||||
|
nvm use 18
|
||||||
|
```
|
||||||
+291
@@ -0,0 +1,291 @@
|
|||||||
|
# 配置说明
|
||||||
|
|
||||||
|
## 环境变量总表
|
||||||
|
|
||||||
|
后端所有配置通过 `server/.env` 文件管理(通过 dotenv 加载)。下表列出全部变量:
|
||||||
|
|
||||||
|
| 变量名 | 用途 | 示例值 | 必填 | 默认值 |
|
||||||
|
|--------|------|--------|------|--------|
|
||||||
|
| `NODE_ENV` | 运行环境 | `development` / `production` | 否 | `development` |
|
||||||
|
| `PORT` | 监听端口 | `3000` | 否 | `3000` |
|
||||||
|
| `DB_HOST` | MySQL 主机地址 | `127.0.0.1` | 是 | 无 |
|
||||||
|
| `DB_PORT` | MySQL 端口 | `3306` | 否 | `3306` |
|
||||||
|
| `DB_USER` | MySQL 用户名 | `root` | 否 | `root` |
|
||||||
|
| `DB_PASSWORD` | MySQL 密码 | `mypassword` | 是 | 无 |
|
||||||
|
| `DB_NAME` | 数据库名 | `jw_beauty` | 否 | `jw_beauty` |
|
||||||
|
| `WECHAT_APPID` | 微信小程序 AppID | `wxc4045074ef298510` | 生产必填 | 无 |
|
||||||
|
| `WECHAT_SECRET` | 微信小程序 AppSecret | `abcdef1234567890...` | 生产必填 | 无 |
|
||||||
|
| `JWT_SECRET` | 用户 JWT 签名密钥 | `a-long-random-string` | 生产必填 | `dev-user-secret` |
|
||||||
|
| `ADMIN_JWT_SECRET` | 管理员 JWT 签名密钥 | `another-long-random-string` | 生产必填 | `dev-admin-secret` |
|
||||||
|
| `ADMIN_USERNAME` | 初始管理员用户名 | `admin` | 否 | `admin` |
|
||||||
|
| `ADMIN_PASSWORD` | 初始管理员密码 | `strongpassword` | 生产必填 | `admin` |
|
||||||
|
| `TENCENT_SECRET_ID` | 腾讯云 API SecretId | `AKIDxxxx` | COS 功能需要 | 无 |
|
||||||
|
| `TENCENT_SECRET_KEY` | 腾讯云 API SecretKey | `xxxx` | COS 功能需要 | 无 |
|
||||||
|
| `TENCENT_REGION` | 腾讯云默认地域 | `ap-guangzhou` | 否 | `ap-guangzhou` |
|
||||||
|
| `COS_BUCKET` | COS 存储桶名称 | `jw-bucket-1426323813` | 否 | `jw-bucket-1426323813` |
|
||||||
|
| `COS_REGION` | COS 存储桶地域 | `ap-guangzhou` | 否 | 同 `TENCENT_REGION` |
|
||||||
|
| `COS_CDN_DOMAIN` | COS CDN 加速域名 | `tx.vsai.net.cn` | 否 | `tx.vsai.net.cn` |
|
||||||
|
|
||||||
|
### 生产环境安全检查
|
||||||
|
|
||||||
|
当 `NODE_ENV=production` 时,服务启动会强制检查以下条件,不满足则拒绝启动:
|
||||||
|
|
||||||
|
- `JWT_SECRET` 不能是默认值 `dev-user-secret`
|
||||||
|
- `ADMIN_JWT_SECRET` 不能是默认值 `dev-admin-secret`
|
||||||
|
- `ADMIN_USERNAME` 和 `ADMIN_PASSWORD` 不能是默认值 `admin`
|
||||||
|
|
||||||
|
## 微信配置
|
||||||
|
|
||||||
|
### 获取 WECHAT_APPID 和 WECHAT_SECRET
|
||||||
|
|
||||||
|
1. 登录 [微信公众平台](https://mp.weixin.qq.com/) -> 开发管理 -> 开发设置
|
||||||
|
2. AppID(小程序ID) 即为 `WECHAT_APPID`
|
||||||
|
3. AppSecret(小程序密钥) 即为 `WECHAT_SECRET`(需要管理员扫码后才能查看,只显示一次)
|
||||||
|
|
||||||
|
```ini
|
||||||
|
WECHAT_APPID=wxc4045074ef298510
|
||||||
|
WECHAT_SECRET=你的AppSecret
|
||||||
|
```
|
||||||
|
|
||||||
|
### 开发环境
|
||||||
|
|
||||||
|
本地开发时不填这两个值也能运行,但微信登录(`wx.login` -> `code2Session`)会失败。此时可以通过 mock 端点绕过。
|
||||||
|
|
||||||
|
## 数据库配置
|
||||||
|
|
||||||
|
### 本地开发
|
||||||
|
|
||||||
|
```ini
|
||||||
|
DB_HOST=127.0.0.1
|
||||||
|
DB_PORT=3306
|
||||||
|
DB_USER=root
|
||||||
|
DB_PASSWORD=你的本地MySQL密码
|
||||||
|
DB_NAME=jw_beauty
|
||||||
|
```
|
||||||
|
|
||||||
|
使用 Docker 快速启动 MySQL:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -d \
|
||||||
|
--name jw-mysql \
|
||||||
|
-p 3306:3306 \
|
||||||
|
-e MYSQL_ROOT_PASSWORD=rootpass \
|
||||||
|
-e MYSQL_DATABASE=jw_beauty \
|
||||||
|
mysql:8.0 \
|
||||||
|
--character-set-server=utf8mb4 \
|
||||||
|
--collation-server=utf8mb4_unicode_ci
|
||||||
|
```
|
||||||
|
|
||||||
|
然后 `.env` 中填:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
DB_HOST=127.0.0.1
|
||||||
|
DB_PASSWORD=rootpass
|
||||||
|
```
|
||||||
|
|
||||||
|
### 腾讯云 TencentDB
|
||||||
|
|
||||||
|
SCF 函数部署时,需要将函数放在与 TencentDB 同一 VPC/子网中:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
DB_HOST=10.0.0.x # VPC 内网地址
|
||||||
|
DB_PORT=3306
|
||||||
|
DB_USER=root
|
||||||
|
DB_PASSWORD=腾讯云数据库密码
|
||||||
|
DB_NAME=jw_beauty
|
||||||
|
```
|
||||||
|
|
||||||
|
### 数据库表结构
|
||||||
|
|
||||||
|
共 10 张表(定义在 `server/sql/schema.sql`):
|
||||||
|
|
||||||
|
| 表名 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `users` | 小程序用户,openid 唯一索引 |
|
||||||
|
| `devices` | 美容仪设备,device_id 为主键 |
|
||||||
|
| `bindings` | 用户-设备绑定关系 |
|
||||||
|
| `subscriptions` | 用户订阅记录(月卡/年卡) |
|
||||||
|
| `treatment_records` | 护理记录,含时长、模式、光密度等 |
|
||||||
|
| `device_events` | 设备事件日志(错误、告警等) |
|
||||||
|
| `device_commands` | 下发给设备的远程指令 |
|
||||||
|
| `operation_logs` | 操作审计日志 |
|
||||||
|
| `admin_accounts` | 管理员账号 |
|
||||||
|
| `system_settings` | 系统设置键值对(定价、功能开关等) |
|
||||||
|
| `firmware_files` | 固件版本记录 |
|
||||||
|
|
||||||
|
初始化时会自动插入默认系统设置:月卡 99 元、年卡 899 元、试用 7 天等。
|
||||||
|
|
||||||
|
## COS 配置
|
||||||
|
|
||||||
|
COS(对象存储)用于存储用户头像和固件文件,通过 CDN 域名对外提供访问。
|
||||||
|
|
||||||
|
```ini
|
||||||
|
TENCENT_SECRET_ID=AKIDxxxx # 腾讯云控制台 -> 访问管理 -> API密钥管理
|
||||||
|
TENCENT_SECRET_KEY=xxxx
|
||||||
|
COS_BUCKET=jw-bucket-1426323813 # 存储桶名称(含 APPID 后缀)
|
||||||
|
COS_REGION=ap-guangzhou # 存储桶所在地域
|
||||||
|
COS_CDN_DOMAIN=tx.vsai.net.cn # CDN 加速域名(可选,不填有默认值)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 获取密钥
|
||||||
|
|
||||||
|
1. 登录 [腾讯云控制台](https://console.cloud.tencent.com/)
|
||||||
|
2. 访问管理 -> API 密钥管理 -> 新建密钥
|
||||||
|
3. 复制 SecretId 和 SecretKey
|
||||||
|
|
||||||
|
> 建议创建子用户,只授予 COS 相关权限,不要使用主账号密钥。
|
||||||
|
|
||||||
|
### 本地开发
|
||||||
|
|
||||||
|
不配置 COS 相关变量时,头像上传和固件上传功能会报错,但不影响其他功能开发。
|
||||||
|
|
||||||
|
## 安全配置
|
||||||
|
|
||||||
|
### JWT_SECRET
|
||||||
|
|
||||||
|
用于签发用户端 JWT token,有效期 7 天。生成方法:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
||||||
|
```
|
||||||
|
|
||||||
|
将输出填入 `.env`:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
JWT_SECRET=生成的64位十六进制字符串
|
||||||
|
```
|
||||||
|
|
||||||
|
### ADMIN_JWT_SECRET
|
||||||
|
|
||||||
|
用于签发管理后台 JWT token,必须与 `JWT_SECRET` 不同。用同样的方法生成:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
||||||
|
```
|
||||||
|
|
||||||
|
```ini
|
||||||
|
ADMIN_JWT_SECRET=另一个64位十六进制字符串
|
||||||
|
```
|
||||||
|
|
||||||
|
### 管理员初始密码
|
||||||
|
|
||||||
|
`npm run db:init` 会使用 `.env` 中的 `ADMIN_USERNAME` 和 `ADMIN_PASSWORD` 创建管理员账号(bcrypt 哈希存储)。
|
||||||
|
|
||||||
|
```ini
|
||||||
|
ADMIN_USERNAME=admin
|
||||||
|
ADMIN_PASSWORD=一个强密码
|
||||||
|
```
|
||||||
|
|
||||||
|
> 生产环境不能使用默认值 `admin/admin`,服务启动时会报错退出。
|
||||||
|
|
||||||
|
### CORS
|
||||||
|
|
||||||
|
当前 CORS 设置为 `Access-Control-Allow-Origin: *`(见 `server/src/app.js`),允许所有来源。这是开发阶段的配置,生产环境应收紧为具体域名。
|
||||||
|
|
||||||
|
允许的自定义请求头:
|
||||||
|
|
||||||
|
```
|
||||||
|
Content-Type, Authorization, X-Device-Id, X-App-Version, X-Platform
|
||||||
|
```
|
||||||
|
|
||||||
|
## 小程序配置
|
||||||
|
|
||||||
|
### env.js
|
||||||
|
|
||||||
|
文件路径:`miniprogram/config/env.js`
|
||||||
|
|
||||||
|
```js
|
||||||
|
var ENV = 'test' // 可选值:local / test / prod
|
||||||
|
|
||||||
|
var API_BASES = {
|
||||||
|
local: 'http://localhost:3000',
|
||||||
|
test: 'https://api.vsai.net.cn',
|
||||||
|
prod: 'https://api.vsai.net.cn'
|
||||||
|
}
|
||||||
|
|
||||||
|
var __DEV__ = ENV !== 'prod'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### ENV 取值说明
|
||||||
|
|
||||||
|
| 值 | API 地址 | `__DEV__` | 说明 |
|
||||||
|
|----|---------|-----------|------|
|
||||||
|
| `local` | `http://localhost:3000` | `true` | 本地开发 |
|
||||||
|
| `test` | `https://api.vsai.net.cn` | `true` | 连接测试环境 |
|
||||||
|
| `prod` | `https://api.vsai.net.cn` | `false` | 生产环境 |
|
||||||
|
|
||||||
|
#### `__DEV__` 的作用
|
||||||
|
|
||||||
|
当 `__DEV__` 为 `true` 时:
|
||||||
|
|
||||||
|
- 启用 mock 绑定设备(无需蓝牙握手)
|
||||||
|
- 启用 mock 购买订阅(无需微信支付)
|
||||||
|
- 可能显示额外的调试信息
|
||||||
|
|
||||||
|
发布正式版时务必将 `ENV` 设为 `prod`。
|
||||||
|
|
||||||
|
### project.config.json
|
||||||
|
|
||||||
|
文件中的 `appid` 字段需要与实际的小程序 AppID 一致:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"appid": "wxc4045074ef298510",
|
||||||
|
"projectname": "hox-beauty"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
如果没有该 AppID 权限,在微信开发者工具中可以选择测试号。
|
||||||
|
|
||||||
|
## 管理后台配置
|
||||||
|
|
||||||
|
### env.js
|
||||||
|
|
||||||
|
文件路径:`admin-console/src/config/env.js`
|
||||||
|
|
||||||
|
```js
|
||||||
|
const ENV = 'test' // 可选值:local / test / prod
|
||||||
|
|
||||||
|
const API_BASES = {
|
||||||
|
local: 'http://localhost:3000',
|
||||||
|
test: 'https://api.vsai.net.cn',
|
||||||
|
prod: 'https://api.vsai.net.cn'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
与小程序的 `env.js` 功能一致,本地开发时改为 `local`。
|
||||||
|
|
||||||
|
### Vite base path
|
||||||
|
|
||||||
|
`admin-console/vite.config.js` 配置了 base 路径:
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default defineConfig({
|
||||||
|
base: process.env.PUBLIC_PATH || '/admin/',
|
||||||
|
plugins: [uni()]
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
- 默认 base 为 `/admin/`,意味着所有静态资源路径都会加上 `/admin/` 前缀
|
||||||
|
- 部署到 COS 后通过 `https://你的域名/admin/` 访问
|
||||||
|
- 本地开发时访问地址为 `http://localhost:5173/admin/`
|
||||||
|
- 如需改变路径前缀,设置环境变量 `PUBLIC_PATH`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PUBLIC_PATH=/console/ npm run build:h5
|
||||||
|
```
|
||||||
|
|
||||||
|
### 构建与部署
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 开发
|
||||||
|
npm run dev
|
||||||
|
|
||||||
|
# 构建 H5 产物
|
||||||
|
npm run build:h5
|
||||||
|
|
||||||
|
# 构建并部署到 COS
|
||||||
|
npm run deploy:cos
|
||||||
|
```
|
||||||
|
|
||||||
|
`deploy:cos` 脚本会将 `dist/build/h5/` 目录的文件上传到 COS 存储桶,需要在 `server/.env`(或管理后台自己的 `.env`)中配置好 `TENCENT_SECRET_ID`、`TENCENT_SECRET_KEY`、`COS_BUCKET` 等变量。
|
||||||
+441
@@ -0,0 +1,441 @@
|
|||||||
|
# 架构说明
|
||||||
|
|
||||||
|
## 1. 系统架构总览
|
||||||
|
|
||||||
|
```
|
||||||
|
+-----------------+
|
||||||
|
| 腾讯云 COS |
|
||||||
|
| (头像/固件存储) |
|
||||||
|
+--------^--------+
|
||||||
|
|
|
||||||
|
+------------------+ +--------+--------+ +------------------+
|
||||||
|
| | | | | |
|
||||||
|
| 微信小程序 +--->+ SCF 云函数 +<---+ 管理后台 |
|
||||||
|
| (用户端) | | (Express) | | (uni-app H5) |
|
||||||
|
| +<---+ +--->+ |
|
||||||
|
+-------+----------+ +--------+--------+ +------------------+
|
||||||
|
| |
|
||||||
|
| BLE | mysql2
|
||||||
|
v v
|
||||||
|
+-------+----------+ +--------+--------+
|
||||||
|
| 光子美容仪 | | MySQL |
|
||||||
|
| (蓝牙设备) | | (腾讯云) |
|
||||||
|
+------------------+ +-----------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
三端关系:
|
||||||
|
- **小程序** 通过 HTTPS 调用后端 API,通过 BLE 连接硬件设备
|
||||||
|
- **管理后台** 通过同一套后端 API(`/api/v1/admin/*`)管理数据
|
||||||
|
- **后端** 部署为腾讯云 SCF 云函数,连接 MySQL 和 COS
|
||||||
|
|
||||||
|
## 2. 后端架构
|
||||||
|
|
||||||
|
### 2.1 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
server/src/
|
||||||
|
├── index.js # SCF 入口,导出 main_handler
|
||||||
|
├── app.js # Express 应用,中间件 + 路由挂载
|
||||||
|
├── config.js # 环境变量配置
|
||||||
|
├── middleware/
|
||||||
|
│ └── auth.js # JWT 认证中间件
|
||||||
|
├── routes/
|
||||||
|
│ ├── auth.js # 登录/刷新 token
|
||||||
|
│ ├── user.js # 用户信息
|
||||||
|
│ ├── device.js # 设备绑定/解绑/指令
|
||||||
|
│ ├── subscription.js # 订阅计划/购买/试用
|
||||||
|
│ ├── treatment.js # 护理记录同步/查询
|
||||||
|
│ ├── firmware.js # 固件版本管理
|
||||||
|
│ └── admin.js # 管理后台全部接口
|
||||||
|
├── dao/
|
||||||
|
│ ├── index.js # barrel export
|
||||||
|
│ ├── user.dao.js # users 表
|
||||||
|
│ ├── device.dao.js # devices 表
|
||||||
|
│ ├── binding.dao.js # device_bindings 表
|
||||||
|
│ ├── subscription.dao.js # subscriptions 表
|
||||||
|
│ ├── treatment.dao.js # treatment_records 表
|
||||||
|
│ ├── command.dao.js # device_commands 表
|
||||||
|
│ ├── device-event.dao.js # device_events 表
|
||||||
|
│ ├── admin.dao.js # admin_accounts 表
|
||||||
|
│ ├── log.dao.js # operation_logs 表
|
||||||
|
│ ├── settings.dao.js # system_settings 表
|
||||||
|
│ └── firmware.dao.js # firmware_versions 表
|
||||||
|
└── lib/
|
||||||
|
├── serverless.js # SCF event → Express 适配器
|
||||||
|
├── db.js # mysql2 连接池 (query/one/transaction)
|
||||||
|
├── auth.js # JWT 签发/密码哈希/Bearer 读取
|
||||||
|
├── response.js # 统一响应 { code, message, data }
|
||||||
|
├── settings-cache.js # system_settings 内存缓存 (TTL 60s)
|
||||||
|
├── wechat.js # 微信 code2Session / 获取手机号
|
||||||
|
├── cos.js # 腾讯云 COS 客户端
|
||||||
|
└── utils.js # 日期格式化工具
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2 请求处理流程
|
||||||
|
|
||||||
|
```
|
||||||
|
SCF event
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
serverless.js 将 SCF event 转换为 http.IncomingMessage + ServerResponse
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
Express app(req, res)
|
||||||
|
│
|
||||||
|
├── express.json() 解析 JSON body
|
||||||
|
├── CORS 中间件 设置跨域头,处理 OPTIONS
|
||||||
|
├── rate limiter 对 login/upload 路径限流
|
||||||
|
├── authMiddleware 提取 x-forwarded-for → req.ip
|
||||||
|
│
|
||||||
|
├── /health 健康检查
|
||||||
|
├── /api/v1/auth/* → routes/auth.js
|
||||||
|
├── /api/v1/user/* → routes/user.js (requireUser)
|
||||||
|
├── /api/v1/device/* → routes/device.js (requireUser)
|
||||||
|
├── /api/v1/subscription/* → routes/subscription.js
|
||||||
|
├── /api/v1/treatment/* → routes/treatment.js (requireUser)
|
||||||
|
├── /api/v1/admin/* → routes/admin.js (requireAdmin)
|
||||||
|
├── /api/v1/firmware/* → routes/firmware.js
|
||||||
|
│
|
||||||
|
├── 404 handler
|
||||||
|
└── error handler 记录错误日志,返回 3001
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.3 认证机制
|
||||||
|
|
||||||
|
JWT 双密钥体系:
|
||||||
|
|
||||||
|
| 角色 | 签发函数 | 密钥 | payload 字段 |
|
||||||
|
|-------|-------------|---------------------|----------------------------|
|
||||||
|
| user | signUser() | config.jwt.secret | type, user_id, openid |
|
||||||
|
| admin | signAdmin() | config.jwt.adminSecret | type, admin_id, username, role |
|
||||||
|
|
||||||
|
中间件层级:
|
||||||
|
- `authMiddleware` — 全局,仅提取 IP,不验证 token
|
||||||
|
- `requireUser` — 路由级,验证 user token,查库确认用户存在且 status=1,挂载 `req.user`
|
||||||
|
- `requireAdmin` — 路由级,验证 admin token,查库确认管理员存在且 status=1,挂载 `req.admin`
|
||||||
|
|
||||||
|
token 刷新:客户端在 token 剩余 <24h 时自动调用 `/auth/refresh`,过期后有 1 天宽限期。
|
||||||
|
|
||||||
|
### 2.4 DAO 层
|
||||||
|
|
||||||
|
每个 DAO 文件只操作一张表,通过 `db.js` 提供的 `query/one/transaction` 与数据库交互:
|
||||||
|
|
||||||
|
| DAO 文件 | 负责表 | 核心操作 |
|
||||||
|
|-----------------------|---------------------|----------------------------------|
|
||||||
|
| user.dao.js | users | CRUD、openid 查找、分页列表 |
|
||||||
|
| device.dao.js | devices | 设备列表、按用户绑定关系查询 |
|
||||||
|
| binding.dao.js | device_bindings | 创建/确认/取消绑定、活跃绑定查询 |
|
||||||
|
| subscription.dao.js | subscriptions | 试用创建、购买(extend)、查有效订阅 |
|
||||||
|
| treatment.dao.js | treatment_records | 创建记录、按用户分页、更新设备状态 |
|
||||||
|
| command.dao.js | device_commands | 创建指令、拉取待执行、标记完成 |
|
||||||
|
| device-event.dao.js | device_events | 设备异常事件记录 |
|
||||||
|
| admin.dao.js | admin_accounts | 管理员查找/验证 |
|
||||||
|
| log.dao.js | operation_logs | 操作日志写入与分页查询 |
|
||||||
|
| settings.dao.js | system_settings | 全量读取系统配置 |
|
||||||
|
| firmware.dao.js | firmware_versions | 固件版本列表/最新版查询 |
|
||||||
|
|
||||||
|
### 2.5 工具库
|
||||||
|
|
||||||
|
| 文件 | 职责 |
|
||||||
|
|-------------------|-------------------------------------------------------------|
|
||||||
|
| response.js | `ok(data)` / `fail(code, msg)` 统一响应格式 |
|
||||||
|
| settings-cache.js | system_settings 内存缓存,TTL 60秒,`invalidateCache()` 手动失效 |
|
||||||
|
| wechat.js | 微信登录 `code2Session`、获取手机号 `getPhoneNumber` |
|
||||||
|
| cos.js | 腾讯云 COS 签名 URL 生成 |
|
||||||
|
| utils.js | `toMysqlDate()` 日期格式化(UTC+8) |
|
||||||
|
| wxpay.js | (规划中) 微信支付下单、回调签名验证 |
|
||||||
|
|
||||||
|
## 3. 小程序架构
|
||||||
|
|
||||||
|
### 3.1 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
miniprogram/
|
||||||
|
├── app.js / app.json / app.wxss # 应用入口
|
||||||
|
├── config/
|
||||||
|
│ └── env.js # API_BASE 配置
|
||||||
|
├── pages/ # 18 个页面
|
||||||
|
│ ├── login/ # 微信登录
|
||||||
|
│ ├── register/ # 补充信息
|
||||||
|
│ ├── index/ # 首页 (tab)
|
||||||
|
│ ├── scan/ # 扫码绑定
|
||||||
|
│ ├── auto-scan/ # 自动扫描蓝牙设备
|
||||||
|
│ ├── ble-connect/ # BLE 连接
|
||||||
|
│ ├── bind-success/ # 绑定成功
|
||||||
|
│ ├── subscribe-prompt/ # 订阅提示
|
||||||
|
│ ├── subscribe-plans/ # 选择计划
|
||||||
|
│ ├── subscribe-success/ # 订阅成功
|
||||||
|
│ ├── wear-check/ # 佩戴检测
|
||||||
|
│ ├── treatment-setup/ # 护理参数设置
|
||||||
|
│ ├── treating/ # 护理进行中
|
||||||
|
│ ├── treatment-done/ # 护理完成
|
||||||
|
│ ├── history/ # 护理记录 (tab)
|
||||||
|
│ ├── profile/ # 我的 (tab)
|
||||||
|
│ ├── help/ # 帮助
|
||||||
|
│ └── contact/ # 联系我们
|
||||||
|
├── services/
|
||||||
|
│ ├── ble.js # proxy → ble/index.js
|
||||||
|
│ ├── ble/ # BLE 模块(见 3.3)
|
||||||
|
│ └── command-sync.js # 远程指令拉取与执行
|
||||||
|
└── utils/
|
||||||
|
├── request.js # HTTP 请求封装
|
||||||
|
└── api.js # 命名 API 函数
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 页面导航流程
|
||||||
|
|
||||||
|
完整用户旅程(从登录到护理完成):
|
||||||
|
|
||||||
|
```
|
||||||
|
login ──→ register(新用户) ──→ index(首页)
|
||||||
|
│
|
||||||
|
┌───────┴──────┐
|
||||||
|
▼ ▼
|
||||||
|
scan auto-scan
|
||||||
|
(扫码绑定) (自动扫描BLE)
|
||||||
|
│ │
|
||||||
|
└──────┬───────┘
|
||||||
|
▼
|
||||||
|
ble-connect
|
||||||
|
(蓝牙连接设备)
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
bind-success
|
||||||
|
(绑定成功)
|
||||||
|
│
|
||||||
|
┌──────┴──────┐
|
||||||
|
▼ ▼
|
||||||
|
subscribe-prompt (已订阅则跳过)
|
||||||
|
(提示订阅)
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
subscribe-plans
|
||||||
|
(选择计划)
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
subscribe-success ──→ wear-check
|
||||||
|
(佩戴检测)
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
treatment-setup
|
||||||
|
(设置护理参数)
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
treating
|
||||||
|
(护理中)
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
treatment-done
|
||||||
|
(护理完成,同步记录)
|
||||||
|
```
|
||||||
|
|
||||||
|
底部 Tab 页:首页(index) | 记录(history) | 我的(profile)
|
||||||
|
|
||||||
|
### 3.3 BLE 模块拆分
|
||||||
|
|
||||||
|
```
|
||||||
|
services/ble.js # proxy,直接 re-export ble/index.js
|
||||||
|
│
|
||||||
|
services/ble/
|
||||||
|
├── index.js # barrel,统一导出所有 API
|
||||||
|
├── protocol.js # 协议常量 + 帧编解码
|
||||||
|
├── connection.js # 扫描/连接/断开/自动重连
|
||||||
|
└── commands.js # 指令发送 + ACK 管理
|
||||||
|
```
|
||||||
|
|
||||||
|
**协议模式**:`PROTOCOL_MODE = 'vendor_33'`,使用自定义 BLE 服务(FFE0/FFE1/FFE2)而非标准 GATT profile。
|
||||||
|
|
||||||
|
**关键设计决策**:
|
||||||
|
- connection.js 维护共享状态(`_deviceId`, `_connected`, `_chars`),commands.js 通过 getter 访问
|
||||||
|
- 事件系统在 connection.js 中实现(`on/off/emit`),心跳和状态通知作为独立事件分发
|
||||||
|
- command-sync.js 负责从服务器拉取待执行指令,逐条执行后上报结果
|
||||||
|
|
||||||
|
### 3.4 API 调用层
|
||||||
|
|
||||||
|
```
|
||||||
|
页面代码
|
||||||
|
│
|
||||||
|
│ var api = require('../../utils/api')
|
||||||
|
│ api.getProfile()
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
api.js 命名函数,封装路径和参数
|
||||||
|
│
|
||||||
|
│ http.get('/api/v1/user/profile')
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
request.js 统一封装 wx.request
|
||||||
|
│
|
||||||
|
├── 自动附加 Authorization / X-App-Version / X-Platform
|
||||||
|
├── token 过期前 <24h 自动刷新
|
||||||
|
├── code 1001/1002 → 清除 token → reLaunch 到登录页
|
||||||
|
└── 统一错误格式 { code, message }
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. 管理后台架构
|
||||||
|
|
||||||
|
### 4.1 SPA 架构
|
||||||
|
|
||||||
|
基于 uni-app (Vue 2) 构建的 H5 单页应用。不使用 vue-router,而是通过动态组件实现页面切换:
|
||||||
|
|
||||||
|
```
|
||||||
|
AdminLayout 固定侧边栏 + 顶栏
|
||||||
|
└── <keep-alive>
|
||||||
|
└── <component :is="currentComponent"> 动态视图
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 VIEW_MAP 与 KEEP_ALIVE_VIEWS
|
||||||
|
|
||||||
|
`pages/admin/index.vue` 中定义了两个核心映射:
|
||||||
|
|
||||||
|
```js
|
||||||
|
VIEW_MAP = {
|
||||||
|
dashboard: DashboardView,
|
||||||
|
device: DeviceListView,
|
||||||
|
'device-detail': DeviceDetailView,
|
||||||
|
user: UserListView,
|
||||||
|
'user-detail': UserDetailView,
|
||||||
|
subscription: SubscriptionView,
|
||||||
|
record: RecordView,
|
||||||
|
log: LogView,
|
||||||
|
settings: SettingsView
|
||||||
|
}
|
||||||
|
|
||||||
|
KEEP_ALIVE_VIEWS = [
|
||||||
|
'DeviceListView', 'UserListView',
|
||||||
|
'SubscriptionView', 'RecordView', 'LogView'
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
列表页被 keep-alive 缓存,从详情页返回时保留滚动位置和筛选状态。详情页(device-detail, user-detail)通过 `viewKey` 携带 ID,保证每次进入重新挂载。
|
||||||
|
|
||||||
|
导航通过 `$emit('navigate', viewName, props)` 冒泡到 index.vue,由 `onNavigate` 更新 `currentView` 和 `viewProps`。
|
||||||
|
|
||||||
|
### 4.3 API 调用模式
|
||||||
|
|
||||||
|
```
|
||||||
|
View 组件
|
||||||
|
│
|
||||||
|
│ import { get, post } from '../utils/request'
|
||||||
|
│ get('/api/v1/admin/users')
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
utils/request.js 基于 uni.request 封装
|
||||||
|
│
|
||||||
|
├── 自动附加 admin_token (Bearer)
|
||||||
|
├── code 1001/1002 → 清除 token → reLaunch 到登录页
|
||||||
|
└── 统一 resolve(data) / reject(error)
|
||||||
|
```
|
||||||
|
|
||||||
|
状态管理:Pinia store (`store/user.js`) 管理 admin token 和登录信息。
|
||||||
|
|
||||||
|
### 4.4 构建和部署
|
||||||
|
|
||||||
|
- 框架:uni-app,编译目标 H5
|
||||||
|
- 部署方式:构建产物上传至腾讯云 COS 静态托管,或直接部署到 SCF
|
||||||
|
- 菜单项:仪表盘、设备管理、用户管理、订阅管理、护理记录、操作日志、系统设置
|
||||||
|
|
||||||
|
## 5. 数据流
|
||||||
|
|
||||||
|
### 5.1 支付流程
|
||||||
|
|
||||||
|
```
|
||||||
|
用户点击购买 后端 微信支付
|
||||||
|
│ │ │
|
||||||
|
│ api.purchase(plan) │ │
|
||||||
|
├─────────────────────────────>│ │
|
||||||
|
│ │ (当前: 返回 order_id) │
|
||||||
|
│ { order_id, payment_params }│ │
|
||||||
|
│<─────────────────────────────│ │
|
||||||
|
│ │ │
|
||||||
|
│ === 正式支付流程(规划中) ====│ │
|
||||||
|
│ wx.requestPayment(params) │ │
|
||||||
|
│ ────────────────────────────┼───────────────────────────>│
|
||||||
|
│ │ 支付回调 (notify) │
|
||||||
|
│ │<───────────────────────────│
|
||||||
|
│ │ 验签 → 更新 subscription │
|
||||||
|
│ │ subscriptionDao.purchase() │
|
||||||
|
│ │ (extend 模式,叠加天数) │
|
||||||
|
│ │ │
|
||||||
|
│ === 开发环境替代方案 ========│ │
|
||||||
|
│ api.mockPurchase(plan) │ │
|
||||||
|
├─────────────────────────────>│ │
|
||||||
|
│ │ 直接激活订阅 │
|
||||||
|
│ { status: 'active' } │ │
|
||||||
|
│<─────────────────────────────│ │
|
||||||
|
```
|
||||||
|
|
||||||
|
订阅模型:`subscriptionDao.purchase()` 采用 extend 模式 —— 如已有有效订阅,在现有到期日基础上叠加天数,而非覆盖。
|
||||||
|
|
||||||
|
### 5.2 护理记录同步流程
|
||||||
|
|
||||||
|
```
|
||||||
|
treating 页面 BLE 设备 后端
|
||||||
|
│ │ │
|
||||||
|
│ ble.setParams({...}) │ │
|
||||||
|
├─────────────────────────────>│ │
|
||||||
|
│ ACK │ │
|
||||||
|
│<─────────────────────────────│ │
|
||||||
|
│ ble.startTreatment() │ │
|
||||||
|
├─────────────────────────────>│ │
|
||||||
|
│ status notify (周期) │ │
|
||||||
|
│<─────────────────────────────│ │
|
||||||
|
│ ...护理进行中... │ │
|
||||||
|
│ ble.stopTreatment() │ │
|
||||||
|
├─────────────────────────────>│ │
|
||||||
|
│ treatment_complete notify │ │
|
||||||
|
│<─────────────────────────────│ │
|
||||||
|
│ │ │
|
||||||
|
│ 跳转 treatment-done 页面 │
|
||||||
|
│ │
|
||||||
|
│ api.syncTreatment({ │
|
||||||
|
│ device_id, session_id, │
|
||||||
|
│ start_time, end_time, │
|
||||||
|
│ regions, duration_ms, │
|
||||||
|
│ mode, wavelength, │
|
||||||
|
│ battery, temperature, │
|
||||||
|
│ pd_values ... │
|
||||||
|
│ }) │
|
||||||
|
├───────────────────────────────────────────────────────>│
|
||||||
|
│ treatmentDao.create() │
|
||||||
|
│ treatmentDao. │
|
||||||
|
│ updateDevice() │
|
||||||
|
│ { record_id } │
|
||||||
|
│<───────────────────────────────────────────────────────│
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.3 设备绑定流程
|
||||||
|
|
||||||
|
```
|
||||||
|
用户 小程序 后端
|
||||||
|
│ │ │
|
||||||
|
│ 扫码/自动扫描获取 device_id│ │
|
||||||
|
│─────────────────────────────│ │
|
||||||
|
│ │ api.bindDevice(deviceId) │
|
||||||
|
│ ├───────────────────────────>│
|
||||||
|
│ │ │ 检查:用户未绑定其他设备
|
||||||
|
│ │ │ 检查:设备存在于 devices 表
|
||||||
|
│ │ │ 取消旧的 pending 绑定
|
||||||
|
│ │ │ 创建 pending 绑定 + bind_token
|
||||||
|
│ │ { device_id, bind_token } │
|
||||||
|
│ │<───────────────────────────│
|
||||||
|
│ │ │
|
||||||
|
│ │ BLE 连接设备 │
|
||||||
|
│ │ ble.connect(deviceId) │
|
||||||
|
│ │ ble.bindDevice(bind_token) │
|
||||||
|
│ │ ──BLE──> 设备 │
|
||||||
|
│ │ <──ACK── 设备 │
|
||||||
|
│ │ │
|
||||||
|
│ │ api.confirmBind( │
|
||||||
|
│ │ deviceId, bind_token) │
|
||||||
|
│ ├───────────────────────────>│
|
||||||
|
│ │ │ bindingDao.confirmBind()
|
||||||
|
│ │ │ pending → active
|
||||||
|
│ │ { message: 'success' } │
|
||||||
|
│ │<───────────────────────────│
|
||||||
|
│ │ │
|
||||||
|
│ 跳转 bind-success 页面 │ │
|
||||||
|
│<────────────────────────────│ │
|
||||||
|
```
|
||||||
|
|
||||||
|
绑定约束:一个用户同时只能绑定一台设备;绑定前需先通过 BLE 与设备完成配对确认。
|
||||||
+335
@@ -0,0 +1,335 @@
|
|||||||
|
# 部署指南
|
||||||
|
|
||||||
|
本文档面向将 jw-beauty 项目部署到腾讯云生产环境的运维人员。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 部署架构
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────┐ HTTPS ┌──────────────────┐
|
||||||
|
│ 微信小程序 │ ───────────────► │ SCF HTTP 函数 │
|
||||||
|
└─────────────┘ │ jw-beauty-api │
|
||||||
|
│ (Node.js 18) │
|
||||||
|
┌─────────────┐ HTTPS │ │ VPC 内网 ┌──────────────┐
|
||||||
|
│ 管理后台H5 │ ──► COS/CDN │ scf_bootstrap │ ──────────────────► │ TencentDB │
|
||||||
|
│ (UniApp) │ │ → local-server │ │ MySQL 5.7+ │
|
||||||
|
└─────────────┘ └──────────────────┘ └──────────────┘
|
||||||
|
│
|
||||||
|
│ COS SDK
|
||||||
|
▼
|
||||||
|
┌──────────────────┐
|
||||||
|
│ COS Bucket │
|
||||||
|
│ 头像/固件/后台H5 │
|
||||||
|
└──────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
| 组件 | 服务 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| 后端 API | 腾讯云 SCF (HTTP 函数) | Express 应用,通过 scf_bootstrap 启动 |
|
||||||
|
| 数据库 | TencentDB for MySQL | 同 VPC 内网连接,端口 3306 |
|
||||||
|
| 对象存储 | COS | 存放头像、固件包、管理后台静态文件 |
|
||||||
|
| API 域名 | api.vsai.net.cn | 指向 SCF 函数 URL / API 网关 |
|
||||||
|
| CDN 域名 | tx.vsai.net.cn | COS 自定义域名,用于头像和固件下载 |
|
||||||
|
| 小程序 | 微信小程序 | 通过微信开发者工具上传并提审 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 后端部署(SCF)
|
||||||
|
|
||||||
|
### 2.1 打包
|
||||||
|
|
||||||
|
部署包以 `server/` 为根目录打包,包含以下文件和目录:
|
||||||
|
|
||||||
|
```
|
||||||
|
index.js # SCF 入口 (exports.main_handler)
|
||||||
|
package.json
|
||||||
|
package-lock.json
|
||||||
|
scf_bootstrap # HTTP 函数启动脚本
|
||||||
|
scripts/ # local-server.js 等
|
||||||
|
src/ # 应用源码
|
||||||
|
sql/ # schema.sql
|
||||||
|
node_modules/ # 依赖
|
||||||
|
```
|
||||||
|
|
||||||
|
**不要** 把 `.env` 文件打进部署包。
|
||||||
|
|
||||||
|
打包命令:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd server
|
||||||
|
npm install --production
|
||||||
|
rm -f /tmp/hox-http-function.zip
|
||||||
|
zip -qry /tmp/hox-http-function.zip \
|
||||||
|
index.js package.json package-lock.json \
|
||||||
|
scripts scf_bootstrap src sql node_modules
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2 scf_bootstrap 配置
|
||||||
|
|
||||||
|
当前使用 HTTP 函数模式,`scf_bootstrap` 内容:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
export PORT=9000
|
||||||
|
node scripts/local-server.js
|
||||||
|
```
|
||||||
|
|
||||||
|
`scf_bootstrap` 必须有可执行权限。SCF 平台会直接运行此文件启动 HTTP 服务,监听 `PORT` 端口。
|
||||||
|
|
||||||
|
> 备注:`index.js` 中的 `main_handler` 是事件函数入口,目前未使用。如果切换到事件函数触发模式,SCF 入口改为 `index.main_handler`。
|
||||||
|
|
||||||
|
### 2.3 环境变量设置
|
||||||
|
|
||||||
|
在 SCF 控制台的函数配置中添加以下环境变量:
|
||||||
|
|
||||||
|
| 变量名 | 必填 | 说明 |
|
||||||
|
|--------|------|------|
|
||||||
|
| `NODE_ENV` | 是 | 必须设为 `production` |
|
||||||
|
| `PORT` | 否 | 默认 `9000`,scf_bootstrap 已设置 |
|
||||||
|
| `TENCENT_SECRET_ID` | 是 | 腾讯云 API 密钥 ID(COS 签名用) |
|
||||||
|
| `TENCENT_SECRET_KEY` | 是 | 腾讯云 API 密钥 Key |
|
||||||
|
| `TENCENT_REGION` | 否 | 默认 `ap-guangzhou` |
|
||||||
|
| `DB_HOST` | 是 | 数据库内网地址 |
|
||||||
|
| `DB_PORT` | 否 | 默认 `3306` |
|
||||||
|
| `DB_USER` | 是 | 数据库用户名 |
|
||||||
|
| `DB_PASSWORD` | 是 | 数据库密码 |
|
||||||
|
| `DB_NAME` | 否 | 默认 `jw_beauty` |
|
||||||
|
| `COS_BUCKET` | 否 | 默认 `jw-bucket-1426323813` |
|
||||||
|
| `COS_REGION` | 否 | 默认 `ap-guangzhou` |
|
||||||
|
| `COS_CDN_DOMAIN` | 否 | 默认 `tx.vsai.net.cn` |
|
||||||
|
| `WECHAT_APPID` | 是 | 微信小程序 AppID |
|
||||||
|
| `WECHAT_SECRET` | 是 | 微信小程序 AppSecret |
|
||||||
|
| `JWT_SECRET` | 是 | 用户 JWT 签名密钥(随机长字符串) |
|
||||||
|
| `ADMIN_JWT_SECRET` | 是 | 管理员 JWT 签名密钥(随机长字符串) |
|
||||||
|
| `ADMIN_USERNAME` | 是 | 初始管理员用户名(不要用默认 admin) |
|
||||||
|
| `ADMIN_PASSWORD` | 是 | 初始管理员密码(不要用默认 admin) |
|
||||||
|
|
||||||
|
> 生产环境安全检查:代码在 `NODE_ENV=production` 时会校验 `JWT_SECRET` 和 `ADMIN_JWT_SECRET` 不是默认值,`ADMIN_USERNAME` / `ADMIN_PASSWORD` 不是 `admin/admin`,否则启动报错。
|
||||||
|
|
||||||
|
参考模板文件:`server/.env.production.example`
|
||||||
|
|
||||||
|
### 2.4 VPC 网络配置
|
||||||
|
|
||||||
|
SCF 函数必须配置与 TencentDB 相同的 VPC 和子网,才能通过内网地址访问数据库。
|
||||||
|
|
||||||
|
操作步骤:
|
||||||
|
1. 在 SCF 控制台 → 函数管理 → 选择函数 → 函数配置 → 网络配置
|
||||||
|
2. 选择与 TencentDB 实例相同的 VPC 和子网
|
||||||
|
3. 确认安全组允许 SCF 访问数据库端口(默认 3306)
|
||||||
|
|
||||||
|
### 2.5 注意事项
|
||||||
|
|
||||||
|
- **冷启动**:SCF 冷启动时需加载 Node.js 运行时和 `node_modules`,首次请求延迟较高(约 1-3 秒)。可配置预置并发实例减少冷启动。
|
||||||
|
- **超时设置**:建议函数超时设为 30 秒以上。
|
||||||
|
- **内存**:建议 256MB 或以上。
|
||||||
|
- **日志**:错误日志通过 `console.error` 输出,可在 SCF 日志服务中查看。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 数据库初始化
|
||||||
|
|
||||||
|
### 3.1 连接 TencentDB
|
||||||
|
|
||||||
|
本地连接 TencentDB 需要:
|
||||||
|
- 数据库已开启公网访问,或通过 VPN/跳板机连接内网
|
||||||
|
- 安全组白名单中已添加本机公网 IP
|
||||||
|
- `DB_PORT` 使用控制台显示的公网端口
|
||||||
|
|
||||||
|
在 `server/.env` 中配置连接信息后执行:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd server
|
||||||
|
npm install
|
||||||
|
npm run db:init
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 执行 schema.sql
|
||||||
|
|
||||||
|
`db:init` 脚本会自动执行 `sql/schema.sql`,创建以下业务表:
|
||||||
|
|
||||||
|
| 表名 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `users` | 用户信息 |
|
||||||
|
| `devices` | 设备(产品码) |
|
||||||
|
| `bindings` | 用户-设备绑定关系 |
|
||||||
|
| `subscriptions` | 订阅记录 |
|
||||||
|
| `treatment_records` | 护理记录 |
|
||||||
|
| `device_events` | 设备事件 |
|
||||||
|
| `device_commands` | 远程指令队列 |
|
||||||
|
| `operation_logs` | 操作日志 |
|
||||||
|
| `admin_accounts` | 管理员账户 |
|
||||||
|
| `system_settings` | 系统设置 |
|
||||||
|
| `firmware_files` | 固件版本 |
|
||||||
|
|
||||||
|
同时写入默认系统设置(月卡价格、年卡价格、试用天数等)。
|
||||||
|
|
||||||
|
### 3.3 初始管理员创建
|
||||||
|
|
||||||
|
`db:init` 会使用环境变量 `ADMIN_USERNAME` / `ADMIN_PASSWORD` 创建初始管理员账户。
|
||||||
|
|
||||||
|
首次登录后应立即在管理后台修改默认密码。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 管理后台部署(COS)
|
||||||
|
|
||||||
|
### 4.1 构建
|
||||||
|
|
||||||
|
确认 `admin-console/src/config/env.js` 中 `ENV` 已设为 `prod`(或 API 地址正确):
|
||||||
|
|
||||||
|
```js
|
||||||
|
const ENV = 'prod'
|
||||||
|
```
|
||||||
|
|
||||||
|
然后构建:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd admin-console
|
||||||
|
npm install
|
||||||
|
npm run build:h5
|
||||||
|
```
|
||||||
|
|
||||||
|
构建产物位于 `admin-console/dist/build/h5/`。
|
||||||
|
|
||||||
|
### 4.2 上传到 COS
|
||||||
|
|
||||||
|
方式一:使用部署脚本(推荐)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd admin-console
|
||||||
|
npm run deploy:cos
|
||||||
|
```
|
||||||
|
|
||||||
|
脚本会读取 `server/.env` 中的 COS 凭证,将构建产物上传到 COS bucket 的 `admin/` 前缀下。
|
||||||
|
|
||||||
|
可通过环境变量自定义前缀:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ADMIN_COS_PREFIX=admin-test/ npm run deploy:cos
|
||||||
|
```
|
||||||
|
|
||||||
|
方式二:手动上传
|
||||||
|
|
||||||
|
通过 COS 控制台或 COSCMD 工具将 `dist/build/h5/` 目录下所有文件上传到 bucket 的 `admin/` 目录。
|
||||||
|
|
||||||
|
### 4.3 CDN/域名配置
|
||||||
|
|
||||||
|
管理后台通过 COS 的自定义域名(`tx.vsai.net.cn`)访问:
|
||||||
|
|
||||||
|
- 在 COS 控制台为 bucket 绑定自定义域名
|
||||||
|
- 配置 CDN 加速(可选)
|
||||||
|
- 访问地址:`https://tx.vsai.net.cn/admin/`
|
||||||
|
|
||||||
|
### 4.4 base path 设置
|
||||||
|
|
||||||
|
管理后台的路由 base path 为 `/admin/`,确保 COS 上传前缀与此一致。
|
||||||
|
|
||||||
|
如果需要配置单页应用(SPA)的 history 模式回退,可在 COS 静态网站配置中设置错误文档为 `/admin/index.html`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 小程序发布
|
||||||
|
|
||||||
|
### 5.1 环境切换
|
||||||
|
|
||||||
|
发布前将 `miniprogram/config/env.js` 中的 `ENV` 改为 `prod`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var ENV = 'prod'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2 微信开发者工具上传
|
||||||
|
|
||||||
|
1. 打开微信开发者工具
|
||||||
|
2. 导入项目目录 `miniprogram/`
|
||||||
|
3. 确认 AppID 正确
|
||||||
|
4. 点击"上传",填写版本号和备注
|
||||||
|
5. 在微信公众平台 → 版本管理 → 提交审核
|
||||||
|
|
||||||
|
### 5.3 审核注意事项
|
||||||
|
|
||||||
|
- **用户协议** 和 **隐私政策** 页面必须存在且内容完整,否则审核不通过
|
||||||
|
- 涉及蓝牙权限的小程序需要在 `app.json` 中声明并说明用途
|
||||||
|
- 隐私信息收集弹窗需符合微信规范
|
||||||
|
- 建议提交审核前在体验版充分测试
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 域名和证书
|
||||||
|
|
||||||
|
### 6.1 API 域名
|
||||||
|
|
||||||
|
| 域名 | 用途 | 指向 |
|
||||||
|
|------|------|------|
|
||||||
|
| `api.vsai.net.cn` | 后端 API | SCF 函数 URL / API 网关 |
|
||||||
|
|
||||||
|
需要配置 HTTPS 证书(腾讯云可申请免费 SSL 证书)。
|
||||||
|
|
||||||
|
### 6.2 COS CDN 域名
|
||||||
|
|
||||||
|
| 域名 | 用途 | 指向 |
|
||||||
|
|------|------|------|
|
||||||
|
| `tx.vsai.net.cn` | 头像/固件下载/管理后台 | COS bucket CDN |
|
||||||
|
|
||||||
|
在 COS 控制台绑定自定义域名并配置 HTTPS。
|
||||||
|
|
||||||
|
### 6.3 小程序合法域名配置
|
||||||
|
|
||||||
|
在微信公众平台 → 开发管理 → 开发设置 → 服务器域名中配置:
|
||||||
|
|
||||||
|
| 类型 | 域名 |
|
||||||
|
|------|------|
|
||||||
|
| request 合法域名 | `https://api.vsai.net.cn` |
|
||||||
|
| downloadFile 合法域名 | `https://tx.vsai.net.cn` |
|
||||||
|
| uploadFile 合法域名 | `https://api.vsai.net.cn` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 上线检查清单
|
||||||
|
|
||||||
|
### 环境配置
|
||||||
|
|
||||||
|
- [ ] `NODE_ENV=production` 已设置
|
||||||
|
- [ ] `JWT_SECRET` 和 `ADMIN_JWT_SECRET` 已更换为强随机字符串
|
||||||
|
- [ ] `ADMIN_USERNAME` / `ADMIN_PASSWORD` 已更换默认值
|
||||||
|
- [ ] 数据库连接使用 VPC 内网地址
|
||||||
|
- [ ] 安全组规则正确(SCF → MySQL 3306)
|
||||||
|
- [ ] COS 凭证配置正确
|
||||||
|
|
||||||
|
### 数据库
|
||||||
|
|
||||||
|
- [ ] `schema.sql` 已执行成功,所有表已创建
|
||||||
|
- [ ] 初始管理员已创建并更改了默认密码
|
||||||
|
- [ ] 默认系统设置已写入 `system_settings` 表
|
||||||
|
|
||||||
|
### 后端
|
||||||
|
|
||||||
|
- [ ] `GET /health` 返回 `{"code":0}`
|
||||||
|
- [ ] `POST /api/v1/admin/login` 可正常登录
|
||||||
|
- [ ] `GET /api/v1/admin/dashboard` 返回统计数据
|
||||||
|
- [ ] `GET /api/v1/admin/settings` 返回系统设置
|
||||||
|
|
||||||
|
### 管理后台
|
||||||
|
|
||||||
|
- [ ] 构建时 `ENV` 已设为 `prod`
|
||||||
|
- [ ] 构建产物已上传到 COS `admin/` 目录
|
||||||
|
- [ ] `https://tx.vsai.net.cn/admin/` 可正常访问
|
||||||
|
- [ ] 管理员可登录并查看仪表盘
|
||||||
|
|
||||||
|
### 小程序
|
||||||
|
|
||||||
|
- [ ] `miniprogram/config/env.js` 中 `ENV='prod'`
|
||||||
|
- [ ] 微信公众平台已配置 request/download/upload 合法域名
|
||||||
|
- [ ] 小程序登录流程正常
|
||||||
|
- [ ] 蓝牙扫码绑定流程正常
|
||||||
|
- [ ] 护理记录同步正常
|
||||||
|
- [ ] 用户协议和隐私政策页面内容完整
|
||||||
|
|
||||||
|
### 安全
|
||||||
|
|
||||||
|
- [ ] `.env` 文件未包含在部署包中
|
||||||
|
- [ ] 生产环境 `mock-bind` 和 `mock-purchase` 接口已自动禁用
|
||||||
|
- [ ] CORS 策略按需收紧(当前为 `*`)
|
||||||
|
- [ ] Rate limiting 已生效(登录 15min/10次,管理员 15min/5次)
|
||||||
+1297
文件差异内容过多而无法显示
加载差异
@@ -0,0 +1,34 @@
|
|||||||
|
# 开发文档
|
||||||
|
|
||||||
|
光子美容仪项目开发文档,面向开发者和运维人员。
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
| 文档 | 说明 | 适合谁读 |
|
||||||
|
|------|------|---------|
|
||||||
|
| [01-快速开始](01-快速开始.md) | 本地环境搭建、三端启动步骤、常见问题 | 新加入的开发者 |
|
||||||
|
| [02-配置说明](02-配置说明.md) | 所有环境变量详解、微信/支付/数据库/COS 配置 | 开发者、运维 |
|
||||||
|
| [03-架构说明](03-架构说明.md) | 系统架构、目录结构、数据流、模块设计 | 需要改代码的开发者 |
|
||||||
|
| [04-部署指南](04-部署指南.md) | 腾讯云 SCF/COS 部署、数据库初始化、上线检查清单 | 运维、负责发布的人 |
|
||||||
|
| [05-API接口文档](05-API接口文档.md) | 全部 42 个 API 接口的方法、参数、响应格式 | 前后端开发者 |
|
||||||
|
|
||||||
|
## 项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
jw-beauty/
|
||||||
|
├── miniprogram/ 小程序(微信原生)
|
||||||
|
├── server/ 后端(Express + SCF)
|
||||||
|
├── admin-console/ 管理后台(Vue 3 + uni-app H5)
|
||||||
|
└── docs/ 文档
|
||||||
|
├── dev/ 开发文档(本目录)
|
||||||
|
├── design/ 设计文档
|
||||||
|
├── protocols/ BLE 协议文档
|
||||||
|
└── deploy/ 部署笔记
|
||||||
|
```
|
||||||
|
|
||||||
|
## 快速链接
|
||||||
|
|
||||||
|
- 本地启动后端:`cd server && npm install && npm start`
|
||||||
|
- 健康检查:`curl http://localhost:3000/health`
|
||||||
|
- 管理后台开发:`cd admin-console && npm install && npm run dev:h5`
|
||||||
|
- 数据库初始化:`cd server && npm run db:init`
|
||||||
在新工单中引用
屏蔽一个用户