feat: 迭代
This commit is contained in:
@@ -36,7 +36,22 @@
|
||||
"Read(//e/project/wb/**)",
|
||||
"Bash(pnpm dev:server)",
|
||||
"Bash(pnpm --filter @rent/server run build)",
|
||||
"Bash(pnpm --filter @rent/server run dev)"
|
||||
"Bash(pnpm --filter @rent/server run dev)",
|
||||
"Bash(curl -s http://localhost:3000/api/app/merchants)",
|
||||
"Bash(awk '{print $5}')",
|
||||
"Bash(xargs -I {} taskkill //PID {} //F)",
|
||||
"Bash(curl -X GET \"http://localhost:3000/api/app/activity/list\" -H \"Content-Type: application/json\")",
|
||||
"Bash(curl -X GET \"http://localhost:3000/api/app/activity/invite/config\" -H \"Content-Type: application/json\")",
|
||||
"Bash(curl -X GET \"http://localhost:3000/api/app/finance/wallet\" -H \"Content-Type: application/json\" -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOjEsInR5cGUiOiJ1c2VyIiwiaWF0IjoxNzQ3MjMzNTMxLCJleHAiOjE3NDk4MjU1MzF9.Y7Ky8VGE5gqFN_SEZx-VvdVJhkန_example_token\")",
|
||||
"Bash(curl -s -X GET \"http://localhost:3000/api/app/activity/invite/records?page=1&pageSize=20\" -H \"Content-Type: application/json\" -H \"Authorization: Bearer test\")",
|
||||
"Bash(curl -X GET \"http://localhost:3000/api/admin/merchants/3\" -H \"Content-Type: application/json\")",
|
||||
"Bash(curl -X GET \"http://localhost:3000/api/admin/finance/reports/overview\" -H \"Content-Type: application/json\")",
|
||||
"Bash(curl -X GET \"http://localhost:3000/api/admin/reviews?page=1&pageSize=10\" -H \"Content-Type: application/json\")",
|
||||
"Bash(curl -X GET \"http://localhost:3000/api/merchant/finance/wallet\" -H \"Content-Type: application/json\")",
|
||||
"Bash(curl -X GET \"http://localhost:3000/api/admin/finance/reports/weekly\" -H \"Content-Type: application/json\")",
|
||||
"Bash(xargs grep -l \"room\" -i)",
|
||||
"Bash(mysql -h localhost -u root -p123456 -D rent -e \"DESCRIBE user_coupons;\")",
|
||||
"Bash(docker exec *)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,584 @@
|
||||
# 接口分类重构计划
|
||||
|
||||
## 一、重构目标
|
||||
|
||||
将所有后端接口按照使用端分成四类,通过文件夹和路由前缀清晰区分:
|
||||
|
||||
1. **应用端 (app)** - 小程序C端用户使用的接口
|
||||
2. **商家端 (merchant)** - 小程序商家端 + 商家管理后台使用的接口
|
||||
3. **平台管理端 (admin)** - 平台管理后台使用的接口
|
||||
4. **官网 (website)** - 官方网站使用的接口
|
||||
|
||||
## 二、目标目录结构
|
||||
|
||||
```
|
||||
apps/server/src/modules/
|
||||
├── app/ # 应用端接口 (路由前缀: /api/app/*)
|
||||
│ ├── auth/ # 用户认证
|
||||
│ ├── profile/ # 用户资料
|
||||
│ ├── order/ # 订单管理
|
||||
│ ├── review/ # 评价管理
|
||||
│ ├── coupon/ # 优惠券
|
||||
│ ├── guest/ # 入住人管理
|
||||
│ ├── activity/ # 活动/邀请
|
||||
│ ├── finance/ # 钱包/提现
|
||||
│ └── app.module.ts
|
||||
│
|
||||
├── merchant/ # 商家端接口 (路由前缀: /api/merchant/*)
|
||||
│ ├── auth/ # 商家认证
|
||||
│ ├── profile/ # 商家资料
|
||||
│ ├── room/ # 房源管理
|
||||
│ ├── room-calendar/ # 房态日历
|
||||
│ ├── order/ # 订单管理
|
||||
│ ├── review/ # 评价管理
|
||||
│ ├── statistics/ # 数据统计
|
||||
│ ├── finance/ # 财务管理
|
||||
│ └── merchant.module.ts
|
||||
│
|
||||
├── admin/ # 平台管理端接口 (路由前缀: /api/admin/*)
|
||||
│ ├── auth/ # 管理员认证
|
||||
│ ├── user/ # 用户管理
|
||||
│ ├── merchant/ # 商家管理
|
||||
│ ├── room/ # 房源管理
|
||||
│ ├── order/ # 订单管理
|
||||
│ ├── review/ # 评价管理
|
||||
│ ├── coupon/ # 优惠券管理
|
||||
│ ├── activity/ # 活动管理
|
||||
│ ├── config/ # 系统配置
|
||||
│ ├── website/ # 官网内容管理
|
||||
│ ├── finance/ # 财务管理
|
||||
│ │ ├── account/ # 账户管理
|
||||
│ │ ├── transaction/ # 交易记录
|
||||
│ │ ├── withdrawal/ # 提现管理
|
||||
│ │ ├── settlement/ # 结算管理
|
||||
│ │ ├── reconciliation/# 对账管理
|
||||
│ │ └── report/ # 财务报表
|
||||
│ └── admin.module.ts
|
||||
│
|
||||
├── website/ # 官网接口 (路由前缀: /api/website/*)
|
||||
│ ├── info/ # 网站信息
|
||||
│ ├── room/ # 房源展示(公开)
|
||||
│ ├── merchant/ # 商家展示(公开)
|
||||
│ └── website.module.ts
|
||||
│
|
||||
└── shared/ # 共享模块(不对外暴露路由)
|
||||
├── upload/ # 文件上传
|
||||
└── config/ # 配置服务
|
||||
```
|
||||
|
||||
## 三、接口分类详情
|
||||
|
||||
### 3.1 应用端接口 (48个接口)
|
||||
|
||||
**路由前缀**: `/api/app/*`
|
||||
|
||||
| 模块 | 当前路由 | 新路由 | 文件位置 |
|
||||
|------|---------|--------|----------|
|
||||
| 用户认证 | `/user/auth/*` | `/api/app/auth/*` | user/auth/ |
|
||||
| 用户资料 | `/user/profile/*` | `/api/app/profile/*` | user/profile/ |
|
||||
| 订单管理 | `/user/orders/*` | `/api/app/orders/*` | user/order/ |
|
||||
| 评价管理 | `/user/reviews/*` | `/api/app/reviews/*` | user/review/ |
|
||||
| 优惠券 | `/user/coupons/*` | `/api/app/coupons/*` | user/coupon/ |
|
||||
| 入住人 | `/user/guests/*` | `/api/app/guests/*` | user/guest/ |
|
||||
| 活动邀请 | `/user/activity/invite/*` | `/api/app/activity/*` | user/activity/ |
|
||||
| 钱包财务 | `/user/finance/*` | `/api/app/finance/*` | user/finance/ |
|
||||
|
||||
**涉及的Controller文件**:
|
||||
- `user/auth/auth.controller.ts`
|
||||
- `user/profile/profile.controller.ts`
|
||||
- `user/order/order.controller.ts`
|
||||
- `user/review/review.controller.ts`
|
||||
- `user/coupon/coupon.controller.ts`
|
||||
- `user/guest/guest.controller.ts`
|
||||
- `user/activity/activity.controller.ts`
|
||||
- `common/finance/finance-user.controller.ts`
|
||||
- `common/finance/withdrawal-user.controller.ts`
|
||||
- `common/coupon/coupon-user.controller.ts`
|
||||
|
||||
### 3.2 商家端接口 (56个接口)
|
||||
|
||||
**路由前缀**: `/api/merchant/*`
|
||||
|
||||
| 模块 | 当前路由 | 新路由 | 文件位置 |
|
||||
|------|---------|--------|----------|
|
||||
| 商家认证 | `/merchant/auth/*` | `/api/merchant/auth/*` | merchant/auth/ |
|
||||
| 商家资料 | `/merchant/profile/*` | `/api/merchant/profile/*` | merchant/profile/ |
|
||||
| 房源管理 | `/merchant/rooms/*` | `/api/merchant/rooms/*` | merchant/room/ |
|
||||
| 房态日历 | `/merchant/room-calendar/*` | `/api/merchant/room-calendar/*` | merchant/room-calendar/ |
|
||||
| 订单管理 | `/merchant/orders/*` | `/api/merchant/orders/*` | merchant/order/ |
|
||||
| 评价管理 | `/merchant/reviews/*` | `/api/merchant/reviews/*` | merchant/review/ |
|
||||
| 数据统计 | `/merchant/statistics/*` | `/api/merchant/statistics/*` | merchant/statistics/ |
|
||||
| 财务管理 | `/merchant/finance/*` | `/api/merchant/finance/*` | merchant/finance/ |
|
||||
|
||||
**涉及的Controller文件**:
|
||||
- `merchant/auth/auth.controller.ts`
|
||||
- `merchant/profile/profile.controller.ts`
|
||||
- `merchant/room/room.controller.ts`
|
||||
- `merchant/room-calendar/room-calendar.controller.ts`
|
||||
- `merchant/order/order.controller.ts`
|
||||
- `merchant/review/review.controller.ts`
|
||||
- `merchant/statistics/statistics.controller.ts`
|
||||
- `merchant/finance/finance.controller.ts`
|
||||
- `common/finance/transaction-seller.controller.ts`
|
||||
- `common/finance/withdrawal-merchant.controller.ts`
|
||||
- `common/finance/settlement-merchant.controller.ts`
|
||||
|
||||
### 3.3 平台管理端接口 (72个接口)
|
||||
|
||||
**路由前缀**: `/api/admin/*`
|
||||
|
||||
| 模块 | 当前路由 | 新路由 | 文件位置 |
|
||||
|------|---------|--------|----------|
|
||||
| 管理员认证 | `/admin/auth/*` | `/api/admin/auth/*` | admin/auth/ |
|
||||
| 用户管理 | `/admin/users/*` | `/api/admin/users/*` | admin/user/ |
|
||||
| 商家管理 | `/admin/merchants/*` | `/api/admin/merchants/*` | admin/merchant/ |
|
||||
| 房源管理 | `/admin/rooms/*` | `/api/admin/rooms/*` | admin/room/ |
|
||||
| 订单管理 | `/admin/orders/*` | `/api/admin/orders/*` | admin/order/ |
|
||||
| 评价管理 | `/admin/reviews/*` | `/api/admin/reviews/*` | admin/review/ |
|
||||
| 优惠券管理 | `/admin/coupons/*` | `/api/admin/coupons/*` | admin/coupon/ |
|
||||
| 活动管理 | `/admin/activity/*` | `/api/admin/activity/*` | admin/activity/ |
|
||||
| 系统配置 | `/admin/config/*` | `/api/admin/config/*` | admin/config/ |
|
||||
| 官网管理 | `/admin/website/info/*` | `/api/admin/website/*` | admin/website/ |
|
||||
| 账户管理 | `/admin/finance/accounts/*` | `/api/admin/finance/accounts/*` | admin/finance/ |
|
||||
| 交易记录 | `/admin/finance/transactions/*` | `/api/admin/finance/transactions/*` | admin/finance/ |
|
||||
| 提现管理 | `/admin/finance/withdrawals/*` | `/api/admin/finance/withdrawals/*` | admin/finance/ |
|
||||
| 结算管理 | `/admin/finance/settlements/*` | `/api/admin/finance/settlements/*` | admin/finance/ |
|
||||
| 对账管理 | `/admin/finance/reconciliations/*` | `/api/admin/finance/reconciliations/*` | admin/finance/ |
|
||||
| 财务报表 | `/admin/finance/reports/*` | `/api/admin/finance/reports/*` | admin/finance/ |
|
||||
|
||||
**涉及的Controller文件**:
|
||||
- `admin/auth/auth.controller.ts`
|
||||
- `admin/user/user.controller.ts`
|
||||
- `admin/merchant/merchant.controller.ts`
|
||||
- `admin/room/room.controller.ts`
|
||||
- `admin/order/order.controller.ts`
|
||||
- `admin/review/review.controller.ts`
|
||||
- `admin/coupon/coupon.controller.ts`
|
||||
- `admin/activity/activity.controller.ts`
|
||||
- `admin/config/config.controller.ts`
|
||||
- `admin/website/website.controller.ts`
|
||||
- `common/finance/account-admin.controller.ts`
|
||||
- `common/finance/transaction-admin.controller.ts`
|
||||
- `common/finance/withdrawal-admin.controller.ts`
|
||||
- `common/finance/settlement-admin.controller.ts`
|
||||
- `common/finance/reconciliation-admin.controller.ts`
|
||||
- `common/finance/report-admin.controller.ts`
|
||||
- `common/coupon/coupon-admin.controller.ts`
|
||||
|
||||
### 3.4 官网接口 (12个接口)
|
||||
|
||||
**路由前缀**: `/api/website/*`
|
||||
|
||||
| 模块 | 当前路由 | 新路由 | 文件位置 |
|
||||
|------|---------|--------|----------|
|
||||
| 网站信息 | `/website/info/*` | `/api/website/info/*` | website/info/ |
|
||||
| 房源展示 | `/public/rooms/*` | `/api/website/rooms/*` | website/room/ |
|
||||
| 商家展示 | `/public/merchants/*` | `/api/website/merchants/*` | website/merchant/ |
|
||||
|
||||
**涉及的Controller文件**:
|
||||
- `website/info/info.controller.ts`
|
||||
- 需要新建: `website/room/room.controller.ts` (公开房源查询)
|
||||
- 需要新建: `website/merchant/merchant.controller.ts` (公开商家查询)
|
||||
|
||||
## 四、执行步骤
|
||||
|
||||
### 步骤1: 重命名和移动目录 (30分钟)
|
||||
|
||||
```bash
|
||||
# 1. 重命名 user 为 app
|
||||
cd apps/server/src/modules
|
||||
mv user app
|
||||
|
||||
# 2. 保持 merchant 不变
|
||||
|
||||
# 3. 保持 admin 不变
|
||||
|
||||
# 4. 保持 website 不变
|
||||
|
||||
# 5. 重命名 common 为 shared
|
||||
mv common shared
|
||||
```
|
||||
|
||||
### 步骤2: 移动 common 中的 controller 到对应模块 (45分钟)
|
||||
|
||||
#### 2.1 移动应用端相关的 controller
|
||||
|
||||
```bash
|
||||
# 移动用户优惠券
|
||||
mv shared/coupon/coupon-user.controller.ts app/coupon/
|
||||
mv shared/coupon/coupon-user.service.ts app/coupon/
|
||||
|
||||
# 移动用户财务
|
||||
mv shared/finance/finance-user.controller.ts app/finance/
|
||||
mv shared/finance/withdrawal-user.controller.ts app/finance/
|
||||
```
|
||||
|
||||
#### 2.2 移动商家端相关的 controller
|
||||
|
||||
```bash
|
||||
# 移动商家财务
|
||||
mv shared/finance/transaction-seller.controller.ts merchant/finance/
|
||||
mv shared/finance/withdrawal-merchant.controller.ts merchant/finance/
|
||||
mv shared/finance/settlement-merchant.controller.ts merchant/finance/
|
||||
```
|
||||
|
||||
#### 2.3 移动平台管理端相关的 controller
|
||||
|
||||
```bash
|
||||
# 移动管理优惠券
|
||||
mv shared/coupon/coupon-admin.controller.ts admin/coupon/
|
||||
|
||||
# 移动管理财务
|
||||
mv shared/finance/account-admin.controller.ts admin/finance/
|
||||
mv shared/finance/transaction-admin.controller.ts admin/finance/
|
||||
mv shared/finance/withdrawal-admin.controller.ts admin/finance/
|
||||
mv shared/finance/settlement-admin.controller.ts admin/finance/
|
||||
mv shared/finance/reconciliation-admin.controller.ts admin/finance/
|
||||
mv shared/finance/report-admin.controller.ts admin/finance/
|
||||
```
|
||||
|
||||
### 步骤3: 修改所有 Controller 的路由前缀 (60分钟)
|
||||
|
||||
使用 VS Code 全局查找替换功能 (`Ctrl+Shift+H`):
|
||||
|
||||
#### 3.1 应用端路由
|
||||
|
||||
在 `apps/server/src/modules/app` 目录下:
|
||||
|
||||
```
|
||||
查找: @Controller\('user/auth
|
||||
替换: @Controller('api/app/auth
|
||||
|
||||
查找: @Controller\('user/profile
|
||||
替换: @Controller('api/app/profile
|
||||
|
||||
查找: @Controller\('user/orders
|
||||
替换: @Controller('api/app/orders
|
||||
|
||||
查找: @Controller\('user/reviews
|
||||
替换: @Controller('api/app/reviews
|
||||
|
||||
查找: @Controller\('user/coupons
|
||||
替换: @Controller('api/app/coupons
|
||||
|
||||
查找: @Controller\('user/guests
|
||||
替换: @Controller('api/app/guests
|
||||
|
||||
查找: @Controller\('user/activity
|
||||
替换: @Controller('api/app/activity
|
||||
|
||||
查找: @Controller\('user/finance
|
||||
替换: @Controller('api/app/finance
|
||||
|
||||
查找: @Controller\('user
|
||||
替换: @Controller('api/app
|
||||
```
|
||||
|
||||
#### 3.2 商家端路由
|
||||
|
||||
在 `apps/server/src/modules/merchant` 目录下:
|
||||
|
||||
```
|
||||
查找: @Controller\('merchant/auth
|
||||
替换: @Controller('api/merchant/auth
|
||||
|
||||
查找: @Controller\('merchant/profile
|
||||
替换: @Controller('api/merchant/profile
|
||||
|
||||
查找: @Controller\('merchant/rooms
|
||||
替换: @Controller('api/merchant/rooms
|
||||
|
||||
查找: @Controller\('merchant/room-calendar
|
||||
替换: @Controller('api/merchant/room-calendar
|
||||
|
||||
查找: @Controller\('merchant/orders
|
||||
替换: @Controller('api/merchant/orders
|
||||
|
||||
查找: @Controller\('merchant/reviews
|
||||
替换: @Controller('api/merchant/reviews
|
||||
|
||||
查找: @Controller\('merchant/statistics
|
||||
替换: @Controller('api/merchant/statistics
|
||||
|
||||
查找: @Controller\('merchant/finance
|
||||
替换: @Controller('api/merchant/finance
|
||||
|
||||
# 处理旧的 seller 前缀
|
||||
查找: @Controller\('seller/
|
||||
替换: @Controller('api/merchant/
|
||||
```
|
||||
|
||||
#### 3.3 平台管理端路由
|
||||
|
||||
在 `apps/server/src/modules/admin` 目录下:
|
||||
|
||||
```
|
||||
查找: @Controller\('admin/
|
||||
替换: @Controller('api/admin/
|
||||
```
|
||||
|
||||
#### 3.4 官网路由
|
||||
|
||||
在 `apps/server/src/modules/website` 目录下:
|
||||
|
||||
```
|
||||
查找: @Controller\('website/
|
||||
替换: @Controller('api/website/
|
||||
|
||||
查找: @Controller\('public/
|
||||
替换: @Controller('api/website/
|
||||
```
|
||||
|
||||
### 步骤4: 更新模块导入和注册 (45分钟)
|
||||
|
||||
#### 4.1 更新各模块的 module.ts 文件
|
||||
|
||||
需要修改的文件:
|
||||
- `app/app.module.ts` (重命名自 user.module.ts)
|
||||
- `merchant/merchant.module.ts`
|
||||
- `admin/admin.module.ts`
|
||||
- `website/website.module.ts`
|
||||
|
||||
#### 4.2 更新根模块 app.module.ts
|
||||
|
||||
```typescript
|
||||
import { AppModule as AppClientModule } from './modules/app/app.module';
|
||||
import { MerchantModule } from './modules/merchant/merchant.module';
|
||||
import { AdminModule } from './modules/admin/admin.module';
|
||||
import { WebsiteModule } from './modules/website/website.module';
|
||||
import { SharedModule } from './modules/shared/shared.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
// ... 其他配置
|
||||
AppClientModule,
|
||||
MerchantModule,
|
||||
AdminModule,
|
||||
WebsiteModule,
|
||||
SharedModule,
|
||||
],
|
||||
})
|
||||
export class AppModule {}
|
||||
```
|
||||
|
||||
### 步骤5: 更新前端 API 调用路径 (90分钟)
|
||||
|
||||
#### 5.1 小程序端 (apps/miniapp/src/api/)
|
||||
|
||||
在整个 `apps/miniapp/src/api` 目录下执行替换:
|
||||
|
||||
```
|
||||
查找: '/user/auth/
|
||||
替换: '/api/app/auth/
|
||||
|
||||
查找: '/user/profile
|
||||
替换: '/api/app/profile
|
||||
|
||||
查找: '/user/orders
|
||||
替换: '/api/app/orders
|
||||
|
||||
查找: '/user/reviews
|
||||
替换: '/api/app/reviews
|
||||
|
||||
查找: '/user/coupons
|
||||
替换: '/api/app/coupons
|
||||
|
||||
查找: '/user/guests
|
||||
替换: '/api/app/guests
|
||||
|
||||
查找: '/user/activity
|
||||
替换: '/api/app/activity
|
||||
|
||||
查找: '/user/finance
|
||||
替换: '/api/app/finance
|
||||
|
||||
查找: '/user
|
||||
替换: '/api/app
|
||||
|
||||
# 公开接口
|
||||
查找: '/public/rooms
|
||||
替换: '/api/website/rooms
|
||||
|
||||
查找: '/public/merchants
|
||||
替换: '/api/website/merchants
|
||||
```
|
||||
|
||||
#### 5.2 商家管理后台 (apps/merchant-admin/src/api/)
|
||||
|
||||
在整个 `apps/merchant-admin/src/api` 目录下执行替换:
|
||||
|
||||
```
|
||||
查找: '/merchant/auth/
|
||||
替换: '/api/merchant/auth/
|
||||
|
||||
查找: '/merchant/
|
||||
替换: '/api/merchant/
|
||||
|
||||
查找: '/seller/
|
||||
替换: '/api/merchant/
|
||||
```
|
||||
|
||||
#### 5.3 平台管理后台 (apps/platform-admin/src/api/)
|
||||
|
||||
在整个 `apps/platform-admin/src/api` 目录下执行替换:
|
||||
|
||||
```
|
||||
查找: '/admin/
|
||||
替换: '/api/admin/
|
||||
```
|
||||
|
||||
#### 5.4 官网 (apps/official-website/)
|
||||
|
||||
```
|
||||
查找: '/website/
|
||||
替换: '/api/website/
|
||||
|
||||
查找: '/public/
|
||||
替换: '/api/website/
|
||||
```
|
||||
|
||||
### 步骤6: 更新 Swagger 配置 (15分钟)
|
||||
|
||||
修改 `apps/server/src/main.ts`,为不同模块添加 API 标签分组:
|
||||
|
||||
```typescript
|
||||
const config = new DocumentBuilder()
|
||||
.setTitle('酒店民宿短租预订平台 API')
|
||||
.setDescription('API 文档')
|
||||
.setVersion('1.0')
|
||||
.addBearerAuth()
|
||||
.addTag('应用端', '小程序C端用户使用的接口')
|
||||
.addTag('商家端', '小程序商家端和商家管理后台使用的接口')
|
||||
.addTag('平台管理端', '平台管理后台使用的接口')
|
||||
.addTag('官网', '官方网站使用的接口')
|
||||
.build();
|
||||
```
|
||||
|
||||
在各个 Controller 中添加对应的 `@ApiTags` 装饰器。
|
||||
|
||||
### 步骤7: 测试验证 (60分钟)
|
||||
|
||||
#### 7.1 后端测试
|
||||
|
||||
```bash
|
||||
# 启动后端服务
|
||||
cd apps/server
|
||||
pnpm run start:dev
|
||||
|
||||
# 检查控制台是否有错误
|
||||
# 访问 Swagger 文档
|
||||
# http://localhost:3000/api/docs
|
||||
```
|
||||
|
||||
#### 7.2 前端测试
|
||||
|
||||
```bash
|
||||
# 启动小程序
|
||||
cd apps/miniapp
|
||||
pnpm run dev:mp-weixin
|
||||
|
||||
# 启动商家后台
|
||||
cd apps/merchant-admin
|
||||
pnpm run dev
|
||||
|
||||
# 启动平台后台
|
||||
cd apps/platform-admin
|
||||
pnpm run dev
|
||||
|
||||
# 启动官网
|
||||
cd apps/official-website
|
||||
pnpm run dev
|
||||
```
|
||||
|
||||
#### 7.3 功能测试清单
|
||||
|
||||
- [ ] 应用端
|
||||
- [ ] 用户登录/注册
|
||||
- [ ] 浏览房源
|
||||
- [ ] 创建订单
|
||||
- [ ] 查看订单列表
|
||||
- [ ] 发表评价
|
||||
- [ ] 优惠券领取
|
||||
- [ ] 钱包充值/提现
|
||||
|
||||
- [ ] 商家端
|
||||
- [ ] 商家登录
|
||||
- [ ] 房源管理(增删改查)
|
||||
- [ ] 订单管理
|
||||
- [ ] 数据统计
|
||||
- [ ] 财务管理
|
||||
|
||||
- [ ] 平台管理端
|
||||
- [ ] 管理员登录
|
||||
- [ ] 用户管理
|
||||
- [ ] 商家审核
|
||||
- [ ] 订单管理
|
||||
- [ ] 财务管理
|
||||
- [ ] 系统配置
|
||||
|
||||
- [ ] 官网
|
||||
- [ ] 首页展示
|
||||
- [ ] 房源浏览
|
||||
- [ ] 商家展示
|
||||
|
||||
## 五、风险控制
|
||||
|
||||
### 5.1 备份策略
|
||||
|
||||
在开始重构前,创建 Git 分支:
|
||||
|
||||
```bash
|
||||
git checkout -b refactor/interface-classification
|
||||
git add .
|
||||
git commit -m "feat: 开始接口分类重构"
|
||||
```
|
||||
|
||||
### 5.2 回滚方案
|
||||
|
||||
如果出现问题,可以快速回滚:
|
||||
|
||||
```bash
|
||||
git checkout dev
|
||||
git branch -D refactor/interface-classification
|
||||
```
|
||||
|
||||
### 5.3 分阶段提交
|
||||
|
||||
建议按以下阶段提交代码:
|
||||
|
||||
1. 第一次提交:目录重命名和移动
|
||||
2. 第二次提交:Controller 路由前缀修改
|
||||
3. 第三次提交:模块导入更新
|
||||
4. 第四次提交:前端 API 路径更新
|
||||
5. 第五次提交:测试通过后的最终调整
|
||||
|
||||
## 六、预计时间
|
||||
|
||||
| 步骤 | 预计时间 | 说明 |
|
||||
|------|---------|------|
|
||||
| 步骤1: 目录重命名移动 | 30分钟 | 使用命令行批量操作 |
|
||||
| 步骤2: 移动 controller | 45分钟 | 手动移动并调整导入 |
|
||||
| 步骤3: 修改路由前缀 | 60分钟 | VS Code 批量替换 |
|
||||
| 步骤4: 更新模块注册 | 45分钟 | 修改 module.ts 文件 |
|
||||
| 步骤5: 更新前端路径 | 90分钟 | 四个前端项目批量替换 |
|
||||
| 步骤6: 更新 Swagger | 15分钟 | 添加 API 分组 |
|
||||
| 步骤7: 测试验证 | 60分钟 | 全面功能测试 |
|
||||
| **总计** | **5.75小时** | 约半个工作日 |
|
||||
|
||||
## 七、注意事项
|
||||
|
||||
1. **路径别名**: 确保所有 `@/` 路径别名正确指向新的目录结构
|
||||
2. **导入语句**: 检查所有 import 语句是否正确
|
||||
3. **DTO 共享**: 如果有共享的 DTO,考虑放在 `shared/dto` 目录
|
||||
4. **Guard 和 Decorator**: 确保认证守卫和装饰器路径正确
|
||||
5. **测试文件**: 同步更新所有 `.spec.ts` 测试文件
|
||||
6. **环境变量**: 检查是否有硬编码的路径需要更新
|
||||
7. **文档更新**: 更新 CLAUDE.md 和其他文档中的路径说明
|
||||
|
||||
## 八、后续优化建议
|
||||
|
||||
1. **API 版本控制**: 考虑添加 `/api/v1/` 版本前缀
|
||||
2. **接口文档**: 为每个模块生成独立的 Swagger 文档
|
||||
3. **权限控制**: 基于路由前缀实现更细粒度的权限控制
|
||||
4. **监控日志**: 按模块分类记录 API 调用日志
|
||||
5. **性能优化**: 为不同端的接口设置不同的缓存策略
|
||||
@@ -2,15 +2,15 @@ import { get, post } from '@/utils/request';
|
||||
|
||||
// 获取可领取的优惠券列表
|
||||
export function getAvailableCoupons(params?: { merchantId?: number; roomId?: number }) {
|
||||
return get('/api/user/coupons/available', params);
|
||||
return get('/api/app/coupons/available', params);
|
||||
}
|
||||
|
||||
// 领取优惠券
|
||||
export function claimCoupon(couponId: number) {
|
||||
return post('/api/user/coupons/claim', { couponId });
|
||||
return post('/api/app/coupons/claim', { couponId });
|
||||
}
|
||||
|
||||
// 获取我的优惠券列表
|
||||
export function getMyCoupons(params?: { status?: string }) {
|
||||
return get('/api/user/coupons', params);
|
||||
return get('/api/app/coupons/my', params);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { get, post, put, del } from '@/utils/request';
|
||||
|
||||
// 获取常住人列表
|
||||
export function getGuestList() {
|
||||
return get('/api/user/guests');
|
||||
return get('/api/app/guests');
|
||||
}
|
||||
|
||||
// 获取常住人详情
|
||||
@@ -12,7 +12,7 @@ export function getGuestDetail(id: number) {
|
||||
|
||||
// 添加常住人
|
||||
export function createGuest(data: any) {
|
||||
return post('/api/user/guests', data);
|
||||
return post('/api/app/guests', data);
|
||||
}
|
||||
|
||||
// 更新常住人
|
||||
|
||||
@@ -30,25 +30,25 @@ export interface SellerLoginResult {
|
||||
|
||||
// 发送商家验证码
|
||||
export function sellerSendCode(phone: string) {
|
||||
return post('/seller/auth/send-code', { phone });
|
||||
return post('/api/merchant/auth/send-code', { phone });
|
||||
}
|
||||
|
||||
// 商家注册(验证码)
|
||||
export function sellerRegister(data: SellerRegisterParams) {
|
||||
return request<SellerLoginResult>({ url: '/seller/auth/register', method: 'POST', data, useSellerToken: true, skipAuthRedirect: true });
|
||||
return request<SellerLoginResult>({ url: '/api/merchant/auth/register', method: 'POST', data, useSellerToken: true, skipAuthRedirect: true });
|
||||
}
|
||||
|
||||
// 商家登录(验证码或密码)
|
||||
export function sellerLogin(data: SellerLoginParams) {
|
||||
return request<SellerLoginResult>({ url: '/seller/auth/login', method: 'POST', data, useSellerToken: true, skipAuthRedirect: true });
|
||||
return request<SellerLoginResult>({ url: '/api/merchant/auth/login', method: 'POST', data, useSellerToken: true, skipAuthRedirect: true });
|
||||
}
|
||||
|
||||
// 刷新商家令牌
|
||||
export function sellerRefreshToken(refreshToken: string) {
|
||||
return post<SellerLoginResult>('/seller/auth/refresh', { refreshToken });
|
||||
return post<SellerLoginResult>('/api/merchant/auth/refresh', { refreshToken });
|
||||
}
|
||||
|
||||
// 获取商家信息(需要商家token)
|
||||
export function getSellerProfile() {
|
||||
return request({ url: '/seller/auth/profile', method: 'GET', useSellerToken: true });
|
||||
return request({ url: '/api/merchant/auth/profile', method: 'GET', useSellerToken: true });
|
||||
}
|
||||
|
||||
@@ -7,17 +7,17 @@ export const financeApi = {
|
||||
/**
|
||||
* 获取钱包信息
|
||||
*/
|
||||
getWallet: () => get('/seller/finance/wallet'),
|
||||
getWallet: () => get('/api/merchant/finance/wallet'),
|
||||
|
||||
/**
|
||||
* 获取交易流水
|
||||
*/
|
||||
getTransactions: (params?: any) => get('/seller/finance/transactions', params),
|
||||
getTransactions: (params?: any) => get('/api/merchant/finance/transactions', params),
|
||||
|
||||
/**
|
||||
* 获取结算记录
|
||||
*/
|
||||
getSettlements: (params?: any) => get('/seller/finance/settlements', params),
|
||||
getSettlements: (params?: any) => get('/api/merchant/finance/settlements', params),
|
||||
|
||||
/**
|
||||
* 获取结算详情
|
||||
@@ -39,12 +39,12 @@ export const financeApi = {
|
||||
accountName: string;
|
||||
accountNumber: string;
|
||||
bankName?: string;
|
||||
}) => post('/seller/finance/withdrawals', data),
|
||||
}) => post('/api/merchant/finance/withdrawals', data),
|
||||
|
||||
/**
|
||||
* 获取提现记录
|
||||
*/
|
||||
getWithdrawals: (params?: any) => get('/seller/finance/withdrawals', params),
|
||||
getWithdrawals: (params?: any) => get('/api/merchant/finance/withdrawals', params),
|
||||
|
||||
/**
|
||||
* 获取提现详情
|
||||
@@ -59,11 +59,11 @@ export const statisticsApi = {
|
||||
/**
|
||||
* 获取数据概览
|
||||
*/
|
||||
getOverview: () => get('/seller/statistics/overview'),
|
||||
getOverview: () => get('/api/merchant/statistics/overview'),
|
||||
|
||||
/**
|
||||
* 获取收入趋势
|
||||
*/
|
||||
getIncomeTrend: (type: 'day' | 'week' | 'month' = 'day') =>
|
||||
get('/seller/statistics/income-trend', { type }),
|
||||
get('/api/merchant/statistics/income-trend', { type }),
|
||||
};
|
||||
|
||||
@@ -62,7 +62,7 @@ export interface UpdateMerchantParams {
|
||||
// 申请创建店铺(需要商家token)
|
||||
export function applyMerchant(data: ApplyMerchantParams) {
|
||||
return request({
|
||||
url: '/seller/merchant/apply',
|
||||
url: '/api/merchant/merchant/apply',
|
||||
method: 'POST',
|
||||
data,
|
||||
useSellerToken: true,
|
||||
@@ -72,7 +72,7 @@ export function applyMerchant(data: ApplyMerchantParams) {
|
||||
// 获取我的店铺信息(需要商家token)
|
||||
export function getMyMerchant() {
|
||||
return request({
|
||||
url: '/seller/merchant/mine',
|
||||
url: '/api/merchant/merchant/mine',
|
||||
method: 'GET',
|
||||
useSellerToken: true,
|
||||
});
|
||||
@@ -81,7 +81,7 @@ export function getMyMerchant() {
|
||||
// 更新店铺信息(需要商家token)
|
||||
export function updateMerchant(data: UpdateMerchantParams) {
|
||||
return request({
|
||||
url: '/seller/merchant/update',
|
||||
url: '/api/merchant/merchant/update',
|
||||
method: 'PUT',
|
||||
data,
|
||||
useSellerToken: true,
|
||||
|
||||
@@ -8,7 +8,7 @@ export function getSellerOrders(params: {
|
||||
orderNo?: string;
|
||||
}) {
|
||||
return request({
|
||||
url: '/seller/orders',
|
||||
url: '/api/merchant/orders',
|
||||
method: 'GET',
|
||||
data: params,
|
||||
useSellerToken: true,
|
||||
|
||||
@@ -18,7 +18,7 @@ export function batchUpdateCalendar(data: {
|
||||
status?: string;
|
||||
}) {
|
||||
return request({
|
||||
url: '/seller/room-calendar/batch',
|
||||
url: '/api/merchant/room-calendar/batch',
|
||||
method: 'PUT',
|
||||
data,
|
||||
useSellerToken: true,
|
||||
@@ -33,7 +33,7 @@ export function singleDayUpdate(data: {
|
||||
status?: string;
|
||||
}) {
|
||||
return request({
|
||||
url: '/seller/room-calendar/single',
|
||||
url: '/api/merchant/room-calendar/single',
|
||||
method: 'PUT',
|
||||
data,
|
||||
useSellerToken: true,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { request } from '@/utils/request';
|
||||
|
||||
// 商家管理接口(需要 sellerToken)
|
||||
export function getMerchantRooms(params: any) {
|
||||
return request({ url: '/seller/rooms', method: 'GET', data: params, useSellerToken: true });
|
||||
return request({ url: '/api/merchant/rooms', method: 'GET', data: params, useSellerToken: true });
|
||||
}
|
||||
|
||||
export function getMerchantRoom(id: number) {
|
||||
@@ -10,7 +10,7 @@ export function getMerchantRoom(id: number) {
|
||||
}
|
||||
|
||||
export function createMerchantRoom(data: any) {
|
||||
return request({ url: '/seller/rooms', method: 'POST', data, useSellerToken: true });
|
||||
return request({ url: '/api/merchant/rooms', method: 'POST', data, useSellerToken: true });
|
||||
}
|
||||
|
||||
export function updateMerchantRoom(id: number, data: any) {
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
import { post, get } from '@/utils/request';
|
||||
|
||||
export function sendCode(phone: string) {
|
||||
return post('/api/user/auth/send-code', { phone });
|
||||
return post('/api/app/auth/send-code', { phone });
|
||||
}
|
||||
|
||||
export function loginByPhone(phone: string, code: string) {
|
||||
return post('/api/user/auth/login/phone', { phone, code });
|
||||
return post('/api/app/auth/login/phone', { phone, code });
|
||||
}
|
||||
|
||||
export function loginByPassword(phone: string, password: string) {
|
||||
return post('/api/user/auth/login/password', { phone, password });
|
||||
return post('/api/app/auth/login/password', { phone, password });
|
||||
}
|
||||
|
||||
export function loginByWechat(code: string, nickname?: string, avatar?: string) {
|
||||
return post('/api/user/auth/login/wechat', { code, nickname, avatar });
|
||||
return post('/api/app/auth/login/wechat', { code, nickname, avatar });
|
||||
}
|
||||
|
||||
export function register(data: { phone: string; code: string; password?: string; nickname?: string }) {
|
||||
return post('/api/user/auth/register', data);
|
||||
return post('/api/app/auth/register', data);
|
||||
}
|
||||
|
||||
export function refreshToken(refreshToken: string) {
|
||||
return post('/api/user/auth/refresh', { refreshToken });
|
||||
return post('/api/app/auth/refresh', { refreshToken });
|
||||
}
|
||||
|
||||
export function getUserProfile() {
|
||||
return get('/api/user/profile/profile');
|
||||
return get('/api/app/profile/profile');
|
||||
}
|
||||
|
||||
export function updateUserProfile(data: { nickname?: string; avatar?: string }) {
|
||||
return post('/api/user/profile/profile', data);
|
||||
return post('/api/app/profile/profile', data);
|
||||
}
|
||||
|
||||
export function uploadAvatar(filePath: string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.uploadFile({
|
||||
url: import.meta.env.VITE_API_BASE_URL + '/api/user/profile/avatar',
|
||||
url: import.meta.env.VITE_API_BASE_URL + '/api/app/profile/avatar',
|
||||
filePath,
|
||||
name: 'file',
|
||||
header: {
|
||||
@@ -54,9 +54,9 @@ export function uploadAvatar(filePath: string) {
|
||||
}
|
||||
|
||||
export function verifyIdentity(data: { realName: string; idCard: string }) {
|
||||
return post('/api/user/profile/verify', data);
|
||||
return post('/api/app/profile/verify', data);
|
||||
}
|
||||
|
||||
export function getVerifyStatus() {
|
||||
return get('/api/user/profile/verify/status');
|
||||
return get('/api/app/profile/verify/status');
|
||||
}
|
||||
|
||||
@@ -2,32 +2,32 @@ import { get, post } from '@/utils/request';
|
||||
|
||||
// 获取活动列表
|
||||
export const getActivityList = () =>
|
||||
get('/api/public/activity/list');
|
||||
get('/api/app/activity/list');
|
||||
|
||||
// 获取邀请活动配置
|
||||
export const getInviteConfig = () =>
|
||||
get('/api/public/activity/invite/config');
|
||||
get('/api/app/activity/invite/config');
|
||||
|
||||
// 获取我的邀请统计
|
||||
export const getInviteStats = () =>
|
||||
get('/api/user/activity/invite/stats');
|
||||
get('/api/app/activity/invite/stats');
|
||||
|
||||
// 绑定邀请关系
|
||||
export const bindInvitation = (inviteCode: string) =>
|
||||
post('/api/user/activity/invite/bind', { inviteCode });
|
||||
post('/api/app/activity/invite/bind', { inviteCode });
|
||||
|
||||
// 邀请记录列表
|
||||
export const getInviteRecords = (params?: { page?: number; pageSize?: number }) =>
|
||||
get('/api/user/activity/invite/records', params);
|
||||
get('/api/app/activity/invite/records', params);
|
||||
|
||||
// 返现记录列表
|
||||
export const getCashbackRecords = (params?: { page?: number; pageSize?: number }) =>
|
||||
get('/api/user/activity/invite/cashbacks', params);
|
||||
get('/api/app/activity/invite/cashbacks', params);
|
||||
|
||||
// 申请提现
|
||||
export const createInviteWithdrawal = (amount: number) =>
|
||||
post('/api/user/activity/invite/withdraw', { amount });
|
||||
post('/api/app/activity/invite/withdraw', { amount });
|
||||
|
||||
// 提现记录列表
|
||||
export const getInviteWithdrawals = (params?: { page?: number; pageSize?: number }) =>
|
||||
get('/api/user/activity/invite/withdrawals', params);
|
||||
get('/api/app/activity/invite/withdrawals', params);
|
||||
|
||||
@@ -28,7 +28,7 @@ export interface MerchantInfo {
|
||||
|
||||
// 获取商家详情(公开)
|
||||
export function getMerchantById(id: number) {
|
||||
return get<MerchantInfo>(`/api/public/merchants/${id}`);
|
||||
return get<MerchantInfo>(`/api/app/merchants/${id}`);
|
||||
}
|
||||
|
||||
// 获取商家列表(公开,已审核通过)
|
||||
@@ -38,5 +38,5 @@ export function getMerchantList(params: {
|
||||
keyword?: string;
|
||||
city?: string;
|
||||
}) {
|
||||
return get('/api/public/merchants', params);
|
||||
return get('/api/app/merchants', params);
|
||||
}
|
||||
|
||||
@@ -13,11 +13,11 @@ export function createOrder(data: {
|
||||
remark?: string;
|
||||
paymentMethod?: string;
|
||||
}) {
|
||||
return post('/api/user/orders', data);
|
||||
return post('/api/app/orders', data);
|
||||
}
|
||||
|
||||
export function getOrderList(params: { page?: number; pageSize?: number; status?: string }) {
|
||||
return get('/api/user/orders', params);
|
||||
return get('/api/app/orders', params);
|
||||
}
|
||||
|
||||
export function getOrderDetail(id: number) {
|
||||
@@ -33,5 +33,5 @@ export function refundOrder(id: number, reason: string) {
|
||||
}
|
||||
|
||||
export function payOrder(orderId: number, paymentMethod: 'wechat' | 'alipay' | 'balance' = 'wechat') {
|
||||
return post('/api/user/orders/pay', { orderId, paymentMethod });
|
||||
return post('/api/app/orders/pay', { orderId, paymentMethod });
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { post, get } from '@/utils/request';
|
||||
|
||||
export function createReview(orderId: number, data: { rating: number; content?: string; images?: string[]; isAnonymous?: boolean }) {
|
||||
return post('/api/user/reviews/order', { orderId, ...data });
|
||||
return post('/api/app/reviews/order', { orderId, ...data });
|
||||
}
|
||||
|
||||
export function getReviewList(params: { merchantId?: number; roomId?: number; page?: number; pageSize?: number }) {
|
||||
return get('/api/user/reviews', params);
|
||||
return get('/api/app/reviews', params);
|
||||
}
|
||||
|
||||
export function checkOrderReviewed(orderId: number) {
|
||||
|
||||
@@ -16,7 +16,7 @@ export function getRoomList(params: {
|
||||
roomCount?: number;
|
||||
adultCount?: number;
|
||||
}) {
|
||||
return get('/api/public/rooms', params);
|
||||
return get('/api/app/rooms', params);
|
||||
}
|
||||
|
||||
export function getRoomDetail(id: number) {
|
||||
|
||||
@@ -41,7 +41,7 @@ export const walletApi = {
|
||||
// 获取钱包信息
|
||||
getWallet() {
|
||||
return request<WalletInfo>({
|
||||
url: '/api/user/finance/wallet',
|
||||
url: '/api/app/finance/wallet',
|
||||
method: 'GET',
|
||||
});
|
||||
},
|
||||
@@ -56,7 +56,7 @@ export const walletApi = {
|
||||
pageSize?: number;
|
||||
}) {
|
||||
return request<{ items: Transaction[]; total: number }>({
|
||||
url: '/api/user/finance/transactions',
|
||||
url: '/api/app/finance/transactions',
|
||||
method: 'GET',
|
||||
data: params,
|
||||
});
|
||||
@@ -70,7 +70,7 @@ export const walletApi = {
|
||||
accountNumber: string;
|
||||
}) {
|
||||
return request({
|
||||
url: '/api/user/finance/withdraw',
|
||||
url: '/api/app/finance/withdraw',
|
||||
method: 'POST',
|
||||
data,
|
||||
});
|
||||
@@ -83,7 +83,7 @@ export const walletApi = {
|
||||
pageSize?: number;
|
||||
}) {
|
||||
return request<{ items: Withdrawal[]; total: number }>({
|
||||
url: '/api/user/finance/withdrawals',
|
||||
url: '/api/app/finance/withdrawals',
|
||||
method: 'GET',
|
||||
data: params,
|
||||
});
|
||||
|
||||
@@ -49,9 +49,9 @@
|
||||
<u-icon name="rmb-circle-fill" :size="14" color="#FFB800" />
|
||||
<text class="tag-text">最高¥{{ activity.config.maxCashback }}</text>
|
||||
</view>
|
||||
<view v-if="activity.config.minWithdraw" class="tag-item">
|
||||
<view v-if="activity.config.withdrawThreshold" class="tag-item">
|
||||
<u-icon name="checkmark-circle-fill" :size="14" color="#52C41A" />
|
||||
<text class="tag-text">满{{ activity.config.minWithdraw }}元可提现</text>
|
||||
<text class="tag-text">满{{ activity.config.withdrawThreshold }}元可提现</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -105,7 +105,10 @@ interface Activity {
|
||||
config?: {
|
||||
maxCashback?: number;
|
||||
firstOrderRate?: number;
|
||||
minWithdraw?: number;
|
||||
secondOrderRate?: number;
|
||||
withdrawThreshold?: number;
|
||||
minCashback?: number;
|
||||
maxOrderIndex?: number;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -120,7 +123,20 @@ async function fetchActivities() {
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await getActivityList();
|
||||
activities.value = (res.data?.list || []).filter((item: Activity) => item.enabled);
|
||||
const list = Array.isArray(res.data) ? res.data : (res.data?.list || []);
|
||||
|
||||
// 转换后端数据格式为前端需要的格式
|
||||
activities.value = list
|
||||
.filter((item: any) => item.enabled)
|
||||
.map((item: any) => ({
|
||||
id: item.id,
|
||||
type: item.type === 'invite_cashback' ? 'invite' : item.type,
|
||||
title: item.name || '活动',
|
||||
description: getActivityDescription(item.type),
|
||||
icon: getActivityIcon(item.type),
|
||||
enabled: item.enabled,
|
||||
config: item.config,
|
||||
}));
|
||||
} catch (e) {
|
||||
console.error('获取活动列表失败:', e);
|
||||
uni.showToast({ title: '加载失败,请重试', icon: 'none' });
|
||||
@@ -129,6 +145,24 @@ async function fetchActivities() {
|
||||
}
|
||||
}
|
||||
|
||||
function getActivityDescription(type: string) {
|
||||
const descMap: Record<string, string> = {
|
||||
invite_cashback: '邀请好友下单,双方都有奖励',
|
||||
coupon: '领取优惠券,享受更多优惠',
|
||||
discount: '限时折扣,不容错过',
|
||||
};
|
||||
return descMap[type] || '参与活动,赢取奖励';
|
||||
}
|
||||
|
||||
function getActivityIcon(type: string) {
|
||||
const iconMap: Record<string, string> = {
|
||||
invite_cashback: '🎁',
|
||||
coupon: '🎫',
|
||||
discount: '💰',
|
||||
};
|
||||
return iconMap[type] || '🎉';
|
||||
}
|
||||
|
||||
function getCardClass(type: string) {
|
||||
const classMap: Record<string, string> = {
|
||||
invite: 'card-invite',
|
||||
|
||||
@@ -169,6 +169,7 @@ const activeUsers = computed(() => {
|
||||
|
||||
// 筛选记录
|
||||
const filteredRecords = computed(() => {
|
||||
console.log('计算筛选记录, 当前筛选:', currentFilter.value);
|
||||
if (currentFilter.value === 'ordered') {
|
||||
return records.value.filter(item => item.orderCount > 0);
|
||||
} else if (currentFilter.value === 'not-ordered') {
|
||||
@@ -223,7 +224,10 @@ function onRefresh() {
|
||||
}
|
||||
|
||||
function changeFilter(value: string) {
|
||||
console.log('切换筛选:', value);
|
||||
currentFilter.value = value;
|
||||
console.log('当前筛选值:', currentFilter.value);
|
||||
console.log('筛选后记录数:', filteredRecords.value.length);
|
||||
}
|
||||
|
||||
function formatTime(dateStr: string) {
|
||||
|
||||
@@ -11,6 +11,8 @@ const { RangePicker } = DatePicker;
|
||||
interface EarningRecord {
|
||||
id: number;
|
||||
date: string;
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
orderCount: number;
|
||||
totalAmount: number;
|
||||
platformCommission: number;
|
||||
@@ -81,6 +83,8 @@ const Earnings: React.FC = () => {
|
||||
setDataSource([{
|
||||
id: 1,
|
||||
date: data.startDate,
|
||||
startDate: data.startDate,
|
||||
endDate: data.endDate,
|
||||
orderCount: data.orderCount || 0,
|
||||
totalAmount: data.orderAmount || 0,
|
||||
platformCommission: data.serviceFee || 0,
|
||||
@@ -109,10 +113,15 @@ const Earnings: React.FC = () => {
|
||||
|
||||
const columns: ColumnsType<EarningRecord> = [
|
||||
{
|
||||
title: '日期',
|
||||
title: '日期范围',
|
||||
dataIndex: 'date',
|
||||
key: 'date',
|
||||
render: (date: string) => formatDateTime(date).split(' ')[0],
|
||||
render: (date: string, record: EarningRecord) => {
|
||||
if (record.startDate && record.endDate) {
|
||||
return `${formatDateTime(record.startDate).split(' ')[0]} ~ ${formatDateTime(record.endDate).split(' ')[0]}`;
|
||||
}
|
||||
return formatDateTime(date).split(' ')[0];
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '订单数',
|
||||
|
||||
@@ -7,11 +7,11 @@ import jwtConfig from './config/jwt.config';
|
||||
import redisConfig from './config/redis.config';
|
||||
import { ScheduleModule as TaskScheduleModule } from './schedule/schedule.module';
|
||||
|
||||
// 新的模块结构
|
||||
import { UserModule } from './modules/user/user.module';
|
||||
// 新的模块结构 - 按端分类
|
||||
import { AppModule as AppClientModule } from './modules/app/app.module';
|
||||
import { MerchantModule } from './modules/merchant/merchant.module';
|
||||
import { AdminModule } from './modules/admin/admin.module';
|
||||
import { CommonModule } from './modules/common/common.module';
|
||||
import { SharedModule } from './modules/shared/shared.module';
|
||||
import { WebsiteModule } from './modules/website/website.module';
|
||||
|
||||
@Module({
|
||||
@@ -39,11 +39,11 @@ import { WebsiteModule } from './modules/website/website.module';
|
||||
}),
|
||||
}),
|
||||
// 新的模块结构:按端分组
|
||||
UserModule, // 用户端(C端)
|
||||
MerchantModule, // 商家端(B端)
|
||||
AppClientModule, // 应用端(小程序C端)
|
||||
MerchantModule, // 商家端(小程序商家端+商家管理后台)
|
||||
AdminModule, // 平台管理端
|
||||
CommonModule, // 公共模块
|
||||
WebsiteModule, // 官网模块
|
||||
SharedModule, // 共享模块(上传、配置等)
|
||||
WebsiteModule, // 官网
|
||||
],
|
||||
})
|
||||
export class AppModule {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, Index } from 'typeorm';
|
||||
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, Index, ManyToOne, JoinColumn } from 'typeorm';
|
||||
import { User } from './user.entity';
|
||||
|
||||
@Entity('mkt_invite_withdrawals')
|
||||
export class MktInviteWithdrawal {
|
||||
@@ -13,6 +14,10 @@ export class MktInviteWithdrawal {
|
||||
@Index()
|
||||
user_id: number;
|
||||
|
||||
@ManyToOne(() => User)
|
||||
@JoinColumn({ name: 'user_id' })
|
||||
user: User;
|
||||
|
||||
@Column({ type: 'decimal', precision: 10, scale: 2, comment: '提现金额' })
|
||||
amount: number;
|
||||
|
||||
|
||||
@@ -16,14 +16,26 @@ export class Review {
|
||||
@Column({ name: 'order_id', type: 'bigint', unsigned: true, unique: true, comment: '订单ID' })
|
||||
orderId: number;
|
||||
|
||||
@ManyToOne(() => User)
|
||||
@JoinColumn({ name: 'user_id' })
|
||||
user: User;
|
||||
|
||||
@Index()
|
||||
@Column({ name: 'user_id', type: 'bigint', unsigned: true, comment: '用户ID' })
|
||||
userId: number;
|
||||
|
||||
@ManyToOne(() => Merchant)
|
||||
@JoinColumn({ name: 'merchant_id' })
|
||||
merchant: Merchant;
|
||||
|
||||
@Index()
|
||||
@Column({ name: 'merchant_id', type: 'bigint', unsigned: true, comment: '商家ID' })
|
||||
merchantId: number;
|
||||
|
||||
@ManyToOne(() => Room)
|
||||
@JoinColumn({ name: 'room_id' })
|
||||
room: Room;
|
||||
|
||||
@Column({ name: 'room_id', type: 'bigint', unsigned: true, comment: '房型ID' })
|
||||
roomId: number;
|
||||
|
||||
|
||||
@@ -42,6 +42,10 @@ async function bootstrap() {
|
||||
.setDescription('平台后端接口文档')
|
||||
.setVersion('1.0')
|
||||
.addBearerAuth()
|
||||
.addTag('应用端', '小程序C端用户使用的接口')
|
||||
.addTag('商家端', '小程序商家端和商家管理后台使用的接口')
|
||||
.addTag('平台管理端', '平台管理后台使用的接口')
|
||||
.addTag('官网', '官方网站使用的接口')
|
||||
.build();
|
||||
const document = SwaggerModule.createDocument(app, config);
|
||||
SwaggerModule.setup('api/docs', app, document);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Controller, Get, Put, Body, UseGuards } from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { ConfigService } from '@/modules/common/config/config.service';
|
||||
import { ConfigService } from '@/modules/shared/config/config.service';
|
||||
import { JwtAuthGuard, RolesGuard, Roles } from '@/common';
|
||||
import { UploadService } from '@/modules/common/upload/upload.service';
|
||||
import { UploadService } from '@/modules/shared/upload/upload.service';
|
||||
|
||||
@ApiTags('管理端-系统配置')
|
||||
@ApiBearerAuth()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule as CommonConfigModule } from '@/modules/common/config/config.module';
|
||||
import { UploadModule } from '@/modules/common/upload/upload.module';
|
||||
import { ConfigModule as CommonConfigModule } from '@/modules/shared/config/config.module';
|
||||
import { UploadModule } from '@/modules/shared/upload/upload.module';
|
||||
import { AdminConfigController } from './config.controller';
|
||||
|
||||
@Module({
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { CouponService } from '@/modules/common/coupon/coupon.service';
|
||||
import { CouponService } from '@/modules/shared/coupon/coupon.service';
|
||||
import { JwtAuthGuard, RolesGuard } from '@/common';
|
||||
import { Roles } from '@/common/decorators/roles.decorator';
|
||||
import { CurrentUser } from '@/common/decorators/current-user.decorator';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { CouponModule } from '@/modules/common/coupon/coupon.module';
|
||||
import { CouponModule } from '@/modules/shared/coupon/coupon.module';
|
||||
import { CouponController } from './coupon.controller';
|
||||
|
||||
@Module({
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
// 复用共享的 CouponService
|
||||
export { CouponService } from '@/modules/common/coupon/coupon.service';
|
||||
export { CouponService } from '@/modules/shared/coupon/coupon.service';
|
||||
|
||||
@@ -1 +1 @@
|
||||
export * from '@/modules/common/coupon/dto/coupon.dto';
|
||||
export * from '@/modules/shared/coupon/dto/coupon.dto';
|
||||
|
||||
+2
-2
@@ -6,10 +6,10 @@ import {
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { AccountService } from './account.service';
|
||||
import { AccountService } from '@/modules/shared/finance/account.service';
|
||||
import { JwtAuthGuard, RolesGuard } from '@/common';
|
||||
import { Roles } from '@/common/decorators/roles.decorator';
|
||||
import { QueryUserAccountsDto, QueryMerchantAccountsDto } from './dto/account.dto';
|
||||
import { QueryUserAccountsDto, QueryMerchantAccountsDto } from '@/modules/shared/finance/dto/account.dto';
|
||||
|
||||
@ApiTags('账户管理(管理员)')
|
||||
@Controller('admin/finance/accounts')
|
||||
@@ -1,9 +1,22 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { FinanceModule as CommonFinanceModule } from '@/modules/common/finance/finance.module';
|
||||
import { FinanceModule as CommonFinanceModule } from '@/modules/shared/finance/finance.module';
|
||||
import { AccountAdminController } from './account-admin.controller';
|
||||
import { ReconciliationAdminController } from './reconciliation-admin.controller';
|
||||
import { ReportAdminController } from './report-admin.controller';
|
||||
import { SettlementAdminController } from './settlement-admin.controller';
|
||||
import { TransactionAdminController } from './transaction-admin.controller';
|
||||
import { WithdrawalAdminController } from './withdrawal-admin.controller';
|
||||
|
||||
@Module({
|
||||
imports: [CommonFinanceModule],
|
||||
controllers: [],
|
||||
controllers: [
|
||||
AccountAdminController,
|
||||
ReconciliationAdminController,
|
||||
ReportAdminController,
|
||||
SettlementAdminController,
|
||||
TransactionAdminController,
|
||||
WithdrawalAdminController,
|
||||
],
|
||||
})
|
||||
export class AdminFinanceModule {}
|
||||
|
||||
|
||||
+2
-2
@@ -10,11 +10,11 @@ import {
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { JwtAuthGuard, RolesGuard } from '@/common';
|
||||
import { Roles } from '@/common/decorators/roles.decorator';
|
||||
import { ReconciliationService } from './reconciliation.service';
|
||||
import { ReconciliationService } from '@/modules/shared/finance/reconciliation.service';
|
||||
import {
|
||||
ManualReconciliationDto,
|
||||
QueryReconciliationDto,
|
||||
} from './dto/reconciliation.dto';
|
||||
} from '@/modules/shared/finance/dto/reconciliation.dto';
|
||||
|
||||
@ApiTags('对账管理(管理员)')
|
||||
@Controller('admin/finance/reconciliations')
|
||||
+10
-11
@@ -5,7 +5,7 @@ import {
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { ReportService } from './report.service';
|
||||
import { ReportService } from '@/modules/shared/finance/report.service';
|
||||
import { JwtAuthGuard, RolesGuard } from '@/common';
|
||||
import { Roles } from '@/common/decorators/roles.decorator';
|
||||
import {
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
QueryDailyReportDto,
|
||||
QueryWeeklyReportDto,
|
||||
QueryMonthlyReportDto,
|
||||
} from './dto/report.dto';
|
||||
} from '@/modules/shared/finance/dto/report.dto';
|
||||
|
||||
@ApiTags('财务报表(管理员)')
|
||||
@Controller('admin/finance/reports')
|
||||
@@ -32,25 +32,24 @@ export class ReportAdminController {
|
||||
@Get('trend')
|
||||
@ApiOperation({ summary: '财务趋势' })
|
||||
async getTrend(@Query() dto: QueryTrendDto) {
|
||||
return this.reportService.getTrend({
|
||||
startDate: dto.startDate,
|
||||
endDate: dto.endDate,
|
||||
});
|
||||
const startDate = dto.startDate || new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
|
||||
const endDate = dto.endDate || new Date().toISOString().split('T')[0];
|
||||
return this.reportService.getTrend({ startDate, endDate });
|
||||
}
|
||||
|
||||
@Get('daily')
|
||||
@ApiOperation({ summary: '日报表' })
|
||||
async getDailyReport(@Query() dto: QueryDailyReportDto) {
|
||||
return this.reportService.getDailyReport(dto.date);
|
||||
const date = dto.date || new Date().toISOString().split('T')[0];
|
||||
return this.reportService.getDailyReport(date);
|
||||
}
|
||||
|
||||
@Get('weekly')
|
||||
@ApiOperation({ summary: '周报表' })
|
||||
async getWeeklyReport(@Query() dto: QueryWeeklyReportDto) {
|
||||
return this.reportService.getWeeklyReport({
|
||||
startDate: dto.startDate,
|
||||
endDate: dto.endDate,
|
||||
});
|
||||
const endDate = dto.endDate || new Date().toISOString().split('T')[0];
|
||||
const startDate = dto.startDate || new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
|
||||
return this.reportService.getWeeklyReport({ startDate, endDate });
|
||||
}
|
||||
|
||||
@Get('monthly')
|
||||
+2
-2
@@ -9,7 +9,7 @@ import {
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { SettlementService } from './settlement.service';
|
||||
import { SettlementService } from '@/modules/shared/finance/settlement.service';
|
||||
import { JwtAuthGuard, RolesGuard } from '@/common';
|
||||
import { Roles } from '@/common/decorators/roles.decorator';
|
||||
import {
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
ManualSettlementDto,
|
||||
ApproveSettlementDto,
|
||||
RejectSettlementDto,
|
||||
} from './dto/settlement.dto';
|
||||
} from '@/modules/shared/finance/dto/settlement.dto';
|
||||
|
||||
@ApiTags('结算管理(管理员)')
|
||||
@Controller('admin/finance/settlements')
|
||||
+2
-2
@@ -8,12 +8,12 @@ import {
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { JwtAuthGuard, RolesGuard } from '@/common';
|
||||
import { Roles } from '@/common/decorators/roles.decorator';
|
||||
import { TransactionService } from './transaction.service';
|
||||
import { TransactionService } from '@/modules/shared/finance/transaction.service';
|
||||
import {
|
||||
QueryUserTransactionDto,
|
||||
QueryMerchantTransactionDto,
|
||||
QueryPlatformTransactionDto,
|
||||
} from './dto/transaction.dto';
|
||||
} from '@/modules/shared/finance/dto/transaction.dto';
|
||||
|
||||
@ApiTags('交易流水管理(管理员)')
|
||||
@Controller('admin/finance/transactions')
|
||||
+2
-2
@@ -9,7 +9,7 @@ import {
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { WithdrawalService } from './withdrawal.service';
|
||||
import { WithdrawalService } from '@/modules/shared/finance/withdrawal.service';
|
||||
import { JwtAuthGuard, RolesGuard } from '@/common';
|
||||
import { Roles } from '@/common/decorators/roles.decorator';
|
||||
import { CurrentUser } from '@/common/decorators/current-user.decorator';
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
QueryMerchantWithdrawalDto,
|
||||
RejectWithdrawalDto,
|
||||
ConfirmPaymentDto,
|
||||
} from './dto/withdrawal.dto';
|
||||
} from '@/modules/shared/finance/dto/withdrawal.dto';
|
||||
|
||||
@ApiTags('提现管理(管理员)')
|
||||
@Controller('admin/finance/withdrawals')
|
||||
@@ -0,0 +1,84 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Body,
|
||||
Query,
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { ActivityService } from './activity.service';
|
||||
import { JwtAuthGuard, CurrentUser } from '@/common';
|
||||
import {
|
||||
BindInvitationDto,
|
||||
CreateInviteWithdrawalDto,
|
||||
QueryInviteRecordsDto,
|
||||
} from './dto/activity.dto';
|
||||
|
||||
// ===== 用户端活动接口 =====
|
||||
@ApiTags('用户端-活动')
|
||||
@Controller('app/activity')
|
||||
export class ActivityController {
|
||||
constructor(private readonly activityService: ActivityService) {}
|
||||
|
||||
@Get('list')
|
||||
@ApiOperation({ summary: '获取活动列表' })
|
||||
async getActivityList() {
|
||||
const activity = await this.activityService.getEnabledInviteCashbackActivity();
|
||||
return activity ? [activity] : [];
|
||||
}
|
||||
|
||||
@Get('invite/config')
|
||||
@ApiOperation({ summary: '获取邀请活动配置' })
|
||||
async getInviteConfig() {
|
||||
return this.activityService.getEnabledInviteCashbackActivity();
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('invite/stats')
|
||||
@ApiOperation({ summary: '获取我的邀请统计' })
|
||||
async getStats(@CurrentUser('sub') userId: number) {
|
||||
return this.activityService.getUserStats(userId);
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('invite/bind')
|
||||
@ApiOperation({ summary: '绑定邀请关系' })
|
||||
async bind(@CurrentUser('sub') userId: number, @Body() dto: BindInvitationDto) {
|
||||
return this.activityService.bindInvitation(userId, dto);
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('invite/records')
|
||||
@ApiOperation({ summary: '邀请记录列表' })
|
||||
async getRecords(@CurrentUser('sub') userId: number, @Query() dto: QueryInviteRecordsDto) {
|
||||
return this.activityService.getInviteRecords(userId, dto);
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('invite/cashbacks')
|
||||
@ApiOperation({ summary: '返现记录列表' })
|
||||
async getCashbacks(@CurrentUser('sub') userId: number, @Query() dto: QueryInviteRecordsDto) {
|
||||
return this.activityService.getCashbackRecords(userId, dto);
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('invite/withdraw')
|
||||
@ApiOperation({ summary: '申请提现' })
|
||||
async createWithdrawal(@CurrentUser('sub') userId: number, @Body() dto: CreateInviteWithdrawalDto) {
|
||||
return this.activityService.createWithdrawal(userId, dto);
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('invite/withdrawals')
|
||||
@ApiOperation({ summary: '提现记录列表' })
|
||||
async getWithdrawals(@CurrentUser('sub') userId: number, @Query() dto: QueryInviteRecordsDto) {
|
||||
return this.activityService.getWithdrawalRecords(userId, dto);
|
||||
}
|
||||
}
|
||||
+5
@@ -205,6 +205,11 @@ export class ActivityService {
|
||||
take: pageSize,
|
||||
});
|
||||
|
||||
// 如果没有邀请记录,直接返回
|
||||
if (list.length === 0) {
|
||||
return { list: [], total: 0 };
|
||||
}
|
||||
|
||||
// 获取每个被邀请人的订单数
|
||||
const inviteeIds = list.map((item) => item.inviteeId);
|
||||
const orderCounts = await this.orderRepo
|
||||
+13
-1
@@ -1,4 +1,9 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { Merchant } from '@/entities/merchant.entity';
|
||||
import { MerchantAccount } from '@/entities/merchant-account.entity';
|
||||
import { Room } from '@/entities/room.entity';
|
||||
import { RoomCalendar } from '@/entities/room-calendar.entity';
|
||||
import { UserAuthModule } from './auth/auth.module';
|
||||
import { UserProfileModule } from './profile/profile.module';
|
||||
import { UserGuestModule } from './guest/guest.module';
|
||||
@@ -7,9 +12,13 @@ import { UserReviewModule } from './review/review.module';
|
||||
import { UserCouponModule } from './coupon/coupon.module';
|
||||
import { UserFinanceModule } from './finance/finance.module';
|
||||
import { UserActivityModule } from './activity/activity.module';
|
||||
import { RoomModule } from './room/room.module';
|
||||
import { MerchantController } from './merchant/merchant.controller';
|
||||
import { MerchantService } from '@/modules/merchant/merchant.service';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([Merchant, MerchantAccount, Room, RoomCalendar]),
|
||||
UserAuthModule,
|
||||
UserProfileModule,
|
||||
UserGuestModule,
|
||||
@@ -18,6 +27,9 @@ import { UserActivityModule } from './activity/activity.module';
|
||||
UserCouponModule,
|
||||
UserFinanceModule,
|
||||
UserActivityModule,
|
||||
RoomModule,
|
||||
],
|
||||
controllers: [MerchantController],
|
||||
providers: [MerchantService],
|
||||
})
|
||||
export class UserModule {}
|
||||
export class AppModule {}
|
||||
+1
-1
@@ -11,7 +11,7 @@ import {
|
||||
import { JwtAuthGuard } from '@/common/guards/jwt-auth.guard';
|
||||
|
||||
@ApiTags('用户认证')
|
||||
@Controller('user/auth')
|
||||
@Controller('app/auth')
|
||||
export class AuthController {
|
||||
constructor(private readonly authService: AuthService) {}
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ import { CurrentUser } from '@/common/decorators/current-user.decorator';
|
||||
import { ReceiveCouponDto, QueryUserCouponDto, QueryCouponDto } from './dto/coupon.dto';
|
||||
|
||||
@ApiTags('优惠券(用户)')
|
||||
@Controller('user/coupons')
|
||||
@Controller('app/coupons')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
export class CouponUserController {
|
||||
+1
-1
@@ -14,7 +14,7 @@ import { CurrentUser } from '@/common/decorators/current-user.decorator';
|
||||
import { ReceiveCouponDto, QueryUserCouponDto, QueryCouponDto } from './dto/coupon.dto';
|
||||
|
||||
@ApiTags('优惠券(用户)')
|
||||
@Controller('user/coupons')
|
||||
@Controller('app/coupons')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
export class CouponController {
|
||||
@@ -0,0 +1,2 @@
|
||||
// 复用现有的 CouponDto
|
||||
export * from '@/modules/shared/coupon/dto/coupon.dto';
|
||||
+5
-5
@@ -9,17 +9,17 @@ import {
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { JwtAuthGuard } from '@/common';
|
||||
import { CurrentUser } from '@/common/decorators/current-user.decorator';
|
||||
import { WithdrawalService } from './withdrawal.service';
|
||||
import { TransactionService } from './transaction.service';
|
||||
import { AccountService } from './account.service';
|
||||
import { WithdrawalService } from '@/modules/shared/finance/withdrawal.service';
|
||||
import { TransactionService } from '@/modules/shared/finance/transaction.service';
|
||||
import { AccountService } from '@/modules/shared/finance/account.service';
|
||||
import {
|
||||
CreateUserWithdrawalDto,
|
||||
QueryUserWithdrawalDto,
|
||||
QueryTransactionDto,
|
||||
} from './dto/finance.dto';
|
||||
} from '@/modules/shared/finance/dto/finance.dto';
|
||||
|
||||
@ApiTags('财务管理(用户)')
|
||||
@Controller('user/finance')
|
||||
@Controller('app/finance')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
export class FinanceUserController {
|
||||
+3
-2
@@ -1,9 +1,10 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { FinanceModule as CommonFinanceModule } from '@/modules/common/finance/finance.module';
|
||||
import { FinanceModule as CommonFinanceModule } from '@/modules/shared/finance/finance.module';
|
||||
import { FinanceUserController } from './finance-user.controller';
|
||||
|
||||
@Module({
|
||||
imports: [CommonFinanceModule],
|
||||
controllers: [],
|
||||
controllers: [FinanceUserController],
|
||||
})
|
||||
export class UserFinanceModule {}
|
||||
|
||||
+3
-3
@@ -8,16 +8,16 @@ import {
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { WithdrawalService } from './withdrawal.service';
|
||||
import { WithdrawalService } from '@/modules/shared/finance/withdrawal.service';
|
||||
import { JwtAuthGuard } from '@/common';
|
||||
import { CurrentUser } from '@/common/decorators/current-user.decorator';
|
||||
import {
|
||||
CreateUserWithdrawalDto,
|
||||
QueryUserWithdrawalDto,
|
||||
} from './dto/withdrawal.dto';
|
||||
} from '@/modules/shared/finance/dto/withdrawal.dto';
|
||||
|
||||
@ApiTags('提现管理(用户)')
|
||||
@Controller('user/finance/withdrawals')
|
||||
@Controller('app/finance/withdrawals')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
export class WithdrawalUserController {
|
||||
+1
-1
@@ -13,7 +13,7 @@ import { GuestService } from './guest.service';
|
||||
import { CreateGuestDto, UpdateGuestDto } from './dto/guest.dto';
|
||||
import { JwtAuthGuard } from '@/common/guards/jwt-auth.guard';
|
||||
|
||||
@Controller('user/guests')
|
||||
@Controller('app/guests')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
export class GuestController {
|
||||
constructor(private readonly guestService: GuestService) {}
|
||||
+4
-4
@@ -1,11 +1,11 @@
|
||||
import { Controller, Get, Param, Query } from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation } from '@nestjs/swagger';
|
||||
import { MerchantService } from './merchant.service';
|
||||
import { QueryMerchantDto } from './dto/merchant.dto';
|
||||
import { MerchantService } from '@/modules/merchant/merchant.service';
|
||||
import { QueryMerchantDto } from '@/modules/merchant/dto/merchant.dto';
|
||||
|
||||
@ApiTags('商家')
|
||||
@Controller('public/merchants')
|
||||
export class MerchantPublicController {
|
||||
@Controller('app/merchants')
|
||||
export class MerchantController {
|
||||
constructor(private readonly merchantService: MerchantService) {}
|
||||
|
||||
@Get()
|
||||
+1
-1
@@ -19,7 +19,7 @@ import {
|
||||
} from './dto/order.dto';
|
||||
|
||||
@ApiTags('订单(用户)')
|
||||
@Controller('user/orders')
|
||||
@Controller('app/orders')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
export class OrderController {
|
||||
+4
-4
@@ -6,10 +6,10 @@ import { Order } from '@/entities/order.entity';
|
||||
import { Room } from '@/entities/room.entity';
|
||||
import { RoomCalendar } from '@/entities/room-calendar.entity';
|
||||
import { Review } from '@/entities/review.entity';
|
||||
import { UserActivityModule } from '@/modules/user/activity/activity.module';
|
||||
import { ConfigModule } from '@/modules/common/config/config.module';
|
||||
import { FinanceModule } from '@/modules/common/finance/finance.module';
|
||||
import { UserCouponModule } from '@/modules/user/coupon/coupon.module';
|
||||
import { UserActivityModule } from '@/modules/app/activity/activity.module';
|
||||
import { ConfigModule } from '@/modules/shared/config/config.module';
|
||||
import { FinanceModule } from '@/modules/shared/finance/finance.module';
|
||||
import { UserCouponModule } from '@/modules/app/coupon/coupon.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
+4
-4
@@ -6,10 +6,10 @@ import { Room } from '@/entities/room.entity';
|
||||
import { RoomCalendar } from '@/entities/room-calendar.entity';
|
||||
import { Review } from '@/entities/review.entity';
|
||||
import { CreateOrderDto, QueryOrderDto } from './dto/order.dto';
|
||||
import { ActivityService } from '@/modules/user/activity/activity.service';
|
||||
import { ConfigService } from '@/modules/common/config/config.service';
|
||||
import { RefundService } from '@/modules/common/finance/refund.service';
|
||||
import { CouponService } from '@/modules/user/coupon/coupon.service';
|
||||
import { ActivityService } from '@/modules/app/activity/activity.service';
|
||||
import { ConfigService } from '@/modules/shared/config/config.service';
|
||||
import { RefundService } from '@/modules/shared/finance/refund.service';
|
||||
import { CouponService } from '@/modules/app/coupon/coupon.service';
|
||||
|
||||
@Injectable()
|
||||
export class OrderService {
|
||||
+1
-1
@@ -20,7 +20,7 @@ import {
|
||||
} from './dto/user.dto';
|
||||
|
||||
@ApiTags('用户信息')
|
||||
@Controller('user/profile')
|
||||
@Controller('app/profile')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
export class ProfileController {
|
||||
+1
-1
@@ -14,7 +14,7 @@ import { CreateReviewDto, QueryReviewDto } from './dto/review.dto';
|
||||
import { JwtAuthGuard } from '@/common/guards/jwt-auth.guard';
|
||||
|
||||
// 用户端评价接口
|
||||
@Controller('user/reviews')
|
||||
@Controller('app/reviews')
|
||||
export class ReviewController {
|
||||
constructor(private readonly reviewService: ReviewService) {}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import { IsOptional, IsInt, IsDateString, Min } from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||
|
||||
export class QueryAvailableRoomsDto {
|
||||
@ApiPropertyOptional({ description: '商家ID' })
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
merchantId?: number;
|
||||
|
||||
@ApiPropertyOptional({ description: '入住日期', example: '2026-05-15' })
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
checkIn?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: '退房日期', example: '2026-05-16' })
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
checkOut?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: '房间数量', default: 1 })
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
@Min(1)
|
||||
roomCount?: number;
|
||||
|
||||
@ApiPropertyOptional({ description: '成人数量', default: 1 })
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
@Min(1)
|
||||
adultCount?: number;
|
||||
|
||||
@ApiPropertyOptional({ description: '儿童数量', default: 0 })
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
@Min(0)
|
||||
childCount?: number;
|
||||
|
||||
@ApiPropertyOptional({ description: '页码', default: 1 })
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
@Min(1)
|
||||
page?: number;
|
||||
|
||||
@ApiPropertyOptional({ description: '每页数量', default: 10 })
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
@Min(1)
|
||||
pageSize?: number;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { Controller, Get, Query, Param } from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation } from '@nestjs/swagger';
|
||||
import { RoomService } from './room.service';
|
||||
import { QueryAvailableRoomsDto } from './dto/room.dto';
|
||||
|
||||
@ApiTags('房源')
|
||||
@Controller('app/rooms')
|
||||
export class RoomController {
|
||||
constructor(private readonly roomService: RoomService) {}
|
||||
|
||||
@Get()
|
||||
@ApiOperation({ summary: '查询可用房源' })
|
||||
async findAvailable(@Query() query: QueryAvailableRoomsDto) {
|
||||
return this.roomService.findAvailable(query);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@ApiOperation({ summary: '获取房源详情' })
|
||||
async findOne(@Param('id') id: number) {
|
||||
return this.roomService.findById(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { Room } from '@/entities/room.entity';
|
||||
import { RoomCalendar } from '@/entities/room-calendar.entity';
|
||||
import { Merchant } from '@/entities/merchant.entity';
|
||||
import { RoomController } from './room.controller';
|
||||
import { RoomService } from './room.service';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([Room, RoomCalendar, Merchant])],
|
||||
controllers: [RoomController],
|
||||
providers: [RoomService],
|
||||
exports: [RoomService],
|
||||
})
|
||||
export class RoomModule {}
|
||||
@@ -0,0 +1,83 @@
|
||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository, Between, LessThanOrEqual, MoreThanOrEqual } from 'typeorm';
|
||||
import { Room } from '@/entities/room.entity';
|
||||
import { RoomCalendar } from '@/entities/room-calendar.entity';
|
||||
import { QueryAvailableRoomsDto } from './dto/room.dto';
|
||||
|
||||
@Injectable()
|
||||
export class RoomService {
|
||||
constructor(
|
||||
@InjectRepository(Room)
|
||||
private roomRepo: Repository<Room>,
|
||||
@InjectRepository(RoomCalendar)
|
||||
private calendarRepo: Repository<RoomCalendar>,
|
||||
) {}
|
||||
|
||||
async findById(id: number) {
|
||||
const room = await this.roomRepo.findOne({
|
||||
where: { id: Number(id) },
|
||||
relations: ['merchant'],
|
||||
});
|
||||
if (!room) throw new NotFoundException('房源不存在');
|
||||
return room;
|
||||
}
|
||||
|
||||
async findAvailable(query: QueryAvailableRoomsDto) {
|
||||
const {
|
||||
merchantId,
|
||||
checkIn,
|
||||
checkOut,
|
||||
roomCount = 1,
|
||||
adultCount = 1,
|
||||
childCount = 0,
|
||||
page = 1,
|
||||
pageSize = 10,
|
||||
} = query;
|
||||
|
||||
const qb = this.roomRepo
|
||||
.createQueryBuilder('room')
|
||||
.leftJoinAndSelect('room.merchant', 'merchant')
|
||||
.where('room.status = :status', { status: 'on_sale' })
|
||||
.andWhere('room.audit_status = :auditStatus', { auditStatus: 'approved' });
|
||||
|
||||
// 按商家筛选
|
||||
if (merchantId) {
|
||||
qb.andWhere('room.merchant_id = :merchantId', { merchantId });
|
||||
}
|
||||
|
||||
// 按容纳人数筛选
|
||||
const totalGuests = adultCount + childCount;
|
||||
qb.andWhere('room.max_guests >= :totalGuests', { totalGuests });
|
||||
|
||||
// 如果提供了日期,检查可用性
|
||||
if (checkIn && checkOut) {
|
||||
// 查询在该日期范围内有库存的房间
|
||||
const availableRoomIds = await this.calendarRepo
|
||||
.createQueryBuilder('cal')
|
||||
.select('DISTINCT cal.room_id', 'roomId')
|
||||
.where('cal.date >= :checkIn', { checkIn })
|
||||
.andWhere('cal.date < :checkOut', { checkOut })
|
||||
.andWhere('cal.status = :status', { status: 'available' })
|
||||
.andWhere('(cal.stock - cal.sold) >= :roomCount', { roomCount })
|
||||
.groupBy('cal.room_id')
|
||||
.having('COUNT(*) = DATEDIFF(:checkOut, :checkIn)', { checkIn, checkOut })
|
||||
.getRawMany();
|
||||
|
||||
if (availableRoomIds.length > 0) {
|
||||
const roomIds = availableRoomIds.map(item => item.roomId);
|
||||
qb.andWhere('room.id IN (:...roomIds)', { roomIds });
|
||||
} else {
|
||||
// 没有可用房间,返回空结果
|
||||
return { list: [], total: 0, page, pageSize };
|
||||
}
|
||||
}
|
||||
|
||||
qb.orderBy('room.created_at', 'DESC');
|
||||
qb.skip((page - 1) * pageSize).take(pageSize);
|
||||
|
||||
const [list, total] = await qb.getManyAndCount();
|
||||
|
||||
return { list, total, page, pageSize };
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -20,7 +20,7 @@ import {
|
||||
} from './dto/user.dto';
|
||||
|
||||
@ApiTags('用户')
|
||||
@Controller('user')
|
||||
@Controller('app')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
export class UserUserController {
|
||||
@@ -37,6 +37,12 @@ export class MerchantFinanceController {
|
||||
return account;
|
||||
}
|
||||
|
||||
@Get('wallet')
|
||||
@ApiOperation({ summary: '获取商家钱包信息' })
|
||||
async getWallet(@CurrentSeller('sub') sellerId: number) {
|
||||
return this.getAccount(sellerId);
|
||||
}
|
||||
|
||||
@Get('transactions')
|
||||
@ApiOperation({ summary: '交易流水列表' })
|
||||
async getTransactions(
|
||||
|
||||
+2
-2
@@ -7,11 +7,11 @@ import {
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { SettlementService } from './settlement.service';
|
||||
import { SettlementService } from '@/modules/shared/finance/settlement.service';
|
||||
import { SellerJwtAuthGuard } from '@/common/guards/seller-jwt-auth.guard';
|
||||
import { CurrentSeller } from '@/common/decorators/current-seller.decorator';
|
||||
import { MerchantService } from '@/modules/merchant/merchant.service';
|
||||
import { QuerySettlementDto } from './dto/settlement.dto';
|
||||
import { QuerySettlementDto } from '@/modules/shared/finance/dto/settlement.dto';
|
||||
|
||||
@ApiTags('结算管理(商家)')
|
||||
@Controller('merchant/finance/settlements')
|
||||
+3
-3
@@ -8,10 +8,10 @@ import {
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { SellerJwtAuthGuard } from '@/common/guards/seller-jwt-auth.guard';
|
||||
import { CurrentSeller } from '@/common/decorators/current-seller.decorator';
|
||||
import { TransactionService } from './transaction.service';
|
||||
import { AccountService } from './account.service';
|
||||
import { TransactionService } from '@/modules/shared/finance/transaction.service';
|
||||
import { AccountService } from '@/modules/shared/finance/account.service';
|
||||
import { MerchantService } from '@/modules/merchant/merchant.service';
|
||||
import { QueryTransactionDto } from './dto/finance.dto';
|
||||
import { QueryTransactionDto } from '@/modules/shared/finance/dto/finance.dto';
|
||||
|
||||
@ApiTags('交易流水(商家)')
|
||||
@Controller('merchant/finance/transactions')
|
||||
+2
-2
@@ -9,14 +9,14 @@ import {
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { WithdrawalService } from './withdrawal.service';
|
||||
import { WithdrawalService } from '@/modules/shared/finance/withdrawal.service';
|
||||
import { SellerJwtAuthGuard } from '@/common/guards/seller-jwt-auth.guard';
|
||||
import { CurrentSeller } from '@/common/decorators/current-seller.decorator';
|
||||
import { MerchantService } from '@/modules/merchant/merchant.service';
|
||||
import {
|
||||
CreateMerchantWithdrawalDto,
|
||||
QueryMerchantWithdrawalDto,
|
||||
} from './dto/withdrawal.dto';
|
||||
} from '@/modules/shared/finance/dto/withdrawal.dto';
|
||||
|
||||
@ApiTags('提现管理(商家)')
|
||||
@Controller('merchant/finance/withdrawals')
|
||||
@@ -27,6 +27,12 @@ export class MerchantAdminController {
|
||||
return this.merchantService.findAll(query);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@ApiOperation({ summary: '获取商家详情' })
|
||||
async findById(@Param('id') id: number) {
|
||||
return this.merchantService.findById(id);
|
||||
}
|
||||
|
||||
@Put(':id/approve')
|
||||
@ApiOperation({ summary: '审核通过' })
|
||||
async approve(@Param('id') id: number) {
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
} from './dto/merchant.dto';
|
||||
|
||||
@ApiTags('商家管理(商家)')
|
||||
@Controller('seller/merchant')
|
||||
@Controller('merchant/merchant')
|
||||
@UseGuards(SellerJwtAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
export class MerchantSellerController {
|
||||
|
||||
@@ -7,7 +7,6 @@ import { RoomCalendar } from '@/entities/room-calendar.entity';
|
||||
import { Order } from '@/entities/order.entity';
|
||||
import { MerchantService } from './merchant.service';
|
||||
import { StatisticsService } from './statistics.service';
|
||||
import { MerchantPublicController } from './merchant-public.controller';
|
||||
import { MerchantSellerController } from './merchant-seller.controller';
|
||||
import { MerchantAdminController } from './merchant-admin.controller';
|
||||
import { StatisticsSellerController } from './statistics-seller.controller';
|
||||
@@ -33,7 +32,6 @@ import { MerchantStatisticsModule } from './statistics/statistics.module';
|
||||
MerchantStatisticsModule,
|
||||
],
|
||||
controllers: [
|
||||
MerchantPublicController,
|
||||
MerchantSellerController,
|
||||
MerchantAdminController,
|
||||
StatisticsSellerController,
|
||||
|
||||
@@ -10,7 +10,7 @@ import { StatisticsService } from './statistics.service';
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles('merchant')
|
||||
@Controller('seller/statistics')
|
||||
@Controller('merchant/statistics')
|
||||
export class StatisticsSellerController {
|
||||
constructor(private readonly statisticsService: StatisticsService) {}
|
||||
|
||||
|
||||
+2
-4
@@ -3,13 +3,11 @@ import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { Coupon } from '@/entities/coupon.entity';
|
||||
import { UserCoupon } from '@/entities/user-coupon.entity';
|
||||
import { CouponService } from './coupon.service';
|
||||
import { CouponAdminController } from './coupon-admin.controller';
|
||||
import { CouponUserController } from './coupon-user.controller';
|
||||
// 注意:coupon-admin 和 coupon-user controller 已移动到各自模块
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([Coupon, UserCoupon])],
|
||||
controllers: [CouponAdminController, CouponUserController],
|
||||
providers: [CouponService],
|
||||
exports: [CouponService],
|
||||
exports: [CouponService, TypeOrmModule],
|
||||
})
|
||||
export class CouponModule {}
|
||||
+15
-10
@@ -3,29 +3,34 @@ import { Type } from 'class-transformer';
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
|
||||
export class QueryTrendDto {
|
||||
@ApiProperty({ description: '开始日期', example: '2026-05-01' })
|
||||
@ApiPropertyOptional({ description: '开始日期', example: '2026-05-01' })
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
startDate: string;
|
||||
startDate?: string;
|
||||
|
||||
@ApiProperty({ description: '结束日期', example: '2026-05-31' })
|
||||
@ApiPropertyOptional({ description: '结束日期', example: '2026-05-31' })
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
endDate: string;
|
||||
endDate?: string;
|
||||
}
|
||||
|
||||
export class QueryDailyReportDto {
|
||||
@ApiProperty({ description: '日期', example: '2026-05-12' })
|
||||
@ApiPropertyOptional({ description: '日期', example: '2026-05-12' })
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
date: string;
|
||||
date?: string;
|
||||
}
|
||||
|
||||
export class QueryWeeklyReportDto {
|
||||
@ApiProperty({ description: '开始日期', example: '2026-05-06' })
|
||||
@ApiPropertyOptional({ description: '开始日期', example: '2026-05-06' })
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
startDate: string;
|
||||
startDate?: string;
|
||||
|
||||
@ApiProperty({ description: '结束日期', example: '2026-05-12' })
|
||||
@ApiPropertyOptional({ description: '结束日期', example: '2026-05-12' })
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
endDate: string;
|
||||
endDate?: string;
|
||||
}
|
||||
|
||||
export class QueryMonthlyReportDto {
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user