diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..729aef0 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,57 @@ +# rui-frontend 文档中心 + +> 本目录包含前端项目相关的设计文档、实施计划和开发规范。 +> 文档来源:`spring-ai/docs`(后端仓库),定期同步更新。 + +## 📁 目录结构 + +``` +docs/ +├── design/ # 设计文档 +│ ├── rui-admin功能设计文档.md +│ ├── cashier-design.md +│ └── admin-ui-module-build-design.md +├── plans/ # 实施计划 +│ └── cashier-admin-implementation.md +├── standards/ # 开发规范 +│ ├── 前端开发规则.md +│ └── API设计规范.md +└── README.md # 本文档 +``` + +## 📋 文档说明 + +### 设计文档(design/) + +| 文档 | 说明 | 来源 | +|------|------|------| +| `rui-admin功能设计文档.md` | rui-admin 管理后台功能模块设计 | spring-ai/docs | +| `cashier-design.md` | 收银系统(POS)整体架构设计 | spring-ai/docs/superpowers/specs | +| `admin-ui-module-build-design.md` | Admin-UI 分模块打包功能设计 | spring-ai/docs/superpowers/specs | + +### 实施计划(plans/) + +| 文档 | 说明 | 来源 | +|------|------|------| +| `cashier-admin-implementation.md` | 收银系统后台管理功能完善实施计划 | spring-ai/docs/superpowers/plans | + +### 开发规范(standards/) + +| 文档 | 说明 | 来源 | +|------|------|------| +| `前端开发规则.md` | 前端编码规范、目录结构、命名约定 | spring-ai/docs | +| `API设计规范.md` | RESTful API 设计规范 | spring-ai/docs | + +## 🔄 同步说明 + +当后端仓库 `spring-ai/docs` 中的文档更新时,前端仓库应同步更新副本: + +```bash +# 示例:同步收银系统设计文档 +cp ~/rhkj/spring-ai/docs/superpowers/specs/2026-06-03-cashier-design.md \ + ~/rhkj/rui-frontend/docs/design/cashier-design.md +``` + +## 📝 新增文档 + +如需新增前端专属文档,直接在此目录下创建,无需同步到后端仓库。 diff --git a/docs/design/admin-ui-module-build-design.md b/docs/design/admin-ui-module-build-design.md new file mode 100644 index 0000000..5774d80 --- /dev/null +++ b/docs/design/admin-ui-module-build-design.md @@ -0,0 +1,371 @@ +# Admin-UI 分模块打包功能设计文档 + +> **设计日期**: 2026-06-04 +> **版本**: v1.0 +> **状态**: 已批准 +> **目标**: 实现 Admin-UI 按系统配置分模块打包,支持不同租户类型输出不同产物包 + +--- + +## 一、背景与目标 + +### 1.1 现状分析 + +当前 Admin-UI 存在以下问题: + +1. **路由硬编码**:所有页面路由集中在 `router/index.ts` 中硬编码,无法按模块裁剪 +2. **构建产物单一**:无论服务哪个租户,都打包所有页面代码,产物体积大 +3. **缺乏系统差异化**:Dashboard、登录页等核心页面无法根据不同系统定制 +4. **模块管理已有雏形**:后端已支持租户模块配置(`ModuleDialog.vue`),但前端构建未与之配合 + +### 1.2 目标定义 + +1. **构建时分包**:根据 JSON 配置文件,构建时只打包指定模块的代码 +2. **动态路由生成**:替换硬编码路由,构建时根据配置动态生成路由表 +3. **系统差异化页面**:支持 Dashboard、登录页按系统配置加载不同子组件 +4. **多产物输出**:不同系统输出到 `dist/{systemKey}/` 目录 +5. **保持现有功能**:菜单 API 获取、权限控制、主题切换等功能不受影响 + +--- + +## 二、详细设计 + +### 2.1 整体架构 + +``` +构建流程: +┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐ +│ build-config/ │ │ Vite Plugin │ │ 构建产物 │ +│ cashier.json │────→│ (module-build) │────→│ dist/cashier/ │ +│ admin.json │ │ │ │ dist/admin/ │ +│ super.json │ │ 1. 读取配置 │ │ dist/super/ │ +└─────────────────┘ │ 2. 生成路由 │ │ │ + │ 3. 注入配置 │ └─────────────────┘ + │ 4. 配置输出 │ + └──────────────────┘ + +运行时: +┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐ +│ 统一入口页面 │────→│ 虚拟模块配置 │────→│ 系统特定子组件 │ +│ Dashboard │ │ __SYSTEM_CONFIG__│ │ systems/ │ +│ Login │ │ │ │ Cashier.vue │ +└─────────────────┘ └──────────────────┘ │ Super.vue │ + └─────────────────┘ +``` + +### 2.2 核心组件 + +#### 2.2.1 配置文件(`build-config/`) + +每个系统一个 JSON 配置文件: + +```typescript +interface BuildConfig { + /** 系统唯一标识,产物目录名 */ + key: string + /** 系统显示名称 */ + name: string + /** 系统描述 */ + description?: string + /** 包含的模块列表 */ + modules: string[] + /** 登录页配置 */ + login: { + /** 登录组件名(对应 views/login/systems/ 下的组件) */ + component: string + /** 是否显示租户ID输入 */ + showTenantInput: boolean + /** 页面标题 */ + title: string + /** 副标题 */ + subtitle?: string + /** 背景图路径 */ + background?: string + /** Logo路径 */ + logo?: string + } + /** Dashboard配置 */ + dashboard: { + /** Dashboard组件名(对应 views/dashboard/systems/ 下的组件) */ + component: string + /** 页面标题 */ + title: string + } + /** 主题配置 */ + theme: { + /** 主题色 */ + primaryColor: string + /** 页面标题 */ + title: string + } +} +``` + +**示例配置:** + +```json +// build-config/super.json +{ + "key": "super", + "name": "超级管理后台", + "description": "超级租户专用,包含租户管理", + "modules": ["system", "user"], + "login": { + "component": "Super", + "showTenantInput": false, + "title": "睿核平台管理", + "subtitle": "超级管理员登录" + }, + "dashboard": { + "component": "Super", + "title": "平台运营概览" + }, + "theme": { + "primaryColor": "#722ed1", + "title": "睿核平台管理" + } +} +``` + +```json +// build-config/cashier.json +{ + "key": "cashier", + "name": "收银系统", + "description": "面向收银场景的管理后台", + "modules": ["system", "user", "cms", "cashier"], + "login": { + "component": "Cashier", + "showTenantInput": true, + "title": "睿核收银", + "subtitle": "门店管理系统" + }, + "dashboard": { + "component": "Cashier", + "title": "收银数据概览" + }, + "theme": { + "primaryColor": "#1677ff", + "title": "睿核收银" + } +} +``` + +#### 2.2.2 Vite 插件(`scripts/vite-plugin-module-build.ts`) + +插件职责: + +1. **解析命令行参数**:读取 `--system={key}` 参数 +2. **加载配置**:读取 `build-config/{key}.json` +3. **生成虚拟路由模块**:`virtual:generated-routes` + - 根据 `config.modules` 从路由模板中组装路由表 + - 只包含指定模块的路由 + 核心页面路由(登录、Dashboard入口、个人中心、设置) +4. **生成虚拟配置模块**:`virtual:system-config` + - 将配置对象注入为全局常量 `__SYSTEM_CONFIG__` +5. **配置构建输出**: + - `build.outDir = dist/${config.key}` + - `build.rollupOptions.treeshake = true` 确保未使用代码被移除 + +**路由生成逻辑:** + +```typescript +// router/modules/system.ts +export const systemRoutes = [ + { path: 'system/menu', name: 'SystemMenu', component: () => import('@/views/system/menu/Index.vue'), meta: { i18n: 'menu.systemMenu' } }, + { path: 'system/role', name: 'SystemRole', component: () => import('@/views/system/role/Index.vue'), meta: { i18n: 'menu.systemRole' } }, + // ... +] + +// router/modules/user.ts +export const userRoutes = [ + { path: 'user/info', name: 'UserInfo', component: () => import('@/views/user/info/Index.vue'), meta: { i18n: 'menu.userInfo' } }, + // ... +] + +// 插件根据 config.modules 动态组装 +const moduleRoutes = config.modules.flatMap(module => { + const routeModule = routeModules[module] + return routeModule ? routeModule.routes : [] +}) +``` + +#### 2.2.3 统一入口页面 + +**Dashboard 入口(`views/dashboard/Index.vue`):** + +```vue + + + +``` + +**登录页入口(`views/login/Index.vue`):** + +```vue + + + +``` + +### 2.3 模块映射关系 + +建立 `src/views/` 下的页面目录与模块标识的映射: + +| 模块标识 | 对应目录 | 包含页面 | +|---------|---------|---------| +| `system` | `views/system/*` | 菜单、角色、部门、岗位、字典、配置、日志、登录日志、租户、租户套餐、数据权限、OAuth2客户端 | +| `user` | `views/user/*` | 用户信息、用户详情、等级、等级日志、地址、账户 | +| `order` | `views/order/*` | 订单列表、退款记录 | +| `cms` | `views/cms/*` | 文章、分类、轮播图 | +| `marketing` | `views/marketing/*` | 优惠券、活动管理 | +| `demo` | `views/demo/*` | 图标演示、列表演示 | +| `cashier` | `views/cashier/*` | 门店、包间、定价、订单、商品、报表 | + +**核心页面(所有系统默认包含,不依赖模块配置):** +- `views/login/Index.vue` - 登录页入口 +- `views/login/systems/*.vue` - 系统特定登录组件 +- `views/dashboard/Index.vue` - Dashboard 入口 +- `views/dashboard/systems/*.vue` - 系统特定 Dashboard 组件 +- `views/profile/Index.vue` - 个人中心 +- `views/settings/Index.vue` - 系统设置 + +### 2.4 目录结构 + +``` +admin-ui/ +├── build-config/ # 系统打包配置 +│ ├── cashier.json +│ ├── admin.json +│ ├── super.json +│ └── default.json # 默认配置(全模块,用于开发) +├── scripts/ # 构建脚本 +│ └── vite-plugin-module-build.ts # Vite 插件 +├── src/ +│ ├── router/ +│ │ ├── index.ts # 改造:使用虚拟路由模块 +│ │ └── modules/ # 新增:按模块拆分路由配置 +│ │ ├── core.ts # 核心路由(登录、Dashboard入口等) +│ │ ├── system.ts +│ │ ├── user.ts +│ │ ├── order.ts +│ │ ├── cms.ts +│ │ ├── marketing.ts +│ │ ├── demo.ts +│ │ └── cashier.ts +│ ├── views/ +│ │ ├── login/ +│ │ │ ├── Index.vue # 改造:统一入口 +│ │ │ └── systems/ # 新增:系统特定登录组件 +│ │ │ ├── Default.vue # 默认登录页 +│ │ │ ├── Super.vue # 超级租户登录页 +│ │ │ └── Cashier.vue # 收银系统登录页 +│ │ ├── dashboard/ +│ │ │ ├── Index.vue # 改造:统一入口 +│ │ │ └── systems/ # 新增:系统特定 Dashboard +│ │ │ ├── Default.vue # 默认 Dashboard +│ │ │ ├── Cashier.vue # 收银系统 Dashboard +│ │ │ └── Super.vue # 超级租户 Dashboard +│ │ └── ... # 业务页面(保持现有结构) +│ ├── types/ +│ │ └── system-config.d.ts # 系统配置类型定义 +│ └── ... +├── package.json # 改造:添加构建命令 +└── vite.config.ts # 改造:注册插件 +``` + +### 2.5 构建命令 + +```json +// package.json +{ + "scripts": { + "dev": "vite --port 3000", + "dev:cashier": "vite --port 3000 -- --system=cashier", + "dev:super": "vite --port 3000 -- --system=super", + "build": "vue-tsc && vite build", + "build:cashier": "vue-tsc && vite build -- --system=cashier", + "build:super": "vue-tsc && vite build -- --system=super", + "build:admin": "vue-tsc && vite build -- --system=admin", + "build:all": "pnpm build:cashier && pnpm build:super && pnpm build:admin" + } +} +``` + +**产物输出:** + +``` +dist/ +├── cashier/ # 收银系统(system + user + cms + cashier) +├── super/ # 超级租户(system + user) +├── admin/ # 普通后台(system + user + order + cms + marketing) +└── default/ # 默认(全模块,用于开发测试) +``` + +### 2.6 主题配置应用 + +系统配置中的 `theme` 字段在运行时应用: + +```typescript +// App.vue 或布局组件 +import systemConfig from 'virtual:system-config' + +// 设置页面标题 +document.title = systemConfig.theme.title + +// 设置主题色(Element Plus) +const el = document.documentElement +el.style.setProperty('--el-color-primary', systemConfig.theme.primaryColor) +``` + +--- + +## 三、验收标准 + +- [ ] 执行 `pnpm build:super` 成功构建,产物输出到 `dist/super/`,只包含 system 和 user 模块的页面 +- [ ] 执行 `pnpm build:cashier` 成功构建,产物输出到 `dist/cashier/`,包含 system、user、cms、cashier 模块的页面 +- [ ] 不同系统的 Dashboard 显示不同的子组件内容 +- [ ] 不同系统的登录页显示不同的子组件内容(超级租户无租户ID输入) +- [ ] 构建产物中不包含未配置模块的页面代码(Tree Shaking 生效) +- [ ] 现有菜单 API 获取、权限控制、主题切换功能正常 +- [ ] 开发模式 `pnpm dev:cashier` 正常工作,热更新无问题 + +--- + +## 四、风险与依赖 + +| 风险 | 影响 | 缓解措施 | +|------|------|---------| +| Vite 插件开发复杂度 | 中 | 插件逻辑清晰拆分:配置读取、路由生成、虚拟模块、输出配置 | +| Tree Shaking 不彻底 | 中 | 使用 `import()` 动态导入,配合 Rollup 的 `treeshake` 配置,构建后检查产物 | +| 动态组件加载失败 | 低 | 添加错误处理,加载失败时回退到 Default 组件 | +| 现有功能回归 | 中 | 构建后逐一验证核心功能:登录、菜单、CRUD、主题切换 | +| 多人协作冲突 | 低 | 配置文件集中管理,模块路由独立文件,减少冲突 | + +--- + +## 五、后续扩展 + +1. **国际化支持**:配置文件中可扩展 `locales` 字段,支持系统特定的翻译覆盖 +2. **模块懒加载**:未来可考虑运行时动态加载模块(Module Federation) +3. **版本管理**:配置文件支持 `version` 字段,用于产物版本控制 +4. **CI/CD 集成**:构建命令可直接接入 Jenkins/GitHub Actions,参数化构建不同系统 diff --git a/docs/design/cashier-design.md b/docs/design/cashier-design.md new file mode 100644 index 0000000..15716a2 --- /dev/null +++ b/docs/design/cashier-design.md @@ -0,0 +1,1126 @@ +# 收银系统(POS)设计文档 + +> **设计日期**: 2026-06-03 +> **版本**: v2.0 +> **状态**: 设计中 +> **目标**: 为棋牌室、酒吧、KTV 等服务业态构建多端收银系统,支持多门店连锁运营 + +--- + +## 一、背景与目标 + +### 1.1 现状分析 + +目前运营 100+ 棋牌室门店,采用总部 → 代理商 → 门店三级管理模式。各门店急需一套收银系统来管理包间/桌台的开台、计费、结账流程。现有系统空缺,依赖人工记账,效率低、易出错、无法统一管理。 + +### 1.2 目标定义 + +1. **建立标准化收银流程**:支持开台、计时/计费、结账、退款的完整闭环 +2. **多门店统一管理**:总部可查看所有门店数据,代理商管理名下门店,门店独立运营 +3. **多端覆盖**:管理后台(Web)、收银台(APP/小程序),后续扩展收银机、PC 端 +4. **灵活计费模式**:支持按时计费、包时段套餐、按局/圈等混合计费方式 +5. **复杂结算场景**:预付款/后付款、小程序下单、小商品分离结算 +6. **预留扩展能力**:会员钱包、优惠券/团购券、支付通道、第三方平台对接、智能设备控制 + +--- + +## 二、详细设计 + +### 2.1 整体架构 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 前端层 │ +├──────────────┬──────────────┬────────────────┬─────────────────┤ +│ 管理后台 │ 收银台 APP │ 顾客小程序 │ 第三方平台 │ +│ (admin-ui) │ (uni-app) │ (独立uni-app) │ (美团等) │ +│ Vue3+Element│ Vue3语法 │ 二期开发 │ 三期对接 │ +└──────────────┴──────────────┴────────────────┴─────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ 网关层 (rui-gateway) │ +│ 路由转发 │ 鉴权 │ 限流 │ 负载均衡 │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ 业务服务层 (app/rui-cashier/) │ +├──────────────┬──────────────┬────────────────┬─────────────────┤ +│ rui-cashier-store│ rui-cashier-order│ rui-cashier-product│ rui-cashier-report │ +│ 门店+包间服务 │ 订单服务 │ 商品服务 │ 报表服务 │ +│ │ │ │ │ +│ • 组织架构 │ • 开台/结账 │ • 商品档案 │ • 营业日报 │ +│ • 门店管理 │ • 计费规则 │ • 服务分类 │ • 数据统计 │ +│ • 包间/桌台 │ • 子订单管理 │ • 定价管理 │ • 趋势分析 │ +│ • 套餐策略 │ • 退款处理 │ │ │ +│ • 设备管理 │ │ │ │ +└──────────────┴──────────────┴────────────────┴─────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ 基础设施层 │ +│ MySQL 8.0 │ Redis │ Nacos │ MQ(RabbitMQ) │ Seata │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 2.2 服务职责划分 + +#### rui-cashier-store(门店+包间服务) + +**职责**:组织架构、门店管理、包间/桌台管理、套餐策略、设备管理 + +**核心实体**: +- `Store`(门店):基本信息、所属代理商、营业状态、配置 +- `StoreConfig`(门店配置):预付款/后付款、余额支付商品开关等 +- `Agent`(代理商):基本信息、管理的门店列表 +- `RoomType`(包间类型):名称、容纳人数 +- `Room`(包间/桌台):所属门店、类型、状态、设备绑定 +- `PricingStrategy`(定价策略):包间类型关联的套餐集合 +- `PricingPackage`(套餐):具体的价格套餐,支持时段/日期限制 +- `Device`(设备):网关、门锁、电源、音箱、打印机、锁球器等 + +**套餐策略设计**(核心变更): + +```java +// 计费方式枚举 +public enum BillingType { + HOURLY(1, "按时计费"), // 按小时计费,可设最低消费时长 + FIXED_PERIOD(2, "包时段"), // 固定时段买断,如包下午场 + PER_GAME(3, "按局计费"), // 按局/圈计费 + MIXED(4, "混合模式"); // 组合计费 +} + +// 定价策略(一个包间类型对应一个策略,包含多条套餐) +@Data +public class PricingStrategy { + private Long id; + private Long roomTypeId; // 包间类型ID + private String strategyName; // 策略名称,如"标准计费" + private Integer status; // 状态:0-禁用 1-启用 +} + +// 套餐(策略中的具体套餐项) +@Data +public class PricingPackage { + private Long id; + private Long strategyId; // 所属策略ID + private String packageName; // 套餐名称,如"3小时套餐" + private Integer billingType; // 计费方式 + private BigDecimal price; // 套餐价格 + private Integer duration; // 时长(分钟),包时段时有效 + private Integer sort; // 排序,第一条是默认/fallback + + // 限制条件(JSON格式) + private String restrictions; // { + // "weekdays": [1,2,3,4,5], // 工作日可用 + // "weekends": [6,7], // 周末可用 + // "timeRanges": [ // 时段范围 + // {"start": "08:00", "end": "12:00"} + // ], + // "holidays": { // 节假日设置 + // "mode": "EXCLUDE", // EXCLUDE-不可用 INCLUDE-仅可用 + // "dates": ["2026-10-01", "2026-10-02"] + // } + // } + + private Integer isDefault; // 是否默认套餐(1-是 0-否),默认套餐不可配置限制条件 + private Integer status; // 状态:0-禁用 1-启用 +} +``` + +**套餐匹配逻辑**: + +```java +public PricingPackage matchPackage(Long roomTypeId, LocalDateTime startTime) { + // 1. 获取包间类型的定价策略 + PricingStrategy strategy = strategyService.getByRoomTypeId(roomTypeId); + + // 2. 获取策略下的所有套餐,按 sort 排序 + List packages = packageService.getByStrategyId(strategy.getId()); + + // 3. 依次匹配套餐限制条件 + for (PricingPackage pkg : packages) { + if (pkg.getIsDefault() == 1) { + continue; // 默认套餐跳过,作为fallback + } + if (matchRestrictions(pkg.getRestrictions(), startTime)) { + return pkg; // 找到匹配的套餐 + } + } + + // 4. 没有匹配的,返回默认套餐(第一条) + return packages.stream() + .filter(p -> p.getIsDefault() == 1) + .findFirst() + .orElseThrow(() -> new BizException("无可用套餐")); +} +``` + +**包间状态机**: + +``` +空闲 ──[开台]──► 使用中 ──[结账]──► 待清洁 ──[清洁完成]──► 空闲 + ▲ │ │ + │ │ [挂单] │ + │ ▼ │ + │ 已挂单 ──[恢复]───────────────────┘ + │ │ + │ │ [预约](二期) + │ ▼ + │ 已预约 ──[开台]──► 使用中 + │ + └──[取消预约]─── 已预约 +``` + +#### rui-cashier-order(订单服务) + +**职责**:开台、计费计算、结账、退款、订单生命周期管理 + +**核心实体**: +- `Order`(主订单):订单整体信息 +- `RoomSubOrder`(包间子订单):包间消费、计时计费 +- `ProductSubOrder`(商品子订单):小商品消费 +- `OrderTimeline`(订单时间线):开台、结账等关键时间点 + +**订单体系设计**(核心变更): + +```java +// 主订单 +@Data +public class Order { + private Long id; + private String orderNo; // 订单编号 + private Long storeId; // 门店ID + private Long roomId; // 包间ID(包间订单时) + private Integer orderType; // 订单类型:1-包间订单 2-纯商品订单 + private String customerName; // 顾客姓名 + private String customerPhone; // 顾客电话 + + // 金额汇总 + private BigDecimal roomAmount; // 包间费用 + private BigDecimal productAmount; // 商品费用 + private BigDecimal discountAmount;// 优惠金额 + private BigDecimal totalAmount; // 订单总金额 + private BigDecimal payAmount; // 实付金额 + + // 支付信息 + private Integer payStatus; // 支付状态:0-未支付 1-部分支付 2-已支付 + private Integer payType; // 支付方式 + private LocalDateTime payTime; // 支付时间 + + // 状态 + private Integer status; // 订单状态 + private String remark; // 备注 + private Long cashierId; // 收银员ID +} + +// 包间子订单 +@Data +public class RoomSubOrder { + private Long id; + private Long orderId; // 主订单ID + private Long roomId; // 包间ID + private Long packageId; // 使用的套餐ID + private Integer billingType; // 计费方式 + private BigDecimal price; // 套餐价格/单价 + private LocalDateTime startTime; // 开台时间 + private LocalDateTime endTime; // 结账时间 + private Integer duration; // 使用时长(分钟) + private Integer gameCount; // 局数 + private BigDecimal amount; // 包间费用 + private Integer status; // 状态 +} + +// 商品子订单 +@Data +public class ProductSubOrder { + private Long id; + private Long orderId; // 主订单ID + private Long productId; // 商品ID + private String productName; // 商品名称 + private BigDecimal productPrice; // 商品单价 + private Integer quantity; // 数量 + private BigDecimal amount; // 小计金额 + private Integer payStatus; // 支付状态(单独控制) + private Integer source; // 来源:1-收银台 2-顾客小程序 + private LocalDateTime createTime; // 创建时间 +} +``` + +**结算场景支持**: + +```java +// 门店配置 +@Data +public class StoreConfig { + private Long storeId; + private Integer productPayMode; // 商品支付模式:1-先付款 2-后付款 + private Integer balancePayProduct;// 余额是否可支付商品:0-否 1-是 + private Integer notifyOnOrder; // 下单是否通知:0-否 1-是(喇叭+打印) +} + +// 结算逻辑 +public void checkout(Long orderId) { + Order order = orderService.getById(orderId); + StoreConfig config = storeService.getConfig(order.getStoreId()); + + // 1. 计算包间费用 + RoomSubOrder roomOrder = roomSubOrderService.getByOrderId(orderId); + BigDecimal roomAmount = calculateRoomAmount(roomOrder); + + // 2. 计算商品费用 + List products = productSubOrderService.getByOrderId(orderId); + BigDecimal productAmount = products.stream() + .map(ProductSubOrder::getAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add); + + // 3. 计算优惠(预留) + BigDecimal discountAmount = discountService.calculate(orderId); + + // 4. 计算应付金额 + BigDecimal totalAmount = roomAmount.add(productAmount).subtract(discountAmount); + + // 5. 如果商品是先付款模式,商品费用已从实付中扣除 + if (config.getProductPayMode() == 1) { + BigDecimal paidProductAmount = products.stream() + .filter(p -> p.getPayStatus() == 2) + .map(ProductSubOrder::getAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add); + totalAmount = totalAmount.subtract(paidProductAmount); + } + + // 6. 更新订单 + order.setRoomAmount(roomAmount); + order.setProductAmount(productAmount); + order.setDiscountAmount(discountAmount); + order.setTotalAmount(totalAmount); + order.setStatus(2); // 待支付 + orderService.update(order); +} +``` + +**开台流程**(支持小程序预下单): + +``` +场景1:收银台直接开台 +1. 收银员选择包间 → 检查包间状态"空闲" +2. 选择套餐(系统自动匹配当前时段可用套餐) +3. 确认顾客信息 +4. 创建主订单 + 包间子订单 +5. 包间状态变更为"使用中" + +场景2:顾客小程序预订包间 +1. 顾客选择门店、包间类型、时间段 +2. 系统匹配可用套餐,显示价格 +3. 顾客支付包间费用(预付款) +4. 创建主订单 + 包间子订单(状态:已支付) +5. 顾客到店后,收银员确认开台,包间状态变更为"使用中" + +场景3:顾客小程序购买小商品 +1. 顾客扫描包间二维码 +2. 浏览商品,下单 +3. 如果门店配置"先付款":在线支付 → 创建商品子订单 +4. 如果门店配置"后付款":创建商品子订单(未支付) +5. 触发智能喇叭通知、打印小票(如配置) +6. 后付款的商品可在收银台统一结算 +``` + +#### rui-cashier-product(商品服务) + +**职责**:商品/服务档案管理、分类管理、价格管理 + +**核心实体**: +- `Product`(商品/服务):名称、分类、价格、状态 +- `ProductCategory`(分类):名称、层级、排序 +- `StoreProduct`(门店商品):门店可售商品及自定义价格 + +**设计要点**: +- 商品分为"普通商品"(饮料、零食)和"服务商品"(加时、换桌等) +- 支持总部统一配置,门店可自定义价格和上下架 + +#### rui-cashier-report(报表服务) + +**职责**:营业数据统计、报表生成、数据看板 + +**核心功能**: +- 营业日报:按门店、按日期统计营业额、订单数、客单价 +- 包间利用率:各包间使用时长/空闲时长占比 +- 时段分析:高峰时段、低谷时段统计 +- 代理商汇总:名下门店汇总数据 +- 商品销售统计:各商品销量、销售额 + +**技术要点**: +- 报表数据定时从 order 服务同步,避免实时查询拖垮核心服务 +- 支持按门店、代理商、时间维度筛选 + +### 2.3 数据流 + +#### 开台-结账核心流程 + +``` +收银员(APP)/ 顾客(小程序) + │ + ▼ +[选择包间/商品] ──► rui-cashier-store(检查包间状态/商品库存) + │ + ▼ +[确认开台/下单] ──► rui-cashier-order(创建订单) + │ │ + │ ├─ 创建主订单 + │ ├─ 创建包间子订单(或商品子订单) + │ ▼ + │ 包间状态变更为"使用中" + │ │ + ▼ ▼ +[追加商品] ──► rui-cashier-product(查询商品) + │ │ + │ ▼ + │ 创建商品子订单 + │ 触发硬件通知(喇叭+打印,如配置) + ▼ +[结账] ─────► rui-cashier-order(计算费用) + │ │ + │ ├─ 计算包间费用(按时/套餐) + │ ├─ 汇总商品费用(扣除已支付的) + │ ├─ 计算优惠(预留) + │ ▼ + │ 生成应付金额 + │ │ + ▼ ▼ +[支付完成] ──► rui-cashier-order(更新订单状态) + │ │ + │ ▼ + │ 包间状态变更为"待清洁" + ▼ +[清洁完成] ──► rui-cashier-store(包间状态变更为"空闲") +``` + +### 2.4 接口设计 + +#### rui-cashier-store 核心接口 + +```yaml +# 门店管理 +POST /cashier/admin/store # 创建门店 +PUT /cashier/admin/store/{id} # 更新门店 +GET /cashier/admin/store/{id} # 门店详情 +GET /cashier/admin/store/list # 门店列表(按代理商筛选) +DELETE /cashier/admin/store/{id} # 删除门店 + +# 门店配置 +GET /cashier/admin/store/{id}/config # 获取门店配置 +PUT /cashier/admin/store/{id}/config # 更新门店配置 + +# 包间类型管理 +POST /cashier/admin/room-type # 创建包间类型 +PUT /cashier/admin/room-type/{id} # 更新包间类型 +GET /cashier/admin/room-type/list # 包间类型列表 + +# 包间管理 +POST /cashier/admin/room # 创建包间 +PUT /cashier/admin/room/{id} # 更新包间 +GET /cashier/admin/room/list # 包间列表(按门店筛选) +GET /cashier/admin/room/{id}/status # 包间实时状态 + +# 定价策略管理 +POST /cashier/admin/pricing-strategy # 创建定价策略 +PUT /cashier/admin/pricing-strategy/{id} # 更新定价策略 +GET /cashier/admin/pricing-strategy/list # 策略列表 + +# 套餐管理 +POST /cashier/admin/pricing-package # 创建套餐 +PUT /cashier/admin/pricing-package/{id} # 更新套餐 +GET /cashier/admin/pricing-package/list # 套餐列表(按策略筛选) + +# 设备管理 +POST /cashier/admin/device # 注册设备 +PUT /cashier/admin/device/{id} # 更新设备 +GET /cashier/admin/device/list # 设备列表 +POST /cashier/admin/device/{id}/control # 设备控制(预留) +``` + +#### rui-cashier-order 核心接口 + +```yaml +# 开台 +POST /cashier/admin/order/open # 开台(创建订单) + body: { + "roomId": 1, + "packageId": 1, # 选择的套餐ID + "customerName": "张三", // 可选 + "customerPhone": "138...", // 可选 + "remark": "..." // 备注 + } + +# 追加商品(收银台) +POST /cashier/admin/order/{id}/product # 追加商品到订单 + body: { + "productId": 1, + "quantity": 2, + "price": 15.00 + } + +# 顾客小程序下单商品 +POST /cashier/app/order/{id}/product # 顾客下单商品 + body: { + "productId": 1, + "quantity": 2, + "source": 2 // 来源:2-顾客小程序 + } + +# 结账 +POST /cashier/admin/order/{id}/checkout # 结账 + response: { + "orderId": 1, + "roomAmount": 120.00, // 包间费用 + "productAmount": 30.00, // 商品费用(未支付部分) + "paidProductAmount": 20.00, // 已支付商品金额 + "discountAmount": 0.00, // 优惠金额(预留) + "totalAmount": 130.00, // 应付金额 + "duration": 120, // 使用时长(分钟) + "startTime": "2026-06-03T10:00:00", + "endTime": "2026-06-03T12:00:00" + } + +# 确认支付 +POST /cashier/admin/order/{id}/pay # 确认支付(预留支付通道) + body: { + "payType": "CASH", // CASH-现金, WECHAT-微信, ALIPAY-支付宝, BALANCE-余额 + "amount": 130.00, + "remark": "..." + } + +# 商品子订单支付(小程序先付款) +POST /cashier/app/product-order/{id}/pay # 商品子订单支付 + body: { + "payType": "WECHAT", + "amount": 20.00 + } + +# 退款 +POST /cashier/admin/order/{id}/refund # 订单退款 + body: { + "refundAmount": 130.00, + "reason": "..." + } + +# 订单查询 +GET /cashier/admin/order/{id} # 订单详情 +GET /cashier/admin/order/list # 订单列表(按门店、日期筛选) +GET /cashier/admin/order/{id}/timeline # 订单时间线 + +# 包间状态操作 +POST /cashier/admin/room/{id}/clean # 清洁完成(包间恢复空闲) +``` + +### 2.5 数据库设计 + +#### 门店表(rui_cashier_store) + +```sql +CREATE TABLE #prefix#cashier_store ( + id BIGINT PRIMARY KEY COMMENT '门店ID', + agent_id BIGINT NOT NULL COMMENT '所属代理商ID', + store_name VARCHAR(100) NOT NULL COMMENT '门店名称', + store_code VARCHAR(50) NOT NULL COMMENT '门店编码', + contact_name VARCHAR(50) COMMENT '联系人', + contact_phone VARCHAR(20) COMMENT '联系电话', + address VARCHAR(200) COMMENT '地址', + business_hours VARCHAR(50) COMMENT '营业时间', + status TINYINT DEFAULT 1 COMMENT '状态:0-禁用 1-启用', + remark VARCHAR(500) COMMENT '备注', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + deleted TINYINT DEFAULT 0 COMMENT '删除标志', + create_by BIGINT COMMENT '创建人', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_by BIGINT COMMENT '更新人', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', + UNIQUE KEY uk_store_code (store_code), + KEY idx_agent_id (agent_id) +) COMMENT='门店表'; +``` + +#### 门店配置表(rui_cashier_store_config) + +```sql +CREATE TABLE #prefix#cashier_store_config ( + id BIGINT PRIMARY KEY COMMENT '配置ID', + store_id BIGINT NOT NULL COMMENT '门店ID', + config JSON NOT NULL COMMENT '配置内容:{ + \"productPayMode\": 2, // 商品支付模式:1-先付款 2-后付款 + \"balancePayProduct\": 0, // 余额是否可支付商品:0-否 1-是 + \"notifyOnOrder\": 1, // 下单是否通知:0-否 1-是 + \"autoCleanTime\": 10, // 自动清洁时间(分钟) + \"minDeposit\": 50.00, // 最低押金(可选) + \"overtimeRule\": { // 超时规则(可选) + \"type\": 1, // 1-按小时收费 2-按套餐收费 + \"price\": 20.00 + } + }', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', + UNIQUE KEY uk_store_id (store_id) +) COMMENT='门店配置表'; +``` + +#### 包间类型表(rui_cashier_room_type) + +```sql +CREATE TABLE #prefix#cashier_room_type ( + id BIGINT PRIMARY KEY COMMENT '类型ID', + store_id BIGINT NOT NULL COMMENT '所属门店ID', + type_name VARCHAR(50) NOT NULL COMMENT '类型名称', + capacity INT DEFAULT 4 COMMENT '容纳人数', + icon VARCHAR(200) COMMENT '图标', + sort INT DEFAULT 0 COMMENT '排序', + status TINYINT DEFAULT 1 COMMENT '状态:0-禁用 1-启用', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + deleted TINYINT DEFAULT 0 COMMENT '删除标志', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', + KEY idx_store_id (store_id) +) COMMENT='包间类型表'; +``` + +#### 包间表(rui_cashier_room) + +```sql +CREATE TABLE #prefix#cashier_room ( + id BIGINT PRIMARY KEY COMMENT '包间ID', + store_id BIGINT NOT NULL COMMENT '所属门店ID', + room_type_id BIGINT NOT NULL COMMENT '包间类型ID', + room_name VARCHAR(50) NOT NULL COMMENT '包间名称', + room_no VARCHAR(20) NOT NULL COMMENT '包间编号', + room_status TINYINT DEFAULT 0 COMMENT '状态:0-空闲 1-使用中 2-待清洁 3-已挂单 4-已预约', + current_order_id BIGINT COMMENT '当前订单ID', + device_config JSON COMMENT '设备配置(关联的设备ID列表)', + sort INT DEFAULT 0 COMMENT '排序', + enabled TINYINT DEFAULT 1 COMMENT '启用状态:0-禁用 1-启用', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + deleted TINYINT DEFAULT 0 COMMENT '删除标志', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', + UNIQUE KEY uk_room_no (store_id, room_no), + KEY idx_store_id (store_id), + KEY idx_room_status (room_status) +) COMMENT='包间表'; +``` + +#### 定价策略表(rui_cashier_pricing_strategy) + +```sql +CREATE TABLE #prefix#cashier_pricing_strategy ( + id BIGINT PRIMARY KEY COMMENT '策略ID', + room_type_id BIGINT NOT NULL COMMENT '包间类型ID', + strategy_name VARCHAR(50) NOT NULL COMMENT '策略名称', + status TINYINT DEFAULT 1 COMMENT '状态:0-禁用 1-启用', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + deleted TINYINT DEFAULT 0 COMMENT '删除标志', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', + UNIQUE KEY uk_room_type_id (room_type_id), + KEY idx_status (status) +) COMMENT='定价策略表'; +``` + +#### 套餐表(rui_cashier_pricing_package) + +```sql +CREATE TABLE #prefix#cashier_pricing_package ( + id BIGINT PRIMARY KEY COMMENT '套餐ID', + strategy_id BIGINT NOT NULL COMMENT '策略ID', + package_name VARCHAR(50) NOT NULL COMMENT '套餐名称', + billing_type TINYINT NOT NULL COMMENT '计费方式:1-按时 2-包时段 3-按局', + price DECIMAL(19,4) NOT NULL COMMENT '套餐价格', + duration INT COMMENT '时长(分钟),包时段时有效', + min_duration INT DEFAULT 60 COMMENT '最低消费时长(分钟),按时计费时有效', + restrictions JSON COMMENT '限制条件(时段、工作日、节假日)', + is_default TINYINT DEFAULT 0 COMMENT '是否默认套餐:0-否 1-是', + sort INT DEFAULT 0 COMMENT '排序', + status TINYINT DEFAULT 1 COMMENT '状态:0-禁用 1-启用', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + deleted TINYINT DEFAULT 0 COMMENT '删除标志', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', + KEY idx_strategy_id (strategy_id), + KEY idx_status (status) +) COMMENT='套餐表'; +``` + +#### 设备表(rui_cashier_device) + +```sql +CREATE TABLE #prefix#cashier_device ( + id BIGINT PRIMARY KEY COMMENT '设备ID', + store_id BIGINT NOT NULL COMMENT '所属门店ID', + room_id BIGINT COMMENT '关联包间ID(设备可在公共区域,此时为空)', + location VARCHAR(100) COMMENT '设备位置:前台、茶水间、大厅等(设备在公共区域时填写)', + device_name VARCHAR(50) NOT NULL COMMENT '设备名称', + device_code VARCHAR(50) NOT NULL COMMENT '设备编号(唯一标识)', + device_type TINYINT NOT NULL COMMENT '设备类型:1-网关 2-门锁 3-电源 4-音箱 5-打印机 6-锁球器', + parent_id BIGINT COMMENT '父设备ID(门锁/电源等关联网关)', + online_status TINYINT DEFAULT 0 COMMENT '在线状态:0-离线 1-在线', + last_heartbeat DATETIME(3) COMMENT '最后心跳时间', + -- 4G设备信息 + imei VARCHAR(20) COMMENT 'IMEI号(4G设备)', + sim_card_no VARCHAR(20) COMMENT '流量卡号(4G设备)', + sim_operator VARCHAR(20) COMMENT '运营商(移动/联通/电信)', + sim_expire_date DATE COMMENT '流量卡到期日期', + -- 设备功能配置 + functions JSON COMMENT '设备功能配置:{ + \"speaker\": { // 音箱功能(电源控制器自带音箱时) + \"enabled\": true, + \"type\": \"EXTERNAL\", // EXTERNAL-外置 INTERNAL-内置 + \"volume\": 80 // 音量 0-100 + }, + \"power\": { // 电源功能 + \"channels\": 4, // 通道数 + \"channelNames\": [\"照明\", \"空调\", \"插座\", \"备用\"] + } + }', + config JSON COMMENT '扩展配置', + sort INT DEFAULT 0 COMMENT '排序', + status TINYINT DEFAULT 1 COMMENT '状态:0-禁用 1-启用', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + deleted TINYINT DEFAULT 0 COMMENT '删除标志', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', + UNIQUE KEY uk_device_code (device_code), + KEY idx_store_id (store_id), + KEY idx_room_id (room_id), + KEY idx_device_type (device_type), + KEY idx_imei (imei) +) COMMENT='设备表'; +``` + +#### 主订单表(rui_cashier_order) + +```sql +CREATE TABLE #prefix#cashier_order ( + id BIGINT PRIMARY KEY COMMENT '订单ID', + order_no VARCHAR(32) NOT NULL COMMENT '订单编号', + store_id BIGINT NOT NULL COMMENT '门店ID', + room_id BIGINT COMMENT '包间ID(包间订单时)', + order_type TINYINT DEFAULT 1 COMMENT '订单类型:1-包间订单 2-纯商品订单', + customer_name VARCHAR(50) COMMENT '顾客姓名', + customer_phone VARCHAR(20) COMMENT '顾客电话', + room_amount DECIMAL(19,4) DEFAULT 0 COMMENT '包间费用', + product_amount DECIMAL(19,4) DEFAULT 0 COMMENT '商品费用', + discount_amount DECIMAL(19,4) DEFAULT 0 COMMENT '优惠金额', + total_amount DECIMAL(19,4) DEFAULT 0 COMMENT '订单总金额', + pay_amount DECIMAL(19,4) DEFAULT 0 COMMENT '实付金额', + pay_status TINYINT DEFAULT 0 COMMENT '支付状态:0-未支付 1-部分支付 2-已支付', + pay_type VARCHAR(20) COMMENT '支付方式:CASH/WECHAT/ALIPAY/BALANCE', + pay_time DATETIME(3) COMMENT '支付时间', + status TINYINT DEFAULT 0 COMMENT '状态:0-开台中 1-已挂单 2-待支付 3-已完成 4-已退款', + remark VARCHAR(500) COMMENT '备注', + refund_amount DECIMAL(19,4) DEFAULT 0 COMMENT '退款金额', + refund_reason VARCHAR(500) COMMENT '退款原因', + refund_time DATETIME(3) COMMENT '退款时间', + cashier_id BIGINT COMMENT '收银员ID', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + deleted TINYINT DEFAULT 0 COMMENT '删除标志', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', + UNIQUE KEY uk_order_no (order_no), + KEY idx_store_id (store_id), + KEY idx_room_id (room_id), + KEY idx_status (status), + KEY idx_create_time (create_time) +) COMMENT='主订单表'; +``` + +#### 包间子订单表(rui_cashier_room_sub_order) + +```sql +CREATE TABLE #prefix#cashier_room_sub_order ( + id BIGINT PRIMARY KEY COMMENT '子订单ID', + order_id BIGINT NOT NULL COMMENT '主订单ID', + room_id BIGINT NOT NULL COMMENT '包间ID', + package_id BIGINT COMMENT '套餐ID', + billing_type TINYINT NOT NULL COMMENT '计费方式:1-按时 2-包时段 3-按局', + price DECIMAL(19,4) NOT NULL COMMENT '套餐价格/单价', + start_time DATETIME(3) COMMENT '开台时间', + end_time DATETIME(3) COMMENT '结账时间', + duration INT COMMENT '使用时长(分钟)', + game_count INT DEFAULT 0 COMMENT '局数', + amount DECIMAL(19,4) DEFAULT 0 COMMENT '包间费用', + status TINYINT DEFAULT 0 COMMENT '状态:0-进行中 1-已完成 2-已取消', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + deleted TINYINT DEFAULT 0 COMMENT '删除标志', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', + UNIQUE KEY uk_order_id (order_id), + KEY idx_room_id (room_id) +) COMMENT='包间子订单表'; +``` + +#### 商品子订单表(rui_cashier_product_sub_order) + +```sql +CREATE TABLE #prefix#cashier_product_sub_order ( + id BIGINT PRIMARY KEY COMMENT '子订单ID', + order_id BIGINT NOT NULL COMMENT '主订单ID', + product_id BIGINT NOT NULL COMMENT '商品ID', + product_name VARCHAR(100) NOT NULL COMMENT '商品名称', + product_price DECIMAL(19,4) NOT NULL COMMENT '商品单价', + quantity INT NOT NULL COMMENT '数量', + amount DECIMAL(19,4) NOT NULL COMMENT '小计金额', + pay_status TINYINT DEFAULT 0 COMMENT '支付状态:0-未支付 1-部分支付 2-已支付', + source TINYINT DEFAULT 1 COMMENT '来源:1-收银台 2-顾客小程序', + status TINYINT DEFAULT 0 COMMENT '状态:0-待处理 1-已确认 2-已取消', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + deleted TINYINT DEFAULT 0 COMMENT '删除标志', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', + KEY idx_order_id (order_id), + KEY idx_product_id (product_id) +) COMMENT='商品子订单表'; +``` + +#### 商品表(rui_cashier_product) + +```sql +CREATE TABLE #prefix#cashier_product ( + id BIGINT PRIMARY KEY COMMENT '商品ID', + category_id BIGINT COMMENT '分类ID', + product_name VARCHAR(100) NOT NULL COMMENT '商品名称', + product_code VARCHAR(50) COMMENT '商品编码', + product_type TINYINT DEFAULT 1 COMMENT '类型:1-普通商品 2-服务商品', + unit VARCHAR(20) COMMENT '单位', + sale_price DECIMAL(19,4) NOT NULL COMMENT '售价', + cost_price DECIMAL(19,4) COMMENT '成本价', + status TINYINT DEFAULT 1 COMMENT '状态:0-禁用 1-启用', + sort INT DEFAULT 0 COMMENT '排序', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + deleted TINYINT DEFAULT 0 COMMENT '删除标志', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', + KEY idx_category_id (category_id) +) COMMENT='商品表'; +``` + +### 2.6 错误码设计 + +收银系统错误码区间:**5000-5999** + +| 错误码 | 含义 | 场景 | +|--------|------|------| +| 5000 | 门店不存在 | 操作不存在的门店 | +| 5001 | 门店已禁用 | 门店状态为禁用 | +| 5010 | 包间不存在 | 操作不存在的包间 | +| 5011 | 包间已占用 | 开台时包间不是空闲状态 | +| 5012 | 包间已禁用 | 包间状态为禁用 | +| 5020 | 订单不存在 | 操作不存在的订单 | +| 5021 | 订单状态错误 | 操作与当前状态不符 | +| 5022 | 订单已支付 | 重复支付 | +| 5023 | 退款金额超过订单金额 | 退款金额校验失败 | +| 5030 | 商品不存在 | 添加商品时商品不存在或已下架 | +| 5040 | 定价策略不存在 | 包间类型没有配置定价策略 | +| 5041 | 无可用套餐 | 当前时段没有匹配的套餐 | +| 5050 | 设备不存在 | 操作不存在的设备 | +| 5051 | 设备离线 | 设备控制时设备离线 | +| 5060 | 门店配置不存在 | 门店未配置 | + +--- + +## 三、验收标准 + +### MVP 阶段验收标准 + +- [ ] **门店管理**:可创建、编辑、禁用门店,支持按代理商筛选 +- [ ] **门店配置**:可配置商品支付模式、余额支付开关、下单通知开关 +- [ ] **包间管理**:可创建包间类型和包间,配置设备绑定 +- [ ] **套餐策略**:可创建定价策略,添加多个套餐,支持排序和默认套餐 +- [ ] **开台流程**:收银员可选择空闲包间开台,系统自动匹配当前时段可用套餐 +- [ ] **计费计算**:按时计费正确计算时长和费用,支持最低消费时长 +- [ ] **商品管理**:可添加商品,支持收银台追加到订单 +- [ ] **结账流程**:可正常结账,生成订单,支持预付款/后付款模式 +- [ ] **退款功能**:可对已支付订单进行部分或全额退款 +- [ ] **营业报表**:可查看门店营业日报(营业额、订单数、包间利用率) +- [ ] **权限控制**:不同角色(总部/代理商/店长/收银员)看到不同数据和功能 + +### 性能标准 + +- [ ] 包间状态查询响应时间 < 200ms +- [ ] 套餐匹配响应时间 < 300ms +- [ ] 开台操作响应时间 < 500ms +- [ ] 结账计算响应时间 < 500ms +- [ ] 报表查询响应时间 < 2s(支持日期范围筛选) + +--- + +## 四、风险与依赖 + +| 风险 | 影响 | 缓解措施 | +|------|------|----------| +| **多门店数据量大** | 中 | 报表服务独立,定时同步数据;数据库按租户分表 | +| **套餐策略复杂** | 中 | 策略+套餐两级设计,限制条件JSON化;充分测试边界场景 | +| **支付 SDK 延迟** | 高 | 先实现现金支付,预留支付接口;等 SDK 就绪后对接 | +| **uni-app 性能** | 低 | 收银场景简单,无复杂动画;如性能不足可考虑原生小程序 | +| **智能设备对接** | 高 | 预留设备控制接口;等 IOT 平台就绪后对接;APP 端先集成插件 | +| **并发开台** | 中 | 包间状态变更加分布式锁;订单号使用雪花算法 | +| **第三方平台对接** | 中 | 预留开放平台 API;三期按需对接美团等平台 | +| **子订单分离** | 中 | 商品子订单独立支付状态,需保证数据一致性 | + +--- + +## 五、预留扩展设计 + +### 5.1 会员钱包预留 + +```sql +-- 会员钱包表(二期) +CREATE TABLE #prefix#cashier_member_wallet ( + id BIGINT PRIMARY KEY COMMENT '钱包ID', + member_id BIGINT NOT NULL COMMENT '会员ID', + real_balance DECIMAL(19,4) DEFAULT 0 COMMENT '实际金额', + gift_balance DECIMAL(19,4) DEFAULT 0 COMMENT '赠送金额', + total_balance DECIMAL(19,4) DEFAULT 0 COMMENT '总余额', + status TINYINT DEFAULT 1 COMMENT '状态', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', + UNIQUE KEY uk_member_id (member_id) +) COMMENT='会员钱包表'; + +-- 钱包流水表(二期) +CREATE TABLE #prefix#cashier_wallet_transaction ( + id BIGINT PRIMARY KEY COMMENT '流水ID', + wallet_id BIGINT NOT NULL COMMENT '钱包ID', + transaction_type TINYINT NOT NULL COMMENT '类型:1-充值 2-消费 3-退款', + amount DECIMAL(19,4) NOT NULL COMMENT '金额', + real_amount DECIMAL(19,4) COMMENT '实际金额变动', + gift_amount DECIMAL(19,4) COMMENT '赠送金额变动', + order_no VARCHAR(32) COMMENT '关联订单号', + remark VARCHAR(500) COMMENT '备注', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + KEY idx_wallet_id (wallet_id) +) COMMENT='钱包流水表'; +``` + +```java +// 余额支付接口(预留) +public interface BalancePaymentService { + // 检查余额是否足够 + boolean checkBalance(Long memberId, BigDecimal amount); + + // 扣款(先扣赠送金额,再扣实际金额) + PaymentResult deduct(Long memberId, BigDecimal amount, String orderNo); + + // 退款(退回实际金额) + PaymentResult refund(Long memberId, BigDecimal amount, String orderNo); +} + +// 门店配置余额支付范围 +// StoreConfig.balance_pay_product:0-余额不可支付商品 1-余额可支付商品 +``` + +### 5.2 优惠券/团购券预留 + +```sql +-- 优惠券表(二期) +CREATE TABLE #prefix#cashier_coupon ( + id BIGINT PRIMARY KEY COMMENT '优惠券ID', + coupon_name VARCHAR(100) NOT NULL COMMENT '优惠券名称', + coupon_type TINYINT NOT NULL COMMENT '类型:1-满减 2-折扣 3-立减', + face_value DECIMAL(19,4) NOT NULL COMMENT '面值', + min_amount DECIMAL(19,4) DEFAULT 0 COMMENT '最低消费金额', + valid_days INT COMMENT '有效天数', + status TINYINT DEFAULT 1 COMMENT '状态', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间' +) COMMENT='优惠券表'; + +-- 第三方团购券表(二期) +CREATE TABLE #prefix#cashier_third_party_voucher ( + id BIGINT PRIMARY KEY COMMENT '券ID', + platform VARCHAR(20) NOT NULL COMMENT '平台:MEITUAN/DIANPING', + voucher_code VARCHAR(50) NOT NULL COMMENT '券码', + voucher_name VARCHAR(100) COMMENT '券名称', + face_value DECIMAL(19,4) NOT NULL COMMENT '面值', + status TINYINT DEFAULT 0 COMMENT '状态:0-未使用 1-已使用 2-已过期', + use_time DATETIME(3) COMMENT '使用时间', + order_no VARCHAR(32) COMMENT '关联订单号', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + UNIQUE KEY uk_voucher_code (voucher_code) +) COMMENT='第三方团购券表'; +``` + +```java +// 优惠计算接口(预留) +public interface DiscountService { + // 计算订单可使用的优惠 + List calculateAvailableDiscounts(Long orderId, Long memberId); + + // 应用优惠 + DiscountResult applyDiscount(Long orderId, List couponIds, List voucherCodes); + + // 核销团购券 + VoucherResult verifyVoucher(String voucherCode); +} +``` + +### 5.3 支付通道预留 + +```java +// 支付接口(预留) +public interface PaymentService { + // 发起支付 + PaymentResult pay(Long orderId, String payType, BigDecimal amount); + + // 查询支付状态 + PaymentStatus queryStatus(String payOrderNo); + + // 退款 + RefundResult refund(Long orderId, BigDecimal amount, String reason); +} + +// 当前实现:现金支付 +@Component +public class CashPaymentService implements PaymentService { + // 仅记录支付流水,不调用第三方 +} + +// 后续扩展:微信支付、支付宝、余额支付等 +@Component +public class WechatPaymentService implements PaymentService { + // 对接支付平台 SDK +} +``` + +### 5.4 第三方平台对接预留 + +```java +// 开放平台接口(预留) +@RestController +@RequestMapping("/cashier/open") +public class OpenPlatformController { + + // 查询包间可用性 + @GetMapping("/room/availability") + public Result> queryAvailability( + @RequestParam Long storeId, + @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startTime, + @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endTime) { + // 返回各包间在指定时段的可用状态 + } + + // 查询套餐价格 + @GetMapping("/room/{roomTypeId}/packages") + public Result> queryPackages( + @PathVariable Long roomTypeId, + @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startTime) { + // 返回当前时段可用套餐 + } + + // 第三方下单 + @PostMapping("/order/create") + public Result createOrder(@RequestBody @Valid OpenOrderDTO dto) { + // 创建订单,返回订单信息 + } + + // 订单状态同步 + @GetMapping("/order/{orderNo}/status") + public Result queryStatus(@PathVariable String orderNo) { + // 返回订单当前状态 + } + + // 退款 + @PostMapping("/order/{orderNo}/refund") + public Result refund(@PathVariable String orderNo, @RequestBody RefundDTO dto) { + // 处理退款 + } +} +``` + +### 5.5 智能设备控制预留 + +```java +// 设备控制服务(预留) +public interface DeviceControlService { + // 开锁 + Result unlock(Long roomId); + + // 关锁 + Result lock(Long roomId); + + // 通电 + Result powerOn(Long roomId); + + // 断电 + Result powerOff(Long roomId); + + // 语音播报 + Result playVoice(Long roomId, String content); + + // 打印小票 + Result printTicket(Long roomId, String content); +} + +// 当前实现:空实现(记录日志) +@Component +public class DummyDeviceControlService implements DeviceControlService { + // 仅记录操作日志,等 IOT 平台对接后替换 +} +``` + +--- + +## 六、模块结构 + +``` +app/rui-cashier/ +├── pom.xml # 聚合 POM +├── rui-cashier-store/ # 门店+包间服务 +│ ├── rui-cashier-store-common/ # DTO、枚举、常量 +│ ├── rui-cashier-store-core/ # Entity、Mapper、Service +│ └── rui-cashier-store-api/ # REST API +├── rui-cashier-order/ # 订单服务 +│ ├── rui-cashier-order-common/ +│ ├── rui-cashier-order-core/ +│ └── rui-cashier-order-api/ +├── rui-cashier-product/ # 商品服务 +│ ├── rui-cashier-product-common/ +│ ├── rui-cashier-product-core/ +│ └── rui-cashier-product-api/ +└── rui-cashier-report/ # 报表服务 + ├── rui-cashier-report-common/ + ├── rui-cashier-report-core/ + └── rui-cashier-report-api/ +``` + +--- + +## 七、实施阶段规划 + +### 阶段一:MVP(6-8 周) +- 搭建项目结构 +- 实现 rui-cashier-store(门店+包间+套餐策略+设备管理) +- 实现 rui-cashier-order(开台、计费、结账、退款、子订单) +- 实现 rui-cashier-product(商品管理) +- 实现基础报表 +- 开发管理后台页面(admin-ui) +- 开发收银台 APP(uni-app) + +### 阶段二:会员+营销+顾客小程序(4-6 周) +- 会员系统(注册、积分、储值) +- 会员钱包(实际金额+赠送金额) +- 优惠券、营销活动 +- 顾客小程序(预约、扫码开台、在线支付) + +### 阶段三:生态对接(4-6 周) +- 支付通道对接(微信、支付宝、余额) +- 第三方平台对接(美团等) +- 第三方团购券对接 +- IOT 设备对接(通过 IOT 平台) +- 收银机/PC 端开发 + +--- + +*文档结束* diff --git a/docs/design/rui-admin功能设计文档.md b/docs/design/rui-admin功能设计文档.md new file mode 100644 index 0000000..2311e05 --- /dev/null +++ b/docs/design/rui-admin功能设计文档.md @@ -0,0 +1,268 @@ +# rui-admin 功能设计文档 + +## 1. 项目概述 + +rui-admin 是睿核通用平台框架的后台管理前端系统,基于 Vue 3 + Element Plus + UnoCSS 构建,提供完整的系统管理、用户管理、内容管理、订单管理、营销管理等功能。 + +## 2. 功能模块划分 + +### 2.1 系统管理(system)- 核心模块 + +| 功能 | 状态 | 后端API | 说明 | +|------|------|---------|------| +| 菜单管理 | ✅ 已完成 | SysMenuController | 树形结构、图标修复 | +| 角色管理 | ✅ 已完成 | SysRoleController | CRUD + 权限分配 | +| 部门管理 | ✅ 已完成 | SysDeptController | 树形表格 | +| 字典管理 | ✅ 已完成 | SysDictTypeController | 字典类型 + 字典项 | +| 参数配置 | ✅ 已完成 | SysConfigController | 系统参数维护 | +| 租户管理 | ✅ 已完成 | SysTenantController | 多租户管理 | +| **操作日志** | ⏳ 待开发 | 需新建 | 用户操作审计 | +| **登录日志** | ⏳ 待开发 | 需新建 | 登录行为记录 | +| **OAuth2客户端** | ⏳ 待开发 | SystemOAuth2ClientController | 客户端管理前端 | + +### 2.2 用户中心(user)- 核心模块 + +| 功能 | 状态 | 后端API | 说明 | +|------|------|---------|------| +| 用户管理 | ✅ 已完成 | UserController | 用户CRUD | +| 用户等级 | ✅ 已完成 | UserLevelController | 等级体系管理 | +| **用户详情** | ⏳ 待开发 | UserDetailController | 用户详细信息 | +| **等级日志** | ⏳ 待开发 | UserLevelLogController | 等级变更记录 | +| **用户账户** | ⏳ 待开发 | 需评估 | 账户安全设置 | +| **用户地址** | ⏳ 待开发 | 需新建 | 收货地址管理 | + +### 2.3 系统设置(settings)- 基础模块 + +| 功能 | 状态 | 后端API | 说明 | +|------|------|---------|------| +| **个人设置** | ⏳ 待开发 | 需评估 | 个人信息修改 | +| **系统设置** | ⏳ 待开发 | SysConfigController | 全局参数配置界面 | +| **密码修改** | ⏳ 待开发 | UserController | 修改登录密码 | + +### 2.4 订单管理(order)- 业务模块 + +| 功能 | 状态 | 后端API | 说明 | +|------|------|---------|------| +| **订单列表** | ⏳ 预留 | 需新建服务 | 订单查询、状态管理 | +| **退款管理** | ⏳ 预留 | 需新建服务 | 退款申请处理 | + +### 2.5 内容管理(cms)- 业务模块 + +| 功能 | 状态 | 后端API | 说明 | +|------|------|---------|------| +| **文章管理** | ⏳ 预留 | 需新建服务 | CMS文章CRUD | +| **分类管理** | ⏳ 预留 | 需新建服务 | 文章分类 | +| **轮播管理** | ⏳ 预留 | 需新建服务 | Banner管理 | + +### 2.6 营销管理(marketing)- 业务模块 + +| 功能 | 状态 | 后端API | 说明 | +|------|------|---------|------| +| **优惠券** | ⏳ 预留 | 需新建服务 | 优惠券CRUD | +| **活动管理** | ⏳ 预留 | 需新建服务 | 营销活动 | + +## 3. 开发优先级 + +### Phase 1:核心功能完善(立即开始) + +1. **操作日志**(system/log) + - 后端:创建 OperLog 实体、Mapper、Service、Controller + - 前端:日志列表页、详情弹窗 + - 优先级:🔴 高 + +2. **用户详情**(user/info/detail) + - 后端:UserDetailController 已有,补充前端 + - 前端:用户详情查看/编辑 + - 优先级:🔴 高 + +3. **等级日志**(user/level-log) + - 后端:UserLevelLogController 已有,补充前端 + - 前端:等级变更记录列表 + - 优先级:🟡 中 + +4. **系统设置**(settings) + - 后端:复用 SysConfigController + - 前端:参数配置界面(与 system/config 区别:更友好的展示) + - 优先级:🟡 中 + +### Phase 2:基础功能补充(近期) + +5. **登录日志**(system/login-log) + - 后端:创建 LoginLog 实体、Mapper、Service、Controller + - 前端:登录记录列表 + - 优先级:🟡 中 + +6. **OAuth2客户端管理**(system/client) + - 后端:SystemOAuth2ClientController 已有 + - 前端:客户端CRUD + - 优先级:🟡 中 + +7. **个人中心**(profile) + - 后端:复用现有接口 + - 前端:个人信息展示与修改 + - 优先级:🟢 低 + +### Phase 3:业务模块(按需) + +8. **订单管理** - 需新建 rui-service-order 服务 +9. **CMS内容管理** - 需新建 rui-service-cms 服务 +10. **营销管理** - 需新建 rui-service-marketing 服务 + +## 4. 技术规范 + +### 4.1 前端规范 + +```typescript +// 页面结构标准 +views/ +├── {module}/ +│ ├── Index.vue # 列表页(必须) +│ ├── {Module}FormDialog.vue # 表单弹窗(新增/编辑) +│ └── {Module}DetailDialog.vue # 详情弹窗(可选) +``` + +### 4.2 后端规范 + +```java +// Controller 标准结构 +@RestController +@RequestMapping("/{模块}/admin/{功能}") +public class XxxController extends BaseController { + // 自动获得:page、list、getById、save、updateById、remove +} +``` + +### 4.3 API 路径规范 + +| 类型 | 路径前缀 | 示例 | +|------|---------|------| +| 对外管理 | `/{模块}/admin/{功能}` | `/system/admin/log` | +| 内部调用 | `/{模块}/inner/{功能}` | `/system/inner/client` | +| 对外入口 | `/{模块}/entry/{功能}` | `/auth/entry/login` | + +## 5. 数据库设计(新增表) + +### 5.1 操作日志表(rui_sys_oper_log) + +```sql +CREATE TABLE rui_sys_oper_log ( + id BIGINT NOT NULL, + tenant_id BIGINT NOT NULL DEFAULT 0, + oper_type TINYINT NOT NULL DEFAULT 1 COMMENT '操作类型 1:新增 2:修改 3:删除 4:查询 5:导出 6:登录 7:登出', + title VARCHAR(200) NOT NULL COMMENT '操作模块', + method VARCHAR(500) DEFAULT NULL COMMENT '请求方法', + request_url VARCHAR(500) DEFAULT NULL, + request_method VARCHAR(10) DEFAULT NULL COMMENT 'GET/POST/PUT/DELETE', + request_params TEXT DEFAULT NULL, + response_data TEXT DEFAULT NULL, + user_id BIGINT DEFAULT NULL, + user_name VARCHAR(100) DEFAULT NULL, + oper_ip VARCHAR(128) DEFAULT NULL, + oper_location VARCHAR(255) DEFAULT NULL, + status TINYINT NOT NULL DEFAULT 1 COMMENT '状态 0:失败 1:成功', + error_msg TEXT DEFAULT NULL, + cost_time BIGINT DEFAULT 0 COMMENT '耗时(ms)', + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + INDEX idx_user (user_id), + INDEX idx_tenant (tenant_id), + INDEX idx_created (created_at) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='操作日志'; +``` + +### 5.2 登录日志表(rui_sys_login_log) + +```sql +CREATE TABLE rui_sys_login_log ( + id BIGINT NOT NULL, + tenant_id BIGINT NOT NULL DEFAULT 0, + user_id BIGINT DEFAULT NULL, + username VARCHAR(100) DEFAULT NULL, + login_type TINYINT NOT NULL DEFAULT 1 COMMENT '登录类型 1:密码 2:短信 3:微信', + client_id VARCHAR(100) DEFAULT NULL, + ip VARCHAR(128) DEFAULT NULL, + location VARCHAR(255) DEFAULT NULL, + browser VARCHAR(200) DEFAULT NULL, + os VARCHAR(200) DEFAULT NULL, + status TINYINT NOT NULL DEFAULT 1 COMMENT '状态 0:失败 1:成功', + msg VARCHAR(500) DEFAULT NULL, + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + INDEX idx_user (user_id), + INDEX idx_tenant (tenant_id), + INDEX idx_created (created_at) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='登录日志'; +``` + +## 6. 实施计划 + +### 第1周:Phase 1 核心功能 +- [ ] 后端:操作日志 AOP 拦截 + API +- [ ] 前端:system/log 页面 +- [ ] 前端:user/info 详情弹窗 +- [ ] 前端:user/level-log 页面 + +### 第2周:Phase 2 基础功能 +- [ ] 后端:登录日志 API +- [ ] 前端:system/login-log 页面 +- [ ] 前端:settings 系统设置页 +- [ ] 前端:profile 个人中心 + +### 第3周+:Phase 3 业务模块(按需) +- [ ] 订单服务 + 前端页面 +- [ ] CMS服务 + 前端页面 +- [ ] 营销服务 + 前端页面 + +## 7. 前端组件规划 + +### 7.1 复用组件 + +| 组件 | 用途 | 位置 | +|------|------|------| +| RuiTable | 通用表格 | components/RuiTable.vue | +| RuiIcon | 图标渲染 | components/RuiIcon.vue | +| IconPicker | 图标选择 | components/IconPicker.vue | + +### 7.2 新增组件需求 + +| 组件 | 用途 | 优先级 | +|------|------|--------| +| LogDetailDialog | 日志详情展示 | 🔴 高 | +| UserDetailPanel | 用户信息卡片 | 🔴 高 | +| ConfigGroupPanel | 配置分组展示 | 🟡 中 | + +## 8. 权限设计 + +### 8.1 菜单权限 + +``` +system:menu:list - 菜单列表 +system:menu:add - 新增菜单 +system:menu:edit - 编辑菜单 +system:menu:remove - 删除菜单 +system:log:list - 日志列表 +system:log:remove - 删除日志 +``` + +### 8.2 数据权限 + +- 超级管理员:查看所有租户数据 +- 租户管理员:仅查看本租户数据 +- 普通用户:仅查看个人数据 + +## 9. 注意事项 + +1. **操作日志性能**:大量操作日志可能影响性能,建议: + - 异步写入(MQ或线程池) + - 定期归档(30天前的日志迁移到历史表) + - 提供日志清理功能 + +2. **登录日志安全**: + - 记录失败登录尝试,用于安全审计 + - 支持 IP 黑名单 + - 异常登录告警 + +3. **预留模块**: + - order/cms/marketing 为业务预留模块 + - 需要时创建对应后端服务 + - 前端页面保持占位状态即可 diff --git a/docs/plans/cashier-admin-implementation.md b/docs/plans/cashier-admin-implementation.md new file mode 100644 index 0000000..96d2439 --- /dev/null +++ b/docs/plans/cashier-admin-implementation.md @@ -0,0 +1,1387 @@ +# 收银系统后台管理功能完善实施计划 + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers-subagent-driven-development (recommended) or superpowers-executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 完善收银系统后台管理的前端页面功能,为所有列表页面添加新增/编辑表单弹窗,完善订单开台功能,优化营业报表展示 + +**Architecture:** 基于现有 admin-ui 框架和 RuiTable 组件,为每个收银模块创建 FormDialog 组件,遵循项目已有的组件模式和编码规范 + +**Tech Stack:** Vue 3 + TypeScript + Element Plus + Vite + +--- + +## 文件结构 + +### 新增文件 +- `src/views/cashier/store/StoreFormDialog.vue` - 门店表单弹窗 +- `src/views/cashier/room/RoomFormDialog.vue` - 包间表单弹窗 +- `src/views/cashier/product/ProductFormDialog.vue` - 商品表单弹窗 +- `src/views/cashier/pricing/PricingStrategyFormDialog.vue` - 定价策略表单弹窗 +- `src/views/cashier/pricing/PricingPackageDialog.vue` - 套餐管理弹窗 +- `src/views/cashier/order/OpenRoomDialog.vue` - 开台弹窗 + +### 修改文件 +- `src/views/cashier/store/Index.vue` - 集成门店表单弹窗 +- `src/views/cashier/room/Index.vue` - 集成包间表单弹窗 +- `src/views/cashier/product/Index.vue` - 集成商品表单弹窗 +- `src/views/cashier/pricing/Index.vue` - 集成定价策略表单弹窗和套餐管理 +- `src/views/cashier/order/Index.vue` - 集成开台弹窗 +- `src/service/cashier/*Service.ts` - 补充缺失的方法 + +--- + +## 模块优先级 + +按业务依赖关系,实施顺序为: +1. 门店管理(最基础,其他模块依赖门店) +2. 商品管理 +3. 包间管理(依赖门店和包间类型) +4. 定价策略(依赖包间类型) +5. 订单管理(依赖门店和包间) +6. 营业报表优化 + +--- + +## Task 1: 完善门店管理 + +**Files:** +- Create: `src/views/cashier/store/StoreFormDialog.vue` +- Modify: `src/views/cashier/store/Index.vue` + +**Context:** 门店实体字段:name, address, phone, contactName, status, remark + +### Step 1: 创建门店表单弹窗 + +Create `src/views/cashier/store/StoreFormDialog.vue`: + +```vue + + + +``` + +### Step 2: 修改门店管理页面集成弹窗 + +Modify `src/views/cashier/store/Index.vue`: + +Add imports: +```typescript +import StoreFormDialog from './StoreFormDialog.vue' +``` + +Add state: +```typescript +const dialogVisible = ref(false) +const currentRow = ref() +``` + +Replace handleAdd: +```typescript +function handleAdd() { + currentRow.value = undefined + dialogVisible.value = true +} +``` + +Replace handleEdit: +```typescript +function handleEdit(row: any) { + currentRow.value = row + dialogVisible.value = true +} +``` + +Add dialog component in template: +```vue + +``` + +### Step 3: 验证 + +Run: +```bash +cd /Users/zhangsheng/rhkj/spring-ai/admin-ui +pnpm dev:cashier +``` + +Expected: 门店管理页面可以正常打开新增/编辑弹窗 + +### Step 4: Commit + +```bash +git add src/views/cashier/store/ +git commit -m "feat(cashier): 完善门店管理新增编辑功能" +``` + +--- + +## Task 2: 完善商品管理 + +**Files:** +- Create: `src/views/cashier/product/ProductFormDialog.vue` +- Modify: `src/views/cashier/product/Index.vue` +- Modify: `src/service/cashier/productService.ts` + +**Context:** 商品实体字段:name, price, productType(1实物/2服务/3虚拟), category, unit, stock, status, description, storeId + +### Step 1: 补充商品 Service 方法 + +Verify `src/service/cashier/productService.ts` has: +```typescript +import { BaseService } from '../BaseService' + +class ProductService extends BaseService { + constructor() { + super('/cashier/admin/product') + } +} + +export const productService = new ProductService() +``` + +### Step 2: 创建商品表单弹窗 + +Create `src/views/cashier/product/ProductFormDialog.vue`: + +```vue + + + +``` + +### Step 3: 修改商品管理页面 + +Similar to Task 1 Step 2, integrate ProductFormDialog into product/Index.vue + +### Step 4: Commit + +```bash +git add src/views/cashier/product/ src/service/cashier/productService.ts +git commit -m "feat(cashier): 完善商品管理新增编辑功能" +``` + +--- + +## Task 3: 完善包间管理 + +**Files:** +- Create: `src/views/cashier/room/RoomFormDialog.vue` +- Modify: `src/views/cashier/room/Index.vue` + +**Context:** 包间实体字段:storeId, roomTypeId, name, roomNo, roomStatus, enabled, sort +需要获取门店列表和包间类型列表 + +### Step 1: 创建包间表单弹窗 + +Create `src/views/cashier/room/RoomFormDialog.vue`: + +```vue + + + +``` + +### Step 2: 修改包间管理页面 + +Integrate RoomFormDialog into room/Index.vue (similar pattern) + +### Step 3: Commit + +```bash +git add src/views/cashier/room/ +git commit -m "feat(cashier): 完善包间管理新增编辑功能" +``` + +--- + +## Task 4: 完善定价策略 + +**Files:** +- Create: `src/views/cashier/pricing/PricingStrategyFormDialog.vue` +- Create: `src/views/cashier/pricing/PricingPackageDialog.vue` +- Modify: `src/views/cashier/pricing/Index.vue` + +**Context:** 定价策略实体:strategyName, roomTypeId, status +套餐实体:name, price, duration, durationUnit, description, strategyId, billingType, minDuration, restrictions, isDefault, sort, status + +### Step 1: 创建定价策略表单弹窗 + +Create `src/views/cashier/pricing/PricingStrategyFormDialog.vue`: + +```vue + + + +``` + +### Step 2: 创建套餐管理弹窗 + +Create `src/views/cashier/pricing/PricingPackageDialog.vue`: + +```vue + + + +``` + +### Step 3: 补充 pricingService 方法 + +Modify `src/service/cashier/pricingService.ts`: + +```typescript +import { BaseService } from '../BaseService' +import { request } from '@/utils/request' + +class PricingService extends BaseService { + constructor() { + super('/cashier/admin/pricing-strategy') + } + + async getPackages(strategyId: number) { + const res: any = await request({ + url: '/cashier/admin/pricing-package/list', + method: 'get', + params: { strategyId }, + }) + return res.data || [] + } + + async addPackage(data: any) { + const res: any = await request({ + url: '/cashier/admin/pricing-package', + method: 'post', + data, + }) + return res.data + } + + async updatePackage(data: any) { + const res: any = await request({ + url: '/cashier/admin/pricing-package', + method: 'put', + data, + }) + return res.data + } + + async deletePackage(id: number) { + const res: any = await request({ + url: `/cashier/admin/pricing-package/${id}`, + method: 'delete', + }) + return res.data + } +} + +export const pricingService = new PricingService() +``` + +### Step 4: 修改定价策略页面 + +Integrate both dialogs into pricing/Index.vue + +### Step 5: Commit + +```bash +git add src/views/cashier/pricing/ src/service/cashier/pricingService.ts +git commit -m "feat(cashier): 完善定价策略和套餐管理功能" +``` + +--- + +## Task 5: 完善订单管理(开台功能) + +**Files:** +- Create: `src/views/cashier/order/OpenRoomDialog.vue` +- Modify: `src/views/cashier/order/Index.vue` +- Modify: `src/service/cashier/orderService.ts` + +**Context:** 开台需要:门店ID、包间ID、顾客姓名、顾客电话、订单类型、备注 + +### Step 1: 补充 orderService 方法 + +Modify `src/service/cashier/orderService.ts`: + +```typescript +import { BaseService } from '../BaseService' +import { request } from '@/utils/request' + +class OrderService extends BaseService { + constructor() { + super('/cashier/admin/order') + } + + async checkout(id: number) { + const res: any = await request({ + url: `${this.baseUrl}/${id}/checkout`, + method: 'post', + }) + return res.data + } + + async refund(id: number, data: { amount: number; reason: string }) { + const res: any = await request({ + url: `${this.baseUrl}/${id}/refund`, + method: 'post', + data, + }) + return res.data + } + + async openRoom(data: { + storeId: number + roomId: number + customerName?: string + customerPhone?: string + orderType?: number + remark?: string + }) { + const res: any = await request({ + url: `${this.baseUrl}/open`, + method: 'post', + data, + }) + return res.data + } +} + +export const orderService = new OrderService() +``` + +### Step 2: 创建开台弹窗 + +Create `src/views/cashier/order/OpenRoomDialog.vue`: + +```vue + + + +``` + +### Step 3: 修改订单管理页面 + +Integrate OpenRoomDialog into order/Index.vue + +### Step 4: Commit + +```bash +git add src/views/cashier/order/ src/service/cashier/orderService.ts +git commit -m "feat(cashier): 完善订单管理开台功能" +``` + +--- + +## Task 6: 营业报表优化 + +**Files:** +- Modify: `src/views/cashier/report/Index.vue` + +**Context:** 当前报表已展示日报数据和包间利用率,可以优化图表展示 + +### Step 1: 添加图表展示 + +Install echarts if not already installed: +```bash +cd /Users/zhangsheng/rhkj/spring-ai/admin-ui +pnpm add echarts vue-echarts +``` + +### Step 2: 优化报表页面 + +Add chart components for: +- 营业趋势图(折线图) +- 支付方式饼图 +- 包间利用率柱状图 + +### Step 3: Commit + +```bash +git add src/views/cashier/report/ package.json pnpm-lock.yaml +git commit -m "feat(cashier): 优化营业报表图表展示" +``` + +--- + +## Task 7: 验证和文档更新 + +**Files:** +- Modify: `docs/admin-ui-status.md` + +### Step 1: 验证所有功能 + +Run: +```bash +cd /Users/zhangsheng/rhkj/spring-ai/admin-ui +pnpm build:cashier +``` + +Expected: 构建成功,无错误 + +### Step 2: 更新状态文档 + +Update `docs/admin-ui-status.md`: + +```markdown +### 8. 收银系统模块 + +| 功能 | 页面 | 状态 | 说明 | +|------|------|------|------| +| 门店管理 | cashier/store/Index.vue | ✅ 完成 | 增删改查、状态切换 | +| 包间管理 | cashier/room/Index.vue | ✅ 完成 | 增删改查、状态切换 | +| 商品管理 | cashier/product/Index.vue | ✅ 完成 | 增删改查、状态切换 | +| 定价策略 | cashier/pricing/Index.vue | ✅ 完成 | 增删改查、套餐管理 | +| 订单管理 | cashier/order/Index.vue | ✅ 完成 | 开台、结账、退款、查询 | +| 营业报表 | cashier/report/Index.vue | ✅ 完成 | 日报、包间利用率、图表 | +``` + +### Step 3: Commit + +```bash +git add docs/admin-ui-status.md +git commit -m "docs: 更新收银系统功能状态" +``` + +--- + +## 验证清单 + +- [ ] 门店管理:新增、编辑、删除、查询、状态切换正常 +- [ ] 包间管理:新增、编辑、删除、查询、状态切换正常 +- [ ] 商品管理:新增、编辑、删除、查询、状态切换正常 +- [ ] 定价策略:新增、编辑、删除、查询、套餐管理正常 +- [ ] 订单管理:开台、结账、退款、查询正常 +- [ ] 营业报表:数据展示、图表正常 +- [ ] 所有页面无编译错误 +- [ ] 构建产物正常 + +--- + +## 风险与依赖 + +| 风险 | 影响 | 缓解措施 | +|------|------|---------| +| 后端 API 字段与前端不一致 | 高 | 开发时对比后端实体字段,确保一致 | +| 包间类型数据未对接 | 中 | 先使用 ID 输入,后续优化为下拉选择 | +| 图表库引入增加包体积 | 低 | 按需引入 echarts 组件 | +| 开台功能需要实时状态更新 | 中 | 开台成功后刷新列表 | + +--- + +## 后续扩展 + +1. **包间类型管理** - 添加包间类型 CRUD 页面 +2. **设备管理** - 添加门店设备管理页面 +3. **会员管理** - 完善会员等级、积分管理 +4. **库存管理** - 添加商品库存预警功能 +5. **数据导出** - 为所有列表添加导出功能 diff --git a/docs/standards/API设计规范.md b/docs/standards/API设计规范.md new file mode 100644 index 0000000..efe434a --- /dev/null +++ b/docs/standards/API设计规范.md @@ -0,0 +1,505 @@ +# API 设计规范 + +> 睿核科技通用平台框架 RESTful API 统一设计标准 + +--- + +## 一、接口分类 + +| 分类 | 路径前缀 | 认证 | 说明 | +|------|---------|------|------| +| **对外接口** | `/{模块}/api/**` | OAuth2 Token | 对外提供的业务接口 | +| **内部接口** | `/{模块}/inner/**` | `@Inner` + `INTERNAL_REQUEST` | 微服务间 Feign 调用 | +| **入口接口** | `/{模块}/entry/**` | 无需认证 | 对外入口(登录、注册) | +| **回调接口** | `/{模块}/notify/**` | 无需认证 | 第三方回调(支付、Webhook) | +| **管理接口** | `/{模块}/admin/**` | 需管理员权限 | 后台管理 | + +--- + +## 二、URL 设计规范 + +### 2.1 对外接口(RESTful) + +``` +GET /{version}/{模块}/{资源} # 列表查询 +GET /{version}/{模块}/{资源}/{id} # 详情查询 +POST /{version}/{模块}/{资源} # 新增 +PUT /{version}/{模块}/{资源}/{id} # 全量更新 +PATCH /{version}/{模块}/{资源}/{id} # 局部更新 +DELETE /{version}/{模块}/{资源}/{id} # 删除 +``` + +**示例**: +``` +GET /v1/user/users?page=1&size=10 # 查询用户列表 +GET /v1/user/users/1001 # 查询用户详情 +POST /v1/user/users # 新增用户 +PUT /v1/user/users/1001 # 全量更新用户 +PATCH /v1/user/users/1001 # 局部更新(如只改状态) +DELETE /v1/user/users/1001 # 删除用户 +``` + +### 2.2 内部接口(Feign) + +``` +GET /{模块}/inner/{功能}/{方法} +``` + +**示例**: +``` +GET /user/inner/auth/loadByUsername/{username} +GET /system/inner/client/getById/{clientId} +``` + +### 2.3 版本控制 + +- **URI 版本**(推荐):`/v1/user/users` +- **Header 版本**(可选):`Accept: application/vnd.rui.v1+json` + +--- + +## 三、请求规范 + +### 3.1 HTTP 方法 + +| 方法 | 用途 | 幂等性 | +|------|------|--------| +| GET | 查询 | ✅ | +| POST | 新增/提交 | ❌ | +| PUT | 全量更新 | ✅ | +| PATCH | 局部更新 | ❌ | +| DELETE | 删除 | ✅ | + +### 3.2 Content-Type + +``` +Content-Type: application/json; charset=utf-8 +``` + +### 3.3 请求头规范 + +| Header | 必填 | 说明 | +|--------|------|------| +| Authorization | 是(除 entry/notify) | `Bearer {access_token}` | +| Content-Type | 是 | `application/json` | +| X-Request-Id | 否 | 请求追踪 ID(网关自动生成) | +| X-Tenant-Id | 否 | 租户 ID(后端自动注入) | +| Accept-Language | 否 | 语言偏好 `zh-CN` / `en-US` | + +### 3.4 分页参数 + +``` +GET /v1/user/users?page=1&size=10&sort=createdAt,desc +``` + +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| page | int | 1 | 当前页码(从1开始) | +| size | int | 10 | 每页条数(最大100) | +| sort | string | createdAt,desc | 排序字段和方向 | + +### 3.5 查询参数 + +``` +GET /v1/user/users?username=admin&status=1&createdAt_start=2024-01-01&createdAt_end=2024-12-31 +``` + +**规则**: +- 精确匹配:字段名直接等于值 `status=1` +- 模糊匹配:字段名加后缀 `_like` `username_like=admin` +- 范围查询:字段名加后缀 `_start` / `_end` `createdAt_start=2024-01-01` +- 多值查询:字段名加后缀 `_in` `status_in=1,2` + +--- + +## 四、响应规范 + +### 4.1 统一响应格式 + +```json +{ + "code": 200, + "msg": "操作成功", + "data": {} +} +``` + +### 4.2 分页响应格式 + +```json +{ + "code": 200, + "msg": "操作成功", + "data": { + "records": [], + "total": 100, + "size": 10, + "current": 1, + "pages": 10 + } +} +``` + +### 4.3 HTTP 状态码 + +| 状态码 | 含义 | 使用场景 | +|--------|------|---------| +| 200 | OK | 查询成功、更新成功 | +| 201 | Created | 新增成功 | +| 204 | No Content | 删除成功(无返回体) | +| 400 | Bad Request | 参数校验失败 | +| 401 | Unauthorized | 未登录/Token 过期 | +| 403 | Forbidden | 无权限访问 | +| 404 | Not Found | 资源不存在 | +| 409 | Conflict | 资源冲突(如重复提交) | +| 429 | Too Many Requests | 请求过于频繁 | +| 500 | Internal Server Error | 服务器内部错误 | + +### 4.4 错误码规范 + +| 区间 | 模块 | 示例 | +|------|------|------| +| 1000-1999 | 通用 | 1001: 参数校验失败, 1002: 资源不存在 | +| 2000-2999 | 用户模块 | 2001: 用户名已存在, 2002: 密码错误 | +| 3000-3999 | 系统模块 | 3001: 字典不存在, 3002: 配置错误 | +| 4000-4999 | 认证模块 | 4001: Token 过期, 4002: 无权访问 | +| 5000-5999 | 文件模块 | 5001: 上传失败, 5002: 文件过大 | +| 6000-6999 | 消息模块 | 6001: 发送失败, 6002: 模板不存在 | + +**错误响应示例**: +```json +{ + "code": 2001, + "msg": "用户名已存在", + "data": null +} +``` + +--- + +## 五、Controller 命名与路径映射 + +### 5.1 命名规则 + +| 类型 | Controller 命名 | 路径 | 说明 | +|------|----------------|------|------| +| 对外业务 | `UserController` | `/v1/user/users/**` | 常规 CRUD | +| 内部调用 | `UserInnerController` | `/user/inner/**` | Feign 调用 | +| 对外入口 | `UserEntryController` | `/user/entry/**` | 免认证入口 | +| 第三方回调 | `PayNotifyController` | `/pay/notify/**` | Webhook | +| 后台管理 | `UserAdminController` | `/v1/user/admin/**` | 管理接口 | + +### 5.2 方法命名 + +| 操作 | 方法名 | HTTP | 路径 | +|------|--------|------|------| +| 列表 | `list` / `page` | GET | `/{资源}` | +| 详情 | `getById` | GET | `/{资源}/{id}` | +| 新增 | `add` / `save` | POST | `/{资源}` | +| 更新 | `update` / `edit` | PUT | `/{资源}/{id}` | +| 局部更新 | `patch` | PATCH | `/{资源}/{id}` | +| 删除 | `remove` / `delete` | DELETE | `/{资源}/{id}` | +| 批量删除 | `batchRemove` | DELETE | `/{资源}/batch` | +| 导出 | `export` | GET | `/{资源}/export` | +| 导入 | `import` | POST | `/{资源}/import` | + +--- + +## 六、Swagger 注解规范 + +### 6.1 Controller 注解 + +```java +@Tag(name = "用户管理", description = "用户相关接口") +@RestController +@RequestMapping("/v1/user/users") +public class UserController { + + @Operation(summary = "查询用户列表", description = "支持分页、排序、条件查询") + @GetMapping + public Result> list( + @Parameter(description = "页码") @RequestParam(defaultValue = "1") Integer page, + @Parameter(description = "每页条数") @RequestParam(defaultValue = "10") Integer size) { + // ... + } + + @Operation(summary = "新增用户") + @PostMapping + public Result add(@RequestBody @Valid UserDTO dto) { + // ... + } +} +``` + +### 6.2 DTO / VO 注解 + +```java +@Schema(description = "用户新增DTO") +@Data +public class UserDTO { + + @Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "admin") + @NotBlank(message = "用户名不能为空") + @Size(min = 2, max = 50, message = "用户名长度2-50字符") + private String username; + + @Schema(description = "状态 0:禁用 1:启用", example = "1") + private Integer status; +} +``` + +--- + +## 七、数据校验规范 + +### 7.1 分组校验 + +```java +public interface AddGroup {} // 新增分组 +public interface UpdateGroup {} // 更新分组 +``` + +### 7.2 使用示例 + +```java +@Data +public class UserDTO { + + @NotNull(message = "ID不能为空", groups = UpdateGroup.class) + private Long id; + + @NotBlank(message = "用户名不能为空", groups = {AddGroup.class, UpdateGroup.class}) + private String username; +} + +// Controller +@PostMapping +public Result add(@RequestBody @Validated(AddGroup.class) UserDTO dto) { + // 新增 +} + +@PutMapping("/{id}") +public Result update(@RequestBody @Validated(UpdateGroup.class) UserDTO dto) { + // 更新 +} +``` + +--- + +## 八、Feign 接口规范 + +### 8.1 接口定义 + +```java +/** + * 远程用户服务 + */ +@Headers("INTERNAL_REQUEST: INTERNAL") +@FeignClient( + contextId = "remoteUserService", + value = "${feign.providers.user:rui-service-user}", + path = "/user/inner" +) +public interface RemoteUserService { + + @GetMapping("/auth/loadByUsername/{username}") + Result> loadUser(@PathVariable String username); +} +``` + +### 8.2 调用规范 + +```java +@Service +@RequiredArgsConstructor +public class UserRemoteService { + + private final RemoteUserService remoteUserService; + + public UserVO getUserById(Long userId) { + Result result = remoteUserService.getById(userId); + if (result.isSuccess()) { + return result.getData(); + } + throw new BizException(result.getCode(), result.getMsg()); + } +} +``` + +--- + +## 九、文件上传接口规范 + +### 9.1 单文件上传 + +``` +POST /v1/file/files/upload +Content-Type: multipart/form-data + +file: [二进制文件] +module: user +bizId: 1001 +``` + +**响应**: +```json +{ + "code": 200, + "msg": "上传成功", + "data": { + "fileId": "123456", + "fileName": "avatar.jpg", + "fileUrl": "https://oss.example.com/avatar/123456.jpg", + "fileSize": 102400 + } +} +``` + +### 9.2 多文件上传 + +``` +POST /v1/file/files/batchUpload +Content-Type: multipart/form-data + +files: [文件1, 文件2, 文件3] +module: user +``` + +--- + +## 十、导出接口规范 + +### 10.1 Excel 导出 + +``` +GET /v1/user/users/export?username=admin&status=1 +Accept: application/vnd.ms-excel +``` + +**响应**: +``` +Content-Type: application/vnd.ms-excel +Content-Disposition: attachment; filename="用户列表_20240101.xlsx" +``` + +### 10.2 CSV 导出 + +``` +GET /v1/user/users/export?format=csv +Accept: text/csv +``` + +--- + +## 十一、WebSocket 接口规范(预留) + +``` +ws://gateway:9300/ws/{模块}/{topic} +``` + +**示例**: +``` +ws://localhost:9300/ws/msg/notification # 消息通知 +ws://localhost:9300/ws/monitor/metrics # 实时监控 +``` + +--- + +## 十二、接口文档生成 + +### 12.1 配置 SpringDoc + +```yaml +springdoc: + swagger-ui: + path: /swagger-ui.html + enabled: true + api-docs: + path: /v3/api-docs + enabled: true + group-configs: + - group: 用户服务 + display-name: 用户服务 API + paths-to-match: /v1/user/** + - group: 系统服务 + display-name: 系统服务 API + paths-to-match: /v1/system/** +``` + +### 12.2 访问地址 + +``` +http://localhost:9300/swagger-ui.html # 网关聚合文档 +http://localhost:9301/swagger-ui.html # 认证服务文档 +http://localhost:9302/swagger-ui.html # 系统服务文档 +http://localhost:9303/swagger-ui.html # 用户服务文档 +``` + +--- + +## 十三、Postman / APIFox 集合规范 + +### 13.1 目录结构 + +``` +睿核科技通用平台 +├── 01-认证中心 +│ ├── 获取Token +│ ├── 刷新Token +│ └── 退出登录 +├── 02-用户中心 +│ ├── 用户管理 +│ ├── 等级管理 +│ └── 用户查询 +├── 03-系统管理 +│ ├── 租户管理 +│ ├── 菜单管理 +│ ├── 角色管理 +│ ├── 字典管理 +│ └── 参数配置 +├── 04-文件管理 +│ ├── 文件上传 +│ └── 文件下载 +└── 99-内部接口(Feign) + ├── 用户服务 + └── 系统服务 +``` + +### 13.2 环境变量 + +```json +{ + "baseUrl": "http://localhost:9300", + "token": "{{login_response_token}}", + "tenantId": "1" +} +``` + +--- + +## 十四、接口变更管理 + +### 14.1 变更类型 + +| 类型 | 说明 | 版本处理 | +|------|------|---------| +| 新增接口 | 新增资源/功能 | 当前版本可用 | +| 新增字段 | 请求/响应增加字段 | 当前版本可用(兼容) | +| 废弃字段 | 字段标记 deprecated | 当前版本可用,下版本移除 | +| 废弃接口 | 接口标记 deprecated | 保留至少2个版本后移除 | +| 破坏性变更 | 字段删除/类型变更 | 升级版本号(v1 → v2) | + +### 14.2 版本迭代策略 + +``` +v1.0 —— 初始版本 +v1.1 —— 新增字段(兼容) +v1.2 —— 新增接口(兼容) +v2.0 —— 破坏性变更(不兼容) +``` + +--- + +> **文档版本**: v1.0 +> **创建日期**: 2026-05-28 +> **适用范围**: 睿核科技通用平台框架所有 RESTful API diff --git a/docs/standards/前端开发规则.md b/docs/standards/前端开发规则.md new file mode 100644 index 0000000..b0164f0 --- /dev/null +++ b/docs/standards/前端开发规则.md @@ -0,0 +1,111 @@ +# 前端开发规则 + +> 适用于 {root} 仓库下所有前端工程 + +## 技术栈 + +| 场景 | 框架 | UI 库 | CSS | +|------|------|------|-----| +| **管理后台 PC** | Vue 3 + TypeScript + Vite | Element Plus | UnoCSS | +| **移动端/小程序** | uniapp (Vue 3) + TypeScript | uView Plus | UnoCSS | +| **H5 官网** | Vue 3 + TypeScript + Vite | — | UnoCSS | + +## 统一规范 + +### 必选 + +- **Vue 3** Composition API(` + + +``` + +**登录页入口(`views/login/Index.vue`):** + +```vue + + + +``` + +### 2.3 模块映射关系 + +建立 `src/views/` 下的页面目录与模块标识的映射: + +| 模块标识 | 对应目录 | 包含页面 | +|---------|---------|---------| +| `system` | `views/system/*` | 菜单、角色、部门、岗位、字典、配置、日志、登录日志、租户、租户套餐、数据权限、OAuth2客户端 | +| `user` | `views/user/*` | 用户信息、用户详情、等级、等级日志、地址、账户 | +| `order` | `views/order/*` | 订单列表、退款记录 | +| `cms` | `views/cms/*` | 文章、分类、轮播图 | +| `marketing` | `views/marketing/*` | 优惠券、活动管理 | +| `demo` | `views/demo/*` | 图标演示、列表演示 | +| `cashier` | `views/cashier/*` | 门店、包间、定价、订单、商品、报表 | + +**核心页面(所有系统默认包含,不依赖模块配置):** +- `views/login/Index.vue` - 登录页入口 +- `views/login/systems/*.vue` - 系统特定登录组件 +- `views/dashboard/Index.vue` - Dashboard 入口 +- `views/dashboard/systems/*.vue` - 系统特定 Dashboard 组件 +- `views/profile/Index.vue` - 个人中心 +- `views/settings/Index.vue` - 系统设置 + +### 2.4 目录结构 + +``` +admin-ui/ +├── build-config/ # 系统打包配置 +│ ├── cashier.json +│ ├── admin.json +│ ├── super.json +│ └── default.json # 默认配置(全模块,用于开发) +├── scripts/ # 构建脚本 +│ └── vite-plugin-module-build.ts # Vite 插件 +├── src/ +│ ├── router/ +│ │ ├── index.ts # 改造:使用虚拟路由模块 +│ │ └── modules/ # 新增:按模块拆分路由配置 +│ │ ├── core.ts # 核心路由(登录、Dashboard入口等) +│ │ ├── system.ts +│ │ ├── user.ts +│ │ ├── order.ts +│ │ ├── cms.ts +│ │ ├── marketing.ts +│ │ ├── demo.ts +│ │ └── cashier.ts +│ ├── views/ +│ │ ├── login/ +│ │ │ ├── Index.vue # 改造:统一入口 +│ │ │ └── systems/ # 新增:系统特定登录组件 +│ │ │ ├── Default.vue # 默认登录页 +│ │ │ ├── Super.vue # 超级租户登录页 +│ │ │ └── Cashier.vue # 收银系统登录页 +│ │ ├── dashboard/ +│ │ │ ├── Index.vue # 改造:统一入口 +│ │ │ └── systems/ # 新增:系统特定 Dashboard +│ │ │ ├── Default.vue # 默认 Dashboard +│ │ │ ├── Cashier.vue # 收银系统 Dashboard +│ │ │ └── Super.vue # 超级租户 Dashboard +│ │ └── ... # 业务页面(保持现有结构) +│ ├── types/ +│ │ └── system-config.d.ts # 系统配置类型定义 +│ └── ... +├── package.json # 改造:添加构建命令 +└── vite.config.ts # 改造:注册插件 +``` + +### 2.5 构建命令 + +```json +// package.json +{ + "scripts": { + "dev": "vite --port 3000", + "dev:cashier": "vite --port 3000 -- --system=cashier", + "dev:super": "vite --port 3000 -- --system=super", + "build": "vue-tsc && vite build", + "build:cashier": "vue-tsc && vite build -- --system=cashier", + "build:super": "vue-tsc && vite build -- --system=super", + "build:admin": "vue-tsc && vite build -- --system=admin", + "build:all": "pnpm build:cashier && pnpm build:super && pnpm build:admin" + } +} +``` + +**产物输出:** + +``` +dist/ +├── cashier/ # 收银系统(system + user + cms + cashier) +├── super/ # 超级租户(system + user) +├── admin/ # 普通后台(system + user + order + cms + marketing) +└── default/ # 默认(全模块,用于开发测试) +``` + +### 2.6 主题配置应用 + +系统配置中的 `theme` 字段在运行时应用: + +```typescript +// App.vue 或布局组件 +import systemConfig from 'virtual:system-config' + +// 设置页面标题 +document.title = systemConfig.theme.title + +// 设置主题色(Element Plus) +const el = document.documentElement +el.style.setProperty('--el-color-primary', systemConfig.theme.primaryColor) +``` + +--- + +## 三、验收标准 + +- [ ] 执行 `pnpm build:super` 成功构建,产物输出到 `dist/super/`,只包含 system 和 user 模块的页面 +- [ ] 执行 `pnpm build:cashier` 成功构建,产物输出到 `dist/cashier/`,包含 system、user、cms、cashier 模块的页面 +- [ ] 不同系统的 Dashboard 显示不同的子组件内容 +- [ ] 不同系统的登录页显示不同的子组件内容(超级租户无租户ID输入) +- [ ] 构建产物中不包含未配置模块的页面代码(Tree Shaking 生效) +- [ ] 现有菜单 API 获取、权限控制、主题切换功能正常 +- [ ] 开发模式 `pnpm dev:cashier` 正常工作,热更新无问题 + +--- + +## 四、风险与依赖 + +| 风险 | 影响 | 缓解措施 | +|------|------|---------| +| Vite 插件开发复杂度 | 中 | 插件逻辑清晰拆分:配置读取、路由生成、虚拟模块、输出配置 | +| Tree Shaking 不彻底 | 中 | 使用 `import()` 动态导入,配合 Rollup 的 `treeshake` 配置,构建后检查产物 | +| 动态组件加载失败 | 低 | 添加错误处理,加载失败时回退到 Default 组件 | +| 现有功能回归 | 中 | 构建后逐一验证核心功能:登录、菜单、CRUD、主题切换 | +| 多人协作冲突 | 低 | 配置文件集中管理,模块路由独立文件,减少冲突 | + +--- + +## 五、后续扩展 + +1. **国际化支持**:配置文件中可扩展 `locales` 字段,支持系统特定的翻译覆盖 +2. **模块懒加载**:未来可考虑运行时动态加载模块(Module Federation) +3. **版本管理**:配置文件支持 `version` 字段,用于产物版本控制 +4. **CI/CD 集成**:构建命令可直接接入 Jenkins/GitHub Actions,参数化构建不同系统 diff --git a/frontend/design/cashier-design.md b/frontend/design/cashier-design.md new file mode 100644 index 0000000..15716a2 --- /dev/null +++ b/frontend/design/cashier-design.md @@ -0,0 +1,1126 @@ +# 收银系统(POS)设计文档 + +> **设计日期**: 2026-06-03 +> **版本**: v2.0 +> **状态**: 设计中 +> **目标**: 为棋牌室、酒吧、KTV 等服务业态构建多端收银系统,支持多门店连锁运营 + +--- + +## 一、背景与目标 + +### 1.1 现状分析 + +目前运营 100+ 棋牌室门店,采用总部 → 代理商 → 门店三级管理模式。各门店急需一套收银系统来管理包间/桌台的开台、计费、结账流程。现有系统空缺,依赖人工记账,效率低、易出错、无法统一管理。 + +### 1.2 目标定义 + +1. **建立标准化收银流程**:支持开台、计时/计费、结账、退款的完整闭环 +2. **多门店统一管理**:总部可查看所有门店数据,代理商管理名下门店,门店独立运营 +3. **多端覆盖**:管理后台(Web)、收银台(APP/小程序),后续扩展收银机、PC 端 +4. **灵活计费模式**:支持按时计费、包时段套餐、按局/圈等混合计费方式 +5. **复杂结算场景**:预付款/后付款、小程序下单、小商品分离结算 +6. **预留扩展能力**:会员钱包、优惠券/团购券、支付通道、第三方平台对接、智能设备控制 + +--- + +## 二、详细设计 + +### 2.1 整体架构 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 前端层 │ +├──────────────┬──────────────┬────────────────┬─────────────────┤ +│ 管理后台 │ 收银台 APP │ 顾客小程序 │ 第三方平台 │ +│ (admin-ui) │ (uni-app) │ (独立uni-app) │ (美团等) │ +│ Vue3+Element│ Vue3语法 │ 二期开发 │ 三期对接 │ +└──────────────┴──────────────┴────────────────┴─────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ 网关层 (rui-gateway) │ +│ 路由转发 │ 鉴权 │ 限流 │ 负载均衡 │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ 业务服务层 (app/rui-cashier/) │ +├──────────────┬──────────────┬────────────────┬─────────────────┤ +│ rui-cashier-store│ rui-cashier-order│ rui-cashier-product│ rui-cashier-report │ +│ 门店+包间服务 │ 订单服务 │ 商品服务 │ 报表服务 │ +│ │ │ │ │ +│ • 组织架构 │ • 开台/结账 │ • 商品档案 │ • 营业日报 │ +│ • 门店管理 │ • 计费规则 │ • 服务分类 │ • 数据统计 │ +│ • 包间/桌台 │ • 子订单管理 │ • 定价管理 │ • 趋势分析 │ +│ • 套餐策略 │ • 退款处理 │ │ │ +│ • 设备管理 │ │ │ │ +└──────────────┴──────────────┴────────────────┴─────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ 基础设施层 │ +│ MySQL 8.0 │ Redis │ Nacos │ MQ(RabbitMQ) │ Seata │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 2.2 服务职责划分 + +#### rui-cashier-store(门店+包间服务) + +**职责**:组织架构、门店管理、包间/桌台管理、套餐策略、设备管理 + +**核心实体**: +- `Store`(门店):基本信息、所属代理商、营业状态、配置 +- `StoreConfig`(门店配置):预付款/后付款、余额支付商品开关等 +- `Agent`(代理商):基本信息、管理的门店列表 +- `RoomType`(包间类型):名称、容纳人数 +- `Room`(包间/桌台):所属门店、类型、状态、设备绑定 +- `PricingStrategy`(定价策略):包间类型关联的套餐集合 +- `PricingPackage`(套餐):具体的价格套餐,支持时段/日期限制 +- `Device`(设备):网关、门锁、电源、音箱、打印机、锁球器等 + +**套餐策略设计**(核心变更): + +```java +// 计费方式枚举 +public enum BillingType { + HOURLY(1, "按时计费"), // 按小时计费,可设最低消费时长 + FIXED_PERIOD(2, "包时段"), // 固定时段买断,如包下午场 + PER_GAME(3, "按局计费"), // 按局/圈计费 + MIXED(4, "混合模式"); // 组合计费 +} + +// 定价策略(一个包间类型对应一个策略,包含多条套餐) +@Data +public class PricingStrategy { + private Long id; + private Long roomTypeId; // 包间类型ID + private String strategyName; // 策略名称,如"标准计费" + private Integer status; // 状态:0-禁用 1-启用 +} + +// 套餐(策略中的具体套餐项) +@Data +public class PricingPackage { + private Long id; + private Long strategyId; // 所属策略ID + private String packageName; // 套餐名称,如"3小时套餐" + private Integer billingType; // 计费方式 + private BigDecimal price; // 套餐价格 + private Integer duration; // 时长(分钟),包时段时有效 + private Integer sort; // 排序,第一条是默认/fallback + + // 限制条件(JSON格式) + private String restrictions; // { + // "weekdays": [1,2,3,4,5], // 工作日可用 + // "weekends": [6,7], // 周末可用 + // "timeRanges": [ // 时段范围 + // {"start": "08:00", "end": "12:00"} + // ], + // "holidays": { // 节假日设置 + // "mode": "EXCLUDE", // EXCLUDE-不可用 INCLUDE-仅可用 + // "dates": ["2026-10-01", "2026-10-02"] + // } + // } + + private Integer isDefault; // 是否默认套餐(1-是 0-否),默认套餐不可配置限制条件 + private Integer status; // 状态:0-禁用 1-启用 +} +``` + +**套餐匹配逻辑**: + +```java +public PricingPackage matchPackage(Long roomTypeId, LocalDateTime startTime) { + // 1. 获取包间类型的定价策略 + PricingStrategy strategy = strategyService.getByRoomTypeId(roomTypeId); + + // 2. 获取策略下的所有套餐,按 sort 排序 + List packages = packageService.getByStrategyId(strategy.getId()); + + // 3. 依次匹配套餐限制条件 + for (PricingPackage pkg : packages) { + if (pkg.getIsDefault() == 1) { + continue; // 默认套餐跳过,作为fallback + } + if (matchRestrictions(pkg.getRestrictions(), startTime)) { + return pkg; // 找到匹配的套餐 + } + } + + // 4. 没有匹配的,返回默认套餐(第一条) + return packages.stream() + .filter(p -> p.getIsDefault() == 1) + .findFirst() + .orElseThrow(() -> new BizException("无可用套餐")); +} +``` + +**包间状态机**: + +``` +空闲 ──[开台]──► 使用中 ──[结账]──► 待清洁 ──[清洁完成]──► 空闲 + ▲ │ │ + │ │ [挂单] │ + │ ▼ │ + │ 已挂单 ──[恢复]───────────────────┘ + │ │ + │ │ [预约](二期) + │ ▼ + │ 已预约 ──[开台]──► 使用中 + │ + └──[取消预约]─── 已预约 +``` + +#### rui-cashier-order(订单服务) + +**职责**:开台、计费计算、结账、退款、订单生命周期管理 + +**核心实体**: +- `Order`(主订单):订单整体信息 +- `RoomSubOrder`(包间子订单):包间消费、计时计费 +- `ProductSubOrder`(商品子订单):小商品消费 +- `OrderTimeline`(订单时间线):开台、结账等关键时间点 + +**订单体系设计**(核心变更): + +```java +// 主订单 +@Data +public class Order { + private Long id; + private String orderNo; // 订单编号 + private Long storeId; // 门店ID + private Long roomId; // 包间ID(包间订单时) + private Integer orderType; // 订单类型:1-包间订单 2-纯商品订单 + private String customerName; // 顾客姓名 + private String customerPhone; // 顾客电话 + + // 金额汇总 + private BigDecimal roomAmount; // 包间费用 + private BigDecimal productAmount; // 商品费用 + private BigDecimal discountAmount;// 优惠金额 + private BigDecimal totalAmount; // 订单总金额 + private BigDecimal payAmount; // 实付金额 + + // 支付信息 + private Integer payStatus; // 支付状态:0-未支付 1-部分支付 2-已支付 + private Integer payType; // 支付方式 + private LocalDateTime payTime; // 支付时间 + + // 状态 + private Integer status; // 订单状态 + private String remark; // 备注 + private Long cashierId; // 收银员ID +} + +// 包间子订单 +@Data +public class RoomSubOrder { + private Long id; + private Long orderId; // 主订单ID + private Long roomId; // 包间ID + private Long packageId; // 使用的套餐ID + private Integer billingType; // 计费方式 + private BigDecimal price; // 套餐价格/单价 + private LocalDateTime startTime; // 开台时间 + private LocalDateTime endTime; // 结账时间 + private Integer duration; // 使用时长(分钟) + private Integer gameCount; // 局数 + private BigDecimal amount; // 包间费用 + private Integer status; // 状态 +} + +// 商品子订单 +@Data +public class ProductSubOrder { + private Long id; + private Long orderId; // 主订单ID + private Long productId; // 商品ID + private String productName; // 商品名称 + private BigDecimal productPrice; // 商品单价 + private Integer quantity; // 数量 + private BigDecimal amount; // 小计金额 + private Integer payStatus; // 支付状态(单独控制) + private Integer source; // 来源:1-收银台 2-顾客小程序 + private LocalDateTime createTime; // 创建时间 +} +``` + +**结算场景支持**: + +```java +// 门店配置 +@Data +public class StoreConfig { + private Long storeId; + private Integer productPayMode; // 商品支付模式:1-先付款 2-后付款 + private Integer balancePayProduct;// 余额是否可支付商品:0-否 1-是 + private Integer notifyOnOrder; // 下单是否通知:0-否 1-是(喇叭+打印) +} + +// 结算逻辑 +public void checkout(Long orderId) { + Order order = orderService.getById(orderId); + StoreConfig config = storeService.getConfig(order.getStoreId()); + + // 1. 计算包间费用 + RoomSubOrder roomOrder = roomSubOrderService.getByOrderId(orderId); + BigDecimal roomAmount = calculateRoomAmount(roomOrder); + + // 2. 计算商品费用 + List products = productSubOrderService.getByOrderId(orderId); + BigDecimal productAmount = products.stream() + .map(ProductSubOrder::getAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add); + + // 3. 计算优惠(预留) + BigDecimal discountAmount = discountService.calculate(orderId); + + // 4. 计算应付金额 + BigDecimal totalAmount = roomAmount.add(productAmount).subtract(discountAmount); + + // 5. 如果商品是先付款模式,商品费用已从实付中扣除 + if (config.getProductPayMode() == 1) { + BigDecimal paidProductAmount = products.stream() + .filter(p -> p.getPayStatus() == 2) + .map(ProductSubOrder::getAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add); + totalAmount = totalAmount.subtract(paidProductAmount); + } + + // 6. 更新订单 + order.setRoomAmount(roomAmount); + order.setProductAmount(productAmount); + order.setDiscountAmount(discountAmount); + order.setTotalAmount(totalAmount); + order.setStatus(2); // 待支付 + orderService.update(order); +} +``` + +**开台流程**(支持小程序预下单): + +``` +场景1:收银台直接开台 +1. 收银员选择包间 → 检查包间状态"空闲" +2. 选择套餐(系统自动匹配当前时段可用套餐) +3. 确认顾客信息 +4. 创建主订单 + 包间子订单 +5. 包间状态变更为"使用中" + +场景2:顾客小程序预订包间 +1. 顾客选择门店、包间类型、时间段 +2. 系统匹配可用套餐,显示价格 +3. 顾客支付包间费用(预付款) +4. 创建主订单 + 包间子订单(状态:已支付) +5. 顾客到店后,收银员确认开台,包间状态变更为"使用中" + +场景3:顾客小程序购买小商品 +1. 顾客扫描包间二维码 +2. 浏览商品,下单 +3. 如果门店配置"先付款":在线支付 → 创建商品子订单 +4. 如果门店配置"后付款":创建商品子订单(未支付) +5. 触发智能喇叭通知、打印小票(如配置) +6. 后付款的商品可在收银台统一结算 +``` + +#### rui-cashier-product(商品服务) + +**职责**:商品/服务档案管理、分类管理、价格管理 + +**核心实体**: +- `Product`(商品/服务):名称、分类、价格、状态 +- `ProductCategory`(分类):名称、层级、排序 +- `StoreProduct`(门店商品):门店可售商品及自定义价格 + +**设计要点**: +- 商品分为"普通商品"(饮料、零食)和"服务商品"(加时、换桌等) +- 支持总部统一配置,门店可自定义价格和上下架 + +#### rui-cashier-report(报表服务) + +**职责**:营业数据统计、报表生成、数据看板 + +**核心功能**: +- 营业日报:按门店、按日期统计营业额、订单数、客单价 +- 包间利用率:各包间使用时长/空闲时长占比 +- 时段分析:高峰时段、低谷时段统计 +- 代理商汇总:名下门店汇总数据 +- 商品销售统计:各商品销量、销售额 + +**技术要点**: +- 报表数据定时从 order 服务同步,避免实时查询拖垮核心服务 +- 支持按门店、代理商、时间维度筛选 + +### 2.3 数据流 + +#### 开台-结账核心流程 + +``` +收银员(APP)/ 顾客(小程序) + │ + ▼ +[选择包间/商品] ──► rui-cashier-store(检查包间状态/商品库存) + │ + ▼ +[确认开台/下单] ──► rui-cashier-order(创建订单) + │ │ + │ ├─ 创建主订单 + │ ├─ 创建包间子订单(或商品子订单) + │ ▼ + │ 包间状态变更为"使用中" + │ │ + ▼ ▼ +[追加商品] ──► rui-cashier-product(查询商品) + │ │ + │ ▼ + │ 创建商品子订单 + │ 触发硬件通知(喇叭+打印,如配置) + ▼ +[结账] ─────► rui-cashier-order(计算费用) + │ │ + │ ├─ 计算包间费用(按时/套餐) + │ ├─ 汇总商品费用(扣除已支付的) + │ ├─ 计算优惠(预留) + │ ▼ + │ 生成应付金额 + │ │ + ▼ ▼ +[支付完成] ──► rui-cashier-order(更新订单状态) + │ │ + │ ▼ + │ 包间状态变更为"待清洁" + ▼ +[清洁完成] ──► rui-cashier-store(包间状态变更为"空闲") +``` + +### 2.4 接口设计 + +#### rui-cashier-store 核心接口 + +```yaml +# 门店管理 +POST /cashier/admin/store # 创建门店 +PUT /cashier/admin/store/{id} # 更新门店 +GET /cashier/admin/store/{id} # 门店详情 +GET /cashier/admin/store/list # 门店列表(按代理商筛选) +DELETE /cashier/admin/store/{id} # 删除门店 + +# 门店配置 +GET /cashier/admin/store/{id}/config # 获取门店配置 +PUT /cashier/admin/store/{id}/config # 更新门店配置 + +# 包间类型管理 +POST /cashier/admin/room-type # 创建包间类型 +PUT /cashier/admin/room-type/{id} # 更新包间类型 +GET /cashier/admin/room-type/list # 包间类型列表 + +# 包间管理 +POST /cashier/admin/room # 创建包间 +PUT /cashier/admin/room/{id} # 更新包间 +GET /cashier/admin/room/list # 包间列表(按门店筛选) +GET /cashier/admin/room/{id}/status # 包间实时状态 + +# 定价策略管理 +POST /cashier/admin/pricing-strategy # 创建定价策略 +PUT /cashier/admin/pricing-strategy/{id} # 更新定价策略 +GET /cashier/admin/pricing-strategy/list # 策略列表 + +# 套餐管理 +POST /cashier/admin/pricing-package # 创建套餐 +PUT /cashier/admin/pricing-package/{id} # 更新套餐 +GET /cashier/admin/pricing-package/list # 套餐列表(按策略筛选) + +# 设备管理 +POST /cashier/admin/device # 注册设备 +PUT /cashier/admin/device/{id} # 更新设备 +GET /cashier/admin/device/list # 设备列表 +POST /cashier/admin/device/{id}/control # 设备控制(预留) +``` + +#### rui-cashier-order 核心接口 + +```yaml +# 开台 +POST /cashier/admin/order/open # 开台(创建订单) + body: { + "roomId": 1, + "packageId": 1, # 选择的套餐ID + "customerName": "张三", // 可选 + "customerPhone": "138...", // 可选 + "remark": "..." // 备注 + } + +# 追加商品(收银台) +POST /cashier/admin/order/{id}/product # 追加商品到订单 + body: { + "productId": 1, + "quantity": 2, + "price": 15.00 + } + +# 顾客小程序下单商品 +POST /cashier/app/order/{id}/product # 顾客下单商品 + body: { + "productId": 1, + "quantity": 2, + "source": 2 // 来源:2-顾客小程序 + } + +# 结账 +POST /cashier/admin/order/{id}/checkout # 结账 + response: { + "orderId": 1, + "roomAmount": 120.00, // 包间费用 + "productAmount": 30.00, // 商品费用(未支付部分) + "paidProductAmount": 20.00, // 已支付商品金额 + "discountAmount": 0.00, // 优惠金额(预留) + "totalAmount": 130.00, // 应付金额 + "duration": 120, // 使用时长(分钟) + "startTime": "2026-06-03T10:00:00", + "endTime": "2026-06-03T12:00:00" + } + +# 确认支付 +POST /cashier/admin/order/{id}/pay # 确认支付(预留支付通道) + body: { + "payType": "CASH", // CASH-现金, WECHAT-微信, ALIPAY-支付宝, BALANCE-余额 + "amount": 130.00, + "remark": "..." + } + +# 商品子订单支付(小程序先付款) +POST /cashier/app/product-order/{id}/pay # 商品子订单支付 + body: { + "payType": "WECHAT", + "amount": 20.00 + } + +# 退款 +POST /cashier/admin/order/{id}/refund # 订单退款 + body: { + "refundAmount": 130.00, + "reason": "..." + } + +# 订单查询 +GET /cashier/admin/order/{id} # 订单详情 +GET /cashier/admin/order/list # 订单列表(按门店、日期筛选) +GET /cashier/admin/order/{id}/timeline # 订单时间线 + +# 包间状态操作 +POST /cashier/admin/room/{id}/clean # 清洁完成(包间恢复空闲) +``` + +### 2.5 数据库设计 + +#### 门店表(rui_cashier_store) + +```sql +CREATE TABLE #prefix#cashier_store ( + id BIGINT PRIMARY KEY COMMENT '门店ID', + agent_id BIGINT NOT NULL COMMENT '所属代理商ID', + store_name VARCHAR(100) NOT NULL COMMENT '门店名称', + store_code VARCHAR(50) NOT NULL COMMENT '门店编码', + contact_name VARCHAR(50) COMMENT '联系人', + contact_phone VARCHAR(20) COMMENT '联系电话', + address VARCHAR(200) COMMENT '地址', + business_hours VARCHAR(50) COMMENT '营业时间', + status TINYINT DEFAULT 1 COMMENT '状态:0-禁用 1-启用', + remark VARCHAR(500) COMMENT '备注', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + deleted TINYINT DEFAULT 0 COMMENT '删除标志', + create_by BIGINT COMMENT '创建人', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_by BIGINT COMMENT '更新人', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', + UNIQUE KEY uk_store_code (store_code), + KEY idx_agent_id (agent_id) +) COMMENT='门店表'; +``` + +#### 门店配置表(rui_cashier_store_config) + +```sql +CREATE TABLE #prefix#cashier_store_config ( + id BIGINT PRIMARY KEY COMMENT '配置ID', + store_id BIGINT NOT NULL COMMENT '门店ID', + config JSON NOT NULL COMMENT '配置内容:{ + \"productPayMode\": 2, // 商品支付模式:1-先付款 2-后付款 + \"balancePayProduct\": 0, // 余额是否可支付商品:0-否 1-是 + \"notifyOnOrder\": 1, // 下单是否通知:0-否 1-是 + \"autoCleanTime\": 10, // 自动清洁时间(分钟) + \"minDeposit\": 50.00, // 最低押金(可选) + \"overtimeRule\": { // 超时规则(可选) + \"type\": 1, // 1-按小时收费 2-按套餐收费 + \"price\": 20.00 + } + }', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', + UNIQUE KEY uk_store_id (store_id) +) COMMENT='门店配置表'; +``` + +#### 包间类型表(rui_cashier_room_type) + +```sql +CREATE TABLE #prefix#cashier_room_type ( + id BIGINT PRIMARY KEY COMMENT '类型ID', + store_id BIGINT NOT NULL COMMENT '所属门店ID', + type_name VARCHAR(50) NOT NULL COMMENT '类型名称', + capacity INT DEFAULT 4 COMMENT '容纳人数', + icon VARCHAR(200) COMMENT '图标', + sort INT DEFAULT 0 COMMENT '排序', + status TINYINT DEFAULT 1 COMMENT '状态:0-禁用 1-启用', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + deleted TINYINT DEFAULT 0 COMMENT '删除标志', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', + KEY idx_store_id (store_id) +) COMMENT='包间类型表'; +``` + +#### 包间表(rui_cashier_room) + +```sql +CREATE TABLE #prefix#cashier_room ( + id BIGINT PRIMARY KEY COMMENT '包间ID', + store_id BIGINT NOT NULL COMMENT '所属门店ID', + room_type_id BIGINT NOT NULL COMMENT '包间类型ID', + room_name VARCHAR(50) NOT NULL COMMENT '包间名称', + room_no VARCHAR(20) NOT NULL COMMENT '包间编号', + room_status TINYINT DEFAULT 0 COMMENT '状态:0-空闲 1-使用中 2-待清洁 3-已挂单 4-已预约', + current_order_id BIGINT COMMENT '当前订单ID', + device_config JSON COMMENT '设备配置(关联的设备ID列表)', + sort INT DEFAULT 0 COMMENT '排序', + enabled TINYINT DEFAULT 1 COMMENT '启用状态:0-禁用 1-启用', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + deleted TINYINT DEFAULT 0 COMMENT '删除标志', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', + UNIQUE KEY uk_room_no (store_id, room_no), + KEY idx_store_id (store_id), + KEY idx_room_status (room_status) +) COMMENT='包间表'; +``` + +#### 定价策略表(rui_cashier_pricing_strategy) + +```sql +CREATE TABLE #prefix#cashier_pricing_strategy ( + id BIGINT PRIMARY KEY COMMENT '策略ID', + room_type_id BIGINT NOT NULL COMMENT '包间类型ID', + strategy_name VARCHAR(50) NOT NULL COMMENT '策略名称', + status TINYINT DEFAULT 1 COMMENT '状态:0-禁用 1-启用', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + deleted TINYINT DEFAULT 0 COMMENT '删除标志', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', + UNIQUE KEY uk_room_type_id (room_type_id), + KEY idx_status (status) +) COMMENT='定价策略表'; +``` + +#### 套餐表(rui_cashier_pricing_package) + +```sql +CREATE TABLE #prefix#cashier_pricing_package ( + id BIGINT PRIMARY KEY COMMENT '套餐ID', + strategy_id BIGINT NOT NULL COMMENT '策略ID', + package_name VARCHAR(50) NOT NULL COMMENT '套餐名称', + billing_type TINYINT NOT NULL COMMENT '计费方式:1-按时 2-包时段 3-按局', + price DECIMAL(19,4) NOT NULL COMMENT '套餐价格', + duration INT COMMENT '时长(分钟),包时段时有效', + min_duration INT DEFAULT 60 COMMENT '最低消费时长(分钟),按时计费时有效', + restrictions JSON COMMENT '限制条件(时段、工作日、节假日)', + is_default TINYINT DEFAULT 0 COMMENT '是否默认套餐:0-否 1-是', + sort INT DEFAULT 0 COMMENT '排序', + status TINYINT DEFAULT 1 COMMENT '状态:0-禁用 1-启用', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + deleted TINYINT DEFAULT 0 COMMENT '删除标志', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', + KEY idx_strategy_id (strategy_id), + KEY idx_status (status) +) COMMENT='套餐表'; +``` + +#### 设备表(rui_cashier_device) + +```sql +CREATE TABLE #prefix#cashier_device ( + id BIGINT PRIMARY KEY COMMENT '设备ID', + store_id BIGINT NOT NULL COMMENT '所属门店ID', + room_id BIGINT COMMENT '关联包间ID(设备可在公共区域,此时为空)', + location VARCHAR(100) COMMENT '设备位置:前台、茶水间、大厅等(设备在公共区域时填写)', + device_name VARCHAR(50) NOT NULL COMMENT '设备名称', + device_code VARCHAR(50) NOT NULL COMMENT '设备编号(唯一标识)', + device_type TINYINT NOT NULL COMMENT '设备类型:1-网关 2-门锁 3-电源 4-音箱 5-打印机 6-锁球器', + parent_id BIGINT COMMENT '父设备ID(门锁/电源等关联网关)', + online_status TINYINT DEFAULT 0 COMMENT '在线状态:0-离线 1-在线', + last_heartbeat DATETIME(3) COMMENT '最后心跳时间', + -- 4G设备信息 + imei VARCHAR(20) COMMENT 'IMEI号(4G设备)', + sim_card_no VARCHAR(20) COMMENT '流量卡号(4G设备)', + sim_operator VARCHAR(20) COMMENT '运营商(移动/联通/电信)', + sim_expire_date DATE COMMENT '流量卡到期日期', + -- 设备功能配置 + functions JSON COMMENT '设备功能配置:{ + \"speaker\": { // 音箱功能(电源控制器自带音箱时) + \"enabled\": true, + \"type\": \"EXTERNAL\", // EXTERNAL-外置 INTERNAL-内置 + \"volume\": 80 // 音量 0-100 + }, + \"power\": { // 电源功能 + \"channels\": 4, // 通道数 + \"channelNames\": [\"照明\", \"空调\", \"插座\", \"备用\"] + } + }', + config JSON COMMENT '扩展配置', + sort INT DEFAULT 0 COMMENT '排序', + status TINYINT DEFAULT 1 COMMENT '状态:0-禁用 1-启用', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + deleted TINYINT DEFAULT 0 COMMENT '删除标志', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', + UNIQUE KEY uk_device_code (device_code), + KEY idx_store_id (store_id), + KEY idx_room_id (room_id), + KEY idx_device_type (device_type), + KEY idx_imei (imei) +) COMMENT='设备表'; +``` + +#### 主订单表(rui_cashier_order) + +```sql +CREATE TABLE #prefix#cashier_order ( + id BIGINT PRIMARY KEY COMMENT '订单ID', + order_no VARCHAR(32) NOT NULL COMMENT '订单编号', + store_id BIGINT NOT NULL COMMENT '门店ID', + room_id BIGINT COMMENT '包间ID(包间订单时)', + order_type TINYINT DEFAULT 1 COMMENT '订单类型:1-包间订单 2-纯商品订单', + customer_name VARCHAR(50) COMMENT '顾客姓名', + customer_phone VARCHAR(20) COMMENT '顾客电话', + room_amount DECIMAL(19,4) DEFAULT 0 COMMENT '包间费用', + product_amount DECIMAL(19,4) DEFAULT 0 COMMENT '商品费用', + discount_amount DECIMAL(19,4) DEFAULT 0 COMMENT '优惠金额', + total_amount DECIMAL(19,4) DEFAULT 0 COMMENT '订单总金额', + pay_amount DECIMAL(19,4) DEFAULT 0 COMMENT '实付金额', + pay_status TINYINT DEFAULT 0 COMMENT '支付状态:0-未支付 1-部分支付 2-已支付', + pay_type VARCHAR(20) COMMENT '支付方式:CASH/WECHAT/ALIPAY/BALANCE', + pay_time DATETIME(3) COMMENT '支付时间', + status TINYINT DEFAULT 0 COMMENT '状态:0-开台中 1-已挂单 2-待支付 3-已完成 4-已退款', + remark VARCHAR(500) COMMENT '备注', + refund_amount DECIMAL(19,4) DEFAULT 0 COMMENT '退款金额', + refund_reason VARCHAR(500) COMMENT '退款原因', + refund_time DATETIME(3) COMMENT '退款时间', + cashier_id BIGINT COMMENT '收银员ID', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + deleted TINYINT DEFAULT 0 COMMENT '删除标志', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', + UNIQUE KEY uk_order_no (order_no), + KEY idx_store_id (store_id), + KEY idx_room_id (room_id), + KEY idx_status (status), + KEY idx_create_time (create_time) +) COMMENT='主订单表'; +``` + +#### 包间子订单表(rui_cashier_room_sub_order) + +```sql +CREATE TABLE #prefix#cashier_room_sub_order ( + id BIGINT PRIMARY KEY COMMENT '子订单ID', + order_id BIGINT NOT NULL COMMENT '主订单ID', + room_id BIGINT NOT NULL COMMENT '包间ID', + package_id BIGINT COMMENT '套餐ID', + billing_type TINYINT NOT NULL COMMENT '计费方式:1-按时 2-包时段 3-按局', + price DECIMAL(19,4) NOT NULL COMMENT '套餐价格/单价', + start_time DATETIME(3) COMMENT '开台时间', + end_time DATETIME(3) COMMENT '结账时间', + duration INT COMMENT '使用时长(分钟)', + game_count INT DEFAULT 0 COMMENT '局数', + amount DECIMAL(19,4) DEFAULT 0 COMMENT '包间费用', + status TINYINT DEFAULT 0 COMMENT '状态:0-进行中 1-已完成 2-已取消', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + deleted TINYINT DEFAULT 0 COMMENT '删除标志', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', + UNIQUE KEY uk_order_id (order_id), + KEY idx_room_id (room_id) +) COMMENT='包间子订单表'; +``` + +#### 商品子订单表(rui_cashier_product_sub_order) + +```sql +CREATE TABLE #prefix#cashier_product_sub_order ( + id BIGINT PRIMARY KEY COMMENT '子订单ID', + order_id BIGINT NOT NULL COMMENT '主订单ID', + product_id BIGINT NOT NULL COMMENT '商品ID', + product_name VARCHAR(100) NOT NULL COMMENT '商品名称', + product_price DECIMAL(19,4) NOT NULL COMMENT '商品单价', + quantity INT NOT NULL COMMENT '数量', + amount DECIMAL(19,4) NOT NULL COMMENT '小计金额', + pay_status TINYINT DEFAULT 0 COMMENT '支付状态:0-未支付 1-部分支付 2-已支付', + source TINYINT DEFAULT 1 COMMENT '来源:1-收银台 2-顾客小程序', + status TINYINT DEFAULT 0 COMMENT '状态:0-待处理 1-已确认 2-已取消', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + deleted TINYINT DEFAULT 0 COMMENT '删除标志', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', + KEY idx_order_id (order_id), + KEY idx_product_id (product_id) +) COMMENT='商品子订单表'; +``` + +#### 商品表(rui_cashier_product) + +```sql +CREATE TABLE #prefix#cashier_product ( + id BIGINT PRIMARY KEY COMMENT '商品ID', + category_id BIGINT COMMENT '分类ID', + product_name VARCHAR(100) NOT NULL COMMENT '商品名称', + product_code VARCHAR(50) COMMENT '商品编码', + product_type TINYINT DEFAULT 1 COMMENT '类型:1-普通商品 2-服务商品', + unit VARCHAR(20) COMMENT '单位', + sale_price DECIMAL(19,4) NOT NULL COMMENT '售价', + cost_price DECIMAL(19,4) COMMENT '成本价', + status TINYINT DEFAULT 1 COMMENT '状态:0-禁用 1-启用', + sort INT DEFAULT 0 COMMENT '排序', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + deleted TINYINT DEFAULT 0 COMMENT '删除标志', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', + KEY idx_category_id (category_id) +) COMMENT='商品表'; +``` + +### 2.6 错误码设计 + +收银系统错误码区间:**5000-5999** + +| 错误码 | 含义 | 场景 | +|--------|------|------| +| 5000 | 门店不存在 | 操作不存在的门店 | +| 5001 | 门店已禁用 | 门店状态为禁用 | +| 5010 | 包间不存在 | 操作不存在的包间 | +| 5011 | 包间已占用 | 开台时包间不是空闲状态 | +| 5012 | 包间已禁用 | 包间状态为禁用 | +| 5020 | 订单不存在 | 操作不存在的订单 | +| 5021 | 订单状态错误 | 操作与当前状态不符 | +| 5022 | 订单已支付 | 重复支付 | +| 5023 | 退款金额超过订单金额 | 退款金额校验失败 | +| 5030 | 商品不存在 | 添加商品时商品不存在或已下架 | +| 5040 | 定价策略不存在 | 包间类型没有配置定价策略 | +| 5041 | 无可用套餐 | 当前时段没有匹配的套餐 | +| 5050 | 设备不存在 | 操作不存在的设备 | +| 5051 | 设备离线 | 设备控制时设备离线 | +| 5060 | 门店配置不存在 | 门店未配置 | + +--- + +## 三、验收标准 + +### MVP 阶段验收标准 + +- [ ] **门店管理**:可创建、编辑、禁用门店,支持按代理商筛选 +- [ ] **门店配置**:可配置商品支付模式、余额支付开关、下单通知开关 +- [ ] **包间管理**:可创建包间类型和包间,配置设备绑定 +- [ ] **套餐策略**:可创建定价策略,添加多个套餐,支持排序和默认套餐 +- [ ] **开台流程**:收银员可选择空闲包间开台,系统自动匹配当前时段可用套餐 +- [ ] **计费计算**:按时计费正确计算时长和费用,支持最低消费时长 +- [ ] **商品管理**:可添加商品,支持收银台追加到订单 +- [ ] **结账流程**:可正常结账,生成订单,支持预付款/后付款模式 +- [ ] **退款功能**:可对已支付订单进行部分或全额退款 +- [ ] **营业报表**:可查看门店营业日报(营业额、订单数、包间利用率) +- [ ] **权限控制**:不同角色(总部/代理商/店长/收银员)看到不同数据和功能 + +### 性能标准 + +- [ ] 包间状态查询响应时间 < 200ms +- [ ] 套餐匹配响应时间 < 300ms +- [ ] 开台操作响应时间 < 500ms +- [ ] 结账计算响应时间 < 500ms +- [ ] 报表查询响应时间 < 2s(支持日期范围筛选) + +--- + +## 四、风险与依赖 + +| 风险 | 影响 | 缓解措施 | +|------|------|----------| +| **多门店数据量大** | 中 | 报表服务独立,定时同步数据;数据库按租户分表 | +| **套餐策略复杂** | 中 | 策略+套餐两级设计,限制条件JSON化;充分测试边界场景 | +| **支付 SDK 延迟** | 高 | 先实现现金支付,预留支付接口;等 SDK 就绪后对接 | +| **uni-app 性能** | 低 | 收银场景简单,无复杂动画;如性能不足可考虑原生小程序 | +| **智能设备对接** | 高 | 预留设备控制接口;等 IOT 平台就绪后对接;APP 端先集成插件 | +| **并发开台** | 中 | 包间状态变更加分布式锁;订单号使用雪花算法 | +| **第三方平台对接** | 中 | 预留开放平台 API;三期按需对接美团等平台 | +| **子订单分离** | 中 | 商品子订单独立支付状态,需保证数据一致性 | + +--- + +## 五、预留扩展设计 + +### 5.1 会员钱包预留 + +```sql +-- 会员钱包表(二期) +CREATE TABLE #prefix#cashier_member_wallet ( + id BIGINT PRIMARY KEY COMMENT '钱包ID', + member_id BIGINT NOT NULL COMMENT '会员ID', + real_balance DECIMAL(19,4) DEFAULT 0 COMMENT '实际金额', + gift_balance DECIMAL(19,4) DEFAULT 0 COMMENT '赠送金额', + total_balance DECIMAL(19,4) DEFAULT 0 COMMENT '总余额', + status TINYINT DEFAULT 1 COMMENT '状态', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', + UNIQUE KEY uk_member_id (member_id) +) COMMENT='会员钱包表'; + +-- 钱包流水表(二期) +CREATE TABLE #prefix#cashier_wallet_transaction ( + id BIGINT PRIMARY KEY COMMENT '流水ID', + wallet_id BIGINT NOT NULL COMMENT '钱包ID', + transaction_type TINYINT NOT NULL COMMENT '类型:1-充值 2-消费 3-退款', + amount DECIMAL(19,4) NOT NULL COMMENT '金额', + real_amount DECIMAL(19,4) COMMENT '实际金额变动', + gift_amount DECIMAL(19,4) COMMENT '赠送金额变动', + order_no VARCHAR(32) COMMENT '关联订单号', + remark VARCHAR(500) COMMENT '备注', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + KEY idx_wallet_id (wallet_id) +) COMMENT='钱包流水表'; +``` + +```java +// 余额支付接口(预留) +public interface BalancePaymentService { + // 检查余额是否足够 + boolean checkBalance(Long memberId, BigDecimal amount); + + // 扣款(先扣赠送金额,再扣实际金额) + PaymentResult deduct(Long memberId, BigDecimal amount, String orderNo); + + // 退款(退回实际金额) + PaymentResult refund(Long memberId, BigDecimal amount, String orderNo); +} + +// 门店配置余额支付范围 +// StoreConfig.balance_pay_product:0-余额不可支付商品 1-余额可支付商品 +``` + +### 5.2 优惠券/团购券预留 + +```sql +-- 优惠券表(二期) +CREATE TABLE #prefix#cashier_coupon ( + id BIGINT PRIMARY KEY COMMENT '优惠券ID', + coupon_name VARCHAR(100) NOT NULL COMMENT '优惠券名称', + coupon_type TINYINT NOT NULL COMMENT '类型:1-满减 2-折扣 3-立减', + face_value DECIMAL(19,4) NOT NULL COMMENT '面值', + min_amount DECIMAL(19,4) DEFAULT 0 COMMENT '最低消费金额', + valid_days INT COMMENT '有效天数', + status TINYINT DEFAULT 1 COMMENT '状态', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间' +) COMMENT='优惠券表'; + +-- 第三方团购券表(二期) +CREATE TABLE #prefix#cashier_third_party_voucher ( + id BIGINT PRIMARY KEY COMMENT '券ID', + platform VARCHAR(20) NOT NULL COMMENT '平台:MEITUAN/DIANPING', + voucher_code VARCHAR(50) NOT NULL COMMENT '券码', + voucher_name VARCHAR(100) COMMENT '券名称', + face_value DECIMAL(19,4) NOT NULL COMMENT '面值', + status TINYINT DEFAULT 0 COMMENT '状态:0-未使用 1-已使用 2-已过期', + use_time DATETIME(3) COMMENT '使用时间', + order_no VARCHAR(32) COMMENT '关联订单号', + tenant_id BIGINT DEFAULT 0 COMMENT '租户ID', + create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + UNIQUE KEY uk_voucher_code (voucher_code) +) COMMENT='第三方团购券表'; +``` + +```java +// 优惠计算接口(预留) +public interface DiscountService { + // 计算订单可使用的优惠 + List calculateAvailableDiscounts(Long orderId, Long memberId); + + // 应用优惠 + DiscountResult applyDiscount(Long orderId, List couponIds, List voucherCodes); + + // 核销团购券 + VoucherResult verifyVoucher(String voucherCode); +} +``` + +### 5.3 支付通道预留 + +```java +// 支付接口(预留) +public interface PaymentService { + // 发起支付 + PaymentResult pay(Long orderId, String payType, BigDecimal amount); + + // 查询支付状态 + PaymentStatus queryStatus(String payOrderNo); + + // 退款 + RefundResult refund(Long orderId, BigDecimal amount, String reason); +} + +// 当前实现:现金支付 +@Component +public class CashPaymentService implements PaymentService { + // 仅记录支付流水,不调用第三方 +} + +// 后续扩展:微信支付、支付宝、余额支付等 +@Component +public class WechatPaymentService implements PaymentService { + // 对接支付平台 SDK +} +``` + +### 5.4 第三方平台对接预留 + +```java +// 开放平台接口(预留) +@RestController +@RequestMapping("/cashier/open") +public class OpenPlatformController { + + // 查询包间可用性 + @GetMapping("/room/availability") + public Result> queryAvailability( + @RequestParam Long storeId, + @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startTime, + @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endTime) { + // 返回各包间在指定时段的可用状态 + } + + // 查询套餐价格 + @GetMapping("/room/{roomTypeId}/packages") + public Result> queryPackages( + @PathVariable Long roomTypeId, + @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startTime) { + // 返回当前时段可用套餐 + } + + // 第三方下单 + @PostMapping("/order/create") + public Result createOrder(@RequestBody @Valid OpenOrderDTO dto) { + // 创建订单,返回订单信息 + } + + // 订单状态同步 + @GetMapping("/order/{orderNo}/status") + public Result queryStatus(@PathVariable String orderNo) { + // 返回订单当前状态 + } + + // 退款 + @PostMapping("/order/{orderNo}/refund") + public Result refund(@PathVariable String orderNo, @RequestBody RefundDTO dto) { + // 处理退款 + } +} +``` + +### 5.5 智能设备控制预留 + +```java +// 设备控制服务(预留) +public interface DeviceControlService { + // 开锁 + Result unlock(Long roomId); + + // 关锁 + Result lock(Long roomId); + + // 通电 + Result powerOn(Long roomId); + + // 断电 + Result powerOff(Long roomId); + + // 语音播报 + Result playVoice(Long roomId, String content); + + // 打印小票 + Result printTicket(Long roomId, String content); +} + +// 当前实现:空实现(记录日志) +@Component +public class DummyDeviceControlService implements DeviceControlService { + // 仅记录操作日志,等 IOT 平台对接后替换 +} +``` + +--- + +## 六、模块结构 + +``` +app/rui-cashier/ +├── pom.xml # 聚合 POM +├── rui-cashier-store/ # 门店+包间服务 +│ ├── rui-cashier-store-common/ # DTO、枚举、常量 +│ ├── rui-cashier-store-core/ # Entity、Mapper、Service +│ └── rui-cashier-store-api/ # REST API +├── rui-cashier-order/ # 订单服务 +│ ├── rui-cashier-order-common/ +│ ├── rui-cashier-order-core/ +│ └── rui-cashier-order-api/ +├── rui-cashier-product/ # 商品服务 +│ ├── rui-cashier-product-common/ +│ ├── rui-cashier-product-core/ +│ └── rui-cashier-product-api/ +└── rui-cashier-report/ # 报表服务 + ├── rui-cashier-report-common/ + ├── rui-cashier-report-core/ + └── rui-cashier-report-api/ +``` + +--- + +## 七、实施阶段规划 + +### 阶段一:MVP(6-8 周) +- 搭建项目结构 +- 实现 rui-cashier-store(门店+包间+套餐策略+设备管理) +- 实现 rui-cashier-order(开台、计费、结账、退款、子订单) +- 实现 rui-cashier-product(商品管理) +- 实现基础报表 +- 开发管理后台页面(admin-ui) +- 开发收银台 APP(uni-app) + +### 阶段二:会员+营销+顾客小程序(4-6 周) +- 会员系统(注册、积分、储值) +- 会员钱包(实际金额+赠送金额) +- 优惠券、营销活动 +- 顾客小程序(预约、扫码开台、在线支付) + +### 阶段三:生态对接(4-6 周) +- 支付通道对接(微信、支付宝、余额) +- 第三方平台对接(美团等) +- 第三方团购券对接 +- IOT 设备对接(通过 IOT 平台) +- 收银机/PC 端开发 + +--- + +*文档结束* diff --git a/frontend/design/rui-admin功能设计文档.md b/frontend/design/rui-admin功能设计文档.md new file mode 100644 index 0000000..2311e05 --- /dev/null +++ b/frontend/design/rui-admin功能设计文档.md @@ -0,0 +1,268 @@ +# rui-admin 功能设计文档 + +## 1. 项目概述 + +rui-admin 是睿核通用平台框架的后台管理前端系统,基于 Vue 3 + Element Plus + UnoCSS 构建,提供完整的系统管理、用户管理、内容管理、订单管理、营销管理等功能。 + +## 2. 功能模块划分 + +### 2.1 系统管理(system)- 核心模块 + +| 功能 | 状态 | 后端API | 说明 | +|------|------|---------|------| +| 菜单管理 | ✅ 已完成 | SysMenuController | 树形结构、图标修复 | +| 角色管理 | ✅ 已完成 | SysRoleController | CRUD + 权限分配 | +| 部门管理 | ✅ 已完成 | SysDeptController | 树形表格 | +| 字典管理 | ✅ 已完成 | SysDictTypeController | 字典类型 + 字典项 | +| 参数配置 | ✅ 已完成 | SysConfigController | 系统参数维护 | +| 租户管理 | ✅ 已完成 | SysTenantController | 多租户管理 | +| **操作日志** | ⏳ 待开发 | 需新建 | 用户操作审计 | +| **登录日志** | ⏳ 待开发 | 需新建 | 登录行为记录 | +| **OAuth2客户端** | ⏳ 待开发 | SystemOAuth2ClientController | 客户端管理前端 | + +### 2.2 用户中心(user)- 核心模块 + +| 功能 | 状态 | 后端API | 说明 | +|------|------|---------|------| +| 用户管理 | ✅ 已完成 | UserController | 用户CRUD | +| 用户等级 | ✅ 已完成 | UserLevelController | 等级体系管理 | +| **用户详情** | ⏳ 待开发 | UserDetailController | 用户详细信息 | +| **等级日志** | ⏳ 待开发 | UserLevelLogController | 等级变更记录 | +| **用户账户** | ⏳ 待开发 | 需评估 | 账户安全设置 | +| **用户地址** | ⏳ 待开发 | 需新建 | 收货地址管理 | + +### 2.3 系统设置(settings)- 基础模块 + +| 功能 | 状态 | 后端API | 说明 | +|------|------|---------|------| +| **个人设置** | ⏳ 待开发 | 需评估 | 个人信息修改 | +| **系统设置** | ⏳ 待开发 | SysConfigController | 全局参数配置界面 | +| **密码修改** | ⏳ 待开发 | UserController | 修改登录密码 | + +### 2.4 订单管理(order)- 业务模块 + +| 功能 | 状态 | 后端API | 说明 | +|------|------|---------|------| +| **订单列表** | ⏳ 预留 | 需新建服务 | 订单查询、状态管理 | +| **退款管理** | ⏳ 预留 | 需新建服务 | 退款申请处理 | + +### 2.5 内容管理(cms)- 业务模块 + +| 功能 | 状态 | 后端API | 说明 | +|------|------|---------|------| +| **文章管理** | ⏳ 预留 | 需新建服务 | CMS文章CRUD | +| **分类管理** | ⏳ 预留 | 需新建服务 | 文章分类 | +| **轮播管理** | ⏳ 预留 | 需新建服务 | Banner管理 | + +### 2.6 营销管理(marketing)- 业务模块 + +| 功能 | 状态 | 后端API | 说明 | +|------|------|---------|------| +| **优惠券** | ⏳ 预留 | 需新建服务 | 优惠券CRUD | +| **活动管理** | ⏳ 预留 | 需新建服务 | 营销活动 | + +## 3. 开发优先级 + +### Phase 1:核心功能完善(立即开始) + +1. **操作日志**(system/log) + - 后端:创建 OperLog 实体、Mapper、Service、Controller + - 前端:日志列表页、详情弹窗 + - 优先级:🔴 高 + +2. **用户详情**(user/info/detail) + - 后端:UserDetailController 已有,补充前端 + - 前端:用户详情查看/编辑 + - 优先级:🔴 高 + +3. **等级日志**(user/level-log) + - 后端:UserLevelLogController 已有,补充前端 + - 前端:等级变更记录列表 + - 优先级:🟡 中 + +4. **系统设置**(settings) + - 后端:复用 SysConfigController + - 前端:参数配置界面(与 system/config 区别:更友好的展示) + - 优先级:🟡 中 + +### Phase 2:基础功能补充(近期) + +5. **登录日志**(system/login-log) + - 后端:创建 LoginLog 实体、Mapper、Service、Controller + - 前端:登录记录列表 + - 优先级:🟡 中 + +6. **OAuth2客户端管理**(system/client) + - 后端:SystemOAuth2ClientController 已有 + - 前端:客户端CRUD + - 优先级:🟡 中 + +7. **个人中心**(profile) + - 后端:复用现有接口 + - 前端:个人信息展示与修改 + - 优先级:🟢 低 + +### Phase 3:业务模块(按需) + +8. **订单管理** - 需新建 rui-service-order 服务 +9. **CMS内容管理** - 需新建 rui-service-cms 服务 +10. **营销管理** - 需新建 rui-service-marketing 服务 + +## 4. 技术规范 + +### 4.1 前端规范 + +```typescript +// 页面结构标准 +views/ +├── {module}/ +│ ├── Index.vue # 列表页(必须) +│ ├── {Module}FormDialog.vue # 表单弹窗(新增/编辑) +│ └── {Module}DetailDialog.vue # 详情弹窗(可选) +``` + +### 4.2 后端规范 + +```java +// Controller 标准结构 +@RestController +@RequestMapping("/{模块}/admin/{功能}") +public class XxxController extends BaseController { + // 自动获得:page、list、getById、save、updateById、remove +} +``` + +### 4.3 API 路径规范 + +| 类型 | 路径前缀 | 示例 | +|------|---------|------| +| 对外管理 | `/{模块}/admin/{功能}` | `/system/admin/log` | +| 内部调用 | `/{模块}/inner/{功能}` | `/system/inner/client` | +| 对外入口 | `/{模块}/entry/{功能}` | `/auth/entry/login` | + +## 5. 数据库设计(新增表) + +### 5.1 操作日志表(rui_sys_oper_log) + +```sql +CREATE TABLE rui_sys_oper_log ( + id BIGINT NOT NULL, + tenant_id BIGINT NOT NULL DEFAULT 0, + oper_type TINYINT NOT NULL DEFAULT 1 COMMENT '操作类型 1:新增 2:修改 3:删除 4:查询 5:导出 6:登录 7:登出', + title VARCHAR(200) NOT NULL COMMENT '操作模块', + method VARCHAR(500) DEFAULT NULL COMMENT '请求方法', + request_url VARCHAR(500) DEFAULT NULL, + request_method VARCHAR(10) DEFAULT NULL COMMENT 'GET/POST/PUT/DELETE', + request_params TEXT DEFAULT NULL, + response_data TEXT DEFAULT NULL, + user_id BIGINT DEFAULT NULL, + user_name VARCHAR(100) DEFAULT NULL, + oper_ip VARCHAR(128) DEFAULT NULL, + oper_location VARCHAR(255) DEFAULT NULL, + status TINYINT NOT NULL DEFAULT 1 COMMENT '状态 0:失败 1:成功', + error_msg TEXT DEFAULT NULL, + cost_time BIGINT DEFAULT 0 COMMENT '耗时(ms)', + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + INDEX idx_user (user_id), + INDEX idx_tenant (tenant_id), + INDEX idx_created (created_at) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='操作日志'; +``` + +### 5.2 登录日志表(rui_sys_login_log) + +```sql +CREATE TABLE rui_sys_login_log ( + id BIGINT NOT NULL, + tenant_id BIGINT NOT NULL DEFAULT 0, + user_id BIGINT DEFAULT NULL, + username VARCHAR(100) DEFAULT NULL, + login_type TINYINT NOT NULL DEFAULT 1 COMMENT '登录类型 1:密码 2:短信 3:微信', + client_id VARCHAR(100) DEFAULT NULL, + ip VARCHAR(128) DEFAULT NULL, + location VARCHAR(255) DEFAULT NULL, + browser VARCHAR(200) DEFAULT NULL, + os VARCHAR(200) DEFAULT NULL, + status TINYINT NOT NULL DEFAULT 1 COMMENT '状态 0:失败 1:成功', + msg VARCHAR(500) DEFAULT NULL, + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + INDEX idx_user (user_id), + INDEX idx_tenant (tenant_id), + INDEX idx_created (created_at) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='登录日志'; +``` + +## 6. 实施计划 + +### 第1周:Phase 1 核心功能 +- [ ] 后端:操作日志 AOP 拦截 + API +- [ ] 前端:system/log 页面 +- [ ] 前端:user/info 详情弹窗 +- [ ] 前端:user/level-log 页面 + +### 第2周:Phase 2 基础功能 +- [ ] 后端:登录日志 API +- [ ] 前端:system/login-log 页面 +- [ ] 前端:settings 系统设置页 +- [ ] 前端:profile 个人中心 + +### 第3周+:Phase 3 业务模块(按需) +- [ ] 订单服务 + 前端页面 +- [ ] CMS服务 + 前端页面 +- [ ] 营销服务 + 前端页面 + +## 7. 前端组件规划 + +### 7.1 复用组件 + +| 组件 | 用途 | 位置 | +|------|------|------| +| RuiTable | 通用表格 | components/RuiTable.vue | +| RuiIcon | 图标渲染 | components/RuiIcon.vue | +| IconPicker | 图标选择 | components/IconPicker.vue | + +### 7.2 新增组件需求 + +| 组件 | 用途 | 优先级 | +|------|------|--------| +| LogDetailDialog | 日志详情展示 | 🔴 高 | +| UserDetailPanel | 用户信息卡片 | 🔴 高 | +| ConfigGroupPanel | 配置分组展示 | 🟡 中 | + +## 8. 权限设计 + +### 8.1 菜单权限 + +``` +system:menu:list - 菜单列表 +system:menu:add - 新增菜单 +system:menu:edit - 编辑菜单 +system:menu:remove - 删除菜单 +system:log:list - 日志列表 +system:log:remove - 删除日志 +``` + +### 8.2 数据权限 + +- 超级管理员:查看所有租户数据 +- 租户管理员:仅查看本租户数据 +- 普通用户:仅查看个人数据 + +## 9. 注意事项 + +1. **操作日志性能**:大量操作日志可能影响性能,建议: + - 异步写入(MQ或线程池) + - 定期归档(30天前的日志迁移到历史表) + - 提供日志清理功能 + +2. **登录日志安全**: + - 记录失败登录尝试,用于安全审计 + - 支持 IP 黑名单 + - 异常登录告警 + +3. **预留模块**: + - order/cms/marketing 为业务预留模块 + - 需要时创建对应后端服务 + - 前端页面保持占位状态即可 diff --git a/frontend/plans/cashier-admin-implementation.md b/frontend/plans/cashier-admin-implementation.md new file mode 100644 index 0000000..96d2439 --- /dev/null +++ b/frontend/plans/cashier-admin-implementation.md @@ -0,0 +1,1387 @@ +# 收银系统后台管理功能完善实施计划 + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers-subagent-driven-development (recommended) or superpowers-executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 完善收银系统后台管理的前端页面功能,为所有列表页面添加新增/编辑表单弹窗,完善订单开台功能,优化营业报表展示 + +**Architecture:** 基于现有 admin-ui 框架和 RuiTable 组件,为每个收银模块创建 FormDialog 组件,遵循项目已有的组件模式和编码规范 + +**Tech Stack:** Vue 3 + TypeScript + Element Plus + Vite + +--- + +## 文件结构 + +### 新增文件 +- `src/views/cashier/store/StoreFormDialog.vue` - 门店表单弹窗 +- `src/views/cashier/room/RoomFormDialog.vue` - 包间表单弹窗 +- `src/views/cashier/product/ProductFormDialog.vue` - 商品表单弹窗 +- `src/views/cashier/pricing/PricingStrategyFormDialog.vue` - 定价策略表单弹窗 +- `src/views/cashier/pricing/PricingPackageDialog.vue` - 套餐管理弹窗 +- `src/views/cashier/order/OpenRoomDialog.vue` - 开台弹窗 + +### 修改文件 +- `src/views/cashier/store/Index.vue` - 集成门店表单弹窗 +- `src/views/cashier/room/Index.vue` - 集成包间表单弹窗 +- `src/views/cashier/product/Index.vue` - 集成商品表单弹窗 +- `src/views/cashier/pricing/Index.vue` - 集成定价策略表单弹窗和套餐管理 +- `src/views/cashier/order/Index.vue` - 集成开台弹窗 +- `src/service/cashier/*Service.ts` - 补充缺失的方法 + +--- + +## 模块优先级 + +按业务依赖关系,实施顺序为: +1. 门店管理(最基础,其他模块依赖门店) +2. 商品管理 +3. 包间管理(依赖门店和包间类型) +4. 定价策略(依赖包间类型) +5. 订单管理(依赖门店和包间) +6. 营业报表优化 + +--- + +## Task 1: 完善门店管理 + +**Files:** +- Create: `src/views/cashier/store/StoreFormDialog.vue` +- Modify: `src/views/cashier/store/Index.vue` + +**Context:** 门店实体字段:name, address, phone, contactName, status, remark + +### Step 1: 创建门店表单弹窗 + +Create `src/views/cashier/store/StoreFormDialog.vue`: + +```vue + + + +``` + +### Step 2: 修改门店管理页面集成弹窗 + +Modify `src/views/cashier/store/Index.vue`: + +Add imports: +```typescript +import StoreFormDialog from './StoreFormDialog.vue' +``` + +Add state: +```typescript +const dialogVisible = ref(false) +const currentRow = ref() +``` + +Replace handleAdd: +```typescript +function handleAdd() { + currentRow.value = undefined + dialogVisible.value = true +} +``` + +Replace handleEdit: +```typescript +function handleEdit(row: any) { + currentRow.value = row + dialogVisible.value = true +} +``` + +Add dialog component in template: +```vue + +``` + +### Step 3: 验证 + +Run: +```bash +cd /Users/zhangsheng/rhkj/spring-ai/admin-ui +pnpm dev:cashier +``` + +Expected: 门店管理页面可以正常打开新增/编辑弹窗 + +### Step 4: Commit + +```bash +git add src/views/cashier/store/ +git commit -m "feat(cashier): 完善门店管理新增编辑功能" +``` + +--- + +## Task 2: 完善商品管理 + +**Files:** +- Create: `src/views/cashier/product/ProductFormDialog.vue` +- Modify: `src/views/cashier/product/Index.vue` +- Modify: `src/service/cashier/productService.ts` + +**Context:** 商品实体字段:name, price, productType(1实物/2服务/3虚拟), category, unit, stock, status, description, storeId + +### Step 1: 补充商品 Service 方法 + +Verify `src/service/cashier/productService.ts` has: +```typescript +import { BaseService } from '../BaseService' + +class ProductService extends BaseService { + constructor() { + super('/cashier/admin/product') + } +} + +export const productService = new ProductService() +``` + +### Step 2: 创建商品表单弹窗 + +Create `src/views/cashier/product/ProductFormDialog.vue`: + +```vue + + + +``` + +### Step 3: 修改商品管理页面 + +Similar to Task 1 Step 2, integrate ProductFormDialog into product/Index.vue + +### Step 4: Commit + +```bash +git add src/views/cashier/product/ src/service/cashier/productService.ts +git commit -m "feat(cashier): 完善商品管理新增编辑功能" +``` + +--- + +## Task 3: 完善包间管理 + +**Files:** +- Create: `src/views/cashier/room/RoomFormDialog.vue` +- Modify: `src/views/cashier/room/Index.vue` + +**Context:** 包间实体字段:storeId, roomTypeId, name, roomNo, roomStatus, enabled, sort +需要获取门店列表和包间类型列表 + +### Step 1: 创建包间表单弹窗 + +Create `src/views/cashier/room/RoomFormDialog.vue`: + +```vue + + + +``` + +### Step 2: 修改包间管理页面 + +Integrate RoomFormDialog into room/Index.vue (similar pattern) + +### Step 3: Commit + +```bash +git add src/views/cashier/room/ +git commit -m "feat(cashier): 完善包间管理新增编辑功能" +``` + +--- + +## Task 4: 完善定价策略 + +**Files:** +- Create: `src/views/cashier/pricing/PricingStrategyFormDialog.vue` +- Create: `src/views/cashier/pricing/PricingPackageDialog.vue` +- Modify: `src/views/cashier/pricing/Index.vue` + +**Context:** 定价策略实体:strategyName, roomTypeId, status +套餐实体:name, price, duration, durationUnit, description, strategyId, billingType, minDuration, restrictions, isDefault, sort, status + +### Step 1: 创建定价策略表单弹窗 + +Create `src/views/cashier/pricing/PricingStrategyFormDialog.vue`: + +```vue + + + +``` + +### Step 2: 创建套餐管理弹窗 + +Create `src/views/cashier/pricing/PricingPackageDialog.vue`: + +```vue + + + +``` + +### Step 3: 补充 pricingService 方法 + +Modify `src/service/cashier/pricingService.ts`: + +```typescript +import { BaseService } from '../BaseService' +import { request } from '@/utils/request' + +class PricingService extends BaseService { + constructor() { + super('/cashier/admin/pricing-strategy') + } + + async getPackages(strategyId: number) { + const res: any = await request({ + url: '/cashier/admin/pricing-package/list', + method: 'get', + params: { strategyId }, + }) + return res.data || [] + } + + async addPackage(data: any) { + const res: any = await request({ + url: '/cashier/admin/pricing-package', + method: 'post', + data, + }) + return res.data + } + + async updatePackage(data: any) { + const res: any = await request({ + url: '/cashier/admin/pricing-package', + method: 'put', + data, + }) + return res.data + } + + async deletePackage(id: number) { + const res: any = await request({ + url: `/cashier/admin/pricing-package/${id}`, + method: 'delete', + }) + return res.data + } +} + +export const pricingService = new PricingService() +``` + +### Step 4: 修改定价策略页面 + +Integrate both dialogs into pricing/Index.vue + +### Step 5: Commit + +```bash +git add src/views/cashier/pricing/ src/service/cashier/pricingService.ts +git commit -m "feat(cashier): 完善定价策略和套餐管理功能" +``` + +--- + +## Task 5: 完善订单管理(开台功能) + +**Files:** +- Create: `src/views/cashier/order/OpenRoomDialog.vue` +- Modify: `src/views/cashier/order/Index.vue` +- Modify: `src/service/cashier/orderService.ts` + +**Context:** 开台需要:门店ID、包间ID、顾客姓名、顾客电话、订单类型、备注 + +### Step 1: 补充 orderService 方法 + +Modify `src/service/cashier/orderService.ts`: + +```typescript +import { BaseService } from '../BaseService' +import { request } from '@/utils/request' + +class OrderService extends BaseService { + constructor() { + super('/cashier/admin/order') + } + + async checkout(id: number) { + const res: any = await request({ + url: `${this.baseUrl}/${id}/checkout`, + method: 'post', + }) + return res.data + } + + async refund(id: number, data: { amount: number; reason: string }) { + const res: any = await request({ + url: `${this.baseUrl}/${id}/refund`, + method: 'post', + data, + }) + return res.data + } + + async openRoom(data: { + storeId: number + roomId: number + customerName?: string + customerPhone?: string + orderType?: number + remark?: string + }) { + const res: any = await request({ + url: `${this.baseUrl}/open`, + method: 'post', + data, + }) + return res.data + } +} + +export const orderService = new OrderService() +``` + +### Step 2: 创建开台弹窗 + +Create `src/views/cashier/order/OpenRoomDialog.vue`: + +```vue + + + +``` + +### Step 3: 修改订单管理页面 + +Integrate OpenRoomDialog into order/Index.vue + +### Step 4: Commit + +```bash +git add src/views/cashier/order/ src/service/cashier/orderService.ts +git commit -m "feat(cashier): 完善订单管理开台功能" +``` + +--- + +## Task 6: 营业报表优化 + +**Files:** +- Modify: `src/views/cashier/report/Index.vue` + +**Context:** 当前报表已展示日报数据和包间利用率,可以优化图表展示 + +### Step 1: 添加图表展示 + +Install echarts if not already installed: +```bash +cd /Users/zhangsheng/rhkj/spring-ai/admin-ui +pnpm add echarts vue-echarts +``` + +### Step 2: 优化报表页面 + +Add chart components for: +- 营业趋势图(折线图) +- 支付方式饼图 +- 包间利用率柱状图 + +### Step 3: Commit + +```bash +git add src/views/cashier/report/ package.json pnpm-lock.yaml +git commit -m "feat(cashier): 优化营业报表图表展示" +``` + +--- + +## Task 7: 验证和文档更新 + +**Files:** +- Modify: `docs/admin-ui-status.md` + +### Step 1: 验证所有功能 + +Run: +```bash +cd /Users/zhangsheng/rhkj/spring-ai/admin-ui +pnpm build:cashier +``` + +Expected: 构建成功,无错误 + +### Step 2: 更新状态文档 + +Update `docs/admin-ui-status.md`: + +```markdown +### 8. 收银系统模块 + +| 功能 | 页面 | 状态 | 说明 | +|------|------|------|------| +| 门店管理 | cashier/store/Index.vue | ✅ 完成 | 增删改查、状态切换 | +| 包间管理 | cashier/room/Index.vue | ✅ 完成 | 增删改查、状态切换 | +| 商品管理 | cashier/product/Index.vue | ✅ 完成 | 增删改查、状态切换 | +| 定价策略 | cashier/pricing/Index.vue | ✅ 完成 | 增删改查、套餐管理 | +| 订单管理 | cashier/order/Index.vue | ✅ 完成 | 开台、结账、退款、查询 | +| 营业报表 | cashier/report/Index.vue | ✅ 完成 | 日报、包间利用率、图表 | +``` + +### Step 3: Commit + +```bash +git add docs/admin-ui-status.md +git commit -m "docs: 更新收银系统功能状态" +``` + +--- + +## 验证清单 + +- [ ] 门店管理:新增、编辑、删除、查询、状态切换正常 +- [ ] 包间管理:新增、编辑、删除、查询、状态切换正常 +- [ ] 商品管理:新增、编辑、删除、查询、状态切换正常 +- [ ] 定价策略:新增、编辑、删除、查询、套餐管理正常 +- [ ] 订单管理:开台、结账、退款、查询正常 +- [ ] 营业报表:数据展示、图表正常 +- [ ] 所有页面无编译错误 +- [ ] 构建产物正常 + +--- + +## 风险与依赖 + +| 风险 | 影响 | 缓解措施 | +|------|------|---------| +| 后端 API 字段与前端不一致 | 高 | 开发时对比后端实体字段,确保一致 | +| 包间类型数据未对接 | 中 | 先使用 ID 输入,后续优化为下拉选择 | +| 图表库引入增加包体积 | 低 | 按需引入 echarts 组件 | +| 开台功能需要实时状态更新 | 中 | 开台成功后刷新列表 | + +--- + +## 后续扩展 + +1. **包间类型管理** - 添加包间类型 CRUD 页面 +2. **设备管理** - 添加门店设备管理页面 +3. **会员管理** - 完善会员等级、积分管理 +4. **库存管理** - 添加商品库存预警功能 +5. **数据导出** - 为所有列表添加导出功能 diff --git a/standards/API设计规范.md b/standards/API设计规范.md new file mode 100644 index 0000000..efe434a --- /dev/null +++ b/standards/API设计规范.md @@ -0,0 +1,505 @@ +# API 设计规范 + +> 睿核科技通用平台框架 RESTful API 统一设计标准 + +--- + +## 一、接口分类 + +| 分类 | 路径前缀 | 认证 | 说明 | +|------|---------|------|------| +| **对外接口** | `/{模块}/api/**` | OAuth2 Token | 对外提供的业务接口 | +| **内部接口** | `/{模块}/inner/**` | `@Inner` + `INTERNAL_REQUEST` | 微服务间 Feign 调用 | +| **入口接口** | `/{模块}/entry/**` | 无需认证 | 对外入口(登录、注册) | +| **回调接口** | `/{模块}/notify/**` | 无需认证 | 第三方回调(支付、Webhook) | +| **管理接口** | `/{模块}/admin/**` | 需管理员权限 | 后台管理 | + +--- + +## 二、URL 设计规范 + +### 2.1 对外接口(RESTful) + +``` +GET /{version}/{模块}/{资源} # 列表查询 +GET /{version}/{模块}/{资源}/{id} # 详情查询 +POST /{version}/{模块}/{资源} # 新增 +PUT /{version}/{模块}/{资源}/{id} # 全量更新 +PATCH /{version}/{模块}/{资源}/{id} # 局部更新 +DELETE /{version}/{模块}/{资源}/{id} # 删除 +``` + +**示例**: +``` +GET /v1/user/users?page=1&size=10 # 查询用户列表 +GET /v1/user/users/1001 # 查询用户详情 +POST /v1/user/users # 新增用户 +PUT /v1/user/users/1001 # 全量更新用户 +PATCH /v1/user/users/1001 # 局部更新(如只改状态) +DELETE /v1/user/users/1001 # 删除用户 +``` + +### 2.2 内部接口(Feign) + +``` +GET /{模块}/inner/{功能}/{方法} +``` + +**示例**: +``` +GET /user/inner/auth/loadByUsername/{username} +GET /system/inner/client/getById/{clientId} +``` + +### 2.3 版本控制 + +- **URI 版本**(推荐):`/v1/user/users` +- **Header 版本**(可选):`Accept: application/vnd.rui.v1+json` + +--- + +## 三、请求规范 + +### 3.1 HTTP 方法 + +| 方法 | 用途 | 幂等性 | +|------|------|--------| +| GET | 查询 | ✅ | +| POST | 新增/提交 | ❌ | +| PUT | 全量更新 | ✅ | +| PATCH | 局部更新 | ❌ | +| DELETE | 删除 | ✅ | + +### 3.2 Content-Type + +``` +Content-Type: application/json; charset=utf-8 +``` + +### 3.3 请求头规范 + +| Header | 必填 | 说明 | +|--------|------|------| +| Authorization | 是(除 entry/notify) | `Bearer {access_token}` | +| Content-Type | 是 | `application/json` | +| X-Request-Id | 否 | 请求追踪 ID(网关自动生成) | +| X-Tenant-Id | 否 | 租户 ID(后端自动注入) | +| Accept-Language | 否 | 语言偏好 `zh-CN` / `en-US` | + +### 3.4 分页参数 + +``` +GET /v1/user/users?page=1&size=10&sort=createdAt,desc +``` + +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| page | int | 1 | 当前页码(从1开始) | +| size | int | 10 | 每页条数(最大100) | +| sort | string | createdAt,desc | 排序字段和方向 | + +### 3.5 查询参数 + +``` +GET /v1/user/users?username=admin&status=1&createdAt_start=2024-01-01&createdAt_end=2024-12-31 +``` + +**规则**: +- 精确匹配:字段名直接等于值 `status=1` +- 模糊匹配:字段名加后缀 `_like` `username_like=admin` +- 范围查询:字段名加后缀 `_start` / `_end` `createdAt_start=2024-01-01` +- 多值查询:字段名加后缀 `_in` `status_in=1,2` + +--- + +## 四、响应规范 + +### 4.1 统一响应格式 + +```json +{ + "code": 200, + "msg": "操作成功", + "data": {} +} +``` + +### 4.2 分页响应格式 + +```json +{ + "code": 200, + "msg": "操作成功", + "data": { + "records": [], + "total": 100, + "size": 10, + "current": 1, + "pages": 10 + } +} +``` + +### 4.3 HTTP 状态码 + +| 状态码 | 含义 | 使用场景 | +|--------|------|---------| +| 200 | OK | 查询成功、更新成功 | +| 201 | Created | 新增成功 | +| 204 | No Content | 删除成功(无返回体) | +| 400 | Bad Request | 参数校验失败 | +| 401 | Unauthorized | 未登录/Token 过期 | +| 403 | Forbidden | 无权限访问 | +| 404 | Not Found | 资源不存在 | +| 409 | Conflict | 资源冲突(如重复提交) | +| 429 | Too Many Requests | 请求过于频繁 | +| 500 | Internal Server Error | 服务器内部错误 | + +### 4.4 错误码规范 + +| 区间 | 模块 | 示例 | +|------|------|------| +| 1000-1999 | 通用 | 1001: 参数校验失败, 1002: 资源不存在 | +| 2000-2999 | 用户模块 | 2001: 用户名已存在, 2002: 密码错误 | +| 3000-3999 | 系统模块 | 3001: 字典不存在, 3002: 配置错误 | +| 4000-4999 | 认证模块 | 4001: Token 过期, 4002: 无权访问 | +| 5000-5999 | 文件模块 | 5001: 上传失败, 5002: 文件过大 | +| 6000-6999 | 消息模块 | 6001: 发送失败, 6002: 模板不存在 | + +**错误响应示例**: +```json +{ + "code": 2001, + "msg": "用户名已存在", + "data": null +} +``` + +--- + +## 五、Controller 命名与路径映射 + +### 5.1 命名规则 + +| 类型 | Controller 命名 | 路径 | 说明 | +|------|----------------|------|------| +| 对外业务 | `UserController` | `/v1/user/users/**` | 常规 CRUD | +| 内部调用 | `UserInnerController` | `/user/inner/**` | Feign 调用 | +| 对外入口 | `UserEntryController` | `/user/entry/**` | 免认证入口 | +| 第三方回调 | `PayNotifyController` | `/pay/notify/**` | Webhook | +| 后台管理 | `UserAdminController` | `/v1/user/admin/**` | 管理接口 | + +### 5.2 方法命名 + +| 操作 | 方法名 | HTTP | 路径 | +|------|--------|------|------| +| 列表 | `list` / `page` | GET | `/{资源}` | +| 详情 | `getById` | GET | `/{资源}/{id}` | +| 新增 | `add` / `save` | POST | `/{资源}` | +| 更新 | `update` / `edit` | PUT | `/{资源}/{id}` | +| 局部更新 | `patch` | PATCH | `/{资源}/{id}` | +| 删除 | `remove` / `delete` | DELETE | `/{资源}/{id}` | +| 批量删除 | `batchRemove` | DELETE | `/{资源}/batch` | +| 导出 | `export` | GET | `/{资源}/export` | +| 导入 | `import` | POST | `/{资源}/import` | + +--- + +## 六、Swagger 注解规范 + +### 6.1 Controller 注解 + +```java +@Tag(name = "用户管理", description = "用户相关接口") +@RestController +@RequestMapping("/v1/user/users") +public class UserController { + + @Operation(summary = "查询用户列表", description = "支持分页、排序、条件查询") + @GetMapping + public Result> list( + @Parameter(description = "页码") @RequestParam(defaultValue = "1") Integer page, + @Parameter(description = "每页条数") @RequestParam(defaultValue = "10") Integer size) { + // ... + } + + @Operation(summary = "新增用户") + @PostMapping + public Result add(@RequestBody @Valid UserDTO dto) { + // ... + } +} +``` + +### 6.2 DTO / VO 注解 + +```java +@Schema(description = "用户新增DTO") +@Data +public class UserDTO { + + @Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "admin") + @NotBlank(message = "用户名不能为空") + @Size(min = 2, max = 50, message = "用户名长度2-50字符") + private String username; + + @Schema(description = "状态 0:禁用 1:启用", example = "1") + private Integer status; +} +``` + +--- + +## 七、数据校验规范 + +### 7.1 分组校验 + +```java +public interface AddGroup {} // 新增分组 +public interface UpdateGroup {} // 更新分组 +``` + +### 7.2 使用示例 + +```java +@Data +public class UserDTO { + + @NotNull(message = "ID不能为空", groups = UpdateGroup.class) + private Long id; + + @NotBlank(message = "用户名不能为空", groups = {AddGroup.class, UpdateGroup.class}) + private String username; +} + +// Controller +@PostMapping +public Result add(@RequestBody @Validated(AddGroup.class) UserDTO dto) { + // 新增 +} + +@PutMapping("/{id}") +public Result update(@RequestBody @Validated(UpdateGroup.class) UserDTO dto) { + // 更新 +} +``` + +--- + +## 八、Feign 接口规范 + +### 8.1 接口定义 + +```java +/** + * 远程用户服务 + */ +@Headers("INTERNAL_REQUEST: INTERNAL") +@FeignClient( + contextId = "remoteUserService", + value = "${feign.providers.user:rui-service-user}", + path = "/user/inner" +) +public interface RemoteUserService { + + @GetMapping("/auth/loadByUsername/{username}") + Result> loadUser(@PathVariable String username); +} +``` + +### 8.2 调用规范 + +```java +@Service +@RequiredArgsConstructor +public class UserRemoteService { + + private final RemoteUserService remoteUserService; + + public UserVO getUserById(Long userId) { + Result result = remoteUserService.getById(userId); + if (result.isSuccess()) { + return result.getData(); + } + throw new BizException(result.getCode(), result.getMsg()); + } +} +``` + +--- + +## 九、文件上传接口规范 + +### 9.1 单文件上传 + +``` +POST /v1/file/files/upload +Content-Type: multipart/form-data + +file: [二进制文件] +module: user +bizId: 1001 +``` + +**响应**: +```json +{ + "code": 200, + "msg": "上传成功", + "data": { + "fileId": "123456", + "fileName": "avatar.jpg", + "fileUrl": "https://oss.example.com/avatar/123456.jpg", + "fileSize": 102400 + } +} +``` + +### 9.2 多文件上传 + +``` +POST /v1/file/files/batchUpload +Content-Type: multipart/form-data + +files: [文件1, 文件2, 文件3] +module: user +``` + +--- + +## 十、导出接口规范 + +### 10.1 Excel 导出 + +``` +GET /v1/user/users/export?username=admin&status=1 +Accept: application/vnd.ms-excel +``` + +**响应**: +``` +Content-Type: application/vnd.ms-excel +Content-Disposition: attachment; filename="用户列表_20240101.xlsx" +``` + +### 10.2 CSV 导出 + +``` +GET /v1/user/users/export?format=csv +Accept: text/csv +``` + +--- + +## 十一、WebSocket 接口规范(预留) + +``` +ws://gateway:9300/ws/{模块}/{topic} +``` + +**示例**: +``` +ws://localhost:9300/ws/msg/notification # 消息通知 +ws://localhost:9300/ws/monitor/metrics # 实时监控 +``` + +--- + +## 十二、接口文档生成 + +### 12.1 配置 SpringDoc + +```yaml +springdoc: + swagger-ui: + path: /swagger-ui.html + enabled: true + api-docs: + path: /v3/api-docs + enabled: true + group-configs: + - group: 用户服务 + display-name: 用户服务 API + paths-to-match: /v1/user/** + - group: 系统服务 + display-name: 系统服务 API + paths-to-match: /v1/system/** +``` + +### 12.2 访问地址 + +``` +http://localhost:9300/swagger-ui.html # 网关聚合文档 +http://localhost:9301/swagger-ui.html # 认证服务文档 +http://localhost:9302/swagger-ui.html # 系统服务文档 +http://localhost:9303/swagger-ui.html # 用户服务文档 +``` + +--- + +## 十三、Postman / APIFox 集合规范 + +### 13.1 目录结构 + +``` +睿核科技通用平台 +├── 01-认证中心 +│ ├── 获取Token +│ ├── 刷新Token +│ └── 退出登录 +├── 02-用户中心 +│ ├── 用户管理 +│ ├── 等级管理 +│ └── 用户查询 +├── 03-系统管理 +│ ├── 租户管理 +│ ├── 菜单管理 +│ ├── 角色管理 +│ ├── 字典管理 +│ └── 参数配置 +├── 04-文件管理 +│ ├── 文件上传 +│ └── 文件下载 +└── 99-内部接口(Feign) + ├── 用户服务 + └── 系统服务 +``` + +### 13.2 环境变量 + +```json +{ + "baseUrl": "http://localhost:9300", + "token": "{{login_response_token}}", + "tenantId": "1" +} +``` + +--- + +## 十四、接口变更管理 + +### 14.1 变更类型 + +| 类型 | 说明 | 版本处理 | +|------|------|---------| +| 新增接口 | 新增资源/功能 | 当前版本可用 | +| 新增字段 | 请求/响应增加字段 | 当前版本可用(兼容) | +| 废弃字段 | 字段标记 deprecated | 当前版本可用,下版本移除 | +| 废弃接口 | 接口标记 deprecated | 保留至少2个版本后移除 | +| 破坏性变更 | 字段删除/类型变更 | 升级版本号(v1 → v2) | + +### 14.2 版本迭代策略 + +``` +v1.0 —— 初始版本 +v1.1 —— 新增字段(兼容) +v1.2 —— 新增接口(兼容) +v2.0 —— 破坏性变更(不兼容) +``` + +--- + +> **文档版本**: v1.0 +> **创建日期**: 2026-05-28 +> **适用范围**: 睿核科技通用平台框架所有 RESTful API diff --git a/standards/coding-standards.md b/standards/coding-standards.md new file mode 100644 index 0000000..f72fd36 --- /dev/null +++ b/standards/coding-standards.md @@ -0,0 +1,280 @@ +# 编码规范 + +## 🎯 通用原则 + +1. **可读性优先** - 代码是写给人看的,顺便给机器执行 +2. **DRY 原则** - Don't Repeat Yourself +3. **单一职责** - 一个类/方法只做一件事 +4. **开闭原则** - 对扩展开放,对修改关闭 + +--- + +## 📝 Java 编码规范 + +### 命名规范 + +| 类型 | 规范 | 示例 | +|------|------|------| +| 类名 | 大驼峰 | `UserService`, `OrderController` | +| 方法名 | 小驼峰 | `getUserById()`, `createOrder()` | +| 变量名 | 小驼峰 | `userName`, `orderList` | +| 常量 | 全大写下划线 | `MAX_RETRY_COUNT`, `DEFAULT_TIMEOUT` | +| 包名 | 全小写 | `com.rui.service.user` | + +### 代码格式 + +```java +// 正确的类定义 +@Service +public class UserServiceImpl implements IUserService { + + private final UserMapper userMapper; + private final RedisUtil redisUtil; + + // 构造器注入(推荐) + public UserServiceImpl(UserMapper userMapper, RedisUtil redisUtil) { + this.userMapper = userMapper; + this.redisUtil = redisUtil; + } + + // 方法注释 + /** + * 根据ID获取用户信息 + * @param userId 用户ID + * @return 用户信息 + */ + @Override + public UserDTO getUserById(Long userId) { + // 先查缓存 + UserDTO user = redisUtil.get("user:" + userId); + if (user != null) { + return user; + } + + // 再查数据库 + User entity = userMapper.selectById(userId); + if (entity == null) { + throw new BizException("用户不存在"); + } + + // 转换并缓存 + user = convertToDTO(entity); + redisUtil.set("user:" + userId, user, 3600); + + return user; + } +} +``` + +### 注释规范 + +```java +/** + * 用户服务实现类 + * + * @author pigeon + * @since 2024-01-01 + */ +@Service +public class UserServiceImpl { + + /** + * 获取用户详情 + * + * @param userId 用户ID,不能为空 + * @return 用户详情DTO + * @throws BizException 用户不存在时抛出 + */ + public UserDetailDTO getDetail(Long userId) { + // ... + } +} +``` + +--- + +## 🌐 TypeScript/Vue 编码规范 + +### 命名规范 + +| 类型 | 规范 | 示例 | +|------|------|------| +| 组件名 | 大驼峰 | `UserTable.vue`, `OrderForm.vue` | +| 组合式函数 | use前缀 | `useUser()`, `useOrder()` | +| 类型定义 | 大驼峰 | `UserDTO`, `OrderFormData` | +| 常量 | 全大写下划线 | `API_BASE_URL`, `PAGE_SIZE` | +| 变量/函数 | 小驼峰 | `userList`, `getUserList()` | + +### 组件规范 + +```vue + +``` + +--- + +## 🗄️ 数据库规范 + +### 命名规范 + +| 类型 | 规范 | 示例 | +|------|------|------| +| 表名 | 下划线、复数 | `sys_user`, `cashier_order` | +| 字段名 | 下划线 | `user_name`, `created_at` | +| 索引名 | idx_前缀 | `idx_user_name` | +| 外键 | fk_前缀 | `fk_order_user` | + +### 必备字段 + +```sql +-- 所有表必须包含以下字段 +CREATE TABLE example_table ( + id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID', + -- 业务字段 + name VARCHAR(100) NOT NULL COMMENT '名称', + + -- 审计字段(由框架自动填充) + create_by VARCHAR(64) COMMENT '创建者', + create_time DATETIME COMMENT '创建时间', + update_by VARCHAR(64) COMMENT '更新者', + update_time DATETIME COMMENT '更新时间', + deleted TINYINT DEFAULT 0 COMMENT '删除标志(0-正常,1-删除)', + tenant_id BIGINT COMMENT '租户ID', + + -- 索引 + INDEX idx_name (name) +) COMMENT='示例表'; +``` + +--- + +## 🔒 安全规范 + +1. **SQL 注入防护** - 使用 MyBatis 参数绑定,禁止字符串拼接 SQL +2. **XSS 防护** - 前端转义输出,后端校验输入 +3. **敏感信息** - 密码必须加密存储,日志中禁止输出敏感信息 +4. **接口鉴权** - 所有接口必须校验权限(白名单除外) + +--- + +## 🧪 测试规范 + +### Java 测试 + +```java +@SpringBootTest +class UserServiceTest { + + @Autowired + private IUserService userService; + + @Test + @DisplayName("根据ID查询用户-正常情况") + void getUserById_Success() { + // Given + Long userId = 1L; + + // When + UserDTO user = userService.getUserById(userId); + + // Then + assertThat(user).isNotNull(); + assertThat(user.getId()).isEqualTo(userId); + } + + @Test + @DisplayName("根据ID查询用户-用户不存在") + void getUserById_NotFound() { + // Given + Long userId = 999L; + + // Then + assertThrows(BizException.class, () -> { + userService.getUserById(userId); + }); + } +} +``` + +--- + +## 📝 Git 提交规范 + +``` +(): + + + +