diff --git a/gear-admin/src/main/resources/application.yml b/gear-admin/src/main/resources/application.yml index 7d69357..6985b7f 100644 --- a/gear-admin/src/main/resources/application.yml +++ b/gear-admin/src/main/resources/application.yml @@ -70,7 +70,8 @@ spring: # 国际化资源文件路径 basename: i18n/messages profiles: - active: @profiles.active@ + active: prod +# @profiles.active@ # 文件上传 servlet: multipart: diff --git a/gear-mat/src/main/java/com/gear/mat/controller/MatProductAdditionController.java b/gear-mat/src/main/java/com/gear/mat/controller/MatProductAdditionController.java index 227fbd6..550bd97 100644 --- a/gear-mat/src/main/java/com/gear/mat/controller/MatProductAdditionController.java +++ b/gear-mat/src/main/java/com/gear/mat/controller/MatProductAdditionController.java @@ -11,6 +11,7 @@ import com.gear.mat.service.IMatProductAdditionService; import lombok.Data; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; +import java.util.Map; import java.util.List; /** @@ -37,6 +38,11 @@ public class MatProductAdditionController extends BaseController { List list = productAdditionService.listProductAddition(productAdditionBo); return TableDataInfo.build(list); } + + @PostMapping("/listByProductIds") + public R>> listByProductIds(@RequestBody List productIds) { + return R.ok(productAdditionService.listByProductIds(productIds)); + } /** * 新增产品属性附加表 diff --git a/gear-mat/src/main/java/com/gear/mat/controller/MatProductController.java b/gear-mat/src/main/java/com/gear/mat/controller/MatProductController.java index 3bdf0a5..70c5377 100644 --- a/gear-mat/src/main/java/com/gear/mat/controller/MatProductController.java +++ b/gear-mat/src/main/java/com/gear/mat/controller/MatProductController.java @@ -23,8 +23,13 @@ import com.gear.common.utils.poi.ExcelUtil; import com.gear.mat.domain.vo.MatProductVo; import com.gear.mat.domain.vo.MatProductWithMaterialsVo; import com.gear.mat.domain.bo.MatProductBo; +import com.gear.mat.domain.bo.MatProductImportBo; import com.gear.mat.service.IMatProductService; import com.gear.common.core.page.TableDataInfo; +import org.springframework.web.multipart.MultipartFile; + +import java.io.InputStream; +import java.util.Collections; /** * 产品基础信息 @@ -48,6 +53,14 @@ public class MatProductController extends BaseController { return iMatProductService.queryPageListWithMaterials(bo, pageQuery); } + /** + * 查询产品基础信息列表(不包含配料信息,用于列表页加速) + */ + @GetMapping("/listBase") + public TableDataInfo listBase(MatProductBo bo, PageQuery pageQuery) { + return iMatProductService.queryPageList(bo, pageQuery); + } + /** * 导出产品基础信息列表 */ @@ -58,6 +71,25 @@ public class MatProductController extends BaseController { ExcelUtil.exportExcel(list, "产品基础信息", MatProductVo.class, response); } + @RequestMapping(value = "/importTemplate", method = {RequestMethod.GET, RequestMethod.POST}) + public void importTemplate(HttpServletResponse response) { + ExcelUtil.exportExcel(Collections.singletonList(new MatProductImportBo()), "产品导入模板", MatProductImportBo.class, response); + } + + @Log(title = "产品基础信息", businessType = BusinessType.IMPORT) + @PostMapping("/importData") + public R importData(@RequestPart("file") MultipartFile file, + @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport) throws Exception { + if (file == null || file.isEmpty()) { + return R.fail("导入文件不能为空"); + } + try (InputStream is = file.getInputStream()) { + List list = ExcelUtil.importExcel(is, MatProductImportBo.class); + String msg = iMatProductService.importByExcel(list, updateSupport); + return R.ok(msg); + } + } + /** * 获取产品基础信息详细信息 * diff --git a/gear-mat/src/main/java/com/gear/mat/domain/bo/MatProductImportBo.java b/gear-mat/src/main/java/com/gear/mat/domain/bo/MatProductImportBo.java new file mode 100644 index 0000000..8fa5d42 --- /dev/null +++ b/gear-mat/src/main/java/com/gear/mat/domain/bo/MatProductImportBo.java @@ -0,0 +1,30 @@ +package com.gear.mat.domain.bo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * 产品导入模板对象 + */ +@Data +@ExcelIgnoreUnannotated +public class MatProductImportBo { + + @ExcelProperty("产品名称") + private String productName; + + @ExcelProperty("产品规格") + private String spec; + + @ExcelProperty("产品型号") + private String model; + + @ExcelProperty("产品单价") + private BigDecimal unitPrice; + + @ExcelProperty("备注") + private String remark; +} diff --git a/gear-mat/src/main/java/com/gear/mat/service/IMatProductAdditionService.java b/gear-mat/src/main/java/com/gear/mat/service/IMatProductAdditionService.java index 1ee23fd..0e22fcf 100644 --- a/gear-mat/src/main/java/com/gear/mat/service/IMatProductAdditionService.java +++ b/gear-mat/src/main/java/com/gear/mat/service/IMatProductAdditionService.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.service.IService; import com.gear.mat.domain.MatProductAddition; import com.gear.mat.domain.bo.MatProductAdditionBo; import com.gear.mat.domain.vo.MatProductAdditionVo; +import java.util.Map; import java.util.List; /** @@ -46,4 +47,6 @@ public interface IMatProductAdditionService extends IService boolean delProductAddition(Long addId); boolean batchSaveProductAddition(Long productId, List items); + + Map> listByProductIds(List productIds); } diff --git a/gear-mat/src/main/java/com/gear/mat/service/IMatProductService.java b/gear-mat/src/main/java/com/gear/mat/service/IMatProductService.java index f4c24ac..e10dc85 100644 --- a/gear-mat/src/main/java/com/gear/mat/service/IMatProductService.java +++ b/gear-mat/src/main/java/com/gear/mat/service/IMatProductService.java @@ -1,6 +1,7 @@ package com.gear.mat.service; import com.gear.mat.domain.MatProduct; +import com.gear.mat.domain.bo.MatProductImportBo; import com.gear.mat.domain.vo.MatProductVo; import com.gear.mat.domain.vo.MatProductWithMaterialsVo; import com.gear.mat.domain.bo.MatProductBo; @@ -52,4 +53,9 @@ public interface IMatProductService { * 校验并批量删除产品基础信息信息 */ Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * Excel导入产品基础信息 + */ + String importByExcel(List list, Boolean updateSupport); } diff --git a/gear-mat/src/main/java/com/gear/mat/service/impl/MatProductAdditionServiceImpl.java b/gear-mat/src/main/java/com/gear/mat/service/impl/MatProductAdditionServiceImpl.java index 8961219..5012957 100644 --- a/gear-mat/src/main/java/com/gear/mat/service/impl/MatProductAdditionServiceImpl.java +++ b/gear-mat/src/main/java/com/gear/mat/service/impl/MatProductAdditionServiceImpl.java @@ -10,7 +10,10 @@ import com.gear.mat.service.IMatProductAdditionService; import com.gear.common.utils.BeanCopyUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.HashMap; import java.util.Set; import java.util.stream.Collectors; @@ -105,4 +108,26 @@ public class MatProductAdditionServiceImpl extends ServiceImpl> listByProductIds(List productIds) { + if (productIds == null || productIds.isEmpty()) { + return Collections.emptyMap(); + } + List list = baseMapper.selectList(new LambdaQueryWrapper() + .in(MatProductAddition::getProductId, productIds) + .eq(MatProductAddition::getDelFlag, 0) + .orderByAsc(MatProductAddition::getProductId) + .orderByAsc(MatProductAddition::getAddId)); + + Map> result = new HashMap<>(); + for (MatProductAddition item : list) { + if (item == null || item.getProductId() == null) { + continue; + } + MatProductAdditionVo vo = BeanCopyUtils.copy(item, MatProductAdditionVo.class); + result.computeIfAbsent(item.getProductId(), k -> new java.util.ArrayList<>()).add(vo); + } + return result; + } } diff --git a/gear-mat/src/main/java/com/gear/mat/service/impl/MatProductServiceImpl.java b/gear-mat/src/main/java/com/gear/mat/service/impl/MatProductServiceImpl.java index 63f155c..925ccf6 100644 --- a/gear-mat/src/main/java/com/gear/mat/service/impl/MatProductServiceImpl.java +++ b/gear-mat/src/main/java/com/gear/mat/service/impl/MatProductServiceImpl.java @@ -7,6 +7,7 @@ import com.gear.common.core.domain.PageQuery; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.gear.mat.domain.bo.MatProductImportBo; import com.gear.mat.domain.bo.MatProductMaterialRelationBo; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -25,6 +26,7 @@ import com.gear.mat.domain.vo.MatProductMaterialRelationVo; import java.util.List; import java.util.Map; import java.util.Collection; +import java.util.Objects; import java.util.stream.Collectors; import java.util.ArrayList; @@ -210,4 +212,46 @@ public class MatProductServiceImpl implements IMatProductService { } return baseMapper.deleteBatchIds(ids) > 0; } + + @Override + public String importByExcel(List list, Boolean updateSupport) { + if (list == null || list.isEmpty()) { + return "导入数据为空"; + } + int success = 0; + int skipped = 0; + for (MatProductImportBo row : list) { + String productName = row == null ? null : StringUtils.trim(row.getProductName()); + String spec = row == null ? null : StringUtils.trim(row.getSpec()); + String model = row == null ? null : StringUtils.trim(row.getModel()); + if (StringUtils.isBlank(productName)) { + skipped++; + continue; + } + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(MatProduct::getProductName, productName) + .eq(MatProduct::getSpec, Objects.toString(spec, "")) + .eq(MatProduct::getModel, Objects.toString(model, "")) + .last("limit 1"); + MatProduct exist = baseMapper.selectOne(lqw); + if (exist != null && !Boolean.TRUE.equals(updateSupport)) { + skipped++; + continue; + } + + MatProduct data = exist == null ? new MatProduct() : exist; + data.setProductName(productName); + data.setSpec(spec); + data.setModel(model); + data.setUnitPrice(row.getUnitPrice()); + data.setRemark(row.getRemark()); + if (exist == null) { + baseMapper.insert(data); + } else { + baseMapper.updateById(data); + } + success++; + } + return "导入完成,成功 " + success + " 条,跳过 " + skipped + " 条"; + } } diff --git a/gear-oa/src/main/java/com/gear/oa/domain/vo/GearWageEntryDetailVo.java b/gear-oa/src/main/java/com/gear/oa/domain/vo/GearWageEntryDetailVo.java index 1ad4350..f4b3256 100644 --- a/gear-oa/src/main/java/com/gear/oa/domain/vo/GearWageEntryDetailVo.java +++ b/gear-oa/src/main/java/com/gear/oa/domain/vo/GearWageEntryDetailVo.java @@ -16,7 +16,6 @@ import java.util.Date; @ExcelIgnoreUnannotated public class GearWageEntryDetailVo { - @ExcelProperty(value = "明细ID") private Long detailId; @ExcelProperty(value = "业务日期") @@ -24,63 +23,49 @@ public class GearWageEntryDetailVo { @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") private Date entryDate; - @ExcelProperty(value = "员工ID") private Long empId; @ExcelProperty(value = "员工姓名") private String empName; - @ExcelProperty(value = "计费类型") private String billingType; - @ExcelProperty(value = "费率配置ID") private Long rateId; - @ExcelProperty(value = "工种") private String workTypeName; - @ExcelProperty(value = "加工物品") private String itemName; - @ExcelProperty(value = "工序") private String processName; - @ExcelProperty(value = "订单号") private String orderNo; - @ExcelProperty(value = "工作量") private BigDecimal workload; - @ExcelProperty(value = "单价") private BigDecimal unitPrice; - @ExcelProperty(value = "基础金额") private BigDecimal baseAmount; - @ExcelProperty(value = "额外金额") private BigDecimal extraAmount; - @ExcelProperty(value = "额外原因") private String extraReason; - @ExcelProperty(value = "明细计算金额") private BigDecimal calcAmount; private String calcDetail; - @ExcelProperty(value = "总金额") + @ExcelProperty(value = "每天工资") + private BigDecimal dailyWage; + + @ExcelProperty(value = "当天金额") private BigDecimal totalAmount; - @ExcelProperty(value = "是否补录") private String isMakeup; - @ExcelProperty(value = "补录责任人") private String makeupResponsible; - @ExcelProperty(value = "补录原因") private String makeupReason; - @ExcelProperty(value = "备注") private String remark; @ExcelProperty(value = "累计金额") private BigDecimal cumulativeAmount; diff --git a/gear-oa/src/main/java/com/gear/oa/service/impl/GearWageEntryDetailServiceImpl.java b/gear-oa/src/main/java/com/gear/oa/service/impl/GearWageEntryDetailServiceImpl.java index 3dc09e8..3c77fdb 100644 --- a/gear-oa/src/main/java/com/gear/oa/service/impl/GearWageEntryDetailServiceImpl.java +++ b/gear-oa/src/main/java/com/gear/oa/service/impl/GearWageEntryDetailServiceImpl.java @@ -51,6 +51,13 @@ public class GearWageEntryDetailServiceImpl implements IGearWageEntryDetailServi syncTodayWorkers(bo.getEntryDate()); LambdaQueryWrapper lqw = buildQueryWrapper(bo); Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + if (result != null && result.getRecords() != null) { + for (GearWageEntryDetailVo vo : result.getRecords()) { + if (vo != null) { + vo.setDailyWage(vo.getTotalAmount()); + } + } + } return TableDataInfo.build(result); } @@ -65,6 +72,13 @@ public class GearWageEntryDetailServiceImpl implements IGearWageEntryDetailServi syncTodayWorkers(bo.getEntryDate()); // 将 selectList 改为 selectVoList List list = baseMapper.selectVoList(buildQueryWrapper(bo)); + if (list != null) { + for (GearWageEntryDetailVo vo : list) { + if (vo != null) { + vo.setDailyWage(vo.getTotalAmount()); + } + } + } // 处理累计金额 if (bo.getCumulativeAmounts() != null) { for (GearWageEntryDetailVo vo : list) { diff --git a/gear-ui3/src/api/mat/product.js b/gear-ui3/src/api/mat/product.js index 88eba61..03cda72 100644 --- a/gear-ui3/src/api/mat/product.js +++ b/gear-ui3/src/api/mat/product.js @@ -9,6 +9,15 @@ export function listProduct(query) { }) } +// 查询产品基础信息列表(不包含配料信息,用于列表页加速) +export function listProductBase(query) { + return request({ + url: '/mat/product/listBase', + method: 'get', + params: query + }) +} + // 查询产品基础信息详细 export function getProduct(productId) { return request({ @@ -42,3 +51,21 @@ export function delProduct(productId) { method: 'delete' }) } + +// 下载导入模板 +export function importTemplateProduct() { + return request({ + url: '/mat/product/importTemplate', + method: 'post', + responseType: 'blob' + }) +} + +// 导入产品数据 +export function importProductData(data, updateSupport) { + return request({ + url: '/mat/product/importData?updateSupport=' + (updateSupport ? 1 : 0), + method: 'post', + data: data + }) +} diff --git a/gear-ui3/src/api/mat/productAddition.js b/gear-ui3/src/api/mat/productAddition.js index ba6e3fc..10b8f65 100644 --- a/gear-ui3/src/api/mat/productAddition.js +++ b/gear-ui3/src/api/mat/productAddition.js @@ -42,3 +42,11 @@ export function batchSaveProductAddition(data) { data }) } + +export function listProductAdditionByProductIds(productIds) { + return request({ + url: '/api/mat/productAddition/listByProductIds', + method: 'post', + data: productIds + }) +} diff --git a/gear-ui3/src/views/mat/product/detail.vue b/gear-ui3/src/views/mat/product/detail.vue index 60b2b6a..6012eca 100644 --- a/gear-ui3/src/views/mat/product/detail.vue +++ b/gear-ui3/src/views/mat/product/detail.vue @@ -47,8 +47,8 @@ - - + + - +
@@ -100,7 +100,14 @@
主材 / 辅材 / 工价
- 合计:{{ formatDecimal(totalAmount) }} 元 +
合计:{{ formatDecimal(totalAmount) }} 元
+
+ 主材:{{ formatDecimal(mainSubtotal) }} 元 + | + 辅材:{{ formatDecimal(auxiliarySubtotal) }} 元 + | + 工价:{{ formatDecimal(laborSubtotal) }} 元 +
@@ -187,6 +194,7 @@ const materialLoading = ref(false); const additionLoading = ref(false); const pdfFiles = ref([]); const pdfUrlFiles = ref([]); +const mediaTab = ref('images'); // 材料明细数据 const productMaterialRelationList = ref([]); @@ -222,15 +230,24 @@ const auxiliaryMaterials = computed(() => { })); }); -// 计算总金额 -const totalAmount = computed(() => { - const mainTotal = mainMaterials.value.reduce((sum, item) => sum + item.subtotal, 0); - const auxiliaryTotal = auxiliaryMaterials.value.reduce((sum, item) => sum + item.subtotal, 0); - const manualLaborTotal = productLaborList.value.reduce((sum, item) => { +const mainSubtotal = computed(() => { + return mainMaterials.value.reduce((sum, item) => sum + item.subtotal, 0); +}); + +const auxiliarySubtotal = computed(() => { + return auxiliaryMaterials.value.reduce((sum, item) => sum + item.subtotal, 0); +}); + +const laborSubtotal = computed(() => { + return productLaborList.value.reduce((sum, item) => { const price = item && item.laborPrice !== undefined && item.laborPrice !== null ? Number(item.laborPrice) : 0; return sum + (Number.isFinite(price) ? price : 0); }, 0); - return mainTotal + auxiliaryTotal + manualLaborTotal; +}); + +// 计算总金额 +const totalAmount = computed(() => { + return mainSubtotal.value + auxiliarySubtotal.value + laborSubtotal.value; }); const isOssIdList = (val) => { @@ -378,6 +395,9 @@ function downloadPdf(pdf) { } onMounted(() => { + if (String(route.query?.tab || '') === 'pdf') { + mediaTab.value = 'pdf'; + } getProductDetail(); }); @@ -505,10 +525,29 @@ onMounted(() => { } .total-badge { + display: flex; + flex-direction: column; + align-items: flex-end; + gap: 4px; font-weight: 600; color: #f56c6c; } +.total-main { + font-size: 14px; + line-height: 18px; +} + +.total-breakdown { + font-size: 12px; + line-height: 18px; + color: var(--el-text-color-secondary); +} + +.sep { + margin: 0 6px; +} + .cost-section { margin-top: 14px; } diff --git a/gear-ui3/src/views/mat/product/index.vue b/gear-ui3/src/views/mat/product/index.vue index 2dea80b..26512c6 100644 --- a/gear-ui3/src/views/mat/product/index.vue +++ b/gear-ui3/src/views/mat/product/index.vue @@ -27,7 +27,10 @@ 删除
- 导出 + 导入 + + + 导入模板 @@ -44,6 +47,30 @@ {{ formatDecimal(scope.row.unitPrice) }} + + + + +
+
+
说明书列表({{ manualFiles.length }})
+ + +
+ {{ item.name }} +
+
+
+
+ +