优化 产品导入导出

This commit is contained in:
yf 2025-10-21 10:44:22 +08:00
parent 88d5a41f5c
commit 9df51bddda
5 changed files with 189 additions and 33 deletions

View File

@ -95,7 +95,7 @@ public class ProductInfoController {
@Operation(summary = "产品信息导入模板")
public void importTemplate(HttpServletResponse response) throws IOException {
// 输出
ExcelUtils.write(response, "产品信息导入模板.xls", "产品信息", ProductInfoExcelVO.class, null);
ExcelUtils.write(response, "产品信息导入模板.xlsx", "产品信息", ProductInfoExcelVO.class, null);
}
@PostMapping("/import")
@Operation(summary = "导入生产制单")
@ -116,7 +116,7 @@ public class ProductInfoController {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<ProductInfoRespVO> list = productInfoService.getProductInfoPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "产品资料 .xls", "数据", ProductInfoRespVO.class,list);
ExcelUtils.write(response, "产品资料.xlsx", "数据", ProductInfoRespVO.class,list);
}
}

View File

@ -1,14 +1,17 @@
package cn.hangtag.module.oms.controller.admin.productinfo.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ContentStyle;
import com.alibaba.excel.annotation.write.style.HeadFontStyle;
import com.alibaba.excel.annotation.write.style.HeadStyle;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.IndexedColors;
/**
* 产品信息导入 Excel VO
@ -17,16 +20,48 @@ import java.time.LocalDateTime;
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = false) // 设置 chain = false避免数据导入有问题
@Accessors(chain = false) // 保持 chain = false 避免导入数据异常
public class ProductInfoExcelVO {
@ExcelProperty("产品编码")
@Schema(description = "产品编码")
@ExcelProperty("*产品编码")
@HeadFontStyle(color = Font.COLOR_RED)
private String code;
@ExcelProperty("产品名称")
@Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("*产品名称")
@HeadFontStyle(color = Font.COLOR_RED)
private String name;
@Schema(description = "产品简介")
@ExcelProperty("产品简介")
@HeadFontStyle(color = Font.COLOR_NORMAL)
private String introduction;
@Schema(description = "产品规格-宽")
@ExcelProperty("产品规格-宽")
@HeadFontStyle(color = Font.COLOR_NORMAL)
private String specWidth;
@Schema(description = "产品规格-高")
@ExcelProperty("产品规格-高")
private String specHeight;
@Schema(description = "产品规格-厚度")
@ExcelProperty("产品规格-厚度")
private String specThickness;
@Schema(description = "材质(颜色)")
@ExcelProperty("材质(颜色)")
private String material;
@Schema(description = "品牌名称")
@ExcelProperty("品牌名称")
private String brandName;
}
@Schema(description = "备注")
@ExcelProperty("备注")
private String remarks;
}

View File

@ -1,5 +1,6 @@
package cn.hangtag.module.oms.controller.admin.productinfo.vo;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
@ -15,7 +16,7 @@ import com.alibaba.excel.annotation.*;
@ExcelIgnoreUnannotated
public class ProductInfoRespVO {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "3187")
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "102")
@ExcelProperty("id")
private Long id;
@ -23,35 +24,32 @@ public class ProductInfoRespVO {
@ExcelProperty("产品编码")
private String code;
@Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
@Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "示例名称")
@ExcelProperty("产品名称")
private String name;
@Schema(description = "封面")
@ExcelProperty("封面")
@ColumnWidth(10)
private String cover;
@Schema(description = "品牌", example = "12523")
@ExcelProperty("品牌")
private Long brandId;
@Schema(description = "客户组别id oms_customer_group", example = "12523,1233")
private String customerGroupId;
@Schema(description = "客户组别 oms_customer_group name", example = "vip")
@ExcelProperty("客户组别")
private String customerGroupName;
@Schema(description = "产品类型id", example = "26002")
@ExcelProperty("产品类型id")
private Long productTypeId;
@Schema(description = "设计稿id", example = "29789")
@ExcelProperty("设计稿id")
private String draftDesignDataId;
@Schema(description = "设计稿列表")
@ExcelProperty("设计稿列表")
private String draftDesignList;
@Schema(description = "启用状态")
@ -73,10 +71,12 @@ public class ProductInfoRespVO {
@Schema(description = "详情介绍")
@ExcelProperty("详情介绍")
@ColumnWidth(100)
private String details;
@Schema(description = "简述")
@ExcelProperty("简述")
@ColumnWidth(60)
private String summary;
/**
@ -86,6 +86,9 @@ public class ProductInfoRespVO {
/**
* 默认售价
*/
@Schema(description = "默认售价")
@ExcelProperty("默认售价")
@ColumnWidth(60)
private BigDecimal sellingPrice;
/**
* 币种 字典 currency_type value

View File

@ -23,6 +23,8 @@ import cn.hangtag.module.oms.dal.mysql.productprocess.ProductProcessMapper;
import cn.hangtag.module.oms.serialnumber.CodingRulesUtils;
import cn.hangtag.module.oms.service.brand.BrandService;
import cn.hangtag.module.oms.service.draftdesigndata.DraftDesignDataService;
import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.LFUCache;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@ -185,7 +187,34 @@ public class ProductInfoServiceImpl implements ProductInfoService {
public PageResult<ProductInfoRespVO> getProductInfoPage(ProductInfoPageReqVO pageReqVO) {
PageResult<ProductInfoDO> productInfoDOPageResult = productInfoMapper.selectPage(pageReqVO);
List<ProductInfoDO> list = productInfoDOPageResult.getList();
List<ProductInfoRespVO> resList = wrapperRespVO(list);
List<ProductInfoRespVO> resList = new ArrayList<>();
Set<String> groupIds = new HashSet<>();
Set<Long> productTypeIds = new HashSet<>();
Set<Long> brandIds = new HashSet<>();
for (ProductInfoDO infoDO : list) {
String customerGroupId = infoDO.getCustomerGroupId();
if(FuncUtil.isNotEmpty(customerGroupId)){
groupIds.add(customerGroupId);
}
Long productTypeId = infoDO.getProductTypeId();
if(FuncUtil.isNotEmpty(productTypeId)){
productTypeIds.add(productTypeId);
}
Long brandId = infoDO.getBrandId();
if(FuncUtil.isNotEmpty(brandId)){
brandIds.add(brandId);
}
}
initBrandNameCache(brandIds);
initCustomerGroupNameCache(groupIds);
initProductTypeNameCache(productTypeIds);
list.forEach(productInfoDO -> {
ProductInfoRespVO vo = BeanUtils.toBean(productInfoDO, ProductInfoRespVO.class);
wrapperBrandName(vo);
wrapperProductTypeName(vo);
wrapperCustomerGroupName(vo);
resList.add(vo);
});
return new PageResult<>(resList, productInfoDOPageResult.getTotal());
}
@ -256,10 +285,20 @@ public class ProductInfoServiceImpl implements ProductInfoService {
}
private static LFUCache<String,Long> brandIdCache = CacheUtil.newLFUCache(10000, 1000 * 60 *30);
@Override
public String importExcel(List<ProductInfoExcelVO> list) {
List<ProductInfoDO> newList = new ArrayList<>();
LambdaQueryWrapper<BrandDO> brandDOLambdaQueryWrapper = new LambdaQueryWrapper<>();
brandDOLambdaQueryWrapper.select(BrandDO::getName,BrandDO::getId,BrandDO::getCode);
brandDOLambdaQueryWrapper.eq(BaseDO::getDeleted,false);
List<BrandDO> brandDOS = brandMapper.selectList(brandDOLambdaQueryWrapper);
for (BrandDO brandDO : brandDOS) {
brandIdCache.put(brandDO.getName(),brandDO.getId());
}
for (int i = 0; i < list.size(); i++) {
ProductInfoExcelVO excelVO = list.get(i);
ProductInfoDO productInfo = new ProductInfoDO();
@ -279,10 +318,17 @@ public class ProductInfoServiceImpl implements ProductInfoService {
productInfo.setCode(code);
productInfo.setTemplateType("2");
if(FuncUtil.isNotEmpty(brandName)){
BrandDO brandDO = brandService.getBrandByName(brandName);
if(FuncUtil.isNotEmpty(brandDO)){
productInfo.setBrandId(brandDO.getId());
Long brandId = brandIdCache.get(brandName);
if(FuncUtil.isNotEmpty(brandId)){
productInfo.setBrandId(brandId);
}else {
BrandDO brandDO = brandService.getBrandByName(brandName);
if(FuncUtil.isNotEmpty(brandDO)){
productInfo.setBrandId(brandDO.getId());
brandIdCache.put(brandName,brandDO.getId());
}
}
}
newList.add(productInfo);
}
@ -328,11 +374,44 @@ public class ProductInfoServiceImpl implements ProductInfoService {
}
return vo;
}
private static LFUCache<String, String> CustomerGroupNameCache = CacheUtil.newLFUCache(10000, 1000 * 60 * 60);
private ProductInfoRespVO wrapperCustomerGroupName(ProductInfoRespVO vo){
if(FuncUtil.isNotEmpty(vo)){
if(FuncUtil.isNotEmpty(vo.getCustomerGroupId())){
String s = CustomerGroupNameCache.get(vo.getCustomerGroupId());
if(FuncUtil.isNotEmpty(s)){
vo.setCustomerGroupName(s);
}else {
LambdaQueryWrapper<CustomerGroupDO> wrapper = new LambdaQueryWrapper<>();
wrapper.in(CustomerGroupDO::getId, FuncUtil.toStrList(vo.getCustomerGroupId()));
wrapper.eq(BaseDO::getDeleted,false);
List<CustomerGroupDO> groupDOS = customerGroupMapper.selectList(wrapper);
String name = null;
if(FuncUtil.isNotEmpty(groupDOS)){
List<String> names = new ArrayList<>();
for (CustomerGroupDO groupDO : groupDOS) {
if(names.contains(groupDO.getName())){
continue;
}
names.add(groupDO.getName());
}
name = String.join(",", names);
}
vo.setCustomerGroupName(name);
CustomerGroupNameCache.put(vo.getCustomerGroupId(), name);
}
}
}
return vo;
}
private void initCustomerGroupNameCache(Set<String> ids){
if (FuncUtil.isNotEmpty(ids)) {
for (String db : ids) {
LambdaQueryWrapper<CustomerGroupDO> wrapper = new LambdaQueryWrapper<>();
wrapper.in(CustomerGroupDO::getId, FuncUtil.toStrList(vo.getCustomerGroupId()));
wrapper.in(CustomerGroupDO::getId, FuncUtil.toStrList(db));
wrapper.eq(BaseDO::getDeleted,false);
List<CustomerGroupDO> groupDOS = customerGroupMapper.selectList(wrapper);
String name = null;
@ -346,31 +425,66 @@ public class ProductInfoServiceImpl implements ProductInfoService {
}
name = String.join(",", names);
}
vo.setCustomerGroupName(name);
CustomerGroupNameCache.put(db, name);
}
}
return vo;
}
private static LFUCache<Long, String> ProductTypeNameCache = CacheUtil.newLFUCache(10000, 1000 * 60 * 60);
private ProductInfoRespVO wrapperProductTypeName(ProductInfoRespVO vo){
if(FuncUtil.isNotEmpty(vo)){
if(FuncUtil.isNotEmpty(vo.getProductTypeId())){
ProductTypeDO productTypeDO = productTypeMapper.selectById(vo.getProductTypeId());
if(FuncUtil.isNotEmpty(productTypeDO)){
vo.setProductTypeName(productTypeDO.getLabel());
String s = ProductTypeNameCache.get(vo.getProductTypeId());
if (FuncUtil.isNotEmpty(s)){
vo.setProductTypeName(s);
}else {
ProductTypeDO productTypeDO = productTypeMapper.selectById(vo.getProductTypeId());
if(FuncUtil.isNotEmpty(productTypeDO)){
vo.setProductTypeName(productTypeDO.getLabel());
ProductTypeNameCache.put(vo.getProductTypeId(), vo.getProductTypeName());
}
}
}
}
return vo;
}
private void initProductTypeNameCache(Set<Long> ids){
if(FuncUtil.isNotEmpty(ids)){
List<ProductTypeDO> dos = productTypeMapper.selectBatchIds(ids);
for (ProductTypeDO db : dos) {
brandNameCache.put(db.getId(), db.getLabel());
}
}
}
private static LFUCache<Long, String> brandNameCache = CacheUtil.newLFUCache(10000, 1000 * 60 * 60);
private ProductInfoRespVO wrapperBrandName(ProductInfoRespVO vo){
if(FuncUtil.isNotEmpty(vo)){
if(FuncUtil.isNotEmpty(vo.getBrandId())){
BrandDO brandDO = brandMapper.selectById(vo.getBrandId());
if(FuncUtil.isNotEmpty(brandDO)){
vo.setBrandName(brandDO.getName());
String s = brandNameCache.get(vo.getBrandId());
if(FuncUtil.isNotEmpty(s)){
vo.setBrandName(s);
}else {
BrandDO brandDO = brandMapper.selectById(vo.getBrandId());
if(FuncUtil.isNotEmpty(brandDO)){
vo.setBrandName(brandDO.getName());
brandNameCache.put(vo.getBrandId(), brandDO.getName());
}
}
}
}
return vo;
}
private void initBrandNameCache(Set<Long> ids){
if(FuncUtil.isNotEmpty(ids)){
List<BrandDO> brandDOS = brandMapper.selectBatchIds(ids);
for (BrandDO brandDO : brandDOS) {
brandNameCache.put(brandDO.getId(), brandDO.getName());
}
}
}
}

View File

@ -199,6 +199,7 @@
import download from '@/utils/download'
import {ProductInfoApi, ProductInfoVO} from '@/api/oms/productinfo'
import ProductInfoForm from './ProductInfoForm.vue'
import ProductInfoExcelImport from './ProductInfoExcelImport.vue'
import {ProductTypeApi} from "@/api/base/producttype";
import {buildQuery} from "@/utils/queryUtil";
@ -288,10 +289,12 @@ const handleExport = async () => {
//
exportLoading.value = true
const data = await ProductInfoApi.exportProductInfo(queryParams)
download.excel(data, '产品资料 .xls')
download.excel(data, '产品资料.xlsx')
message.success('导出完成');
} catch {
} finally {
exportLoading.value = false
}
}
const previewDraftDesign = (id) => {
@ -342,6 +345,7 @@ const importSuccess = (res)=>{
const downloadTemplate = ()=>{
ProductInfoApi.downloadTemplate().then(res => {
download.excel(res, '产品导入模板.xlsx')
message.success("下载完成")
})
}
const handleImport = () => {