修复:统一前后端的订单状态
This commit is contained in:
@@ -1,3 +1,3 @@
|
|||||||
VITE_APP_NAME=后台管理(开发环境)
|
VITE_APP_NAME=后台管理(开发环境)
|
||||||
VITE_API_URL=http://127.0.0.1:9200/api
|
#VITE_API_URL=http://127.0.0.1:9200/api
|
||||||
#VITE_SERVER_API_URL=http://127.0.0.1:8000/api
|
#VITE_SERVER_API_URL=http://127.0.0.1:8000/api
|
||||||
|
|||||||
245
docs/ORDER_FILTER_COMPARISON.md
Normal file
245
docs/ORDER_FILTER_COMPARISON.md
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
# 订单筛选逻辑对比
|
||||||
|
|
||||||
|
## 修改前后对比
|
||||||
|
|
||||||
|
### 移动端筛选逻辑
|
||||||
|
|
||||||
|
#### 修改前(复杂的前端筛选)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 原有的复杂筛选逻辑
|
||||||
|
const getOrderStatusParams = (index: string | number) => {
|
||||||
|
let params: ShopOrderParam = {};
|
||||||
|
params.userId = Taro.getStorageSync('UserId');
|
||||||
|
|
||||||
|
const indexStr = String(index);
|
||||||
|
switch (indexStr) {
|
||||||
|
case '1': // 待付款
|
||||||
|
params.payStatus = 0; // 0表示未付款
|
||||||
|
break;
|
||||||
|
case '2': // 待发货
|
||||||
|
params.payStatus = 1; // 1表示已付款
|
||||||
|
params.deliveryStatus = 10; // 10表示未发货
|
||||||
|
break;
|
||||||
|
case '3': // 待收货
|
||||||
|
params.deliveryStatus = 20; // 20表示已发货
|
||||||
|
break;
|
||||||
|
case '4': // 已完成
|
||||||
|
params.orderStatus = 1; // 1表示已完成
|
||||||
|
break;
|
||||||
|
case '5': // 已取消
|
||||||
|
// 对于已取消的订单,获取所有数据然后在前端筛选
|
||||||
|
break;
|
||||||
|
case '0': // 全部
|
||||||
|
default:
|
||||||
|
// 全部订单,不添加额外的筛选条件
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 前端二次筛选
|
||||||
|
const filterOrdersByTab = (orders: OrderWithGoods[], tabIndex: number) => {
|
||||||
|
const indexStr = String(tabIndex);
|
||||||
|
return orders.filter(order => {
|
||||||
|
switch (indexStr) {
|
||||||
|
case '1': // 待付款
|
||||||
|
return !order.payStatus && !isCancelledOrder(order);
|
||||||
|
case '2': // 待发货
|
||||||
|
return order.payStatus && order.deliveryStatus === 10 && !isCancelledOrder(order);
|
||||||
|
case '3': // 待收货
|
||||||
|
return order.deliveryStatus === 20 && !isCancelledOrder(order);
|
||||||
|
case '4': // 已完成
|
||||||
|
return order.orderStatus === 1;
|
||||||
|
case '5': // 已取消
|
||||||
|
return isCancelledOrder(order);
|
||||||
|
case '0': // 全部
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 复杂的取消状态判断
|
||||||
|
const isCancelledOrder = (order: ShopOrder) => {
|
||||||
|
const cancelledStatuses = [2, 3, 4, 6, 7];
|
||||||
|
return cancelledStatuses.includes(order.orderStatus || 0);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 修改后(统一的后端筛选)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 简化的统一筛选逻辑
|
||||||
|
const tabs = [
|
||||||
|
{
|
||||||
|
index: 0,
|
||||||
|
statusFilter: undefined // 全部
|
||||||
|
},
|
||||||
|
{
|
||||||
|
index: 1,
|
||||||
|
statusFilter: 0 // 待付款
|
||||||
|
},
|
||||||
|
{
|
||||||
|
index: 2,
|
||||||
|
statusFilter: 1 // 待发货
|
||||||
|
},
|
||||||
|
{
|
||||||
|
index: 3,
|
||||||
|
statusFilter: 3 // 待收货
|
||||||
|
},
|
||||||
|
{
|
||||||
|
index: 4,
|
||||||
|
statusFilter: 5 // 已完成
|
||||||
|
},
|
||||||
|
{
|
||||||
|
index: 5,
|
||||||
|
statusFilter: 6 // 已取消/已退款
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const getOrderStatusParams = (index: string | number) => {
|
||||||
|
let params: ShopOrderParam = {};
|
||||||
|
params.userId = Taro.getStorageSync('UserId');
|
||||||
|
|
||||||
|
const currentTab = tabs.find(tab => tab.index === Number(index));
|
||||||
|
if (currentTab && currentTab.statusFilter !== undefined) {
|
||||||
|
params.statusFilter = currentTab.statusFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
return params;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 不再需要前端二次筛选,直接使用后端返回的数据
|
||||||
|
```
|
||||||
|
|
||||||
|
### 后台管理系统筛选逻辑
|
||||||
|
|
||||||
|
#### 修改前
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 注释不够清晰
|
||||||
|
// 根据文档,statusFilter的值对应:
|
||||||
|
// -1全部,0待付款,1待发货,2待核销,3待收货,4待评价,5已完成,6已退款,7已删除
|
||||||
|
switch (activeKey.value) {
|
||||||
|
case 'all':
|
||||||
|
filterParams.statusFilter = -1; // 使用-1表示全部
|
||||||
|
break;
|
||||||
|
// ... 其他case
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 修改后
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 更清晰的注释和实现
|
||||||
|
// 根据后端 statusFilter 的值对应:
|
||||||
|
// undefined全部,0待付款,1待发货,2待核销,3待收货,4待评价,5已完成,6已退款,7已删除
|
||||||
|
switch (activeKey.value) {
|
||||||
|
case 'all':
|
||||||
|
// 全部订单:不传statusFilter参数
|
||||||
|
// filterParams.statusFilter = undefined; // 不设置该字段
|
||||||
|
break;
|
||||||
|
// ... 其他case保持一致
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 主要改进点
|
||||||
|
|
||||||
|
### 1. 性能优化
|
||||||
|
|
||||||
|
| 方面 | 修改前 | 修改后 |
|
||||||
|
|------|--------|--------|
|
||||||
|
| 数据筛选位置 | 前端 + 后端 | 纯后端 |
|
||||||
|
| 网络传输 | 传输所有数据再筛选 | 只传输筛选后的数据 |
|
||||||
|
| 前端处理 | 复杂的二次筛选逻辑 | 直接使用后端数据 |
|
||||||
|
| 查询效率 | 低(多次查询+前端筛选) | 高(单次精确查询) |
|
||||||
|
|
||||||
|
### 2. 代码复杂度
|
||||||
|
|
||||||
|
| 方面 | 修改前 | 修改后 |
|
||||||
|
|------|--------|--------|
|
||||||
|
| 筛选逻辑行数 | ~80行 | ~20行 |
|
||||||
|
| 筛选条件数量 | 多个字段组合 | 单个statusFilter |
|
||||||
|
| 维护难度 | 高(前后端都要维护) | 低(只需维护后端) |
|
||||||
|
| 出错概率 | 高(逻辑复杂) | 低(逻辑简单) |
|
||||||
|
|
||||||
|
### 3. 一致性保证
|
||||||
|
|
||||||
|
| 方面 | 修改前 | 修改后 |
|
||||||
|
|------|--------|--------|
|
||||||
|
| 前端移动端 | 自定义筛选逻辑 | 使用statusFilter |
|
||||||
|
| 后台管理系统 | 使用statusFilter | 使用statusFilter |
|
||||||
|
| 数据一致性 | 可能不一致 | 完全一致 |
|
||||||
|
| 维护成本 | 高(两套逻辑) | 低(统一逻辑) |
|
||||||
|
|
||||||
|
## 具体的筛选条件对比
|
||||||
|
|
||||||
|
### 待付款订单
|
||||||
|
|
||||||
|
**修改前(移动端):**
|
||||||
|
```typescript
|
||||||
|
// 后端查询
|
||||||
|
params.payStatus = 0;
|
||||||
|
|
||||||
|
// 前端再筛选
|
||||||
|
return !order.payStatus && !isCancelledOrder(order);
|
||||||
|
```
|
||||||
|
|
||||||
|
**修改后:**
|
||||||
|
```typescript
|
||||||
|
// 只需后端查询
|
||||||
|
params.statusFilter = 0; // 对应 pay_status = false
|
||||||
|
```
|
||||||
|
|
||||||
|
### 待发货订单
|
||||||
|
|
||||||
|
**修改前(移动端):**
|
||||||
|
```typescript
|
||||||
|
// 后端查询
|
||||||
|
params.payStatus = 1;
|
||||||
|
params.deliveryStatus = 10;
|
||||||
|
|
||||||
|
// 前端再筛选
|
||||||
|
return order.payStatus && order.deliveryStatus === 10 && !isCancelledOrder(order);
|
||||||
|
```
|
||||||
|
|
||||||
|
**修改后:**
|
||||||
|
```typescript
|
||||||
|
// 只需后端查询
|
||||||
|
params.statusFilter = 1; // 对应 pay_status = true AND delivery_status = 10
|
||||||
|
```
|
||||||
|
|
||||||
|
### 已取消订单
|
||||||
|
|
||||||
|
**修改前(移动端):**
|
||||||
|
```typescript
|
||||||
|
// 后端查询所有数据
|
||||||
|
// 无特定筛选条件
|
||||||
|
|
||||||
|
// 前端复杂筛选
|
||||||
|
const isCancelledOrder = (order: ShopOrder) => {
|
||||||
|
const cancelledStatuses = [2, 3, 4, 6, 7];
|
||||||
|
return cancelledStatuses.includes(order.orderStatus || 0);
|
||||||
|
};
|
||||||
|
return isCancelledOrder(order);
|
||||||
|
```
|
||||||
|
|
||||||
|
**修改后:**
|
||||||
|
```typescript
|
||||||
|
// 只需后端查询
|
||||||
|
params.statusFilter = 6; // 对应 order_status = 6 (已退款)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 迁移建议
|
||||||
|
|
||||||
|
1. **立即可用**:新的移动端组件已经创建,可以直接使用
|
||||||
|
2. **逐步替换**:可以先在新功能中使用,再逐步替换现有页面
|
||||||
|
3. **测试验证**:建议先在测试环境验证各个筛选条件的正确性
|
||||||
|
4. **性能监控**:关注查询性能的改善情况
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. **移动端显示逻辑**:虽然筛选使用statusFilter,但显示的状态文本仍可以根据业务需求自定义
|
||||||
|
2. **特殊状态处理**:某些复杂的状态组合可能需要在显示层面进行适配
|
||||||
|
3. **向后兼容**:确保现有功能不受影响
|
||||||
192
docs/ORDER_STATUS_UNIFIED_FILTER.md
Normal file
192
docs/ORDER_STATUS_UNIFIED_FILTER.md
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
# 订单状态筛选统一方案
|
||||||
|
|
||||||
|
## 问题描述
|
||||||
|
|
||||||
|
原先前端移动端和后台管理系统的订单状态筛选逻辑不一致:
|
||||||
|
|
||||||
|
### 移动端原有问题:
|
||||||
|
1. 使用多个字段组合进行筛选(payStatus, orderStatus, deliveryStatus)
|
||||||
|
2. 在前端进行二次过滤,效率低下
|
||||||
|
3. 筛选逻辑复杂,容易出错
|
||||||
|
4. 与后端设计的 statusFilter 字段不一致
|
||||||
|
|
||||||
|
### 后台管理系统:
|
||||||
|
1. 已经使用 statusFilter 字段
|
||||||
|
2. 但注释和实现有些不一致的地方
|
||||||
|
|
||||||
|
## 解决方案
|
||||||
|
|
||||||
|
统一使用后端的 `statusFilter` 字段进行订单状态筛选,所有前端页面都采用相同的筛选逻辑。
|
||||||
|
|
||||||
|
## 后端 statusFilter 字段定义
|
||||||
|
|
||||||
|
根据后端 `ShopOrderParam.java` 和 `ShopOrderMapper.xml` 的定义:
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Schema(description = "订单状态筛选:-1全部,0待支付,1待发货,2待核销,3待收货,4待评价,5已完成,6已退款,7已删除")
|
||||||
|
private Integer statusFilter;
|
||||||
|
```
|
||||||
|
|
||||||
|
## 统一的状态筛选映射表
|
||||||
|
|
||||||
|
| statusFilter | 标签名称 | 后端筛选条件 | 说明 |
|
||||||
|
|-------------|---------|-------------|------|
|
||||||
|
| undefined | 全部 | 无筛选条件 | 显示所有订单(包括已删除的) |
|
||||||
|
| 0 | 待付款 | pay_status = false | 未付款的订单 |
|
||||||
|
| 1 | 待发货 | pay_status = true AND delivery_status = 10 | 已付款但未发货 |
|
||||||
|
| 2 | 待核销 | pay_status = true AND delivery_status = 10 | 与待发货相同(特定业务场景) |
|
||||||
|
| 3 | 待收货 | pay_status = true AND delivery_status = 20 | 已发货待收货 |
|
||||||
|
| 4 | 待评价 | order_status = 1 | 与已完成相同(特定业务场景) |
|
||||||
|
| 5 | 已完成 | order_status = 1 | 订单已完成 |
|
||||||
|
| 6 | 已退款 | order_status = 6 | 退款成功的订单 |
|
||||||
|
| 7 | 已删除 | deleted = 1 | 已删除的订单 |
|
||||||
|
|
||||||
|
## 前端实现
|
||||||
|
|
||||||
|
### 移动端(React/Taro)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 统一的订单状态标签配置
|
||||||
|
const tabs = [
|
||||||
|
{
|
||||||
|
index: 0,
|
||||||
|
key: '全部',
|
||||||
|
title: '全部',
|
||||||
|
description: '所有订单',
|
||||||
|
statusFilter: undefined // 不传statusFilter,显示所有订单
|
||||||
|
},
|
||||||
|
{
|
||||||
|
index: 1,
|
||||||
|
key: '待付款',
|
||||||
|
title: '待付款',
|
||||||
|
description: '等待付款的订单',
|
||||||
|
statusFilter: 0 // 对应后端:pay_status = false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
index: 2,
|
||||||
|
key: '待发货',
|
||||||
|
title: '待发货',
|
||||||
|
description: '已付款待发货的订单',
|
||||||
|
statusFilter: 1 // 对应后端:pay_status = true AND delivery_status = 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
index: 3,
|
||||||
|
key: '待收货',
|
||||||
|
title: '待收货',
|
||||||
|
description: '已发货待收货的订单',
|
||||||
|
statusFilter: 3 // 对应后端:pay_status = true AND delivery_status = 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
index: 4,
|
||||||
|
key: '已完成',
|
||||||
|
title: '已完成',
|
||||||
|
description: '已完成的订单',
|
||||||
|
statusFilter: 5 // 对应后端:order_status = 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
index: 5,
|
||||||
|
key: '已取消',
|
||||||
|
title: '已取消',
|
||||||
|
description: '已取消/退款的订单',
|
||||||
|
statusFilter: 6 // 对应后端:order_status = 6 (已退款)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
// 筛选参数生成
|
||||||
|
const getOrderStatusParams = (index: string | number) => {
|
||||||
|
let params: ShopOrderParam = {};
|
||||||
|
params.userId = Taro.getStorageSync('UserId');
|
||||||
|
|
||||||
|
const currentTab = tabs.find(tab => tab.index === Number(index));
|
||||||
|
if (currentTab && currentTab.statusFilter !== undefined) {
|
||||||
|
params.statusFilter = currentTab.statusFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
return params;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 后台管理系统(Vue)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const onTabs = () => {
|
||||||
|
const filterParams: Record<string, any> = {};
|
||||||
|
|
||||||
|
switch (activeKey.value) {
|
||||||
|
case 'all':
|
||||||
|
// 全部订单:不传statusFilter参数
|
||||||
|
break;
|
||||||
|
case 'unpaid':
|
||||||
|
filterParams.statusFilter = 0;
|
||||||
|
break;
|
||||||
|
case 'undelivered':
|
||||||
|
filterParams.statusFilter = 1;
|
||||||
|
break;
|
||||||
|
case 'unreceived':
|
||||||
|
filterParams.statusFilter = 3;
|
||||||
|
break;
|
||||||
|
case 'completed':
|
||||||
|
filterParams.statusFilter = 5;
|
||||||
|
break;
|
||||||
|
case 'refunded':
|
||||||
|
filterParams.statusFilter = 6;
|
||||||
|
break;
|
||||||
|
case 'deleted':
|
||||||
|
filterParams.statusFilter = 7;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
reload(filterParams);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 优化效果
|
||||||
|
|
||||||
|
### 1. 性能提升
|
||||||
|
- 筛选逻辑在后端执行,减少前端数据处理
|
||||||
|
- 减少网络传输的数据量
|
||||||
|
- 提高查询效率
|
||||||
|
|
||||||
|
### 2. 代码简化
|
||||||
|
- 移除前端复杂的筛选逻辑
|
||||||
|
- 统一前后端筛选标准
|
||||||
|
- 减少维护成本
|
||||||
|
|
||||||
|
### 3. 一致性保证
|
||||||
|
- 前端移动端和后台管理系统使用相同的筛选逻辑
|
||||||
|
- 与后端设计保持一致
|
||||||
|
- 避免数据不一致的问题
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
### 1. 移动端特殊处理
|
||||||
|
移动端可能需要将某些后端状态合并显示:
|
||||||
|
- "已取消" 标签可以包含多种取消状态(orderStatus: 2,3,4,6,7)
|
||||||
|
- 可以在前端显示时进行状态文本的转换,但筛选仍使用 statusFilter
|
||||||
|
|
||||||
|
### 2. 向后兼容
|
||||||
|
- 保持现有API接口不变
|
||||||
|
- 逐步迁移现有代码
|
||||||
|
- 确保不影响现有功能
|
||||||
|
|
||||||
|
### 3. 测试验证
|
||||||
|
- 验证各个状态筛选的正确性
|
||||||
|
- 确认前后端数据一致性
|
||||||
|
- 测试边界情况和异常处理
|
||||||
|
|
||||||
|
## 迁移步骤
|
||||||
|
|
||||||
|
1. **创建新的移动端组件**:使用统一的 statusFilter 逻辑
|
||||||
|
2. **更新后台管理系统**:完善注释和实现细节
|
||||||
|
3. **测试验证**:确保所有筛选功能正常工作
|
||||||
|
4. **逐步替换**:将旧的移动端组件替换为新组件
|
||||||
|
5. **清理代码**:移除不再使用的筛选逻辑
|
||||||
|
|
||||||
|
## 相关文件
|
||||||
|
|
||||||
|
- 移动端新组件:`src/views/shop/shopOrder/mobile/index.tsx`
|
||||||
|
- 后台管理系统:`src/views/shop/shopOrder/index.vue`
|
||||||
|
- API接口:`src/api/shop/shopOrder/index.ts`
|
||||||
|
- 数据模型:`src/api/shop/shopOrder/model/index.ts`
|
||||||
|
- 后端参数:`ShopOrderParam.java`
|
||||||
|
- 后端SQL:`ShopOrderMapper.xml`
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import type { ApiResult, PageResult } from '@/api';
|
import type { ApiResult, PageResult } from '@/api/index';
|
||||||
import type { ShopMerchant, ShopMerchantParam } from './model';
|
import type { ShopMerchant, ShopMerchantParam } from './model';
|
||||||
|
import { MODULES_API_URL } from '@/config/setting';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分页查询商户
|
* 分页查询商户
|
||||||
*/
|
*/
|
||||||
export async function pageShopMerchant(params: ShopMerchantParam) {
|
export async function pageShopMerchant(params: ShopMerchantParam) {
|
||||||
const res = await request.get<ApiResult<PageResult<ShopMerchant>>>(
|
const res = await request.get<ApiResult<PageResult<ShopMerchant>>>(
|
||||||
'/shop/shop-merchant/page',
|
MODULES_API_URL + '/shop/shop-merchant/page',
|
||||||
{
|
{
|
||||||
params
|
params
|
||||||
}
|
}
|
||||||
@@ -23,7 +24,7 @@ export async function pageShopMerchant(params: ShopMerchantParam) {
|
|||||||
*/
|
*/
|
||||||
export async function listShopMerchant(params?: ShopMerchantParam) {
|
export async function listShopMerchant(params?: ShopMerchantParam) {
|
||||||
const res = await request.get<ApiResult<ShopMerchant[]>>(
|
const res = await request.get<ApiResult<ShopMerchant[]>>(
|
||||||
'/shop/shop-merchant',
|
MODULES_API_URL + '/shop/shop-merchant',
|
||||||
{
|
{
|
||||||
params
|
params
|
||||||
}
|
}
|
||||||
@@ -39,7 +40,7 @@ export async function listShopMerchant(params?: ShopMerchantParam) {
|
|||||||
*/
|
*/
|
||||||
export async function addShopMerchant(data: ShopMerchant) {
|
export async function addShopMerchant(data: ShopMerchant) {
|
||||||
const res = await request.post<ApiResult<unknown>>(
|
const res = await request.post<ApiResult<unknown>>(
|
||||||
'/shop/shop-merchant',
|
MODULES_API_URL + '/shop/shop-merchant',
|
||||||
data
|
data
|
||||||
);
|
);
|
||||||
if (res.data.code === 0) {
|
if (res.data.code === 0) {
|
||||||
@@ -53,7 +54,7 @@ export async function addShopMerchant(data: ShopMerchant) {
|
|||||||
*/
|
*/
|
||||||
export async function updateShopMerchant(data: ShopMerchant) {
|
export async function updateShopMerchant(data: ShopMerchant) {
|
||||||
const res = await request.put<ApiResult<unknown>>(
|
const res = await request.put<ApiResult<unknown>>(
|
||||||
'/shop/shop-merchant',
|
MODULES_API_URL + '/shop/shop-merchant',
|
||||||
data
|
data
|
||||||
);
|
);
|
||||||
if (res.data.code === 0) {
|
if (res.data.code === 0) {
|
||||||
@@ -67,7 +68,7 @@ export async function updateShopMerchant(data: ShopMerchant) {
|
|||||||
*/
|
*/
|
||||||
export async function removeShopMerchant(id?: number) {
|
export async function removeShopMerchant(id?: number) {
|
||||||
const res = await request.delete<ApiResult<unknown>>(
|
const res = await request.delete<ApiResult<unknown>>(
|
||||||
'/shop/shop-merchant/' + id
|
MODULES_API_URL + '/shop/shop-merchant/' + id
|
||||||
);
|
);
|
||||||
if (res.data.code === 0) {
|
if (res.data.code === 0) {
|
||||||
return res.data.message;
|
return res.data.message;
|
||||||
@@ -80,7 +81,7 @@ export async function removeShopMerchant(id?: number) {
|
|||||||
*/
|
*/
|
||||||
export async function removeBatchShopMerchant(data: (number | undefined)[]) {
|
export async function removeBatchShopMerchant(data: (number | undefined)[]) {
|
||||||
const res = await request.delete<ApiResult<unknown>>(
|
const res = await request.delete<ApiResult<unknown>>(
|
||||||
'/shop/shop-merchant/batch',
|
MODULES_API_URL + '/shop/shop-merchant/batch',
|
||||||
{
|
{
|
||||||
data
|
data
|
||||||
}
|
}
|
||||||
@@ -96,7 +97,7 @@ export async function removeBatchShopMerchant(data: (number | undefined)[]) {
|
|||||||
*/
|
*/
|
||||||
export async function getShopMerchant(id: number) {
|
export async function getShopMerchant(id: number) {
|
||||||
const res = await request.get<ApiResult<ShopMerchant>>(
|
const res = await request.get<ApiResult<ShopMerchant>>(
|
||||||
'/shop/shop-merchant/' + id
|
MODULES_API_URL + '/shop/shop-merchant/' + id
|
||||||
);
|
);
|
||||||
if (res.data.code === 0 && res.data.data) {
|
if (res.data.code === 0 && res.data.data) {
|
||||||
return res.data.data;
|
return res.data.data;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { PageParam } from '@/api';
|
import type { PageParam } from '@/api/index';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 商户
|
* 商户
|
||||||
@@ -56,8 +56,16 @@ export interface ShopMerchant {
|
|||||||
price?: string;
|
price?: string;
|
||||||
// 是否自营
|
// 是否自营
|
||||||
ownStore?: number;
|
ownStore?: number;
|
||||||
|
// 是否可以快递
|
||||||
|
canExpress?: string;
|
||||||
// 是否推荐
|
// 是否推荐
|
||||||
recommend?: number;
|
recommend?: number;
|
||||||
|
// 是否营业
|
||||||
|
isOn?: number;
|
||||||
|
//
|
||||||
|
startTime?: string;
|
||||||
|
//
|
||||||
|
endTime?: string;
|
||||||
// 是否需要审核
|
// 是否需要审核
|
||||||
goodsReview?: number;
|
goodsReview?: number;
|
||||||
// 管理入口
|
// 管理入口
|
||||||
@@ -83,8 +91,5 @@ export interface ShopMerchant {
|
|||||||
*/
|
*/
|
||||||
export interface ShopMerchantParam extends PageParam {
|
export interface ShopMerchantParam extends PageParam {
|
||||||
merchantId?: number;
|
merchantId?: number;
|
||||||
phone?: string;
|
|
||||||
userId?: number;
|
|
||||||
shopType?: string;
|
|
||||||
keywords?: string;
|
keywords?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
41
src/views/shop/shopMerchant/components/search.vue
Normal file
41
src/views/shop/shopMerchant/components/search.vue
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<!-- 搜索表单 -->
|
||||||
|
<template>
|
||||||
|
<a-space :size="10" style="flex-wrap: wrap">
|
||||||
|
<a-button type="primary" class="ele-btn-icon" @click="add">
|
||||||
|
<template #icon>
|
||||||
|
<PlusOutlined />
|
||||||
|
</template>
|
||||||
|
<span>添加</span>
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { PlusOutlined } from '@ant-design/icons-vue';
|
||||||
|
import { watch } from 'vue';
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
// 选中的角色
|
||||||
|
selection?: [];
|
||||||
|
}>(),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'search', where?: any): void;
|
||||||
|
(e: 'add'): void;
|
||||||
|
(e: 'remove'): void;
|
||||||
|
(e: 'batchMove'): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
// 新增
|
||||||
|
const add = () => {
|
||||||
|
emit('add');
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.selection,
|
||||||
|
() => {}
|
||||||
|
);
|
||||||
|
</script>
|
||||||
454
src/views/shop/shopMerchant/components/shopMerchantEdit.vue
Normal file
454
src/views/shop/shopMerchant/components/shopMerchantEdit.vue
Normal file
@@ -0,0 +1,454 @@
|
|||||||
|
<!-- 编辑弹窗 -->
|
||||||
|
<template>
|
||||||
|
<ele-modal
|
||||||
|
:width="800"
|
||||||
|
:visible="visible"
|
||||||
|
:maskClosable="false"
|
||||||
|
:maxable="maxable"
|
||||||
|
:title="isUpdate ? '编辑商户' : '添加商户'"
|
||||||
|
:body-style="{ paddingBottom: '28px' }"
|
||||||
|
@update:visible="updateVisible"
|
||||||
|
@ok="save"
|
||||||
|
>
|
||||||
|
<a-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="form"
|
||||||
|
:rules="rules"
|
||||||
|
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
|
||||||
|
:wrapper-col="
|
||||||
|
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<a-form-item label="商户名称" name="merchantName">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入商户名称"
|
||||||
|
v-model:value="form.merchantName"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="商户编号" name="merchantCode">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入商户编号"
|
||||||
|
v-model:value="form.merchantCode"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="商户类型" name="type">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入商户类型"
|
||||||
|
v-model:value="form.type"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
label="商户图标"
|
||||||
|
name="image">
|
||||||
|
<SelectFile
|
||||||
|
:placeholder="`请选择图片`"
|
||||||
|
:limit="1"
|
||||||
|
:data="images"
|
||||||
|
@done="chooseImage"
|
||||||
|
@del="onDeleteItem"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="商户手机号" name="phone">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入商户手机号"
|
||||||
|
v-model:value="form.phone"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="商户姓名" name="realName">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入商户姓名"
|
||||||
|
v-model:value="form.realName"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="店铺类型" name="shopType">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入店铺类型"
|
||||||
|
v-model:value="form.shopType"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="项目分类" name="itemType">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入项目分类"
|
||||||
|
v-model:value="form.itemType"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="商户分类" name="category">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入商户分类"
|
||||||
|
v-model:value="form.category"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="商户经营分类" name="merchantCategoryId">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入商户经营分类"
|
||||||
|
v-model:value="form.merchantCategoryId"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="商户分类" name="merchantCategoryTitle">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入商户分类"
|
||||||
|
v-model:value="form.merchantCategoryTitle"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="经纬度" name="lngAndLat">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入经纬度"
|
||||||
|
v-model:value="form.lngAndLat"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="" name="lng">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入"
|
||||||
|
v-model:value="form.lng"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="" name="lat">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入"
|
||||||
|
v-model:value="form.lat"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="所在省份" name="province">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入所在省份"
|
||||||
|
v-model:value="form.province"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="所在城市" name="city">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入所在城市"
|
||||||
|
v-model:value="form.city"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="所在辖区" name="region">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入所在辖区"
|
||||||
|
v-model:value="form.region"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="详细地址" name="address">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入详细地址"
|
||||||
|
v-model:value="form.address"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="手续费" name="commission">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入手续费"
|
||||||
|
v-model:value="form.commission"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="关键字" name="keywords">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入关键字"
|
||||||
|
v-model:value="form.keywords"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="资质图片" name="files">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入资质图片"
|
||||||
|
v-model:value="form.files"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="营业时间" name="businessTime">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入营业时间"
|
||||||
|
v-model:value="form.businessTime"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="文章内容" name="content">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入文章内容"
|
||||||
|
v-model:value="form.content"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="每小时价格" name="price">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入每小时价格"
|
||||||
|
v-model:value="form.price"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="是否自营" name="ownStore">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入是否自营"
|
||||||
|
v-model:value="form.ownStore"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="是否可以快递" name="canExpress">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入是否可以快递"
|
||||||
|
v-model:value="form.canExpress"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="是否推荐" name="recommend">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入是否推荐"
|
||||||
|
v-model:value="form.recommend"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="是否营业" name="isOn">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入是否营业"
|
||||||
|
v-model:value="form.isOn"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="" name="startTime">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入"
|
||||||
|
v-model:value="form.startTime"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="" name="endTime">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入"
|
||||||
|
v-model:value="form.endTime"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="是否需要审核" name="goodsReview">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入是否需要审核"
|
||||||
|
v-model:value="form.goodsReview"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="管理入口" name="adminUrl">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入管理入口"
|
||||||
|
v-model:value="form.adminUrl"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="备注" name="comments">
|
||||||
|
<a-textarea
|
||||||
|
:rows="4"
|
||||||
|
:maxlength="200"
|
||||||
|
placeholder="请输入描述"
|
||||||
|
v-model:value="form.comments"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="所有人" name="userId">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入所有人"
|
||||||
|
v-model:value="form.userId"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="状态" name="status">
|
||||||
|
<a-radio-group v-model:value="form.status">
|
||||||
|
<a-radio :value="0">显示</a-radio>
|
||||||
|
<a-radio :value="1">隐藏</a-radio>
|
||||||
|
</a-radio-group>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="排序号" name="sortNumber">
|
||||||
|
<a-input-number
|
||||||
|
:min="0"
|
||||||
|
:max="9999"
|
||||||
|
class="ele-fluid"
|
||||||
|
placeholder="请输入排序号"
|
||||||
|
v-model:value="form.sortNumber"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</ele-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, reactive, watch } from 'vue';
|
||||||
|
import { Form, message } from 'ant-design-vue';
|
||||||
|
import { assignObject, uuid } from 'ele-admin-pro';
|
||||||
|
import { addShopMerchant, updateShopMerchant } from '@/api/shop/shopMerchant';
|
||||||
|
import { ShopMerchant } from '@/api/shop/shopMerchant/model';
|
||||||
|
import { useThemeStore } from '@/store/modules/theme';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
|
||||||
|
import { FormInstance } from 'ant-design-vue/es/form';
|
||||||
|
import { FileRecord } from '@/api/system/file/model';
|
||||||
|
|
||||||
|
// 是否是修改
|
||||||
|
const isUpdate = ref(false);
|
||||||
|
const useForm = Form.useForm;
|
||||||
|
// 是否开启响应式布局
|
||||||
|
const themeStore = useThemeStore();
|
||||||
|
const { styleResponsive } = storeToRefs(themeStore);
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
// 弹窗是否打开
|
||||||
|
visible: boolean;
|
||||||
|
// 修改回显的数据
|
||||||
|
data?: ShopMerchant | null;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'done'): void;
|
||||||
|
(e: 'update:visible', visible: boolean): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
// 提交状态
|
||||||
|
const loading = ref(false);
|
||||||
|
// 是否显示最大化切换按钮
|
||||||
|
const maxable = ref(true);
|
||||||
|
// 表格选中数据
|
||||||
|
const formRef = ref<FormInstance | null>(null);
|
||||||
|
const images = ref<ItemType[]>([]);
|
||||||
|
|
||||||
|
// 用户信息
|
||||||
|
const form = reactive<ShopMerchant>({
|
||||||
|
merchantId: undefined,
|
||||||
|
merchantName: undefined,
|
||||||
|
merchantCode: undefined,
|
||||||
|
type: undefined,
|
||||||
|
image: undefined,
|
||||||
|
phone: undefined,
|
||||||
|
realName: undefined,
|
||||||
|
shopType: undefined,
|
||||||
|
itemType: undefined,
|
||||||
|
category: undefined,
|
||||||
|
merchantCategoryId: undefined,
|
||||||
|
merchantCategoryTitle: undefined,
|
||||||
|
lngAndLat: undefined,
|
||||||
|
lng: undefined,
|
||||||
|
lat: undefined,
|
||||||
|
province: undefined,
|
||||||
|
city: undefined,
|
||||||
|
region: undefined,
|
||||||
|
address: undefined,
|
||||||
|
commission: undefined,
|
||||||
|
keywords: undefined,
|
||||||
|
files: undefined,
|
||||||
|
businessTime: undefined,
|
||||||
|
content: undefined,
|
||||||
|
price: undefined,
|
||||||
|
ownStore: undefined,
|
||||||
|
canExpress: undefined,
|
||||||
|
recommend: undefined,
|
||||||
|
isOn: undefined,
|
||||||
|
startTime: undefined,
|
||||||
|
endTime: undefined,
|
||||||
|
goodsReview: undefined,
|
||||||
|
adminUrl: undefined,
|
||||||
|
comments: undefined,
|
||||||
|
userId: undefined,
|
||||||
|
deleted: undefined,
|
||||||
|
status: undefined,
|
||||||
|
sortNumber: 100,
|
||||||
|
tenantId: undefined,
|
||||||
|
createTime: undefined,
|
||||||
|
shopMerchantId: undefined,
|
||||||
|
shopMerchantName: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
/* 更新visible */
|
||||||
|
const updateVisible = (value: boolean) => {
|
||||||
|
emit('update:visible', value);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 表单验证规则
|
||||||
|
const rules = reactive({
|
||||||
|
shopMerchantName: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
type: 'string',
|
||||||
|
message: '请填写商户名称',
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const chooseImage = (data: FileRecord) => {
|
||||||
|
images.value.push({
|
||||||
|
uid: data.id,
|
||||||
|
url: data.path,
|
||||||
|
status: 'done'
|
||||||
|
});
|
||||||
|
form.image = data.path;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDeleteItem = (index: number) => {
|
||||||
|
images.value.splice(index, 1);
|
||||||
|
form.image = '';
|
||||||
|
};
|
||||||
|
|
||||||
|
const { resetFields } = useForm(form, rules);
|
||||||
|
|
||||||
|
/* 保存编辑 */
|
||||||
|
const save = () => {
|
||||||
|
if (!formRef.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
formRef.value
|
||||||
|
.validate()
|
||||||
|
.then(() => {
|
||||||
|
loading.value = true;
|
||||||
|
const formData = {
|
||||||
|
...form
|
||||||
|
};
|
||||||
|
const saveOrUpdate = isUpdate.value ? updateShopMerchant : addShopMerchant;
|
||||||
|
saveOrUpdate(formData)
|
||||||
|
.then((msg) => {
|
||||||
|
loading.value = false;
|
||||||
|
message.success(msg);
|
||||||
|
updateVisible(false);
|
||||||
|
emit('done');
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
loading.value = false;
|
||||||
|
message.error(e.message);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.visible,
|
||||||
|
(visible) => {
|
||||||
|
if (visible) {
|
||||||
|
images.value = [];
|
||||||
|
if (props.data) {
|
||||||
|
assignObject(form, props.data);
|
||||||
|
if(props.data.image){
|
||||||
|
images.value.push({
|
||||||
|
uid: uuid(),
|
||||||
|
url: props.data.image,
|
||||||
|
status: 'done'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
isUpdate.value = true;
|
||||||
|
} else {
|
||||||
|
isUpdate.value = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resetFields();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
</script>
|
||||||
244
src/views/shop/shopMerchant/index.vue
Normal file
244
src/views/shop/shopMerchant/index.vue
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
<template>
|
||||||
|
<a-page-header :title="getPageTitle()" @back="() => $router.go(-1)">
|
||||||
|
<a-card :bordered="false" :body-style="{ padding: '16px' }">
|
||||||
|
<ele-pro-table
|
||||||
|
ref="tableRef"
|
||||||
|
row-key="merchantId"
|
||||||
|
:columns="columns"
|
||||||
|
:datasource="datasource"
|
||||||
|
:customRow="customRow"
|
||||||
|
tool-class="ele-toolbar-form"
|
||||||
|
class="sys-org-table"
|
||||||
|
>
|
||||||
|
<template #toolbar>
|
||||||
|
<Search
|
||||||
|
@search="reload"
|
||||||
|
:selection="selection"
|
||||||
|
@add="openEdit"
|
||||||
|
@remove="removeBatch"
|
||||||
|
@batchMove="openMove"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'image'">
|
||||||
|
<a-image :src="record.image" :width="50" />
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === 'status'">
|
||||||
|
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
|
||||||
|
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === 'action'">
|
||||||
|
<a-space>
|
||||||
|
<a @click="openEdit(record)">修改</a>
|
||||||
|
<a-divider type="vertical" />
|
||||||
|
<a-popconfirm
|
||||||
|
title="确定要删除此记录吗?"
|
||||||
|
@confirm="remove(record)"
|
||||||
|
>
|
||||||
|
<a class="ele-text-danger">删除</a>
|
||||||
|
</a-popconfirm>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</ele-pro-table>
|
||||||
|
</a-card>
|
||||||
|
|
||||||
|
<!-- 编辑弹窗 -->
|
||||||
|
<ShopMerchantEdit v-model:visible="showEdit" :data="current" @done="reload" />
|
||||||
|
</a-page-header>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { createVNode, ref } from 'vue';
|
||||||
|
import { message, Modal } from 'ant-design-vue';
|
||||||
|
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
|
||||||
|
import type { EleProTable } from 'ele-admin-pro';
|
||||||
|
import { toDateString } from 'ele-admin-pro';
|
||||||
|
import type {
|
||||||
|
DatasourceFunction,
|
||||||
|
ColumnItem
|
||||||
|
} from 'ele-admin-pro/es/ele-pro-table/types';
|
||||||
|
import Search from './components/search.vue';
|
||||||
|
import {getPageTitle} from '@/utils/common';
|
||||||
|
import ShopMerchantEdit from './components/shopMerchantEdit.vue';
|
||||||
|
import { pageShopMerchant, removeShopMerchant, removeBatchShopMerchant } from '@/api/shop/shopMerchant';
|
||||||
|
import type { ShopMerchant, ShopMerchantParam } from '@/api/shop/shopMerchant/model';
|
||||||
|
|
||||||
|
// 表格实例
|
||||||
|
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
|
||||||
|
|
||||||
|
// 表格选中数据
|
||||||
|
const selection = ref<ShopMerchant[]>([]);
|
||||||
|
// 当前编辑数据
|
||||||
|
const current = ref<ShopMerchant | null>(null);
|
||||||
|
// 是否显示编辑弹窗
|
||||||
|
const showEdit = ref(false);
|
||||||
|
// 是否显示批量移动弹窗
|
||||||
|
const showMove = ref(false);
|
||||||
|
// 加载状态
|
||||||
|
const loading = ref(true);
|
||||||
|
|
||||||
|
// 表格数据源
|
||||||
|
const datasource: DatasourceFunction = ({
|
||||||
|
page,
|
||||||
|
limit,
|
||||||
|
where,
|
||||||
|
orders,
|
||||||
|
filters
|
||||||
|
}) => {
|
||||||
|
if (filters) {
|
||||||
|
where.status = filters.status;
|
||||||
|
}
|
||||||
|
return pageShopMerchant({
|
||||||
|
...where,
|
||||||
|
...orders,
|
||||||
|
page,
|
||||||
|
limit
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 表格列配置
|
||||||
|
const columns = ref<ColumnItem[]>([
|
||||||
|
{
|
||||||
|
title: '商户ID',
|
||||||
|
dataIndex: 'merchantId',
|
||||||
|
key: 'merchantId',
|
||||||
|
align: 'center',
|
||||||
|
width: 90,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '商户名称',
|
||||||
|
dataIndex: 'merchantName',
|
||||||
|
key: 'merchantName',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// title: '店铺类型',
|
||||||
|
// dataIndex: 'shopType',
|
||||||
|
// key: 'shopType',
|
||||||
|
// align: 'center',
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
title: '商户分类',
|
||||||
|
dataIndex: 'category',
|
||||||
|
key: 'category',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
dataIndex: 'status',
|
||||||
|
key: 'status',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '排序号',
|
||||||
|
dataIndex: 'sortNumber',
|
||||||
|
key: 'sortNumber',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
dataIndex: 'createTime',
|
||||||
|
key: 'createTime',
|
||||||
|
align: 'center',
|
||||||
|
sorter: true,
|
||||||
|
ellipsis: true,
|
||||||
|
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
|
||||||
|
}
|
||||||
|
// {
|
||||||
|
// title: '操作',
|
||||||
|
// key: 'action',
|
||||||
|
// width: 180,
|
||||||
|
// fixed: 'right',
|
||||||
|
// align: 'center',
|
||||||
|
// hideInSetting: true
|
||||||
|
// }
|
||||||
|
]);
|
||||||
|
|
||||||
|
/* 搜索 */
|
||||||
|
const reload = (where?: ShopMerchantParam) => {
|
||||||
|
selection.value = [];
|
||||||
|
tableRef?.value?.reload({ where: where });
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 打开编辑弹窗 */
|
||||||
|
const openEdit = (row?: ShopMerchant) => {
|
||||||
|
current.value = row ?? null;
|
||||||
|
showEdit.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 打开批量移动弹窗 */
|
||||||
|
const openMove = () => {
|
||||||
|
showMove.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 删除单个 */
|
||||||
|
const remove = (row: ShopMerchant) => {
|
||||||
|
const hide = message.loading('请求中..', 0);
|
||||||
|
removeShopMerchant(row.shopMerchantId)
|
||||||
|
.then((msg) => {
|
||||||
|
hide();
|
||||||
|
message.success(msg);
|
||||||
|
reload();
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
hide();
|
||||||
|
message.error(e.message);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 批量删除 */
|
||||||
|
const removeBatch = () => {
|
||||||
|
if (!selection.value.length) {
|
||||||
|
message.error('请至少选择一条数据');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Modal.confirm({
|
||||||
|
title: '提示',
|
||||||
|
content: '确定要删除选中的记录吗?',
|
||||||
|
icon: createVNode(ExclamationCircleOutlined),
|
||||||
|
maskClosable: true,
|
||||||
|
onOk: () => {
|
||||||
|
const hide = message.loading('请求中..', 0);
|
||||||
|
removeBatchShopMerchant(selection.value.map((d) => d.merchantId))
|
||||||
|
.then((msg) => {
|
||||||
|
hide();
|
||||||
|
message.success(msg);
|
||||||
|
reload();
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
hide();
|
||||||
|
message.error(e.message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 查询 */
|
||||||
|
const query = () => {
|
||||||
|
loading.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 自定义行属性 */
|
||||||
|
const customRow = (record: ShopMerchant) => {
|
||||||
|
return {
|
||||||
|
// 行点击事件
|
||||||
|
onClick: () => {
|
||||||
|
// console.log(record);
|
||||||
|
},
|
||||||
|
// 行双击事件
|
||||||
|
onDblclick: () => {
|
||||||
|
openEdit(record);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
query();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'ShopMerchant'
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped></style>
|
||||||
@@ -12,14 +12,13 @@
|
|||||||
<a-card :bordered="false" :body-style="{ padding: '16px' }">
|
<a-card :bordered="false" :body-style="{ padding: '16px' }">
|
||||||
<a-tabs type="card" v-model:activeKey="activeKey" @change="onTabs">
|
<a-tabs type="card" v-model:activeKey="activeKey" @change="onTabs">
|
||||||
<a-tab-pane key="all" tab="全部"/>
|
<a-tab-pane key="all" tab="全部"/>
|
||||||
<a-tab-pane key="unpaid" tab="待支付"/>
|
<a-tab-pane key="unpaid" tab="待付款"/>
|
||||||
<a-tab-pane key="undelivered" tab="待发货"/>
|
<a-tab-pane key="undelivered" tab="待发货"/>
|
||||||
<a-tab-pane key="unverified" tab="待核销"/>
|
|
||||||
<a-tab-pane key="unreceived" tab="待收货"/>
|
<a-tab-pane key="unreceived" tab="待收货"/>
|
||||||
<a-tab-pane key="unevaluated" tab="待评价"/>
|
|
||||||
<a-tab-pane key="completed" tab="已完成"/>
|
<a-tab-pane key="completed" tab="已完成"/>
|
||||||
<a-tab-pane key="refunded" tab="已退款"/>
|
|
||||||
<a-tab-pane key="deleted" tab="已取消"/>
|
<a-tab-pane key="deleted" tab="已取消"/>
|
||||||
|
<!-- <a-tab-pane key="unevaluated" tab="待评价"/>-->
|
||||||
|
<!-- <a-tab-pane key="refunded" tab="已退款"/>-->
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
<ele-pro-table
|
<ele-pro-table
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
@@ -268,43 +267,43 @@ const onTabs = () => {
|
|||||||
// 使用statusFilter进行筛选,这是后端专门为订单状态筛选设计的字段
|
// 使用statusFilter进行筛选,这是后端专门为订单状态筛选设计的字段
|
||||||
const filterParams: Record<string, any> = {};
|
const filterParams: Record<string, any> = {};
|
||||||
|
|
||||||
// 根据文档,statusFilter的值对应:
|
// 根据后端 statusFilter 的值对应:
|
||||||
// -1全部,0待支付,1待发货,2待核销,3待收货,4待评价,5已完成,6已退款,7已删除
|
// undefined全部,0待付款,1待发货,2待核销,3待收货,4待评价,5已完成,6已退款,7已删除
|
||||||
switch (activeKey.value) {
|
switch (activeKey.value) {
|
||||||
case 'all':
|
case 'all':
|
||||||
// 全部订单(排除已删除)
|
// 全部订单:不传statusFilter参数
|
||||||
filterParams.statusFilter = -1;
|
// filterParams.statusFilter = undefined; // 不设置该字段
|
||||||
break;
|
break;
|
||||||
case 'unpaid':
|
case 'unpaid':
|
||||||
// 待支付
|
// 待付款:pay_status = false
|
||||||
filterParams.statusFilter = 0;
|
filterParams.statusFilter = 0;
|
||||||
break;
|
break;
|
||||||
case 'undelivered':
|
case 'undelivered':
|
||||||
// 待发货
|
// 待发货:pay_status = true AND delivery_status = 10
|
||||||
filterParams.statusFilter = 1;
|
filterParams.statusFilter = 1;
|
||||||
break;
|
break;
|
||||||
case 'unverified':
|
case 'unverified':
|
||||||
// 待核销
|
// 待核销:pay_status = true AND delivery_status = 10 (与待发货相同)
|
||||||
filterParams.statusFilter = 2;
|
filterParams.statusFilter = 2;
|
||||||
break;
|
break;
|
||||||
case 'unreceived':
|
case 'unreceived':
|
||||||
// 待收货
|
// 待收货:pay_status = true AND delivery_status = 20
|
||||||
filterParams.statusFilter = 3;
|
filterParams.statusFilter = 3;
|
||||||
break;
|
break;
|
||||||
case 'unevaluated':
|
case 'unevaluated':
|
||||||
// 待评价
|
// 待评价:order_status = 1 (与已完成相同)
|
||||||
filterParams.statusFilter = 4;
|
filterParams.statusFilter = 4;
|
||||||
break;
|
break;
|
||||||
case 'completed':
|
case 'completed':
|
||||||
// 已完成
|
// 已完成:order_status = 1
|
||||||
filterParams.statusFilter = 5;
|
filterParams.statusFilter = 5;
|
||||||
break;
|
break;
|
||||||
case 'refunded':
|
case 'refunded':
|
||||||
// 已退款
|
// 已退款:order_status = 6
|
||||||
filterParams.statusFilter = 6;
|
filterParams.statusFilter = 6;
|
||||||
break;
|
break;
|
||||||
case 'deleted':
|
case 'deleted':
|
||||||
// 已删除/已取消
|
// 已删除:deleted = 1
|
||||||
filterParams.statusFilter = 7;
|
filterParams.statusFilter = 7;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
391
src/views/shop/shopOrder/mobile/index.tsx
Normal file
391
src/views/shop/shopOrder/mobile/index.tsx
Normal file
@@ -0,0 +1,391 @@
|
|||||||
|
import {Avatar, Cell, Space, Tabs, Button, TabPane, Image} from '@nutui/nutui-react-taro'
|
||||||
|
import {useEffect, useState, CSSProperties} from "react";
|
||||||
|
import {View} from '@tarojs/components'
|
||||||
|
import Taro from '@tarojs/taro';
|
||||||
|
import {InfiniteLoading} from '@nutui/nutui-react-taro'
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import {pageShopOrder, removeShopOrder, updateShopOrder} from "@/api/shop/shopOrder";
|
||||||
|
import {ShopOrder, ShopOrderParam} from "@/api/shop/shopOrder/model";
|
||||||
|
import {listShopOrderGoods} from "@/api/shop/shopOrderGoods";
|
||||||
|
import {ShopOrderGoods} from "@/api/shop/shopOrderGoods/model";
|
||||||
|
import {copyText} from "@/utils/common";
|
||||||
|
|
||||||
|
const getInfiniteUlStyle = (showSearch: boolean = false): CSSProperties => ({
|
||||||
|
marginTop: showSearch ? '65px' : '44px', // 如果显示搜索框,增加更多的上边距
|
||||||
|
height: showSearch ? '75vh' : '82vh', // 相应调整高度
|
||||||
|
width: '100%',
|
||||||
|
padding: '0',
|
||||||
|
overflowY: 'auto',
|
||||||
|
overflowX: 'hidden',
|
||||||
|
boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)',
|
||||||
|
})
|
||||||
|
|
||||||
|
// 统一的订单状态标签配置,与后端 statusFilter 保持一致
|
||||||
|
const tabs = [
|
||||||
|
{
|
||||||
|
index: 0,
|
||||||
|
key: '全部',
|
||||||
|
title: '全部',
|
||||||
|
description: '所有订单',
|
||||||
|
statusFilter: undefined // 不传statusFilter,显示所有订单
|
||||||
|
},
|
||||||
|
{
|
||||||
|
index: 1,
|
||||||
|
key: '待付款',
|
||||||
|
title: '待付款',
|
||||||
|
description: '等待付款的订单',
|
||||||
|
statusFilter: 0 // 对应后端:pay_status = false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
index: 2,
|
||||||
|
key: '待发货',
|
||||||
|
title: '待发货',
|
||||||
|
description: '已付款待发货的订单',
|
||||||
|
statusFilter: 1 // 对应后端:pay_status = true AND delivery_status = 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
index: 3,
|
||||||
|
key: '待收货',
|
||||||
|
title: '待收货',
|
||||||
|
description: '已发货待收货的订单',
|
||||||
|
statusFilter: 3 // 对应后端:pay_status = true AND delivery_status = 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
index: 4,
|
||||||
|
key: '已完成',
|
||||||
|
title: '已完成',
|
||||||
|
description: '已完成的订单',
|
||||||
|
statusFilter: 5 // 对应后端:order_status = 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
index: 5,
|
||||||
|
key: '已取消',
|
||||||
|
title: '已取消',
|
||||||
|
description: '已取消/退款的订单',
|
||||||
|
statusFilter: 6 // 对应后端:order_status = 6 (已退款)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
// 扩展订单接口,包含商品信息
|
||||||
|
interface OrderWithGoods extends ShopOrder {
|
||||||
|
orderGoods?: ShopOrderGoods[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OrderListProps {
|
||||||
|
data: ShopOrder[];
|
||||||
|
onReload?: () => void;
|
||||||
|
searchParams?: ShopOrderParam;
|
||||||
|
showSearch?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
function OrderList(props: OrderListProps) {
|
||||||
|
const [list, setList] = useState<OrderWithGoods[]>([])
|
||||||
|
const [page, setPage] = useState(1)
|
||||||
|
const [hasMore, setHasMore] = useState(true)
|
||||||
|
const [tapIndex, setTapIndex] = useState<string | number>(0)
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
|
||||||
|
// 获取订单状态文本
|
||||||
|
const getOrderStatusText = (order: ShopOrder) => {
|
||||||
|
console.log(order,'order')
|
||||||
|
|
||||||
|
// 优先检查订单状态
|
||||||
|
if (order.orderStatus === 2) return '已取消';
|
||||||
|
if (order.orderStatus === 4) return '退款申请中';
|
||||||
|
if (order.orderStatus === 5) return '退款被拒绝';
|
||||||
|
if (order.orderStatus === 6) return '退款成功';
|
||||||
|
if (order.orderStatus === 7) return '客户端申请退款';
|
||||||
|
|
||||||
|
// 检查支付状态 (payStatus为boolean类型,false/0表示未付款,true/1表示已付款)
|
||||||
|
if (!order.payStatus) return '等待买家付款';
|
||||||
|
|
||||||
|
// 已付款后检查发货状态
|
||||||
|
if (order.deliveryStatus === 10) return '待发货';
|
||||||
|
if (order.deliveryStatus === 20) return '待收货';
|
||||||
|
if (order.deliveryStatus === 30) return '已收货';
|
||||||
|
|
||||||
|
// 最后检查订单完成状态
|
||||||
|
if (order.orderStatus === 1) return '已完成';
|
||||||
|
if (order.orderStatus === 0) return '未使用';
|
||||||
|
|
||||||
|
return '未知状态';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取订单状态颜色
|
||||||
|
const getOrderStatusColor = (order: ShopOrder) => {
|
||||||
|
// 优先检查订单状态
|
||||||
|
if (order.orderStatus === 2) return 'text-gray-500'; // 已取消
|
||||||
|
if (order.orderStatus === 4) return 'text-orange-500'; // 退款申请中
|
||||||
|
if (order.orderStatus === 5) return 'text-red-500'; // 退款被拒绝
|
||||||
|
if (order.orderStatus === 6) return 'text-green-500'; // 退款成功
|
||||||
|
if (order.orderStatus === 7) return 'text-orange-500'; // 客户端申请退款
|
||||||
|
|
||||||
|
// 检查支付状态
|
||||||
|
if (!order.payStatus) return 'text-orange-500'; // 等待买家付款
|
||||||
|
|
||||||
|
// 已付款后检查发货状态
|
||||||
|
if (order.deliveryStatus === 10) return 'text-blue-500'; // 待发货
|
||||||
|
if (order.deliveryStatus === 20) return 'text-purple-500'; // 待收货
|
||||||
|
if (order.deliveryStatus === 30) return 'text-green-500'; // 已收货
|
||||||
|
|
||||||
|
// 最后检查订单完成状态
|
||||||
|
if (order.orderStatus === 1) return 'text-green-600'; // 已完成
|
||||||
|
if (order.orderStatus === 0) return 'text-gray-500'; // 未使用
|
||||||
|
|
||||||
|
return 'text-gray-600'; // 默认颜色
|
||||||
|
};
|
||||||
|
|
||||||
|
// 使用后端统一的 statusFilter 进行筛选
|
||||||
|
const getOrderStatusParams = (index: string | number) => {
|
||||||
|
let params: ShopOrderParam = {};
|
||||||
|
// 添加用户ID过滤
|
||||||
|
params.userId = Taro.getStorageSync('UserId');
|
||||||
|
|
||||||
|
// 获取当前tab的statusFilter配置
|
||||||
|
const currentTab = tabs.find(tab => tab.index === Number(index));
|
||||||
|
if (currentTab && currentTab.statusFilter !== undefined) {
|
||||||
|
params.statusFilter = currentTab.statusFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Tab ${index} (${currentTab?.title}) 筛选参数:`, params);
|
||||||
|
return params;
|
||||||
|
};
|
||||||
|
|
||||||
|
const reload = async (resetPage = false) => {
|
||||||
|
setLoading(true);
|
||||||
|
const currentPage = resetPage ? 1 : page;
|
||||||
|
const statusParams = getOrderStatusParams(tapIndex);
|
||||||
|
const searchConditions = {
|
||||||
|
page: currentPage,
|
||||||
|
...statusParams,
|
||||||
|
...props.searchParams
|
||||||
|
};
|
||||||
|
console.log('订单筛选条件:', {
|
||||||
|
tapIndex,
|
||||||
|
statusParams,
|
||||||
|
searchConditions
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await pageShopOrder(searchConditions);
|
||||||
|
let newList: OrderWithGoods[] = [];
|
||||||
|
|
||||||
|
if (res?.list && res?.list.length > 0) {
|
||||||
|
// 为每个订单获取商品信息
|
||||||
|
const ordersWithGoods = await Promise.all(
|
||||||
|
res.list.map(async (order) => {
|
||||||
|
try {
|
||||||
|
const orderGoods = await listShopOrderGoods({ orderId: order.orderId });
|
||||||
|
return {
|
||||||
|
...order,
|
||||||
|
orderGoods: orderGoods || []
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取订单商品失败:', error);
|
||||||
|
return {
|
||||||
|
...order,
|
||||||
|
orderGoods: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// 合并数据
|
||||||
|
newList = resetPage ? ordersWithGoods : list?.concat(ordersWithGoods);
|
||||||
|
setHasMore(true);
|
||||||
|
} else {
|
||||||
|
newList = [];
|
||||||
|
setHasMore(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
setList(newList || []);
|
||||||
|
setPage(currentPage);
|
||||||
|
setLoading(false);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载订单失败:', error);
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const reloadMore = async () => {
|
||||||
|
setPage(page + 1);
|
||||||
|
reload();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 确认收货
|
||||||
|
const confirmReceive = async (order: ShopOrder) => {
|
||||||
|
try {
|
||||||
|
await updateShopOrder({
|
||||||
|
...order,
|
||||||
|
deliveryStatus: 30, // 已收货
|
||||||
|
orderStatus: 1 // 已完成
|
||||||
|
});
|
||||||
|
Taro.showToast({
|
||||||
|
title: '确认收货成功',
|
||||||
|
});
|
||||||
|
reload(true); // 重新加载列表
|
||||||
|
props.onReload?.(); // 通知父组件刷新
|
||||||
|
} catch (error) {
|
||||||
|
Taro.showToast({
|
||||||
|
title: '确认收货失败',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 取消订单
|
||||||
|
const cancelOrder = async (order: ShopOrder) => {
|
||||||
|
try {
|
||||||
|
await removeShopOrder(order.orderId);
|
||||||
|
Taro.showToast({
|
||||||
|
title: '订单已删除',
|
||||||
|
});
|
||||||
|
reload(true); // 重新加载列表
|
||||||
|
props.onReload?.(); // 通知父组件刷新
|
||||||
|
} catch (error) {
|
||||||
|
console.error('取消订单失败:', error);
|
||||||
|
Taro.showToast({
|
||||||
|
title: '取消订单失败',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
reload(true); // 首次加载或tab切换时重置页码
|
||||||
|
}, [tapIndex]); // 监听tapIndex变化
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
reload(true); // 搜索参数变化时重置页码
|
||||||
|
}, [props.searchParams]); // 监听搜索参数变化
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Tabs
|
||||||
|
align={'left'}
|
||||||
|
className={'fixed left-0'}
|
||||||
|
style={{
|
||||||
|
top: '44px',
|
||||||
|
zIndex: 998,
|
||||||
|
borderBottom: '1px solid #e5e5e5'
|
||||||
|
}}
|
||||||
|
tabStyle={{
|
||||||
|
backgroundColor: '#ffffff',
|
||||||
|
boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
|
||||||
|
}}
|
||||||
|
value={tapIndex}
|
||||||
|
onChange={(paneKey) => {
|
||||||
|
console.log('Tab切换到:', paneKey, '对应状态:', tabs[paneKey]?.title);
|
||||||
|
setTapIndex(paneKey)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
tabs?.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<TabPane
|
||||||
|
key={index}
|
||||||
|
title={loading && tapIndex === index ? `${item.title}...` : item.title}
|
||||||
|
></TabPane>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</Tabs>
|
||||||
|
<div style={getInfiniteUlStyle(props.showSearch)} id="scroll">
|
||||||
|
<InfiniteLoading
|
||||||
|
target="scroll"
|
||||||
|
hasMore={hasMore}
|
||||||
|
onLoadMore={reloadMore}
|
||||||
|
onScroll={() => {
|
||||||
|
|
||||||
|
}}
|
||||||
|
onScrollToUpper={() => {
|
||||||
|
|
||||||
|
}}
|
||||||
|
loadingText={
|
||||||
|
<>
|
||||||
|
加载中
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
loadMoreText={
|
||||||
|
<>
|
||||||
|
没有更多了
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{list?.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<Cell key={index} style={{padding: '16px'}} onClick={() => Taro.navigateTo({url: `/shop/orderDetail/index?orderId=${item.orderId}`})}>
|
||||||
|
<Space direction={'vertical'} className={'w-full flex flex-col'}>
|
||||||
|
<View className={'order-no flex justify-between'}>
|
||||||
|
<View className={'text-gray-600 font-bold text-sm'}
|
||||||
|
onClick={(e) => {e.stopPropagation(); copyText(`${item.orderNo}`)}}>{item.orderNo}</View>
|
||||||
|
<View className={`${getOrderStatusColor(item)} font-medium`}>{getOrderStatusText(item)}</View>
|
||||||
|
</View>
|
||||||
|
<div
|
||||||
|
className={'create-time text-gray-400 text-xs'}>{dayjs(item.createTime).format('YYYY年MM月DD日 HH:mm:ss')}</div>
|
||||||
|
|
||||||
|
{/* 商品信息 */}
|
||||||
|
<div className={'goods-info'}>
|
||||||
|
{item.orderGoods && item.orderGoods.length > 0 ? (
|
||||||
|
item.orderGoods.map((goods, goodsIndex) => (
|
||||||
|
<div key={goodsIndex} className={'flex items-center mb-2'}>
|
||||||
|
<Image
|
||||||
|
src={goods.image || '/default-goods.png'}
|
||||||
|
width="50"
|
||||||
|
height="50"
|
||||||
|
lazyLoad={false}
|
||||||
|
className={'rounded'}
|
||||||
|
/>
|
||||||
|
<div className={'ml-2 flex-1'}>
|
||||||
|
<div className={'text-sm font-bold'}>{goods.goodsName}</div>
|
||||||
|
{goods.spec && <div className={'text-gray-500 text-xs'}>规格:{goods.spec}</div>}
|
||||||
|
<div className={'text-gray-500 text-xs'}>数量:{goods.totalNum}</div>
|
||||||
|
</div>
|
||||||
|
<div className={'text-sm'}>¥{goods.price}</div>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<div className={'flex items-center'}>
|
||||||
|
<Avatar
|
||||||
|
src='/default-goods.png'
|
||||||
|
size={'50'}
|
||||||
|
shape={'square'}
|
||||||
|
/>
|
||||||
|
<div className={'ml-2'}>
|
||||||
|
<div className={'text-sm'}>{item.title || '订单商品'}</div>
|
||||||
|
<div className={'text-gray-400 text-xs'}>{item.totalNum}件商品</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={'w-full text-right'}>实付金额:¥{item.payPrice}</div>
|
||||||
|
|
||||||
|
{/* 操作按钮 */}
|
||||||
|
<Space className={'btn flex justify-end'}>
|
||||||
|
{/* 待付款状态:显示取消订单和立即支付 */}
|
||||||
|
{(!item.payStatus) && item.orderStatus !== 2 && (
|
||||||
|
<Space>
|
||||||
|
<Button size={'small'} onClick={(e) => {e.stopPropagation(); cancelOrder(item)}}>取消订单</Button>
|
||||||
|
<Button size={'small'} type="primary" onClick={(e) => {e.stopPropagation(); console.log('立即支付')}}>立即支付</Button>
|
||||||
|
</Space>
|
||||||
|
)}
|
||||||
|
{/* 待收货状态:显示确认收货 */}
|
||||||
|
{item.deliveryStatus === 20 && (
|
||||||
|
<Button size={'small'} type="primary" onClick={(e) => {e.stopPropagation(); confirmReceive(item)}}>确认收货</Button>
|
||||||
|
)}
|
||||||
|
{/* 已完成状态:显示申请退款 */}
|
||||||
|
{item.orderStatus === 1 && (
|
||||||
|
<Button size={'small'} onClick={(e) => {e.stopPropagation(); console.log('申请退款')}}>申请退款</Button>
|
||||||
|
)}
|
||||||
|
{/* 退款相关状态的按钮可以在这里添加 */}
|
||||||
|
</Space>
|
||||||
|
</Space>
|
||||||
|
</Cell>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</InfiniteLoading>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default OrderList
|
||||||
Reference in New Issue
Block a user