Showing
16 changed files
with
989 additions
and
379 deletions
| ... | @@ -997,6 +997,47 @@ | ... | @@ -997,6 +997,47 @@ |
| 997 | } | 997 | } |
| 998 | ``` | 998 | ``` |
| 999 | 999 | ||
| 1000 | +### 7.9 获取所有产品 | ||
| 1001 | + | ||
| 1002 | +**接口路径:** `GET /api/product/all` | ||
| 1003 | + | ||
| 1004 | +**功能描述:** 获取所有启用的产品信息,用于下拉选择 | ||
| 1005 | + | ||
| 1006 | +**权限要求:** 无 | ||
| 1007 | + | ||
| 1008 | +**请求参数:** 无 | ||
| 1009 | + | ||
| 1010 | +**响应示例:** | ||
| 1011 | +```json | ||
| 1012 | +{ | ||
| 1013 | + "code": 200, | ||
| 1014 | + "message": "操作成功", | ||
| 1015 | + "data": [ | ||
| 1016 | + { | ||
| 1017 | + "productId": 1, | ||
| 1018 | + "productCode": "APL-IP15-128G-BK", | ||
| 1019 | + "productName": "iPhone 15|A2848|iPhone|黑色" | ||
| 1020 | + }, | ||
| 1021 | + { | ||
| 1022 | + "productId": 2, | ||
| 1023 | + "productCode": "APL-IP15-256G-BK", | ||
| 1024 | + "productName": "iPhone 15|A2848|iPhone|黑色" | ||
| 1025 | + }, | ||
| 1026 | + { | ||
| 1027 | + "productId": 3, | ||
| 1028 | + "productCode": "APL-IP15-128G-WH", | ||
| 1029 | + "productName": "iPhone 15|A2848|iPhone|白色" | ||
| 1030 | + } | ||
| 1031 | + ] | ||
| 1032 | +} | ||
| 1033 | +``` | ||
| 1034 | + | ||
| 1035 | +**响应字段说明:** | ||
| 1036 | +- 只返回未删除且销售状态为在售的产品 | ||
| 1037 | +- 按产品编码升序排列 | ||
| 1038 | +- 产品名称格式:`产品名称|产品型号|产品类别|产品颜色` | ||
| 1039 | +- 主要用于订单管理等模块的下拉选择 | ||
| 1040 | + | ||
| 1000 | ## 8. 经销商管理 (DealerInfoController) | 1041 | ## 8. 经销商管理 (DealerInfoController) |
| 1001 | 1042 | ||
| 1002 | ### 8.1 分页查询经销商列表 | 1043 | ### 8.1 分页查询经销商列表 |
| ... | @@ -1328,6 +1369,81 @@ | ... | @@ -1328,6 +1369,81 @@ |
| 1328 | } | 1369 | } |
| 1329 | ``` | 1370 | ``` |
| 1330 | 1371 | ||
| 1372 | +### 8.9 获取所有经销商 | ||
| 1373 | + | ||
| 1374 | +**接口路径:** `GET /api/dealer/all` | ||
| 1375 | + | ||
| 1376 | +**功能描述:** 获取所有启用的经销商信息,用于下拉选择 | ||
| 1377 | + | ||
| 1378 | +**权限要求:** 无 | ||
| 1379 | + | ||
| 1380 | +**请求参数:** 无 | ||
| 1381 | + | ||
| 1382 | +**响应示例:** | ||
| 1383 | +```json | ||
| 1384 | +{ | ||
| 1385 | + "code": 200, | ||
| 1386 | + "message": "操作成功", | ||
| 1387 | + "data": [ | ||
| 1388 | + { | ||
| 1389 | + "dealerId": 1, | ||
| 1390 | + "dealerCode": "DL001", | ||
| 1391 | + "dealerName": "北京经销商", | ||
| 1392 | + "creditCode": "91110000123456789X", | ||
| 1393 | + "dealerLevel": 1, | ||
| 1394 | + "region": "北京", | ||
| 1395 | + "contactPerson": "张三", | ||
| 1396 | + "contactPhone": "13800138000", | ||
| 1397 | + "cooperateStartDate": "2024-01-01", | ||
| 1398 | + "cooperateStatus": 1, | ||
| 1399 | + "businessLicenseUrl": "https://example.com/license.jpg", | ||
| 1400 | + "cooperationAgreementUrl": "https://example.com/agreement.pdf", | ||
| 1401 | + "qualificationAuditStatus": 2, | ||
| 1402 | + "auditOpinion": "审核通过", | ||
| 1403 | + "totalRebateAmount": 10000.00, | ||
| 1404 | + "usedRebateAmount": 5000.00, | ||
| 1405 | + "pendingRebateAmount": 5000.00, | ||
| 1406 | + "lastRebateUpdateTime": "2024-01-01 10:00:00", | ||
| 1407 | + "createBy": "admin", | ||
| 1408 | + "createTime": "2024-01-01 10:00:00", | ||
| 1409 | + "updateBy": "admin", | ||
| 1410 | + "updateTime": "2024-01-01 10:00:00", | ||
| 1411 | + "delFlag": "0" | ||
| 1412 | + }, | ||
| 1413 | + { | ||
| 1414 | + "dealerId": 2, | ||
| 1415 | + "dealerCode": "DL002", | ||
| 1416 | + "dealerName": "上海经销商", | ||
| 1417 | + "creditCode": "91310000123456789Y", | ||
| 1418 | + "dealerLevel": 2, | ||
| 1419 | + "region": "上海", | ||
| 1420 | + "contactPerson": "李四", | ||
| 1421 | + "contactPhone": "13900139000", | ||
| 1422 | + "cooperateStartDate": "2024-02-01", | ||
| 1423 | + "cooperateStatus": 1, | ||
| 1424 | + "businessLicenseUrl": "https://example.com/license2.jpg", | ||
| 1425 | + "cooperationAgreementUrl": "https://example.com/agreement2.pdf", | ||
| 1426 | + "qualificationAuditStatus": 2, | ||
| 1427 | + "auditOpinion": "审核通过", | ||
| 1428 | + "totalRebateAmount": 15000.00, | ||
| 1429 | + "usedRebateAmount": 8000.00, | ||
| 1430 | + "pendingRebateAmount": 7000.00, | ||
| 1431 | + "lastRebateUpdateTime": "2024-02-01 10:00:00", | ||
| 1432 | + "createBy": "admin", | ||
| 1433 | + "createTime": "2024-02-01 10:00:00", | ||
| 1434 | + "updateBy": "admin", | ||
| 1435 | + "updateTime": "2024-02-01 10:00:00", | ||
| 1436 | + "delFlag": "0" | ||
| 1437 | + } | ||
| 1438 | + ] | ||
| 1439 | +} | ||
| 1440 | +``` | ||
| 1441 | + | ||
| 1442 | +**响应字段说明:** | ||
| 1443 | +- 只返回未删除且合作状态为正常的经销商 | ||
| 1444 | +- 按经销商编码升序排列 | ||
| 1445 | +- 主要用于订单管理等模块的下拉选择 | ||
| 1446 | + | ||
| 1331 | ## 数据字典 | 1447 | ## 数据字典 |
| 1332 | 1448 | ||
| 1333 | ### 销售状态(saleStatus) | 1449 | ### 销售状态(saleStatus) | ... | ... |
| ... | @@ -33,6 +33,13 @@ public class DealerInfoController { | ... | @@ -33,6 +33,13 @@ public class DealerInfoController { |
| 33 | return ApiRes.success(page); | 33 | return ApiRes.success(page); |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | + @Operation(summary = "获取所有经销商", description = "获取所有启用的经销商信息,用于下拉选择") | ||
| 37 | + @GetMapping("/all") | ||
| 38 | + public ApiRes<List<DealerInfo>> getAllDealers() { | ||
| 39 | + List<DealerInfo> dealers = dealerInfoService.getAllDealers(); | ||
| 40 | + return ApiRes.success(dealers); | ||
| 41 | + } | ||
| 42 | + | ||
| 36 | @Operation(summary = "获取经销商详情", description = "根据经销商ID获取经销商详细信息") | 43 | @Operation(summary = "获取经销商详情", description = "根据经销商ID获取经销商详细信息") |
| 37 | @GetMapping("/{dealerId}") | 44 | @GetMapping("/{dealerId}") |
| 38 | @PreAuthorize("hasAuthority('dealer:detail')") | 45 | @PreAuthorize("hasAuthority('dealer:detail')") | ... | ... |
| ... | @@ -3,6 +3,7 @@ package com.apple.erp.controller; | ... | @@ -3,6 +3,7 @@ package com.apple.erp.controller; |
| 3 | import com.apple.erp.dto.ProductAddReq; | 3 | import com.apple.erp.dto.ProductAddReq; |
| 4 | import com.apple.erp.dto.ProductQueryReq; | 4 | import com.apple.erp.dto.ProductQueryReq; |
| 5 | import com.apple.erp.dto.ProductUpdateReq; | 5 | import com.apple.erp.dto.ProductUpdateReq; |
| 6 | +import com.apple.erp.dto.ProductSimpleRes; | ||
| 6 | import com.apple.erp.entity.ProductInfo; | 7 | import com.apple.erp.entity.ProductInfo; |
| 7 | import com.apple.erp.service.ProductInfoService; | 8 | import com.apple.erp.service.ProductInfoService; |
| 8 | import com.apple.erp.dto.response.ApiRes; | 9 | import com.apple.erp.dto.response.ApiRes; |
| ... | @@ -174,4 +175,15 @@ public class ProductInfoController { | ... | @@ -174,4 +175,15 @@ public class ProductInfoController { |
| 174 | return ApiRes.error("修改返利标识失败:" + e.getMessage()); | 175 | return ApiRes.error("修改返利标识失败:" + e.getMessage()); |
| 175 | } | 176 | } |
| 176 | } | 177 | } |
| 178 | + | ||
| 179 | + @Operation(summary = "获取所有产品", description = "获取所有启用的产品信息,用于下拉选择") | ||
| 180 | + @GetMapping("/all") | ||
| 181 | + public ApiRes<List<ProductSimpleRes>> getAllProducts() { | ||
| 182 | + try { | ||
| 183 | + List<ProductSimpleRes> products = productInfoService.getAllProducts(); | ||
| 184 | + return ApiRes.success(products); | ||
| 185 | + } catch (Exception e) { | ||
| 186 | + return ApiRes.error("获取产品列表失败:" + e.getMessage()); | ||
| 187 | + } | ||
| 188 | + } | ||
| 177 | } | 189 | } | ... | ... |
| 1 | +package com.apple.erp.dto; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * 产品简单信息响应DTO | ||
| 8 | + * 用于下拉选择等场景 | ||
| 9 | + * | ||
| 10 | + * @author Apple ERP Team | ||
| 11 | + * @since 2025-01-27 | ||
| 12 | + */ | ||
| 13 | +@Data | ||
| 14 | +@Schema(description = "产品简单信息") | ||
| 15 | +public class ProductSimpleRes { | ||
| 16 | + | ||
| 17 | + @Schema(description = "产品ID") | ||
| 18 | + private Long productId; | ||
| 19 | + | ||
| 20 | + @Schema(description = "产品编码") | ||
| 21 | + private String productCode; | ||
| 22 | + | ||
| 23 | + @Schema(description = "产品名称") | ||
| 24 | + private String productName; | ||
| 25 | +} |
| ... | @@ -69,4 +69,10 @@ public interface DealerInfoService extends IService<DealerInfo> { | ... | @@ -69,4 +69,10 @@ public interface DealerInfoService extends IService<DealerInfo> { |
| 69 | * @return 是否成功 | 69 | * @return 是否成功 |
| 70 | */ | 70 | */ |
| 71 | boolean updateDealerAuditStatus(Long dealerId, Integer qualificationAuditStatus, String auditOpinion); | 71 | boolean updateDealerAuditStatus(Long dealerId, Integer qualificationAuditStatus, String auditOpinion); |
| 72 | + | ||
| 73 | + /** | ||
| 74 | + * 获取所有启用的经销商 | ||
| 75 | + * @return 经销商列表 | ||
| 76 | + */ | ||
| 77 | + List<DealerInfo> getAllDealers(); | ||
| 72 | } | 78 | } | ... | ... |
| ... | @@ -3,6 +3,7 @@ package com.apple.erp.service; | ... | @@ -3,6 +3,7 @@ package com.apple.erp.service; |
| 3 | import com.apple.erp.dto.ProductAddReq; | 3 | import com.apple.erp.dto.ProductAddReq; |
| 4 | import com.apple.erp.dto.ProductQueryReq; | 4 | import com.apple.erp.dto.ProductQueryReq; |
| 5 | import com.apple.erp.dto.ProductUpdateReq; | 5 | import com.apple.erp.dto.ProductUpdateReq; |
| 6 | +import com.apple.erp.dto.ProductSimpleRes; | ||
| 6 | import com.apple.erp.entity.ProductInfo; | 7 | import com.apple.erp.entity.ProductInfo; |
| 7 | import com.baomidou.mybatisplus.core.metadata.IPage; | 8 | import com.baomidou.mybatisplus.core.metadata.IPage; |
| 8 | import com.baomidou.mybatisplus.extension.service.IService; | 9 | import com.baomidou.mybatisplus.extension.service.IService; |
| ... | @@ -91,4 +92,11 @@ public interface ProductInfoService extends IService<ProductInfo> { | ... | @@ -91,4 +92,11 @@ public interface ProductInfoService extends IService<ProductInfo> { |
| 91 | * @return 是否存在 | 92 | * @return 是否存在 |
| 92 | */ | 93 | */ |
| 93 | boolean checkProductCodeExists(String productCode, Long productId); | 94 | boolean checkProductCodeExists(String productCode, Long productId); |
| 95 | + | ||
| 96 | + /** | ||
| 97 | + * 获取所有启用的产品简单信息 | ||
| 98 | + * | ||
| 99 | + * @return 产品简单信息列表 | ||
| 100 | + */ | ||
| 101 | + List<ProductSimpleRes> getAllProducts(); | ||
| 94 | } | 102 | } | ... | ... |
| ... | @@ -234,4 +234,13 @@ public class DealerInfoServiceImpl extends ServiceImpl<DealerInfoMapper, DealerI | ... | @@ -234,4 +234,13 @@ public class DealerInfoServiceImpl extends ServiceImpl<DealerInfoMapper, DealerI |
| 234 | } | 234 | } |
| 235 | return count(queryWrapper) > 0; | 235 | return count(queryWrapper) > 0; |
| 236 | } | 236 | } |
| 237 | + | ||
| 238 | + @Override | ||
| 239 | + public List<DealerInfo> getAllDealers() { | ||
| 240 | + LambdaQueryWrapper<DealerInfo> queryWrapper = new LambdaQueryWrapper<>(); | ||
| 241 | + queryWrapper.eq(DealerInfo::getDelFlag, "0") // 未删除 | ||
| 242 | + .eq(DealerInfo::getCooperateStatus, 1) // 正常合作状态 | ||
| 243 | + .orderByAsc(DealerInfo::getDealerCode); // 按经销商编码排序 | ||
| 244 | + return list(queryWrapper); | ||
| 245 | + } | ||
| 237 | } | 246 | } | ... | ... |
| 1 | -package com.apple.erp.service.impl; | ||
| 2 | - | ||
| 3 | -import com.apple.erp.dto.*; | ||
| 4 | -import com.apple.erp.entity.DeliveryItem; | ||
| 5 | -import com.apple.erp.mapper.DeliveryItemMapper; | ||
| 6 | -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||
| 7 | -import com.baomidou.mybatisplus.core.metadata.IPage; | ||
| 8 | -import com.baomidou.mybatisplus.core.toolkit.Wrappers; | ||
| 9 | -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||
| 10 | -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | ||
| 11 | -import com.apple.erp.entity.DeliveryMain; | ||
| 12 | -import com.apple.erp.mapper.DeliveryMainMapper; | ||
| 13 | -import com.apple.erp.service.DeliveryMainService; | ||
| 14 | -import lombok.extern.slf4j.Slf4j; | ||
| 15 | -import org.springframework.beans.BeanUtils; | ||
| 16 | -import org.springframework.beans.factory.annotation.Autowired; | ||
| 17 | -import org.springframework.stereotype.Service; | ||
| 18 | -import org.springframework.transaction.annotation.Transactional; | ||
| 19 | -import org.springframework.util.StringUtils; | ||
| 20 | - | ||
| 21 | -import java.time.LocalDateTime; | ||
| 22 | -import java.time.format.DateTimeFormatter; | ||
| 23 | -import java.util.List; | ||
| 24 | -import java.util.stream.Collectors; | ||
| 25 | - | ||
| 26 | -/** | ||
| 27 | - * 出库主表Service实现类 | ||
| 28 | - * | ||
| 29 | - * @author Apple ERP System | ||
| 30 | - * @since 2025-01-01 | ||
| 31 | - */ | ||
| 32 | -@Slf4j | ||
| 33 | -@Service | ||
| 34 | -public class DeliveryMainServiceImpl extends ServiceImpl<DeliveryMainMapper, DeliveryMain> implements DeliveryMainService { | ||
| 35 | - | ||
| 36 | - @Autowired | ||
| 37 | - private DeliveryItemMapper deliveryItemMapper; | ||
| 38 | - | ||
| 39 | - private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); | ||
| 40 | - | ||
| 41 | - @Override | ||
| 42 | - public Page<DeliveryRes> getDeliveryList(DeliveryQueryReq queryReq) { | ||
| 43 | - LambdaQueryWrapper<DeliveryMain> queryWrapper = Wrappers.lambdaQuery(DeliveryMain.class) | ||
| 44 | - .eq(StringUtils.hasText(queryReq.getDeliveryNo()), DeliveryMain::getDeliveryNo, queryReq.getDeliveryNo()) | ||
| 45 | - .eq(StringUtils.hasText(queryReq.getDealerCode()), DeliveryMain::getDealerCode, queryReq.getDealerCode()) | ||
| 46 | - .like(StringUtils.hasText(queryReq.getDealerName()), DeliveryMain::getDealerName, queryReq.getDealerName()) | ||
| 47 | - .eq(StringUtils.hasText(queryReq.getOrderNo()), DeliveryMain::getOrderNo, queryReq.getOrderNo()) | ||
| 48 | - .eq(queryReq.getDeliveryStatus() != null, DeliveryMain::getDeliveryStatus, queryReq.getDeliveryStatus()) | ||
| 49 | - .eq(StringUtils.hasText(queryReq.getWarehouseCode()), DeliveryMain::getWarehouseCode, queryReq.getWarehouseCode()) | ||
| 50 | - .eq(StringUtils.hasText(queryReq.getDataSource()), DeliveryMain::getDataSource, queryReq.getDataSource()) | ||
| 51 | - .ge(StringUtils.hasText(queryReq.getDeliveryStartDate()), DeliveryMain::getDeliveryDate, parseDateTime(queryReq.getDeliveryStartDate())) | ||
| 52 | - .le(StringUtils.hasText(queryReq.getDeliveryEndDate()), DeliveryMain::getDeliveryDate, parseDateTime(queryReq.getDeliveryEndDate())) | ||
| 53 | - .eq(DeliveryMain::getDelFlag, "0") | ||
| 54 | - .orderByDesc(DeliveryMain::getCreateTime); | ||
| 55 | - | ||
| 56 | - Page<DeliveryMain> page = new Page<>(queryReq.getPageNum(), queryReq.getPageSize()); | ||
| 57 | - IPage<DeliveryMain> deliveryMainPage = baseMapper.selectPage(page, queryWrapper); | ||
| 58 | - | ||
| 59 | - List<DeliveryRes> deliveryResList = deliveryMainPage.getRecords().stream().map(deliveryMain -> { | ||
| 60 | - DeliveryRes deliveryRes = new DeliveryRes(); | ||
| 61 | - BeanUtils.copyProperties(deliveryMain, deliveryRes); | ||
| 62 | - // 查找出库明细 | ||
| 63 | - LambdaQueryWrapper<DeliveryItem> itemQueryWrapper = Wrappers.lambdaQuery(DeliveryItem.class) | ||
| 64 | - .eq(DeliveryItem::getDeliveryId, deliveryMain.getDeliveryId()); | ||
| 65 | - List<DeliveryItem> deliveryItems = deliveryItemMapper.selectList(itemQueryWrapper); | ||
| 66 | - List<DeliveryItemRes> itemResList = deliveryItems.stream().map(deliveryItem -> { | ||
| 67 | - DeliveryItemRes itemRes = new DeliveryItemRes(); | ||
| 68 | - BeanUtils.copyProperties(deliveryItem, itemRes); | ||
| 69 | - return itemRes; | ||
| 70 | - }).collect(Collectors.toList()); | ||
| 71 | - deliveryRes.setDeliveryItems(itemResList); | ||
| 72 | - return deliveryRes; | ||
| 73 | - }).collect(Collectors.toList()); | ||
| 74 | - | ||
| 75 | - Page<DeliveryRes> resultPage = new Page<>(deliveryMainPage.getCurrent(), deliveryMainPage.getSize(), deliveryMainPage.getTotal()); | ||
| 76 | - resultPage.setRecords(deliveryResList); | ||
| 77 | - return resultPage; | ||
| 78 | - } | ||
| 79 | - | ||
| 80 | - @Override | ||
| 81 | - public DeliveryRes getDeliveryDetail(Long deliveryId) { | ||
| 82 | - DeliveryMain deliveryMain = baseMapper.selectById(deliveryId); | ||
| 83 | - if (deliveryMain == null || "2".equals(deliveryMain.getDelFlag())) { | ||
| 84 | - return null; | ||
| 85 | - } | ||
| 86 | - | ||
| 87 | - DeliveryRes deliveryRes = new DeliveryRes(); | ||
| 88 | - BeanUtils.copyProperties(deliveryMain, deliveryRes); | ||
| 89 | - | ||
| 90 | - LambdaQueryWrapper<DeliveryItem> itemQueryWrapper = Wrappers.lambdaQuery(DeliveryItem.class) | ||
| 91 | - .eq(DeliveryItem::getDeliveryId, deliveryId); | ||
| 92 | - List<DeliveryItem> deliveryItems = deliveryItemMapper.selectList(itemQueryWrapper); | ||
| 93 | - List<DeliveryItemRes> itemResList = deliveryItems.stream().map(deliveryItem -> { | ||
| 94 | - DeliveryItemRes itemRes = new DeliveryItemRes(); | ||
| 95 | - BeanUtils.copyProperties(deliveryItem, itemRes); | ||
| 96 | - return itemRes; | ||
| 97 | - }).collect(Collectors.toList()); | ||
| 98 | - deliveryRes.setDeliveryItems(itemResList); | ||
| 99 | - return deliveryRes; | ||
| 100 | - } | ||
| 101 | - | ||
| 102 | - @Override | ||
| 103 | - @Transactional | ||
| 104 | - public boolean addDelivery(DeliveryAddReq addReq) { | ||
| 105 | - // 检查出库单编号是否已存在 | ||
| 106 | - if (isDeliveryNoExist(addReq.getDeliveryNo(), null)) { | ||
| 107 | - throw new IllegalArgumentException("出库单编号已存在"); | ||
| 108 | - } | ||
| 109 | - | ||
| 110 | - DeliveryMain deliveryMain = new DeliveryMain(); | ||
| 111 | - BeanUtils.copyProperties(addReq, deliveryMain); | ||
| 112 | - deliveryMain.setCreateTime(LocalDateTime.now()); | ||
| 113 | - deliveryMain.setUpdateTime(LocalDateTime.now()); | ||
| 114 | - if(StringUtils.hasText(addReq.getDeliveryDate())) { | ||
| 115 | - deliveryMain.setDeliveryDate(parseDateTime(addReq.getDeliveryDate())); | ||
| 116 | - } | ||
| 117 | - deliveryMain.setDelFlag("0"); | ||
| 118 | - int insert = baseMapper.insert(deliveryMain); | ||
| 119 | - if (insert > 0) { | ||
| 120 | - for (DeliveryItemAddReq itemAddReq : addReq.getDeliveryItems()) { | ||
| 121 | - DeliveryItem deliveryItem = new DeliveryItem(); | ||
| 122 | - BeanUtils.copyProperties(itemAddReq, deliveryItem); | ||
| 123 | - deliveryItem.setDeliveryId(deliveryMain.getDeliveryId()); | ||
| 124 | - deliveryItem.setDeliveryNo(deliveryMain.getDeliveryNo()); | ||
| 125 | - deliveryItem.setOrderNo(deliveryMain.getOrderNo()); | ||
| 126 | - deliveryItem.setCreateTime(LocalDateTime.now()); | ||
| 127 | - deliveryItem.setUpdateTime(LocalDateTime.now()); | ||
| 128 | - deliveryItem.setDelFlag("0"); | ||
| 129 | - deliveryItemMapper.insert(deliveryItem); | ||
| 130 | - } | ||
| 131 | - return true; | ||
| 132 | - } | ||
| 133 | - return false; | ||
| 134 | - } | ||
| 135 | - | ||
| 136 | - @Override | ||
| 137 | - @Transactional | ||
| 138 | - public boolean updateDelivery(DeliveryUpdateReq updateReq) { | ||
| 139 | - // 检查出库单编号是否已存在且不属于当前出库单 | ||
| 140 | - if (isDeliveryNoExist(updateReq.getDeliveryNo(), updateReq.getDeliveryId())) { | ||
| 141 | - throw new IllegalArgumentException("出库单编号已存在"); | ||
| 142 | - } | ||
| 143 | - | ||
| 144 | - DeliveryMain deliveryMain = new DeliveryMain(); | ||
| 145 | - BeanUtils.copyProperties(updateReq, deliveryMain); | ||
| 146 | - deliveryMain.setUpdateTime(LocalDateTime.now()); | ||
| 147 | - int update = baseMapper.updateById(deliveryMain); | ||
| 148 | - if (update > 0) { | ||
| 149 | - // 先删除旧的出库明细 | ||
| 150 | - LambdaQueryWrapper<DeliveryItem> deleteWrapper = Wrappers.lambdaQuery(DeliveryItem.class) | ||
| 151 | - .eq(DeliveryItem::getDeliveryId, updateReq.getDeliveryId()); | ||
| 152 | - deliveryItemMapper.delete(deleteWrapper); | ||
| 153 | - | ||
| 154 | - // 插入新的出库明细 | ||
| 155 | - for (DeliveryItemUpdateReq itemUpdateReq : updateReq.getDeliveryItems()) { | ||
| 156 | - DeliveryItem deliveryItem = new DeliveryItem(); | ||
| 157 | - BeanUtils.copyProperties(itemUpdateReq, deliveryItem); | ||
| 158 | - deliveryItem.setDeliveryId(updateReq.getDeliveryId()); | ||
| 159 | - deliveryItem.setDeliveryNo(updateReq.getDeliveryNo()); | ||
| 160 | - deliveryItem.setOrderNo(updateReq.getOrderNo()); | ||
| 161 | - deliveryItem.setCreateTime(LocalDateTime.now()); // 新增明细时设置创建时间 | ||
| 162 | - deliveryItem.setUpdateTime(LocalDateTime.now()); | ||
| 163 | - deliveryItem.setDelFlag("0"); | ||
| 164 | - deliveryItemMapper.insert(deliveryItem); | ||
| 165 | - } | ||
| 166 | - return true; | ||
| 167 | - } | ||
| 168 | - return false; | ||
| 169 | - } | ||
| 170 | - | ||
| 171 | - @Override | ||
| 172 | - @Transactional | ||
| 173 | - public boolean deleteDelivery(Long deliveryId) { | ||
| 174 | - DeliveryMain deliveryMain = new DeliveryMain(); | ||
| 175 | - deliveryMain.setDeliveryId(deliveryId); | ||
| 176 | - deliveryMain.setDelFlag("2"); // 逻辑删除 | ||
| 177 | - deliveryMain.setUpdateTime(LocalDateTime.now()); | ||
| 178 | - return baseMapper.updateById(deliveryMain) > 0; | ||
| 179 | - } | ||
| 180 | - | ||
| 181 | - @Override | ||
| 182 | - @Transactional | ||
| 183 | - public boolean batchDeleteDeliveries(List<Long> deliveryIds) { | ||
| 184 | - List<DeliveryMain> deliveriesToUpdate = deliveryIds.stream().map(deliveryId -> { | ||
| 185 | - DeliveryMain deliveryMain = new DeliveryMain(); | ||
| 186 | - deliveryMain.setDeliveryId(deliveryId); | ||
| 187 | - deliveryMain.setDelFlag("2"); | ||
| 188 | - deliveryMain.setUpdateTime(LocalDateTime.now()); | ||
| 189 | - return deliveryMain; | ||
| 190 | - }).collect(Collectors.toList()); | ||
| 191 | - return updateBatchById(deliveriesToUpdate); | ||
| 192 | - } | ||
| 193 | - | ||
| 194 | - @Override | ||
| 195 | - public boolean updateDeliveryStatus(Long deliveryId, Integer deliveryStatus) { | ||
| 196 | - DeliveryMain deliveryMain = new DeliveryMain(); | ||
| 197 | - deliveryMain.setDeliveryId(deliveryId); | ||
| 198 | - deliveryMain.setDeliveryStatus(deliveryStatus); | ||
| 199 | - deliveryMain.setUpdateTime(LocalDateTime.now()); | ||
| 200 | - return baseMapper.updateById(deliveryMain) > 0; | ||
| 201 | - } | ||
| 202 | - | ||
| 203 | - /** | ||
| 204 | - * 检查出库单编号是否已存在 | ||
| 205 | - * @param deliveryNo 出库单编号 | ||
| 206 | - * @param excludeDeliveryId 排除的出库单ID(用于修改时) | ||
| 207 | - * @return 是否存在 | ||
| 208 | - */ | ||
| 209 | - private boolean isDeliveryNoExist(String deliveryNo, Long excludeDeliveryId) { | ||
| 210 | - LambdaQueryWrapper<DeliveryMain> queryWrapper = Wrappers.lambdaQuery(DeliveryMain.class) | ||
| 211 | - .eq(DeliveryMain::getDeliveryNo, deliveryNo) | ||
| 212 | - .eq(DeliveryMain::getDelFlag, "0"); | ||
| 213 | - if (excludeDeliveryId != null) { | ||
| 214 | - queryWrapper.ne(DeliveryMain::getDeliveryId, excludeDeliveryId); | ||
| 215 | - } | ||
| 216 | - return baseMapper.selectCount(queryWrapper) > 0; | ||
| 217 | - } | ||
| 218 | - | ||
| 219 | - private LocalDateTime parseDateTime(String dateTimeStr) { | ||
| 220 | - if (!StringUtils.hasText(dateTimeStr)) { | ||
| 221 | - return null; | ||
| 222 | - } | ||
| 223 | - try { | ||
| 224 | - return LocalDateTime.parse(dateTimeStr, DATE_TIME_FORMATTER); | ||
| 225 | - } catch (Exception e) { | ||
| 226 | - log.warn("日期时间解析失败: {}", dateTimeStr, e); | ||
| 227 | - return null; | ||
| 228 | - } | ||
| 229 | - } | ||
| 230 | -} | ||
| 231 | - | ||
| 232 | 1 | ... | ... |
| ... | @@ -3,6 +3,7 @@ package com.apple.erp.service.impl; | ... | @@ -3,6 +3,7 @@ package com.apple.erp.service.impl; |
| 3 | import com.apple.erp.dto.ProductAddReq; | 3 | import com.apple.erp.dto.ProductAddReq; |
| 4 | import com.apple.erp.dto.ProductQueryReq; | 4 | import com.apple.erp.dto.ProductQueryReq; |
| 5 | import com.apple.erp.dto.ProductUpdateReq; | 5 | import com.apple.erp.dto.ProductUpdateReq; |
| 6 | +import com.apple.erp.dto.ProductSimpleRes; | ||
| 6 | import com.apple.erp.entity.ProductInfo; | 7 | import com.apple.erp.entity.ProductInfo; |
| 7 | import com.apple.erp.mapper.ProductInfoMapper; | 8 | import com.apple.erp.mapper.ProductInfoMapper; |
| 8 | import com.apple.erp.service.ProductInfoService; | 9 | import com.apple.erp.service.ProductInfoService; |
| ... | @@ -192,4 +193,40 @@ public class ProductInfoServiceImpl extends ServiceImpl<ProductInfoMapper, Produ | ... | @@ -192,4 +193,40 @@ public class ProductInfoServiceImpl extends ServiceImpl<ProductInfoMapper, Produ |
| 192 | 193 | ||
| 193 | return queryWrapper; | 194 | return queryWrapper; |
| 194 | } | 195 | } |
| 196 | + | ||
| 197 | + @Override | ||
| 198 | + public List<ProductSimpleRes> getAllProducts() { | ||
| 199 | + LambdaQueryWrapper<ProductInfo> queryWrapper = new LambdaQueryWrapper<>(); | ||
| 200 | + queryWrapper.eq(ProductInfo::getDelFlag, "0") // 未删除 | ||
| 201 | + .eq(ProductInfo::getSaleStatus, 1) // 在售状态 | ||
| 202 | + .orderByAsc(ProductInfo::getProductCode); // 按产品编码排序 | ||
| 203 | + | ||
| 204 | + List<ProductInfo> products = list(queryWrapper); | ||
| 205 | + return products.stream() | ||
| 206 | + .map(product -> { | ||
| 207 | + ProductSimpleRes res = new ProductSimpleRes(); | ||
| 208 | + res.setProductId(product.getProductId()); | ||
| 209 | + res.setProductCode(product.getProductCode()); | ||
| 210 | + | ||
| 211 | + // 拼接产品名称:产品名称|产品型号|产品类别|产品颜色 | ||
| 212 | + StringBuilder productNameBuilder = new StringBuilder(); | ||
| 213 | + productNameBuilder.append(product.getProductName() != null ? product.getProductName() : ""); | ||
| 214 | + | ||
| 215 | + if (product.getProductModel() != null && !product.getProductModel().trim().isEmpty()) { | ||
| 216 | + productNameBuilder.append("|").append(product.getProductModel()); | ||
| 217 | + } | ||
| 218 | + | ||
| 219 | + if (product.getProductType() != null && !product.getProductType().trim().isEmpty()) { | ||
| 220 | + productNameBuilder.append("|").append(product.getProductType()); | ||
| 221 | + } | ||
| 222 | + | ||
| 223 | + if (product.getColor() != null && !product.getColor().trim().isEmpty()) { | ||
| 224 | + productNameBuilder.append("|").append(product.getColor()); | ||
| 225 | + } | ||
| 226 | + | ||
| 227 | + res.setProductName(productNameBuilder.toString()); | ||
| 228 | + return res; | ||
| 229 | + }) | ||
| 230 | + .collect(java.util.stream.Collectors.toList()); | ||
| 231 | + } | ||
| 195 | } | 232 | } | ... | ... |
| ... | @@ -17,8 +17,8 @@ spring: | ... | @@ -17,8 +17,8 @@ spring: |
| 17 | type: com.alibaba.druid.pool.DruidDataSource | 17 | type: com.alibaba.druid.pool.DruidDataSource |
| 18 | driver-class-name: com.mysql.cj.jdbc.Driver | 18 | driver-class-name: com.mysql.cj.jdbc.Driver |
| 19 | url: jdbc:mysql://localhost:3306/apple_erp?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true | 19 | url: jdbc:mysql://localhost:3306/apple_erp?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true |
| 20 | - username: apple_erp_app | 20 | + username: root |
| 21 | - password: StrongPassw0rd! | 21 | + password: MySQL@123 |
| 22 | druid: | 22 | druid: |
| 23 | # 初始连接数 | 23 | # 初始连接数 |
| 24 | initial-size: 5 | 24 | initial-size: 5 |
| ... | @@ -70,7 +70,7 @@ spring: | ... | @@ -70,7 +70,7 @@ spring: |
| 70 | redis: | 70 | redis: |
| 71 | host: localhost | 71 | host: localhost |
| 72 | port: 6379 | 72 | port: 6379 |
| 73 | - password: 123456 | 73 | + password: |
| 74 | database: 0 | 74 | database: 0 |
| 75 | timeout: 10000ms | 75 | timeout: 10000ms |
| 76 | lettuce: | 76 | lettuce: | ... | ... |
| ... | @@ -7,10 +7,30 @@ export {} | ... | @@ -7,10 +7,30 @@ export {} |
| 7 | 7 | ||
| 8 | declare module 'vue' { | 8 | declare module 'vue' { |
| 9 | export interface GlobalComponents { | 9 | export interface GlobalComponents { |
| 10 | + ElButton: typeof import('element-plus/es')['ElButton'] | ||
| 11 | + ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] | ||
| 12 | + ElDescriptions: typeof import('element-plus/es')['ElDescriptions'] | ||
| 13 | + ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem'] | ||
| 14 | + ElDialog: typeof import('element-plus/es')['ElDialog'] | ||
| 15 | + ElForm: typeof import('element-plus/es')['ElForm'] | ||
| 16 | + ElFormItem: typeof import('element-plus/es')['ElFormItem'] | ||
| 17 | + ElInput: typeof import('element-plus/es')['ElInput'] | ||
| 18 | + ElInputNumber: typeof import('element-plus/es')['ElInputNumber'] | ||
| 19 | + ElOption: typeof import('element-plus/es')['ElOption'] | ||
| 20 | + ElPagination: typeof import('element-plus/es')['ElPagination'] | ||
| 21 | + ElRadio: typeof import('element-plus/es')['ElRadio'] | ||
| 22 | + ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] | ||
| 23 | + ElSelect: typeof import('element-plus/es')['ElSelect'] | ||
| 24 | + ElTable: typeof import('element-plus/es')['ElTable'] | ||
| 25 | + ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] | ||
| 26 | + ElTag: typeof import('element-plus/es')['ElTag'] | ||
| 10 | Header: typeof import('./src/components/layout/Header.vue')['default'] | 27 | Header: typeof import('./src/components/layout/Header.vue')['default'] |
| 11 | RouterLink: typeof import('vue-router')['RouterLink'] | 28 | RouterLink: typeof import('vue-router')['RouterLink'] |
| 12 | RouterView: typeof import('vue-router')['RouterView'] | 29 | RouterView: typeof import('vue-router')['RouterView'] |
| 13 | Sidebar: typeof import('./src/components/layout/Sidebar.vue')['default'] | 30 | Sidebar: typeof import('./src/components/layout/Sidebar.vue')['default'] |
| 14 | SidebarItem: typeof import('./src/components/layout/SidebarItem.vue')['default'] | 31 | SidebarItem: typeof import('./src/components/layout/SidebarItem.vue')['default'] |
| 15 | } | 32 | } |
| 33 | + export interface ComponentCustomProperties { | ||
| 34 | + vLoading: typeof import('element-plus/es')['ElLoadingDirective'] | ||
| 35 | + } | ||
| 16 | } | 36 | } | ... | ... |
| ... | @@ -162,5 +162,10 @@ export const dealerApi = { | ... | @@ -162,5 +162,10 @@ export const dealerApi = { |
| 162 | return api.post<ApiResponse>(`/dealer/${dealerId}/auditStatus`, null, { | 162 | return api.post<ApiResponse>(`/dealer/${dealerId}/auditStatus`, null, { |
| 163 | params: { qualificationAuditStatus, auditOpinion } | 163 | params: { qualificationAuditStatus, auditOpinion } |
| 164 | }) | 164 | }) |
| 165 | + }, | ||
| 166 | + | ||
| 167 | + // 获取所有经销商(用于下拉选择) | ||
| 168 | + getAllDealers: () => { | ||
| 169 | + return api.get<ApiResponse<DealerInfo[]>>('/dealer/all') | ||
| 165 | } | 170 | } |
| 166 | } | 171 | } | ... | ... |
| ... | @@ -55,6 +55,13 @@ export interface ProductInfo { | ... | @@ -55,6 +55,13 @@ export interface ProductInfo { |
| 55 | updateTime: string | 55 | updateTime: string |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | +// 产品简单信息接口(用于下拉选择) | ||
| 59 | +export interface ProductSimpleRes { | ||
| 60 | + productId: number | ||
| 61 | + productCode: string | ||
| 62 | + productName: string | ||
| 63 | +} | ||
| 64 | + | ||
| 58 | // 产品查询请求参数 | 65 | // 产品查询请求参数 |
| 59 | export interface ProductQueryReq { | 66 | export interface ProductQueryReq { |
| 60 | productCode?: string | 67 | productCode?: string |
| ... | @@ -157,5 +164,10 @@ export const productApi = { | ... | @@ -157,5 +164,10 @@ export const productApi = { |
| 157 | // 修改返利标识 | 164 | // 修改返利标识 |
| 158 | updateRebateFlag: (productId: number, rebateFlag: number) => { | 165 | updateRebateFlag: (productId: number, rebateFlag: number) => { |
| 159 | return api.post(`/product/${productId}/rebate`, null, { params: { rebateFlag } }) | 166 | return api.post(`/product/${productId}/rebate`, null, { params: { rebateFlag } }) |
| 167 | + }, | ||
| 168 | + | ||
| 169 | + // 获取所有产品(用于下拉选择) | ||
| 170 | + getAllProducts: () => { | ||
| 171 | + return api.get<ApiResponse<ProductSimpleRes[]>>('/product/all') | ||
| 160 | } | 172 | } |
| 161 | } | 173 | } | ... | ... |
| ... | @@ -4,11 +4,11 @@ | ... | @@ -4,11 +4,11 @@ |
| 4 | <div class="search-section"> | 4 | <div class="search-section"> |
| 5 | <div class="search-row"> | 5 | <div class="search-row"> |
| 6 | <div class="search-item"> | 6 | <div class="search-item"> |
| 7 | - <label>订单编号:</label> | 7 | + <label>出库单编号:</label> |
| 8 | <input | 8 | <input |
| 9 | - v-model="searchParams.orderNo" | 9 | + v-model="searchParams.deliveryNo" |
| 10 | class="search-input" | 10 | class="search-input" |
| 11 | - placeholder="请输入订单编号" | 11 | + placeholder="请输入出库单编号" |
| 12 | /> | 12 | /> |
| 13 | </div> | 13 | </div> |
| 14 | <div class="search-item"> | 14 | <div class="search-item"> |
| ... | @@ -38,17 +38,17 @@ | ... | @@ -38,17 +38,17 @@ |
| 38 | </div> | 38 | </div> |
| 39 | <div class="search-row"> | 39 | <div class="search-row"> |
| 40 | <div class="search-item"> | 40 | <div class="search-item"> |
| 41 | - <label>开始日期:</label> | 41 | + <label>出库开始日期:</label> |
| 42 | <input | 42 | <input |
| 43 | - v-model="searchParams.startDate" | 43 | + v-model="searchParams.deliveryStartDate" |
| 44 | class="search-input" | 44 | class="search-input" |
| 45 | type="date" | 45 | type="date" |
| 46 | /> | 46 | /> |
| 47 | </div> | 47 | </div> |
| 48 | <div class="search-item"> | 48 | <div class="search-item"> |
| 49 | - <label>结束日期:</label> | 49 | + <label>出库结束日期:</label> |
| 50 | <input | 50 | <input |
| 51 | - v-model="searchParams.endDate" | 51 | + v-model="searchParams.deliveryEndDate" |
| 52 | class="search-input" | 52 | class="search-input" |
| 53 | type="date" | 53 | type="date" |
| 54 | /> | 54 | /> |
| ... | @@ -113,6 +113,7 @@ | ... | @@ -113,6 +113,7 @@ |
| 113 | <td>{{ formatTime(delivery.createTime || '') }}</td> | 113 | <td>{{ formatTime(delivery.createTime || '') }}</td> |
| 114 | <td class="action-col"> | 114 | <td class="action-col"> |
| 115 | <button @click="handleView(delivery)" class="view-btn">👁️ 查看</button> | 115 | <button @click="handleView(delivery)" class="view-btn">👁️ 查看</button> |
| 116 | + <button @click="handleEdit(delivery)" class="edit-btn">✏️ 编辑</button> | ||
| 116 | <button @click="handleDelete(delivery)" class="delete-btn">🗑️ 删除</button> | 117 | <button @click="handleDelete(delivery)" class="delete-btn">🗑️ 删除</button> |
| 117 | </td> | 118 | </td> |
| 118 | </tr> | 119 | </tr> |
| ... | @@ -179,15 +180,11 @@ | ... | @@ -179,15 +180,11 @@ |
| 179 | <div class="detail-grid"> | 180 | <div class="detail-grid"> |
| 180 | <div class="detail-item"> | 181 | <div class="detail-item"> |
| 181 | <label>出库单ID:</label> | 182 | <label>出库单ID:</label> |
| 182 | - <span>{{ orderDetail.deliveryId }}</span> | 183 | + <span>{{ deliveryDetail.deliveryId }}</span> |
| 183 | </div> | 184 | </div> |
| 184 | <div class="detail-item"> | 185 | <div class="detail-item"> |
| 185 | <label>出库单编号:</label> | 186 | <label>出库单编号:</label> |
| 186 | - <span>{{ orderDetail.deliveryNo }}</span> | 187 | + <span>{{ deliveryDetail.deliveryNo }}</span> |
| 187 | - </div> | ||
| 188 | - <div class="detail-item"> | ||
| 189 | - <label>关联订单编号:</label> | ||
| 190 | - <span>{{ orderDetail.orderNo }}</span> | ||
| 191 | </div> | 188 | </div> |
| 192 | <div class="detail-item"> | 189 | <div class="detail-item"> |
| 193 | <label>关联订单编号:</label> | 190 | <label>关联订单编号:</label> |
| ... | @@ -203,7 +200,7 @@ | ... | @@ -203,7 +200,7 @@ |
| 203 | </div> | 200 | </div> |
| 204 | <div class="detail-item"> | 201 | <div class="detail-item"> |
| 205 | <label>出库日期:</label> | 202 | <label>出库日期:</label> |
| 206 | - <span>{{ formatDate(orderDetail.deliveryDate) }}</span> | 203 | + <span>{{ formatDate(deliveryDetail.deliveryDate) }}</span> |
| 207 | </div> | 204 | </div> |
| 208 | <div class="detail-item"> | 205 | <div class="detail-item"> |
| 209 | <label>出库状态:</label> | 206 | <label>出库状态:</label> |
| ... | @@ -213,43 +210,43 @@ | ... | @@ -213,43 +210,43 @@ |
| 213 | </div> | 210 | </div> |
| 214 | <div class="detail-item"> | 211 | <div class="detail-item"> |
| 215 | <label>仓库编码:</label> | 212 | <label>仓库编码:</label> |
| 216 | - <span>{{ orderDetail.warehouseCode }}</span> | 213 | + <span>{{ deliveryDetail.warehouseCode }}</span> |
| 217 | </div> | 214 | </div> |
| 218 | <div class="detail-item"> | 215 | <div class="detail-item"> |
| 219 | <label>数据来源:</label> | 216 | <label>数据来源:</label> |
| 220 | - <span>{{ orderDetail.dataSource || '-' }}</span> | 217 | + <span>{{ deliveryDetail.dataSource || '-' }}</span> |
| 221 | </div> | 218 | </div> |
| 222 | <div class="detail-item"> | 219 | <div class="detail-item"> |
| 223 | <label>上传时间:</label> | 220 | <label>上传时间:</label> |
| 224 | - <span>{{ formatTime(orderDetail.uploadTime || '') }}</span> | 221 | + <span>{{ formatTime(deliveryDetail.uploadTime || '') }}</span> |
| 225 | </div> | 222 | </div> |
| 226 | <div class="detail-item"> | 223 | <div class="detail-item"> |
| 227 | <label>创建时间:</label> | 224 | <label>创建时间:</label> |
| 228 | - <span>{{ formatTime(orderDetail.createTime || '') }}</span> | 225 | + <span>{{ formatTime(deliveryDetail.createTime || '') }}</span> |
| 229 | </div> | 226 | </div> |
| 230 | <div class="detail-item"> | 227 | <div class="detail-item"> |
| 231 | <label>更新时间:</label> | 228 | <label>更新时间:</label> |
| 232 | - <span>{{ formatTime(orderDetail.updateTime || '') }}</span> | 229 | + <span>{{ formatTime(deliveryDetail.updateTime || '') }}</span> |
| 233 | </div> | 230 | </div> |
| 234 | </div> | 231 | </div> |
| 235 | </div> | 232 | </div> |
| 236 | 233 | ||
| 237 | - <div class="detail-section" v-if="orderDetail.deliveryItems && orderDetail.deliveryItems.length > 0"> | 234 | + <div class="detail-section" v-if="deliveryDetail.deliveryItems && deliveryDetail.deliveryItems.length > 0"> |
| 238 | <h4>出库明细</h4> | 235 | <h4>出库明细</h4> |
| 239 | <table class="detail-table"> | 236 | <table class="detail-table"> |
| 240 | <thead> | 237 | <thead> |
| 241 | <tr> | 238 | <tr> |
| 242 | - <th>产品编码</th> | ||
| 243 | <th>产品名称</th> | 239 | <th>产品名称</th> |
| 240 | + <th>产品编码</th> | ||
| 244 | <th>出库数量</th> | 241 | <th>出库数量</th> |
| 245 | <th>出库单价</th> | 242 | <th>出库单价</th> |
| 246 | <th>出库金额</th> | 243 | <th>出库金额</th> |
| 247 | </tr> | 244 | </tr> |
| 248 | </thead> | 245 | </thead> |
| 249 | <tbody> | 246 | <tbody> |
| 250 | - <tr v-for="item in orderDetail.deliveryItems" :key="item.deliveryItemId"> | 247 | + <tr v-for="item in deliveryDetail.deliveryItems" :key="item.deliveryItemId"> |
| 251 | - <td>{{ item.productCode }}</td> | ||
| 252 | <td>{{ item.productName }}</td> | 248 | <td>{{ item.productName }}</td> |
| 249 | + <td>{{ item.productCode }}</td> | ||
| 253 | <td>{{ item.deliveryQty }}</td> | 250 | <td>{{ item.deliveryQty }}</td> |
| 254 | <td>{{ formatCurrency(item.deliveryPrice) }}</td> | 251 | <td>{{ formatCurrency(item.deliveryPrice) }}</td> |
| 255 | <td>{{ formatCurrency(item.deliveryAmount) }}</td> | 252 | <td>{{ formatCurrency(item.deliveryAmount) }}</td> |
| ... | @@ -262,15 +259,15 @@ | ... | @@ -262,15 +259,15 @@ |
| 262 | </div> | 259 | </div> |
| 263 | </div> | 260 | </div> |
| 264 | 261 | ||
| 265 | - <!-- 新增出库对话框 --> | 262 | + <!-- 编辑出库对话框 --> |
| 266 | - <div v-if="showAddDialog" class="dialog-overlay" @click="closeAddDialog"> | 263 | + <div v-if="showEditDialog" class="dialog-overlay" @click="closeEditDialog"> |
| 267 | <div class="dialog-content large-dialog" @click.stop> | 264 | <div class="dialog-content large-dialog" @click.stop> |
| 268 | <div class="dialog-header"> | 265 | <div class="dialog-header"> |
| 269 | - <h3>新增出库</h3> | 266 | + <h3>编辑出库</h3> |
| 270 | - <button @click="closeAddDialog" class="close-btn">×</button> | 267 | + <button @click="closeEditDialog" class="close-btn">×</button> |
| 271 | </div> | 268 | </div> |
| 272 | <div class="dialog-body"> | 269 | <div class="dialog-body"> |
| 273 | - <form @submit.prevent="handleSubmitAdd"> | 270 | + <form @submit.prevent="handleSubmitEdit"> |
| 274 | <!-- 出库基本信息 --> | 271 | <!-- 出库基本信息 --> |
| 275 | <div class="form-section"> | 272 | <div class="form-section"> |
| 276 | <h4>出库基本信息</h4> | 273 | <h4>出库基本信息</h4> |
| ... | @@ -278,33 +275,215 @@ | ... | @@ -278,33 +275,215 @@ |
| 278 | <div class="form-item"> | 275 | <div class="form-item"> |
| 279 | <label class="required">出库单编号:</label> | 276 | <label class="required">出库单编号:</label> |
| 280 | <input | 277 | <input |
| 281 | - v-model="addFormData.deliveryNo" | 278 | + v-model="editFormData.deliveryNo" |
| 282 | class="form-input" | 279 | class="form-input" |
| 283 | placeholder="请输入出库单编号" | 280 | placeholder="请输入出库单编号" |
| 284 | required | 281 | required |
| 285 | /> | 282 | /> |
| 286 | </div> | 283 | </div> |
| 287 | <div class="form-item"> | 284 | <div class="form-item"> |
| 288 | - <label class="required">经销商编码:</label> | 285 | + <label class="required">经销商名称:</label> |
| 286 | + <select | ||
| 287 | + v-model="editFormData.dealerName" | ||
| 288 | + class="form-input" | ||
| 289 | + @change="handleEditDealerChange" | ||
| 290 | + required | ||
| 291 | + > | ||
| 292 | + <option value="">请选择经销商</option> | ||
| 293 | + <option | ||
| 294 | + v-for="dealer in dealerList" | ||
| 295 | + :key="dealer.dealerId" | ||
| 296 | + :value="dealer.dealerName" | ||
| 297 | + > | ||
| 298 | + {{ dealer.dealerName }} | ||
| 299 | + </option> | ||
| 300 | + </select> | ||
| 301 | + </div> | ||
| 302 | + </div> | ||
| 303 | + <div class="form-row"> | ||
| 304 | + <div class="form-item"> | ||
| 305 | + <label class="required">关联订单编号:</label> | ||
| 306 | + <input | ||
| 307 | + v-model="editFormData.orderNo" | ||
| 308 | + class="form-input" | ||
| 309 | + placeholder="请输入关联订单编号" | ||
| 310 | + required | ||
| 311 | + /> | ||
| 312 | + </div> | ||
| 313 | + <div class="form-item"> | ||
| 314 | + <label class="required">出库日期:</label> | ||
| 289 | <input | 315 | <input |
| 290 | - v-model="addFormData.dealerCode" | 316 | + v-model="editFormData.deliveryDate" |
| 291 | class="form-input" | 317 | class="form-input" |
| 292 | - placeholder="请输入经销商编码" | 318 | + type="datetime-local" |
| 319 | + step="1" | ||
| 293 | required | 320 | required |
| 294 | /> | 321 | /> |
| 295 | </div> | 322 | </div> |
| 296 | </div> | 323 | </div> |
| 297 | <div class="form-row"> | 324 | <div class="form-row"> |
| 298 | <div class="form-item"> | 325 | <div class="form-item"> |
| 299 | - <label class="required">经销商名称:</label> | 326 | + <label>仓库编码:</label> |
| 300 | <input | 327 | <input |
| 301 | - v-model="addFormData.dealerName" | 328 | + v-model="editFormData.warehouseCode" |
| 302 | class="form-input" | 329 | class="form-input" |
| 303 | - placeholder="请输入经销商名称" | 330 | + placeholder="请输入仓库编码" |
| 331 | + /> | ||
| 332 | + </div> | ||
| 333 | + <div class="form-item"> | ||
| 334 | + <label>仓库名称:</label> | ||
| 335 | + <input | ||
| 336 | + v-model="editFormData.warehouseName" | ||
| 337 | + class="form-input" | ||
| 338 | + placeholder="请输入仓库名称" | ||
| 339 | + /> | ||
| 340 | + </div> | ||
| 341 | + </div> | ||
| 342 | + <div class="form-row"> | ||
| 343 | + <div class="form-item"> | ||
| 344 | + <label>数据来源:</label> | ||
| 345 | + <input | ||
| 346 | + v-model="editFormData.dataSource" | ||
| 347 | + class="form-input" | ||
| 348 | + placeholder="请输入数据来源" | ||
| 349 | + /> | ||
| 350 | + </div> | ||
| 351 | + <!-- 经销商编码字段隐藏,通过选择经销商名称自动填充 --> | ||
| 352 | + <input | ||
| 353 | + v-model="editFormData.dealerCode" | ||
| 354 | + type="hidden" | ||
| 355 | + /> | ||
| 356 | + </div> | ||
| 357 | + </div> | ||
| 358 | + | ||
| 359 | + <!-- 出库明细 --> | ||
| 360 | + <div class="form-section"> | ||
| 361 | + <h4>出库明细</h4> | ||
| 362 | + <div class="order-items-header"> | ||
| 363 | + <button type="button" @click="addEditDeliveryItem" class="add-item-btn">+ 添加明细</button> | ||
| 364 | + </div> | ||
| 365 | + <div class="order-items-container"> | ||
| 366 | + <div v-for="(item, index) in editFormData.deliveryItems" :key="index" class="order-item"> | ||
| 367 | + <div class="item-row-single"> | ||
| 368 | + <div class="form-item"> | ||
| 369 | + <label class="required">产品名称:</label> | ||
| 370 | + <select | ||
| 371 | + v-model="item.productName" | ||
| 372 | + class="form-input" | ||
| 373 | + @change="handleEditProductChange(index)" | ||
| 374 | + required | ||
| 375 | + > | ||
| 376 | + <option value="">请选择产品</option> | ||
| 377 | + <option | ||
| 378 | + v-for="product in productList" | ||
| 379 | + :key="product.productId" | ||
| 380 | + :value="product.productName" | ||
| 381 | + > | ||
| 382 | + {{ product.productName }} | ||
| 383 | + </option> | ||
| 384 | + </select> | ||
| 385 | + </div> | ||
| 386 | + <div class="form-item"> | ||
| 387 | + <label class="required">产品编码:</label> | ||
| 388 | + <input | ||
| 389 | + v-model="item.productCode" | ||
| 390 | + class="form-input readonly" | ||
| 391 | + placeholder="自动填充" | ||
| 392 | + readonly | ||
| 393 | + required | ||
| 394 | + /> | ||
| 395 | + </div> | ||
| 396 | + <div class="form-item"> | ||
| 397 | + <label class="required">出库数量:</label> | ||
| 398 | + <input | ||
| 399 | + v-model.number="item.deliveryQty" | ||
| 400 | + class="form-input" | ||
| 401 | + type="number" | ||
| 402 | + placeholder="请输入出库数量" | ||
| 403 | + @input="calculateEditDeliveryItemTotal(index)" | ||
| 404 | + required | ||
| 405 | + /> | ||
| 406 | + </div> | ||
| 407 | + <div class="form-item"> | ||
| 408 | + <label class="required">出库单价:</label> | ||
| 409 | + <input | ||
| 410 | + v-model.number="item.deliveryPrice" | ||
| 411 | + class="form-input" | ||
| 412 | + type="number" | ||
| 413 | + step="0.01" | ||
| 414 | + placeholder="请输入出库单价" | ||
| 415 | + @input="calculateEditDeliveryItemTotal(index)" | ||
| 416 | + required | ||
| 417 | + /> | ||
| 418 | + </div> | ||
| 419 | + <div class="form-item"> | ||
| 420 | + <label>出库金额:</label> | ||
| 421 | + <input | ||
| 422 | + v-model.number="item.deliveryAmount" | ||
| 423 | + class="form-input" | ||
| 424 | + type="number" | ||
| 425 | + step="0.01" | ||
| 426 | + readonly | ||
| 427 | + /> | ||
| 428 | + </div> | ||
| 429 | + <button type="button" @click="removeEditDeliveryItem(index)" class="remove-item-btn">删除</button> | ||
| 430 | + </div> | ||
| 431 | + </div> | ||
| 432 | + </div> | ||
| 433 | + </div> | ||
| 434 | + | ||
| 435 | + <div class="form-actions"> | ||
| 436 | + <button type="button" @click="closeEditDialog" class="cancel-btn">取消</button> | ||
| 437 | + <button type="submit" class="submit-btn">确定</button> | ||
| 438 | + </div> | ||
| 439 | + </form> | ||
| 440 | + </div> | ||
| 441 | + </div> | ||
| 442 | + </div> | ||
| 443 | + | ||
| 444 | + <!-- 新增出库对话框 --> | ||
| 445 | + <div v-if="showAddDialog" class="dialog-overlay" @click="closeAddDialog"> | ||
| 446 | + <div class="dialog-content large-dialog" @click.stop> | ||
| 447 | + <div class="dialog-header"> | ||
| 448 | + <h3>新增出库</h3> | ||
| 449 | + <button @click="closeAddDialog" class="close-btn">×</button> | ||
| 450 | + </div> | ||
| 451 | + <div class="dialog-body"> | ||
| 452 | + <form @submit.prevent="handleSubmitAdd"> | ||
| 453 | + <!-- 出库基本信息 --> | ||
| 454 | + <div class="form-section"> | ||
| 455 | + <h4>出库基本信息</h4> | ||
| 456 | + <div class="form-row"> | ||
| 457 | + <div class="form-item"> | ||
| 458 | + <label class="required">出库单编号:</label> | ||
| 459 | + <input | ||
| 460 | + v-model="addFormData.deliveryNo" | ||
| 461 | + class="form-input" | ||
| 462 | + placeholder="请输入出库单编号" | ||
| 304 | required | 463 | required |
| 305 | /> | 464 | /> |
| 306 | </div> | 465 | </div> |
| 307 | <div class="form-item"> | 466 | <div class="form-item"> |
| 467 | + <label class="required">经销商名称:</label> | ||
| 468 | + <select | ||
| 469 | + v-model="addFormData.dealerName" | ||
| 470 | + class="form-input" | ||
| 471 | + @change="handleAddDealerChange" | ||
| 472 | + required | ||
| 473 | + > | ||
| 474 | + <option value="">请选择经销商</option> | ||
| 475 | + <option | ||
| 476 | + v-for="dealer in dealerList" | ||
| 477 | + :key="dealer.dealerId" | ||
| 478 | + :value="dealer.dealerName" | ||
| 479 | + > | ||
| 480 | + {{ dealer.dealerName }} | ||
| 481 | + </option> | ||
| 482 | + </select> | ||
| 483 | + </div> | ||
| 484 | + </div> | ||
| 485 | + <div class="form-row"> | ||
| 486 | + <div class="form-item"> | ||
| 308 | <label class="required">关联订单编号:</label> | 487 | <label class="required">关联订单编号:</label> |
| 309 | <input | 488 | <input |
| 310 | v-model="addFormData.orderNo" | 489 | v-model="addFormData.orderNo" |
| ... | @@ -313,8 +492,6 @@ | ... | @@ -313,8 +492,6 @@ |
| 313 | required | 492 | required |
| 314 | /> | 493 | /> |
| 315 | </div> | 494 | </div> |
| 316 | - </div> | ||
| 317 | - <div class="form-row"> | ||
| 318 | <div class="form-item"> | 495 | <div class="form-item"> |
| 319 | <label class="required">出库日期:</label> | 496 | <label class="required">出库日期:</label> |
| 320 | <input | 497 | <input |
| ... | @@ -325,6 +502,8 @@ | ... | @@ -325,6 +502,8 @@ |
| 325 | required | 502 | required |
| 326 | /> | 503 | /> |
| 327 | </div> | 504 | </div> |
| 505 | + </div> | ||
| 506 | + <div class="form-row"> | ||
| 328 | <div class="form-item"> | 507 | <div class="form-item"> |
| 329 | <label>仓库编码:</label> | 508 | <label>仓库编码:</label> |
| 330 | <input | 509 | <input |
| ... | @@ -333,8 +512,6 @@ | ... | @@ -333,8 +512,6 @@ |
| 333 | placeholder="请输入仓库编码" | 512 | placeholder="请输入仓库编码" |
| 334 | /> | 513 | /> |
| 335 | </div> | 514 | </div> |
| 336 | - </div> | ||
| 337 | - <div class="form-row"> | ||
| 338 | <div class="form-item"> | 515 | <div class="form-item"> |
| 339 | <label>仓库名称:</label> | 516 | <label>仓库名称:</label> |
| 340 | <input | 517 | <input |
| ... | @@ -343,6 +520,8 @@ | ... | @@ -343,6 +520,8 @@ |
| 343 | placeholder="请输入仓库名称" | 520 | placeholder="请输入仓库名称" |
| 344 | /> | 521 | /> |
| 345 | </div> | 522 | </div> |
| 523 | + </div> | ||
| 524 | + <div class="form-row"> | ||
| 346 | <div class="form-item"> | 525 | <div class="form-item"> |
| 347 | <label>数据来源:</label> | 526 | <label>数据来源:</label> |
| 348 | <input | 527 | <input |
| ... | @@ -351,6 +530,11 @@ | ... | @@ -351,6 +530,11 @@ |
| 351 | placeholder="请输入数据来源" | 530 | placeholder="请输入数据来源" |
| 352 | /> | 531 | /> |
| 353 | </div> | 532 | </div> |
| 533 | + <!-- 经销商编码字段隐藏,通过选择经销商名称自动填充 --> | ||
| 534 | + <input | ||
| 535 | + v-model="addFormData.dealerCode" | ||
| 536 | + type="hidden" | ||
| 537 | + /> | ||
| 354 | </div> | 538 | </div> |
| 355 | </div> | 539 | </div> |
| 356 | 540 | ||
| ... | @@ -364,20 +548,30 @@ | ... | @@ -364,20 +548,30 @@ |
| 364 | <div v-for="(item, index) in addFormData.deliveryItems" :key="index" class="order-item"> | 548 | <div v-for="(item, index) in addFormData.deliveryItems" :key="index" class="order-item"> |
| 365 | <div class="item-row-single"> | 549 | <div class="item-row-single"> |
| 366 | <div class="form-item"> | 550 | <div class="form-item"> |
| 367 | - <label class="required">产品编码:</label> | 551 | + <label class="required">产品名称:</label> |
| 368 | - <input | 552 | + <select |
| 369 | - v-model="item.productCode" | 553 | + v-model="item.productName" |
| 370 | class="form-input" | 554 | class="form-input" |
| 371 | - placeholder="请输入产品编码" | 555 | + @change="handleAddProductChange(index)" |
| 372 | required | 556 | required |
| 373 | - /> | 557 | + > |
| 558 | + <option value="">请选择产品</option> | ||
| 559 | + <option | ||
| 560 | + v-for="product in productList" | ||
| 561 | + :key="product.productId" | ||
| 562 | + :value="product.productName" | ||
| 563 | + > | ||
| 564 | + {{ product.productName }} | ||
| 565 | + </option> | ||
| 566 | + </select> | ||
| 374 | </div> | 567 | </div> |
| 375 | <div class="form-item"> | 568 | <div class="form-item"> |
| 376 | - <label class="required">产品名称:</label> | 569 | + <label class="required">产品编码:</label> |
| 377 | <input | 570 | <input |
| 378 | - v-model="item.productName" | 571 | + v-model="item.productCode" |
| 379 | - class="form-input" | 572 | + class="form-input readonly" |
| 380 | - placeholder="请输入产品名称" | 573 | + placeholder="自动填充" |
| 574 | + readonly | ||
| 381 | required | 575 | required |
| 382 | /> | 576 | /> |
| 383 | </div> | 577 | </div> |
| ... | @@ -434,12 +628,17 @@ | ... | @@ -434,12 +628,17 @@ |
| 434 | <script setup lang="ts"> | 628 | <script setup lang="ts"> |
| 435 | import { ref, reactive, computed, onMounted } from 'vue' | 629 | import { ref, reactive, computed, onMounted } from 'vue' |
| 436 | import { deliveryApi, type DeliveryAddReq, type DeliveryInfo, type DeliveryQueryReq } from '../../api/delivery' | 630 | import { deliveryApi, type DeliveryAddReq, type DeliveryInfo, type DeliveryQueryReq } from '../../api/delivery' |
| 631 | +import { dealerApi, type DealerInfo } from '../../api/dealer' | ||
| 632 | +import { productApi } from '../../api/product' | ||
| 633 | +import type { ProductSimpleRes } from '../../api/product' | ||
| 437 | 634 | ||
| 438 | // 响应式数据 | 635 | // 响应式数据 |
| 439 | const loading = ref(false) | 636 | const loading = ref(false) |
| 440 | const deliveryList = ref<DeliveryInfo[]>([]) | 637 | const deliveryList = ref<DeliveryInfo[]>([]) |
| 441 | const showDetailDialog = ref(false) | 638 | const showDetailDialog = ref(false) |
| 442 | const deliveryDetail = ref<DeliveryInfo | null>(null) | 639 | const deliveryDetail = ref<DeliveryInfo | null>(null) |
| 640 | +const dealerList = ref<DealerInfo[]>([]) | ||
| 641 | +const productList = ref<ProductSimpleRes[]>([]) | ||
| 443 | 642 | ||
| 444 | // 新增出库相关数据 | 643 | // 新增出库相关数据 |
| 445 | const showAddDialog = ref(false) | 644 | const showAddDialog = ref(false) |
| ... | @@ -455,9 +654,23 @@ const addFormData = reactive({ | ... | @@ -455,9 +654,23 @@ const addFormData = reactive({ |
| 455 | deliveryItems: [] as any[] | 654 | deliveryItems: [] as any[] |
| 456 | }) | 655 | }) |
| 457 | 656 | ||
| 657 | +// 编辑出库相关数据 | ||
| 658 | +const showEditDialog = ref(false) | ||
| 659 | +const editFormData = reactive({ | ||
| 660 | + deliveryId: 0, | ||
| 661 | + deliveryNo: '', | ||
| 662 | + dealerCode: '', | ||
| 663 | + dealerName: '', | ||
| 664 | + orderNo: '', | ||
| 665 | + deliveryDate: '', | ||
| 666 | + warehouseCode: '', | ||
| 667 | + warehouseName: '', | ||
| 668 | + dataSource: '', | ||
| 669 | + deliveryItems: [] as any[] | ||
| 670 | +}) | ||
| 671 | + | ||
| 458 | // 搜索参数 | 672 | // 搜索参数 |
| 459 | const searchParams = reactive({ | 673 | const searchParams = reactive({ |
| 460 | - orderNo: '', | ||
| 461 | deliveryNo: '', | 674 | deliveryNo: '', |
| 462 | dealerCode: '', | 675 | dealerCode: '', |
| 463 | dealerName: '', | 676 | dealerName: '', |
| ... | @@ -466,8 +679,6 @@ const searchParams = reactive({ | ... | @@ -466,8 +679,6 @@ const searchParams = reactive({ |
| 466 | dataSource: '', | 679 | dataSource: '', |
| 467 | deliveryStartDate: '', | 680 | deliveryStartDate: '', |
| 468 | deliveryEndDate: '', | 681 | deliveryEndDate: '', |
| 469 | - startDate: '', | ||
| 470 | - endDate: '', | ||
| 471 | pageNum: 1, | 682 | pageNum: 1, |
| 472 | pageSize: 10 | 683 | pageSize: 10 |
| 473 | }) | 684 | }) |
| ... | @@ -539,7 +750,16 @@ const getPageNumbers = () => { | ... | @@ -539,7 +750,16 @@ const getPageNumbers = () => { |
| 539 | const fetchDeliveries = async () => { | 750 | const fetchDeliveries = async () => { |
| 540 | try { | 751 | try { |
| 541 | loading.value = true | 752 | loading.value = true |
| 542 | - const params = { ...searchParams, pageNum: pagination.pageNum, pageSize: pagination.pageSize } | 753 | + // 处理日期格式,将日期转换为完整的日期时间格式 |
| 754 | + const processedParams = { ...searchParams } | ||
| 755 | + if (processedParams.deliveryStartDate) { | ||
| 756 | + processedParams.deliveryStartDate = processedParams.deliveryStartDate + ' 00:00:00' | ||
| 757 | + } | ||
| 758 | + if (processedParams.deliveryEndDate) { | ||
| 759 | + processedParams.deliveryEndDate = processedParams.deliveryEndDate + ' 23:59:59' | ||
| 760 | + } | ||
| 761 | + | ||
| 762 | + const params = { ...processedParams, pageNum: pagination.pageNum, pageSize: pagination.pageSize } | ||
| 543 | const response = await deliveryApi.getDeliveryList(params) as any | 763 | const response = await deliveryApi.getDeliveryList(params) as any |
| 544 | console.log('出库查询API响应:', response) | 764 | console.log('出库查询API响应:', response) |
| 545 | 765 | ||
| ... | @@ -569,12 +789,12 @@ const handleSearch = () => { | ... | @@ -569,12 +789,12 @@ const handleSearch = () => { |
| 569 | 789 | ||
| 570 | const handleReset = () => { | 790 | const handleReset = () => { |
| 571 | Object.assign(searchParams, { | 791 | Object.assign(searchParams, { |
| 572 | - orderNo: '', | 792 | + deliveryNo: '', |
| 573 | dealerCode: '', | 793 | dealerCode: '', |
| 574 | dealerName: '', | 794 | dealerName: '', |
| 575 | deliveryStatus: undefined, | 795 | deliveryStatus: undefined, |
| 576 | - startDate: '', | 796 | + deliveryStartDate: '', |
| 577 | - endDate: '' | 797 | + deliveryEndDate: '' |
| 578 | }) | 798 | }) |
| 579 | pagination.pageNum = 1 | 799 | pagination.pageNum = 1 |
| 580 | fetchDeliveries() | 800 | fetchDeliveries() |
| ... | @@ -598,6 +818,42 @@ const handleView = async (delivery: DeliveryInfo) => { | ... | @@ -598,6 +818,42 @@ const handleView = async (delivery: DeliveryInfo) => { |
| 598 | } | 818 | } |
| 599 | } | 819 | } |
| 600 | 820 | ||
| 821 | +const handleEdit = async (delivery: DeliveryInfo) => { | ||
| 822 | + try { | ||
| 823 | + // 调用后端接口获取完整的出库详情(包括出库明细) | ||
| 824 | + const response = await deliveryApi.getDeliveryDetail(delivery.deliveryId) as any | ||
| 825 | + console.log('编辑出库API响应:', response) | ||
| 826 | + | ||
| 827 | + if (response && response.deliveryId) { | ||
| 828 | + // 处理日期时间格式,将后端返回的日期时间格式转换为前端datetime-local格式 | ||
| 829 | + let formattedDeliveryDate = response.deliveryDate | ||
| 830 | + if (formattedDeliveryDate && formattedDeliveryDate.includes(' ')) { | ||
| 831 | + // 将 YYYY-MM-DD HH:MM:SS 格式转换为 YYYY-MM-DDTHH:MM:SS 格式 | ||
| 832 | + formattedDeliveryDate = formattedDeliveryDate.replace(' ', 'T') | ||
| 833 | + } | ||
| 834 | + | ||
| 835 | + Object.assign(editFormData, { | ||
| 836 | + deliveryId: response.deliveryId, | ||
| 837 | + deliveryNo: response.deliveryNo, | ||
| 838 | + dealerCode: response.dealerCode, | ||
| 839 | + dealerName: response.dealerName, | ||
| 840 | + orderNo: response.orderNo, | ||
| 841 | + deliveryDate: formattedDeliveryDate, | ||
| 842 | + warehouseCode: response.warehouseCode || '', | ||
| 843 | + warehouseName: response.warehouseName || '', | ||
| 844 | + dataSource: response.dataSource || '', | ||
| 845 | + deliveryItems: response.deliveryItems || [] | ||
| 846 | + }) | ||
| 847 | + showEditDialog.value = true | ||
| 848 | + } else { | ||
| 849 | + showMessage('获取出库详情失败', 'error') | ||
| 850 | + } | ||
| 851 | + } catch (error) { | ||
| 852 | + console.error('获取出库详情失败:', error) | ||
| 853 | + showMessage('获取出库详情失败, 请重试', 'error') | ||
| 854 | + } | ||
| 855 | +} | ||
| 856 | + | ||
| 601 | const handleDelete = async (delivery: DeliveryInfo) => { | 857 | const handleDelete = async (delivery: DeliveryInfo) => { |
| 602 | if (confirm(`确定要删除出库单"${delivery.deliveryNo}"吗?`)) { | 858 | if (confirm(`确定要删除出库单"${delivery.deliveryNo}"吗?`)) { |
| 603 | try { | 859 | try { |
| ... | @@ -637,6 +893,40 @@ const closeAddDialog = () => { | ... | @@ -637,6 +893,40 @@ const closeAddDialog = () => { |
| 637 | showAddDialog.value = false | 893 | showAddDialog.value = false |
| 638 | } | 894 | } |
| 639 | 895 | ||
| 896 | +const closeEditDialog = () => { | ||
| 897 | + showEditDialog.value = false | ||
| 898 | +} | ||
| 899 | + | ||
| 900 | +// 经销商选择处理 | ||
| 901 | +const handleAddDealerChange = () => { | ||
| 902 | + const selectedDealer = dealerList.value.find(dealer => dealer.dealerName === addFormData.dealerName) | ||
| 903 | + if (selectedDealer) { | ||
| 904 | + addFormData.dealerCode = selectedDealer.dealerCode | ||
| 905 | + } | ||
| 906 | +} | ||
| 907 | + | ||
| 908 | +const handleEditDealerChange = () => { | ||
| 909 | + const selectedDealer = dealerList.value.find(dealer => dealer.dealerName === editFormData.dealerName) | ||
| 910 | + if (selectedDealer) { | ||
| 911 | + editFormData.dealerCode = selectedDealer.dealerCode | ||
| 912 | + } | ||
| 913 | +} | ||
| 914 | + | ||
| 915 | +// 产品选择处理 | ||
| 916 | +const handleAddProductChange = (index: number) => { | ||
| 917 | + const selectedProduct = productList.value.find((product: ProductSimpleRes) => product.productName === addFormData.deliveryItems[index].productName) | ||
| 918 | + if (selectedProduct) { | ||
| 919 | + addFormData.deliveryItems[index].productCode = selectedProduct.productCode | ||
| 920 | + } | ||
| 921 | +} | ||
| 922 | + | ||
| 923 | +const handleEditProductChange = (index: number) => { | ||
| 924 | + const selectedProduct = productList.value.find((product: ProductSimpleRes) => product.productName === editFormData.deliveryItems[index].productName) | ||
| 925 | + if (selectedProduct) { | ||
| 926 | + editFormData.deliveryItems[index].productCode = selectedProduct.productCode | ||
| 927 | + } | ||
| 928 | +} | ||
| 929 | + | ||
| 640 | const addDeliveryItem = () => { | 930 | const addDeliveryItem = () => { |
| 641 | addFormData.deliveryItems.push({ | 931 | addFormData.deliveryItems.push({ |
| 642 | productCode: '', | 932 | productCode: '', |
| ... | @@ -651,6 +941,20 @@ const removeDeliveryItem = (index: number) => { | ... | @@ -651,6 +941,20 @@ const removeDeliveryItem = (index: number) => { |
| 651 | addFormData.deliveryItems.splice(index, 1) | 941 | addFormData.deliveryItems.splice(index, 1) |
| 652 | } | 942 | } |
| 653 | 943 | ||
| 944 | +const addEditDeliveryItem = () => { | ||
| 945 | + editFormData.deliveryItems.push({ | ||
| 946 | + productCode: '', | ||
| 947 | + productName: '', | ||
| 948 | + deliveryQty: 1, | ||
| 949 | + deliveryPrice: 0, | ||
| 950 | + deliveryAmount: 0 | ||
| 951 | + }) | ||
| 952 | +} | ||
| 953 | + | ||
| 954 | +const removeEditDeliveryItem = (index: number) => { | ||
| 955 | + editFormData.deliveryItems.splice(index, 1) | ||
| 956 | +} | ||
| 957 | + | ||
| 654 | const calculateDeliveryItemTotal = (index: number) => { | 958 | const calculateDeliveryItemTotal = (index: number) => { |
| 655 | const item = addFormData.deliveryItems[index] | 959 | const item = addFormData.deliveryItems[index] |
| 656 | if (item.deliveryQty && item.deliveryPrice) { | 960 | if (item.deliveryQty && item.deliveryPrice) { |
| ... | @@ -658,6 +962,13 @@ const calculateDeliveryItemTotal = (index: number) => { | ... | @@ -658,6 +962,13 @@ const calculateDeliveryItemTotal = (index: number) => { |
| 658 | } | 962 | } |
| 659 | } | 963 | } |
| 660 | 964 | ||
| 965 | +const calculateEditDeliveryItemTotal = (index: number) => { | ||
| 966 | + const item = editFormData.deliveryItems[index] | ||
| 967 | + if (item.deliveryQty && item.deliveryPrice) { | ||
| 968 | + item.deliveryAmount = item.deliveryQty * item.deliveryPrice | ||
| 969 | + } | ||
| 970 | +} | ||
| 971 | + | ||
| 661 | const handleSubmitAdd = async () => { | 972 | const handleSubmitAdd = async () => { |
| 662 | try { | 973 | try { |
| 663 | // 处理日期时间格式,将datetime-local格式转换为后端需要的格式 | 974 | // 处理日期时间格式,将datetime-local格式转换为后端需要的格式 |
| ... | @@ -680,9 +991,9 @@ const handleSubmitAdd = async () => { | ... | @@ -680,9 +991,9 @@ const handleSubmitAdd = async () => { |
| 680 | deliveryItems: addFormData.deliveryItems.map(item => ({ | 991 | deliveryItems: addFormData.deliveryItems.map(item => ({ |
| 681 | productCode: item.productCode, | 992 | productCode: item.productCode, |
| 682 | productName: item.productName, | 993 | productName: item.productName, |
| 683 | - productQty: item.deliveryQty, | 994 | + deliveryQty: item.deliveryQty, |
| 684 | - unitPrice: item.deliveryPrice, | 995 | + deliveryPrice: item.deliveryPrice, |
| 685 | - totalPrice: item.deliveryAmount | 996 | + deliveryAmount: item.deliveryAmount |
| 686 | })) | 997 | })) |
| 687 | } | 998 | } |
| 688 | 999 | ||
| ... | @@ -696,6 +1007,44 @@ const handleSubmitAdd = async () => { | ... | @@ -696,6 +1007,44 @@ const handleSubmitAdd = async () => { |
| 696 | } | 1007 | } |
| 697 | } | 1008 | } |
| 698 | 1009 | ||
| 1010 | +const handleSubmitEdit = async () => { | ||
| 1011 | + try { | ||
| 1012 | + // 处理日期时间格式,将datetime-local格式转换为后端需要的格式 | ||
| 1013 | + let formattedDeliveryDate = editFormData.deliveryDate | ||
| 1014 | + if (formattedDeliveryDate && formattedDeliveryDate.includes('T')) { | ||
| 1015 | + // 将 YYYY-MM-DDTHH:MM:SS 格式转换为 YYYY-MM-DD HH:MM:SS 格式 | ||
| 1016 | + formattedDeliveryDate = formattedDeliveryDate.replace('T', ' ') | ||
| 1017 | + } | ||
| 1018 | + | ||
| 1019 | + // 构造编辑出库的请求数据 | ||
| 1020 | + const deliveryData = { | ||
| 1021 | + deliveryId: editFormData.deliveryId, | ||
| 1022 | + deliveryNo: editFormData.deliveryNo, | ||
| 1023 | + dealerCode: editFormData.dealerCode, | ||
| 1024 | + dealerName: editFormData.dealerName, | ||
| 1025 | + orderNo: editFormData.orderNo, | ||
| 1026 | + deliveryDate: formattedDeliveryDate, | ||
| 1027 | + warehouseCode: editFormData.warehouseCode, | ||
| 1028 | + dataSource: editFormData.dataSource || '系统录入', | ||
| 1029 | + deliveryItems: editFormData.deliveryItems.map(item => ({ | ||
| 1030 | + productCode: item.productCode, | ||
| 1031 | + productName: item.productName, | ||
| 1032 | + deliveryQty: item.deliveryQty, | ||
| 1033 | + deliveryPrice: item.deliveryPrice, | ||
| 1034 | + deliveryAmount: item.deliveryAmount | ||
| 1035 | + })) | ||
| 1036 | + } | ||
| 1037 | + | ||
| 1038 | + await deliveryApi.updateDelivery(deliveryData) | ||
| 1039 | + showMessage('编辑出库成功', 'success') | ||
| 1040 | + closeEditDialog() | ||
| 1041 | + fetchDeliveries() // 刷新列表 | ||
| 1042 | + } catch (error) { | ||
| 1043 | + console.error('编辑出库失败:', error) | ||
| 1044 | + showMessage('编辑出库失败, 请重试', 'error') | ||
| 1045 | + } | ||
| 1046 | +} | ||
| 1047 | + | ||
| 699 | 1048 | ||
| 700 | 1049 | ||
| 701 | const handlePageChange = (page: number) => { | 1050 | const handlePageChange = (page: number) => { |
| ... | @@ -731,9 +1080,37 @@ const closeDetailDialog = () => { | ... | @@ -731,9 +1080,37 @@ const closeDetailDialog = () => { |
| 731 | deliveryDetail.value = null | 1080 | deliveryDetail.value = null |
| 732 | } | 1081 | } |
| 733 | 1082 | ||
| 1083 | +// 加载经销商列表 | ||
| 1084 | +const loadDealers = async () => { | ||
| 1085 | + try { | ||
| 1086 | + const response = await dealerApi.getAllDealers() as any | ||
| 1087 | + if (response && response.data && Array.isArray(response.data)) { | ||
| 1088 | + dealerList.value = response.data | ||
| 1089 | + } | ||
| 1090 | + } catch (error) { | ||
| 1091 | + console.error('加载经销商列表失败:', error) | ||
| 1092 | + showMessage('加载经销商列表失败', 'error') | ||
| 1093 | + } | ||
| 1094 | +} | ||
| 1095 | + | ||
| 1096 | +// 加载产品列表 | ||
| 1097 | +const loadProducts = async () => { | ||
| 1098 | + try { | ||
| 1099 | + const response = await productApi.getAllProducts() as any | ||
| 1100 | + if (response && response.data && Array.isArray(response.data)) { | ||
| 1101 | + productList.value = response.data | ||
| 1102 | + } | ||
| 1103 | + } catch (error) { | ||
| 1104 | + console.error('加载产品列表失败:', error) | ||
| 1105 | + showMessage('加载产品列表失败', 'error') | ||
| 1106 | + } | ||
| 1107 | +} | ||
| 1108 | + | ||
| 734 | // 生命周期 | 1109 | // 生命周期 |
| 735 | onMounted(() => { | 1110 | onMounted(() => { |
| 736 | fetchDeliveries() | 1111 | fetchDeliveries() |
| 1112 | + loadDealers() | ||
| 1113 | + loadProducts() | ||
| 737 | }) | 1114 | }) |
| 738 | </script> | 1115 | </script> |
| 739 | 1116 | ||
| ... | @@ -958,6 +1335,11 @@ onMounted(() => { | ... | @@ -958,6 +1335,11 @@ onMounted(() => { |
| 958 | color: white; | 1335 | color: white; |
| 959 | } | 1336 | } |
| 960 | 1337 | ||
| 1338 | +.edit-btn { | ||
| 1339 | + background: #ffc107; | ||
| 1340 | + color: #333; | ||
| 1341 | +} | ||
| 1342 | + | ||
| 961 | .delete-btn { | 1343 | .delete-btn { |
| 962 | background: #dc3545; | 1344 | background: #dc3545; |
| 963 | color: white; | 1345 | color: white; |
| ... | @@ -1256,6 +1638,23 @@ onMounted(() => { | ... | @@ -1256,6 +1638,23 @@ onMounted(() => { |
| 1256 | box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.2); | 1638 | box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.2); |
| 1257 | } | 1639 | } |
| 1258 | 1640 | ||
| 1641 | +.form-select { | ||
| 1642 | + padding: 6px 8px; | ||
| 1643 | + border: 1px solid #ddd; | ||
| 1644 | + border-radius: 4px; | ||
| 1645 | + font-size: 12px; | ||
| 1646 | + width: 100%; | ||
| 1647 | + box-sizing: border-box; | ||
| 1648 | + background-color: #fff; | ||
| 1649 | + cursor: pointer; | ||
| 1650 | +} | ||
| 1651 | + | ||
| 1652 | +.form-select:focus { | ||
| 1653 | + outline: none; | ||
| 1654 | + border-color: #007bff; | ||
| 1655 | + box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.2); | ||
| 1656 | +} | ||
| 1657 | + | ||
| 1259 | .form-actions { | 1658 | .form-actions { |
| 1260 | display: flex; | 1659 | display: flex; |
| 1261 | justify-content: flex-end; | 1660 | justify-content: flex-end; |
| ... | @@ -1337,13 +1736,16 @@ onMounted(() => { | ... | @@ -1337,13 +1736,16 @@ onMounted(() => { |
| 1337 | min-width: 0; | 1736 | min-width: 0; |
| 1338 | } | 1737 | } |
| 1339 | 1738 | ||
| 1739 | +/* 产品名称字段 - 占用最多空间(现在在第一位) */ | ||
| 1340 | .order-item .form-item:nth-child(1) { | 1740 | .order-item .form-item:nth-child(1) { |
| 1341 | - flex: 0 0 120px; | 1741 | + flex: 1 1 180px !important; |
| 1742 | + min-width: 120px !important; | ||
| 1743 | + max-width: 200px; | ||
| 1342 | } | 1744 | } |
| 1343 | 1745 | ||
| 1746 | +/* 产品编码字段 - 固定宽度(现在在第二位) */ | ||
| 1344 | .order-item .form-item:nth-child(2) { | 1747 | .order-item .form-item:nth-child(2) { |
| 1345 | - flex: 1 1 200px; | 1748 | + flex: 0 0 140px; |
| 1346 | - min-width: 150px; | ||
| 1347 | } | 1749 | } |
| 1348 | 1750 | ||
| 1349 | .order-item .form-item:nth-child(3) { | 1751 | .order-item .form-item:nth-child(3) { | ... | ... |
| ... | @@ -101,7 +101,7 @@ | ... | @@ -101,7 +101,7 @@ |
| 101 | <th>开票日期</th> | 101 | <th>开票日期</th> |
| 102 | <th>发票金额</th> | 102 | <th>发票金额</th> |
| 103 | <th>开票状态</th> | 103 | <th>开票状态</th> |
| 104 | - <th>上传时间</th> | 104 | + <th>开票时间</th> |
| 105 | <th>关联订单编号</th> | 105 | <th>关联订单编号</th> |
| 106 | <th>操作</th> | 106 | <th>操作</th> |
| 107 | </tr> | 107 | </tr> |
| ... | @@ -187,20 +187,20 @@ | ... | @@ -187,20 +187,20 @@ |
| 187 | <form @submit.prevent="handleSubmit"> | 187 | <form @submit.prevent="handleSubmit"> |
| 188 | <div class="form-row"> | 188 | <div class="form-row"> |
| 189 | <div class="form-item"> | 189 | <div class="form-item"> |
| 190 | - <label class="required">订单编号:</label> | 190 | + <label class="required">发票号码:</label> |
| 191 | <input | 191 | <input |
| 192 | - v-model="formData.orderNo" | 192 | + v-model="formData.invoiceNo" |
| 193 | class="form-input" | 193 | class="form-input" |
| 194 | - placeholder="请输入订单编号" | 194 | + placeholder="请输入发票号码" |
| 195 | required | 195 | required |
| 196 | /> | 196 | /> |
| 197 | </div> | 197 | </div> |
| 198 | <div class="form-item"> | 198 | <div class="form-item"> |
| 199 | - <label class="required">发票号码:</label> | 199 | + <label class="required">订单编号:</label> |
| 200 | <input | 200 | <input |
| 201 | - v-model="formData.invoiceNo" | 201 | + v-model="formData.orderNo" |
| 202 | class="form-input" | 202 | class="form-input" |
| 203 | - placeholder="请输入发票号码" | 203 | + placeholder="请输入订单编号" |
| 204 | required | 204 | required |
| 205 | /> | 205 | /> |
| 206 | </div> | 206 | </div> |
| ... | @@ -215,27 +215,28 @@ | ... | @@ -215,27 +215,28 @@ |
| 215 | /> | 215 | /> |
| 216 | </div> | 216 | </div> |
| 217 | <div class="form-item"> | 217 | <div class="form-item"> |
| 218 | - <label class="required">经销商编码:</label> | ||
| 219 | - <input | ||
| 220 | - v-model="formData.dealerCode" | ||
| 221 | - class="form-input" | ||
| 222 | - placeholder="请输入经销商编码" | ||
| 223 | - required | ||
| 224 | - /> | ||
| 225 | - </div> | ||
| 226 | - </div> | ||
| 227 | - <div class="form-row"> | ||
| 228 | - <div class="form-item"> | ||
| 229 | <label class="required">经销商名称:</label> | 218 | <label class="required">经销商名称:</label> |
| 230 | - <input | 219 | + <select |
| 231 | v-model="formData.dealerName" | 220 | v-model="formData.dealerName" |
| 232 | class="form-input" | 221 | class="form-input" |
| 233 | - placeholder="请输入经销商名称" | 222 | + @change="handleDealerChange" |
| 234 | required | 223 | required |
| 235 | - /> | 224 | + > |
| 225 | + <option value="">请选择经销商</option> | ||
| 226 | + <option | ||
| 227 | + v-for="dealer in dealerList" | ||
| 228 | + :key="dealer.dealerId" | ||
| 229 | + :value="dealer.dealerName" | ||
| 230 | + > | ||
| 231 | + {{ dealer.dealerName }} | ||
| 232 | + </option> | ||
| 233 | + </select> | ||
| 236 | </div> | 234 | </div> |
| 237 | </div> | 235 | </div> |
| 238 | <div class="form-row"> | 236 | <div class="form-row"> |
| 237 | + <input v-model="formData.dealerCode" type="hidden"/> | ||
| 238 | + </div> | ||
| 239 | + <div class="form-row"> | ||
| 239 | <div class="form-item"> | 240 | <div class="form-item"> |
| 240 | <label class="required">开票日期:</label> | 241 | <label class="required">开票日期:</label> |
| 241 | <input | 242 | <input |
| ... | @@ -292,6 +293,23 @@ | ... | @@ -292,6 +293,23 @@ |
| 292 | <div class="invoice-items-container"> | 293 | <div class="invoice-items-container"> |
| 293 | <div v-for="(item, index) in formData.invoiceItems" :key="index" class="invoice-item"> | 294 | <div v-for="(item, index) in formData.invoiceItems" :key="index" class="invoice-item"> |
| 294 | <div class="item-row-single"> | 295 | <div class="item-row-single"> |
| 296 | + <div class="form-item" style="flex: 1 1 200px; min-width: 150px;"> | ||
| 297 | + <label>产品名称:</label> | ||
| 298 | + <select | ||
| 299 | + v-model="item.productName" | ||
| 300 | + class="form-input" | ||
| 301 | + @change="handleProductChange(index)" | ||
| 302 | + > | ||
| 303 | + <option value="">请选择产品</option> | ||
| 304 | + <option | ||
| 305 | + v-for="product in productList" | ||
| 306 | + :key="product.productId" | ||
| 307 | + :value="product.productName" | ||
| 308 | + > | ||
| 309 | + {{ product.productName }} | ||
| 310 | + </option> | ||
| 311 | + </select> | ||
| 312 | + </div> | ||
| 295 | <div class="form-item" style="flex: 0 0 120px;"> | 313 | <div class="form-item" style="flex: 0 0 120px;"> |
| 296 | <label>产品编码:</label> | 314 | <label>产品编码:</label> |
| 297 | <input | 315 | <input |
| ... | @@ -300,14 +318,6 @@ | ... | @@ -300,14 +318,6 @@ |
| 300 | placeholder="产品编码" | 318 | placeholder="产品编码" |
| 301 | /> | 319 | /> |
| 302 | </div> | 320 | </div> |
| 303 | - <div class="form-item" style="flex: 1 1 200px; min-width: 150px;"> | ||
| 304 | - <label>产品名称:</label> | ||
| 305 | - <input | ||
| 306 | - v-model="item.productName" | ||
| 307 | - class="form-input" | ||
| 308 | - placeholder="产品名称" | ||
| 309 | - /> | ||
| 310 | - </div> | ||
| 311 | <div class="form-item" style="flex: 0 0 80px;"> | 321 | <div class="form-item" style="flex: 0 0 80px;"> |
| 312 | <label>数量:</label> | 322 | <label>数量:</label> |
| 313 | <input | 323 | <input |
| ... | @@ -460,8 +470,8 @@ | ... | @@ -460,8 +470,8 @@ |
| 460 | <table class="detail-table"> | 470 | <table class="detail-table"> |
| 461 | <thead> | 471 | <thead> |
| 462 | <tr> | 472 | <tr> |
| 463 | - <th>产品编码</th> | ||
| 464 | <th>产品名称</th> | 473 | <th>产品名称</th> |
| 474 | + <th>产品编码</th> | ||
| 465 | <th>数量</th> | 475 | <th>数量</th> |
| 466 | <th>单价</th> | 476 | <th>单价</th> |
| 467 | <th>金额</th> | 477 | <th>金额</th> |
| ... | @@ -471,8 +481,8 @@ | ... | @@ -471,8 +481,8 @@ |
| 471 | </thead> | 481 | </thead> |
| 472 | <tbody> | 482 | <tbody> |
| 473 | <tr v-for="item in invoiceDetail.invoiceItems" :key="item.invoiceItemId"> | 483 | <tr v-for="item in invoiceDetail.invoiceItems" :key="item.invoiceItemId"> |
| 474 | - <td>{{ item.productCode }}</td> | ||
| 475 | <td>{{ item.productName }}</td> | 484 | <td>{{ item.productName }}</td> |
| 485 | + <td>{{ item.productCode }}</td> | ||
| 476 | <td>{{ item.invoiceQty }}</td> | 486 | <td>{{ item.invoiceQty }}</td> |
| 477 | <td>{{ formatCurrency(item.unitPriceNoTax) }}</td> | 487 | <td>{{ formatCurrency(item.unitPriceNoTax) }}</td> |
| 478 | <td class="amount-text">{{ formatCurrency(item.amountNoTax) }}</td> | 488 | <td class="amount-text">{{ formatCurrency(item.amountNoTax) }}</td> |
| ... | @@ -508,6 +518,9 @@ | ... | @@ -508,6 +518,9 @@ |
| 508 | <script setup lang="ts"> | 518 | <script setup lang="ts"> |
| 509 | import { ref, reactive, computed, onMounted } from 'vue' | 519 | import { ref, reactive, computed, onMounted } from 'vue' |
| 510 | import { invoiceApi, type InvoiceInfo, type InvoiceQueryReq } from '../../api/invoice' | 520 | import { invoiceApi, type InvoiceInfo, type InvoiceQueryReq } from '../../api/invoice' |
| 521 | +import { dealerApi, type DealerInfo } from '../../api/dealer' | ||
| 522 | +import { productApi } from '../../api/product' | ||
| 523 | +import type { ProductSimpleRes } from '../../api/product' | ||
| 511 | 524 | ||
| 512 | // 响应式数据 | 525 | // 响应式数据 |
| 513 | const loading = ref(false) | 526 | const loading = ref(false) |
| ... | @@ -516,6 +529,8 @@ const showDialog = ref(false) | ... | @@ -516,6 +529,8 @@ const showDialog = ref(false) |
| 516 | const showDetailDialog = ref(false) | 529 | const showDetailDialog = ref(false) |
| 517 | const isEdit = ref(false) | 530 | const isEdit = ref(false) |
| 518 | const invoiceDetail = ref<InvoiceInfo | null>(null) | 531 | const invoiceDetail = ref<InvoiceInfo | null>(null) |
| 532 | +const dealerList = ref<DealerInfo[]>([]) | ||
| 533 | +const productList = ref<ProductSimpleRes[]>([]) | ||
| 519 | 534 | ||
| 520 | // 搜索参数 | 535 | // 搜索参数 |
| 521 | const searchParams = reactive({ | 536 | const searchParams = reactive({ |
| ... | @@ -950,6 +965,48 @@ const handleTableViewToggle = () => { | ... | @@ -950,6 +965,48 @@ const handleTableViewToggle = () => { |
| 950 | showMessage('视图切换功能开发中...', 'warning') | 965 | showMessage('视图切换功能开发中...', 'warning') |
| 951 | } | 966 | } |
| 952 | 967 | ||
| 968 | +// 加载经销商列表 | ||
| 969 | +const loadDealers = async () => { | ||
| 970 | + try { | ||
| 971 | + const response = await dealerApi.getAllDealers() as any | ||
| 972 | + if (response && response.data && Array.isArray(response.data)) { | ||
| 973 | + dealerList.value = response.data | ||
| 974 | + } | ||
| 975 | + } catch (error) { | ||
| 976 | + console.error('加载经销商列表失败:', error) | ||
| 977 | + showMessage('加载经销商列表失败', 'error') | ||
| 978 | + } | ||
| 979 | +} | ||
| 980 | + | ||
| 981 | +// 经销商选择变化处理 | ||
| 982 | +const handleDealerChange = () => { | ||
| 983 | + const selectedDealer = dealerList.value.find(dealer => dealer.dealerName === formData.dealerName) | ||
| 984 | + if (selectedDealer) { | ||
| 985 | + formData.dealerCode = selectedDealer.dealerCode | ||
| 986 | + } | ||
| 987 | +} | ||
| 988 | + | ||
| 989 | +// 加载产品列表 | ||
| 990 | +const loadProducts = async () => { | ||
| 991 | + try { | ||
| 992 | + const response = await productApi.getAllProducts() as any | ||
| 993 | + if (response && response.data && Array.isArray(response.data)) { | ||
| 994 | + productList.value = response.data | ||
| 995 | + } | ||
| 996 | + } catch (error) { | ||
| 997 | + console.error('加载产品列表失败:', error) | ||
| 998 | + showMessage('加载产品列表失败', 'error') | ||
| 999 | + } | ||
| 1000 | +} | ||
| 1001 | + | ||
| 1002 | +// 产品选择变化处理 | ||
| 1003 | +const handleProductChange = (index: number) => { | ||
| 1004 | + const selectedProduct = productList.value.find((product: ProductSimpleRes) => product.productName === formData.invoiceItems[index].productName) | ||
| 1005 | + if (selectedProduct) { | ||
| 1006 | + formData.invoiceItems[index].productCode = selectedProduct.productCode | ||
| 1007 | + } | ||
| 1008 | +} | ||
| 1009 | + | ||
| 953 | const closeDialog = () => { | 1010 | const closeDialog = () => { |
| 954 | showDialog.value = false | 1011 | showDialog.value = false |
| 955 | } | 1012 | } |
| ... | @@ -962,6 +1019,8 @@ const closeDetailDialog = () => { | ... | @@ -962,6 +1019,8 @@ const closeDetailDialog = () => { |
| 962 | // 生命周期 | 1019 | // 生命周期 |
| 963 | onMounted(() => { | 1020 | onMounted(() => { |
| 964 | fetchOrders() | 1021 | fetchOrders() |
| 1022 | + loadDealers() | ||
| 1023 | + loadProducts() | ||
| 965 | }) | 1024 | }) |
| 966 | </script> | 1025 | </script> |
| 967 | 1026 | ... | ... |
| ... | @@ -235,25 +235,25 @@ | ... | @@ -235,25 +235,25 @@ |
| 235 | /> | 235 | /> |
| 236 | </div> | 236 | </div> |
| 237 | <div class="form-item"> | 237 | <div class="form-item"> |
| 238 | - <label class="required">经销商编码:</label> | ||
| 239 | - <input | ||
| 240 | - v-model="formData.dealerCode" | ||
| 241 | - class="form-input" | ||
| 242 | - placeholder="请输入经销商编码" | ||
| 243 | - required | ||
| 244 | - /> | ||
| 245 | - </div> | ||
| 246 | - </div> | ||
| 247 | - <div class="form-row"> | ||
| 248 | - <div class="form-item"> | ||
| 249 | <label class="required">经销商名称:</label> | 238 | <label class="required">经销商名称:</label> |
| 250 | - <input | 239 | + <select |
| 251 | v-model="formData.dealerName" | 240 | v-model="formData.dealerName" |
| 252 | - class="form-input" | 241 | + class="form-select" |
| 253 | - placeholder="请输入经销商名称" | 242 | + @change="handleDealerChange" |
| 254 | required | 243 | required |
| 255 | - /> | 244 | + > |
| 245 | + <option value="">请选择经销商</option> | ||
| 246 | + <option | ||
| 247 | + v-for="dealer in dealerList" | ||
| 248 | + :key="dealer.dealerId" | ||
| 249 | + :value="dealer.dealerName" | ||
| 250 | + > | ||
| 251 | + {{ dealer.dealerName }} | ||
| 252 | + </option> | ||
| 253 | + </select> | ||
| 256 | </div> | 254 | </div> |
| 255 | + </div> | ||
| 256 | + <div class="form-row"> | ||
| 257 | <div class="form-item"> | 257 | <div class="form-item"> |
| 258 | <label class="required">订单日期:</label> | 258 | <label class="required">订单日期:</label> |
| 259 | <input | 259 | <input |
| ... | @@ -263,19 +263,19 @@ | ... | @@ -263,19 +263,19 @@ |
| 263 | required | 263 | required |
| 264 | /> | 264 | /> |
| 265 | </div> | 265 | </div> |
| 266 | - </div> | ||
| 267 | - <div class="form-row"> | ||
| 268 | <div class="form-item"> | 266 | <div class="form-item"> |
| 269 | - <label class="required">订单总金额:</label> | 267 | + <label>订单总金额:</label> |
| 270 | <input | 268 | <input |
| 271 | v-model.number="formData.totalAmount" | 269 | v-model.number="formData.totalAmount" |
| 272 | - class="form-input" | 270 | + class="form-input readonly" |
| 273 | type="number" | 271 | type="number" |
| 274 | step="0.01" | 272 | step="0.01" |
| 275 | - placeholder="请输入订单总金额" | 273 | + placeholder="自动计算" |
| 276 | - required | 274 | + readonly |
| 277 | /> | 275 | /> |
| 278 | </div> | 276 | </div> |
| 277 | + </div> | ||
| 278 | + <div class="form-row"> | ||
| 279 | <div class="form-item"> | 279 | <div class="form-item"> |
| 280 | <label>返利金额:</label> | 280 | <label>返利金额:</label> |
| 281 | <input | 281 | <input |
| ... | @@ -286,6 +286,11 @@ | ... | @@ -286,6 +286,11 @@ |
| 286 | placeholder="请输入返利金额" | 286 | placeholder="请输入返利金额" |
| 287 | /> | 287 | /> |
| 288 | </div> | 288 | </div> |
| 289 | + <!-- 经销商编码字段隐藏,通过选择经销商名称自动填充 --> | ||
| 290 | + <input | ||
| 291 | + v-model="formData.dealerCode" | ||
| 292 | + type="hidden" | ||
| 293 | + /> | ||
| 289 | </div> | 294 | </div> |
| 290 | </div> | 295 | </div> |
| 291 | 296 | ||
| ... | @@ -299,21 +304,30 @@ | ... | @@ -299,21 +304,30 @@ |
| 299 | <div v-for="(item, index) in formData.orderItems" :key="index" class="order-item"> | 304 | <div v-for="(item, index) in formData.orderItems" :key="index" class="order-item"> |
| 300 | <div class="item-row-single"> | 305 | <div class="item-row-single"> |
| 301 | <div class="form-item"> | 306 | <div class="form-item"> |
| 302 | - <label class="required">产品编码:</label> | 307 | + <label class="required">产品名称:</label> |
| 303 | - <input | 308 | + <select |
| 304 | - v-model="item.productCode" | 309 | + v-model="item.productName" |
| 305 | - class="form-input" | 310 | + class="form-select" |
| 306 | - placeholder="请输入产品编码" | 311 | + @change="handleProductChange(index)" |
| 307 | required | 312 | required |
| 308 | - /> | 313 | + > |
| 314 | + <option value="">请选择产品</option> | ||
| 315 | + <option | ||
| 316 | + v-for="product in productList" | ||
| 317 | + :key="product.productId" | ||
| 318 | + :value="product.productName" | ||
| 319 | + > | ||
| 320 | + {{ product.productName }} | ||
| 321 | + </option> | ||
| 322 | + </select> | ||
| 309 | </div> | 323 | </div> |
| 310 | <div class="form-item"> | 324 | <div class="form-item"> |
| 311 | - <label class="required">产品名称:</label> | 325 | + <label class="required">产品编码:</label> |
| 312 | <input | 326 | <input |
| 313 | - v-model="item.productName" | 327 | + v-model="item.productCode" |
| 314 | - class="form-input" | 328 | + class="form-input readonly" |
| 315 | - placeholder="请输入产品名称" | 329 | + placeholder="自动填充" |
| 316 | - required | 330 | + readonly |
| 317 | /> | 331 | /> |
| 318 | </div> | 332 | </div> |
| 319 | <div class="form-item"> | 333 | <div class="form-item"> |
| ... | @@ -343,9 +357,10 @@ | ... | @@ -343,9 +357,10 @@ |
| 343 | <label>明细金额:</label> | 357 | <label>明细金额:</label> |
| 344 | <input | 358 | <input |
| 345 | v-model.number="item.itemAmount" | 359 | v-model.number="item.itemAmount" |
| 346 | - class="form-input" | 360 | + class="form-input readonly" |
| 347 | type="number" | 361 | type="number" |
| 348 | step="0.01" | 362 | step="0.01" |
| 363 | + placeholder="自动计算" | ||
| 349 | readonly | 364 | readonly |
| 350 | /> | 365 | /> |
| 351 | </div> | 366 | </div> |
| ... | @@ -420,8 +435,8 @@ | ... | @@ -420,8 +435,8 @@ |
| 420 | <table class="detail-table"> | 435 | <table class="detail-table"> |
| 421 | <thead> | 436 | <thead> |
| 422 | <tr> | 437 | <tr> |
| 423 | - <th>产品编码</th> | ||
| 424 | <th>产品名称</th> | 438 | <th>产品名称</th> |
| 439 | + <th>产品编码</th> | ||
| 425 | <th>商品数量</th> | 440 | <th>商品数量</th> |
| 426 | <th>单价</th> | 441 | <th>单价</th> |
| 427 | <th>明细金额</th> | 442 | <th>明细金额</th> |
| ... | @@ -429,8 +444,8 @@ | ... | @@ -429,8 +444,8 @@ |
| 429 | </thead> | 444 | </thead> |
| 430 | <tbody> | 445 | <tbody> |
| 431 | <tr v-for="item in orderDetail.orderItems" :key="item.itemId"> | 446 | <tr v-for="item in orderDetail.orderItems" :key="item.itemId"> |
| 432 | - <td>{{ item.productCode }}</td> | ||
| 433 | <td>{{ item.productName }}</td> | 447 | <td>{{ item.productName }}</td> |
| 448 | + <td>{{ item.productCode }}</td> | ||
| 434 | <td>{{ item.productQty }}</td> | 449 | <td>{{ item.productQty }}</td> |
| 435 | <td>{{ formatCurrency(item.unitPrice) }}</td> | 450 | <td>{{ formatCurrency(item.unitPrice) }}</td> |
| 436 | <td>{{ formatCurrency(item.itemAmount) }}</td> | 451 | <td>{{ formatCurrency(item.itemAmount) }}</td> |
| ... | @@ -448,6 +463,9 @@ | ... | @@ -448,6 +463,9 @@ |
| 448 | <script setup lang="ts"> | 463 | <script setup lang="ts"> |
| 449 | import { ref, reactive, computed, onMounted } from 'vue' | 464 | import { ref, reactive, computed, onMounted } from 'vue' |
| 450 | import { orderApi, type OrderInfo, type OrderQueryReq, type OrderAddReq, type OrderUpdateReq, type OrderItemAddReq } from '../../api/order' | 465 | import { orderApi, type OrderInfo, type OrderQueryReq, type OrderAddReq, type OrderUpdateReq, type OrderItemAddReq } from '../../api/order' |
| 466 | +import { dealerApi, type DealerInfo } from '../../api/dealer' | ||
| 467 | +import { productApi } from '../../api/product' | ||
| 468 | +import type { ProductSimpleRes } from '../../api/product' | ||
| 451 | 469 | ||
| 452 | // 响应式数据 | 470 | // 响应式数据 |
| 453 | const loading = ref(false) | 471 | const loading = ref(false) |
| ... | @@ -457,6 +475,8 @@ const showDialog = ref(false) | ... | @@ -457,6 +475,8 @@ const showDialog = ref(false) |
| 457 | const showDetailDialog = ref(false) | 475 | const showDetailDialog = ref(false) |
| 458 | const isEdit = ref(false) | 476 | const isEdit = ref(false) |
| 459 | const orderDetail = ref<OrderInfo | null>(null) | 477 | const orderDetail = ref<OrderInfo | null>(null) |
| 478 | +const dealerList = ref<DealerInfo[]>([]) | ||
| 479 | +const productList = ref<ProductSimpleRes[]>([]) | ||
| 460 | 480 | ||
| 461 | // 搜索参数 | 481 | // 搜索参数 |
| 462 | const searchParams = reactive<OrderQueryReq>({ | 482 | const searchParams = reactive<OrderQueryReq>({ |
| ... | @@ -697,6 +717,15 @@ const handleEdit = async (order: OrderInfo) => { | ... | @@ -697,6 +717,15 @@ const handleEdit = async (order: OrderInfo) => { |
| 697 | verifyStatus: response.verifyStatus, | 717 | verifyStatus: response.verifyStatus, |
| 698 | orderItems: response.orderItems || [] | 718 | orderItems: response.orderItems || [] |
| 699 | }) | 719 | }) |
| 720 | + // 编辑时重新计算总金额,确保数据一致性 | ||
| 721 | + calculateTotalAmount() | ||
| 722 | + // 编辑时设置经销商编码(如果经销商名称已选择) | ||
| 723 | + if (formData.dealerName) { | ||
| 724 | + const selectedDealer = dealerList.value.find(dealer => dealer.dealerName === formData.dealerName) | ||
| 725 | + if (selectedDealer) { | ||
| 726 | + formData.dealerCode = selectedDealer.dealerCode | ||
| 727 | + } | ||
| 728 | + } | ||
| 700 | showDialog.value = true | 729 | showDialog.value = true |
| 701 | } else { | 730 | } else { |
| 702 | showMessage('获取订单详情失败', 'error') | 731 | showMessage('获取订单详情失败', 'error') |
| ... | @@ -802,10 +831,14 @@ const addOrderItem = () => { | ... | @@ -802,10 +831,14 @@ const addOrderItem = () => { |
| 802 | unitPrice: 0, | 831 | unitPrice: 0, |
| 803 | itemAmount: 0 | 832 | itemAmount: 0 |
| 804 | }) | 833 | }) |
| 834 | + // 重新计算总金额 | ||
| 835 | + calculateTotalAmount() | ||
| 805 | } | 836 | } |
| 806 | 837 | ||
| 807 | const removeOrderItem = (index: number) => { | 838 | const removeOrderItem = (index: number) => { |
| 808 | formData.orderItems.splice(index, 1) | 839 | formData.orderItems.splice(index, 1) |
| 840 | + // 重新计算总金额 | ||
| 841 | + calculateTotalAmount() | ||
| 809 | } | 842 | } |
| 810 | 843 | ||
| 811 | const calculateItemTotal = (index: number) => { | 844 | const calculateItemTotal = (index: number) => { |
| ... | @@ -813,6 +846,16 @@ const calculateItemTotal = (index: number) => { | ... | @@ -813,6 +846,16 @@ const calculateItemTotal = (index: number) => { |
| 813 | if (item.productQty && item.unitPrice) { | 846 | if (item.productQty && item.unitPrice) { |
| 814 | item.itemAmount = item.productQty * item.unitPrice | 847 | item.itemAmount = item.productQty * item.unitPrice |
| 815 | } | 848 | } |
| 849 | + // 重新计算订单总金额 | ||
| 850 | + calculateTotalAmount() | ||
| 851 | +} | ||
| 852 | + | ||
| 853 | +// 计算订单总金额 | ||
| 854 | +const calculateTotalAmount = () => { | ||
| 855 | + const total = formData.orderItems.reduce((sum, item) => { | ||
| 856 | + return sum + (item.itemAmount || 0) | ||
| 857 | + }, 0) | ||
| 858 | + formData.totalAmount = total | ||
| 816 | } | 859 | } |
| 817 | 860 | ||
| 818 | const handleSubmit = async () => { | 861 | const handleSubmit = async () => { |
| ... | @@ -874,6 +917,48 @@ const handleSubmit = async () => { | ... | @@ -874,6 +917,48 @@ const handleSubmit = async () => { |
| 874 | } | 917 | } |
| 875 | } | 918 | } |
| 876 | 919 | ||
| 920 | +// 经销商选择处理 | ||
| 921 | +const handleDealerChange = () => { | ||
| 922 | + const selectedDealer = dealerList.value.find(dealer => dealer.dealerName === formData.dealerName) | ||
| 923 | + if (selectedDealer) { | ||
| 924 | + formData.dealerCode = selectedDealer.dealerCode | ||
| 925 | + } | ||
| 926 | +} | ||
| 927 | + | ||
| 928 | +// 加载经销商列表 | ||
| 929 | +const loadDealers = async () => { | ||
| 930 | + try { | ||
| 931 | + const response = await dealerApi.getAllDealers() as any | ||
| 932 | + if (response && response.data && Array.isArray(response.data)) { | ||
| 933 | + dealerList.value = response.data | ||
| 934 | + } | ||
| 935 | + } catch (error) { | ||
| 936 | + console.error('加载经销商列表失败:', error) | ||
| 937 | + showMessage('加载经销商列表失败', 'error') | ||
| 938 | + } | ||
| 939 | +} | ||
| 940 | + | ||
| 941 | +// 产品选择处理 | ||
| 942 | +const handleProductChange = (index: number) => { | ||
| 943 | + const selectedProduct = productList.value.find((product: ProductSimpleRes) => product.productName === formData.orderItems[index].productName) | ||
| 944 | + if (selectedProduct) { | ||
| 945 | + formData.orderItems[index].productCode = selectedProduct.productCode | ||
| 946 | + } | ||
| 947 | +} | ||
| 948 | + | ||
| 949 | +// 加载产品列表 | ||
| 950 | +const loadProducts = async () => { | ||
| 951 | + try { | ||
| 952 | + const response = await productApi.getAllProducts() as any | ||
| 953 | + if (response && response.data && Array.isArray(response.data)) { | ||
| 954 | + productList.value = response.data | ||
| 955 | + } | ||
| 956 | + } catch (error) { | ||
| 957 | + console.error('加载产品列表失败:', error) | ||
| 958 | + showMessage('加载产品列表失败', 'error') | ||
| 959 | + } | ||
| 960 | +} | ||
| 961 | + | ||
| 877 | const closeDialog = () => { | 962 | const closeDialog = () => { |
| 878 | showDialog.value = false | 963 | showDialog.value = false |
| 879 | formData.orderItems = [] | 964 | formData.orderItems = [] |
| ... | @@ -887,6 +972,8 @@ const closeDetailDialog = () => { | ... | @@ -887,6 +972,8 @@ const closeDetailDialog = () => { |
| 887 | // 生命周期 | 972 | // 生命周期 |
| 888 | onMounted(() => { | 973 | onMounted(() => { |
| 889 | fetchOrders() | 974 | fetchOrders() |
| 975 | + loadDealers() | ||
| 976 | + loadProducts() | ||
| 890 | }) | 977 | }) |
| 891 | </script> | 978 | </script> |
| 892 | 979 | ||
| ... | @@ -1360,7 +1447,26 @@ onMounted(() => { | ... | @@ -1360,7 +1447,26 @@ onMounted(() => { |
| 1360 | border: 1px solid #ddd; | 1447 | border: 1px solid #ddd; |
| 1361 | border-radius: 4px; | 1448 | border-radius: 4px; |
| 1362 | font-size: 12px; | 1449 | font-size: 12px; |
| 1363 | - width: 200px; | 1450 | + width: 250px; |
| 1451 | + height: 32px; | ||
| 1452 | + box-sizing: border-box; | ||
| 1453 | +} | ||
| 1454 | + | ||
| 1455 | +.form-select { | ||
| 1456 | + background-color: #fff; | ||
| 1457 | + cursor: pointer; | ||
| 1458 | +} | ||
| 1459 | + | ||
| 1460 | +.form-select:focus { | ||
| 1461 | + outline: none; | ||
| 1462 | + border-color: #007bff; | ||
| 1463 | + box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25); | ||
| 1464 | +} | ||
| 1465 | + | ||
| 1466 | +.form-input.readonly { | ||
| 1467 | + background-color: #f5f5f5; | ||
| 1468 | + color: #666; | ||
| 1469 | + cursor: not-allowed; | ||
| 1364 | } | 1470 | } |
| 1365 | 1471 | ||
| 1366 | /* 订单明细中的输入框样式 - 优化空间利用 */ | 1472 | /* 订单明细中的输入框样式 - 优化空间利用 */ |
| ... | @@ -1378,30 +1484,38 @@ onMounted(() => { | ... | @@ -1378,30 +1484,38 @@ onMounted(() => { |
| 1378 | min-width: 0; | 1484 | min-width: 0; |
| 1379 | } | 1485 | } |
| 1380 | 1486 | ||
| 1381 | -/* 产品编码字段 */ | 1487 | +/* 产品名称字段 - 占用最多空间,增加长度(现在在第一位) */ |
| 1382 | .order-item .form-item:nth-child(1) { | 1488 | .order-item .form-item:nth-child(1) { |
| 1383 | - flex: 0 0 120px; | 1489 | + flex: 1.5 1 200px; |
| 1490 | + min-width: 150px; | ||
| 1384 | } | 1491 | } |
| 1385 | 1492 | ||
| 1386 | -/* 产品名称字段 - 占用更多空间 */ | 1493 | +/* 产品编码字段 - 固定宽度(现在在第二位),往左移动 */ |
| 1387 | .order-item .form-item:nth-child(2) { | 1494 | .order-item .form-item:nth-child(2) { |
| 1388 | - flex: 1 1 200px; | 1495 | + flex: 0 0 180px; |
| 1389 | - min-width: 150px; | 1496 | + margin-left: -15px; |
| 1390 | } | 1497 | } |
| 1391 | 1498 | ||
| 1392 | -/* 数量字段 */ | 1499 | +/* 产品编码输入框宽度调整为90% */ |
| 1500 | +.order-item .form-item:nth-child(2) .form-input { | ||
| 1501 | + width: 90%; | ||
| 1502 | +} | ||
| 1503 | + | ||
| 1504 | +/* 数量字段 - 较小宽度,往左移动 */ | ||
| 1393 | .order-item .form-item:nth-child(3) { | 1505 | .order-item .form-item:nth-child(3) { |
| 1394 | flex: 0 0 80px; | 1506 | flex: 0 0 80px; |
| 1507 | + margin-left: -10px; | ||
| 1395 | } | 1508 | } |
| 1396 | 1509 | ||
| 1397 | -/* 单价字段 */ | 1510 | +/* 单价字段 - 中等宽度,往左移动 */ |
| 1398 | .order-item .form-item:nth-child(4) { | 1511 | .order-item .form-item:nth-child(4) { |
| 1399 | - flex: 0 0 100px; | 1512 | + flex: 0 0 110px; |
| 1513 | + margin-left: -5px; | ||
| 1400 | } | 1514 | } |
| 1401 | 1515 | ||
| 1402 | -/* 明细金额字段 */ | 1516 | +/* 明细金额字段 - 中等宽度 */ |
| 1403 | .order-item .form-item:nth-child(5) { | 1517 | .order-item .form-item:nth-child(5) { |
| 1404 | - flex: 0 0 100px; | 1518 | + flex: 0 0 110px; |
| 1405 | } | 1519 | } |
| 1406 | 1520 | ||
| 1407 | .order-item .form-item label { | 1521 | .order-item .form-item label { |
| ... | @@ -1431,16 +1545,19 @@ onMounted(() => { | ... | @@ -1431,16 +1545,19 @@ onMounted(() => { |
| 1431 | .order-items-container { | 1545 | .order-items-container { |
| 1432 | border: 1px solid #eee; | 1546 | border: 1px solid #eee; |
| 1433 | border-radius: 4px; | 1547 | border-radius: 4px; |
| 1434 | - padding: 6px; | 1548 | + padding: 8px; |
| 1435 | background: #f8f9fa; | 1549 | background: #f8f9fa; |
| 1550 | + width: 100%; | ||
| 1436 | } | 1551 | } |
| 1437 | 1552 | ||
| 1438 | .order-item { | 1553 | .order-item { |
| 1439 | background: white; | 1554 | background: white; |
| 1440 | border: 1px solid #ddd; | 1555 | border: 1px solid #ddd; |
| 1441 | border-radius: 4px; | 1556 | border-radius: 4px; |
| 1442 | - padding: 6px; | 1557 | + padding: 8px; |
| 1443 | - margin-bottom: 6px; | 1558 | + margin-bottom: 8px; |
| 1559 | + width: 100%; | ||
| 1560 | + box-sizing: border-box; | ||
| 1444 | } | 1561 | } |
| 1445 | 1562 | ||
| 1446 | .order-item:last-child { | 1563 | .order-item:last-child { |
| ... | @@ -1461,22 +1578,28 @@ onMounted(() => { | ... | @@ -1461,22 +1578,28 @@ onMounted(() => { |
| 1461 | /* 单行布局 - 所有字段在一行显示,优化空间利用 */ | 1578 | /* 单行布局 - 所有字段在一行显示,优化空间利用 */ |
| 1462 | .item-row-single { | 1579 | .item-row-single { |
| 1463 | display: flex; | 1580 | display: flex; |
| 1464 | - gap: 4px; | 1581 | + gap: 8px; |
| 1465 | align-items: end; | 1582 | align-items: end; |
| 1466 | flex-wrap: nowrap; | 1583 | flex-wrap: nowrap; |
| 1467 | - justify-content: space-between; | 1584 | + width: 100%; |
| 1468 | } | 1585 | } |
| 1469 | 1586 | ||
| 1470 | .remove-item-btn { | 1587 | .remove-item-btn { |
| 1471 | - padding: 4px 8px; | 1588 | + padding: 6px 12px; |
| 1472 | background: #dc3545; | 1589 | background: #dc3545; |
| 1473 | color: white; | 1590 | color: white; |
| 1474 | border: none; | 1591 | border: none; |
| 1475 | border-radius: 4px; | 1592 | border-radius: 4px; |
| 1476 | cursor: pointer; | 1593 | cursor: pointer; |
| 1477 | font-size: 11px; | 1594 | font-size: 11px; |
| 1478 | - height: 28px; | 1595 | + height: 32px; |
| 1479 | align-self: end; | 1596 | align-self: end; |
| 1597 | + transition: background-color 0.2s; | ||
| 1598 | + flex-shrink: 0; | ||
| 1599 | +} | ||
| 1600 | + | ||
| 1601 | +.remove-item-btn:hover { | ||
| 1602 | + background: #c82333; | ||
| 1480 | } | 1603 | } |
| 1481 | 1604 | ||
| 1482 | .form-actions { | 1605 | .form-actions { | ... | ... |
-
Please register or login to post a comment