Administrator
2025-07-17 5837c5bfc1ee9a7251bd0218dedd33e00d55e546
feat(clothes): 添加订单打印功能

- 新增 AdminClothesPrintOrderDto 类用于订单打印- 在 ClothesTypeService 接口中添加 printOrder 方法
- 实现 ClothesTypeServiceImpl 中的 printOrder 方法,处理订单打印逻辑
- 在 AdminClothesTypeController 中添加 printOrder 接口
- 更新前端 orderList.html,实现订单打印功能
- 优化订单打印的样式和布局
11 files modified
1 files added
253 ■■■■ changed files
src/main/java/cc/mrbird/febs/common/configure/WebMvcConfigure.java 4 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/controller/clothes/AdminClothesTypeController.java 11 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/dto/clothes/AdminClothesPrintOrderDto.java 9 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/ClothesTypeService.java 2 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/ApiClothesSocialServiceImpl.java 12 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/ClothesTypeServiceImpl.java 91 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/vo/clothes/ApiAllCommentVo.java 3 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/vo/clothes/ApiClothesLocationRemarkVo.java 2 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/vo/clothes/ApiClothesPatternRemarkVo.java 2 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/vo/clothes/ApiClothesSocialMuseVo.java 6 ●●●●● patch | view | raw | blame | history
src/main/resources/mapper/modules/ClothesSocialCommentMapper.xml 9 ●●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/modules/clothesType/orderList.html 102 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/common/configure/WebMvcConfigure.java
@@ -41,5 +41,9 @@
        registration.excludePathPatterns("/api/happyActivity/voteOptionInPage");
        registration.excludePathPatterns("/api/happyActivity/voteActivityHot");
        registration.excludePathPatterns("/api/socialCircle/**");
        registration.excludePathPatterns("/api/clothes/social/allCategory");
        registration.excludePathPatterns("/api/clothes/social/indexCategory");
        registration.excludePathPatterns("/api/clothes/social/allSocial");
        registration.excludePathPatterns("/api/clothes/social/socialInfo");
    }
}
src/main/java/cc/mrbird/febs/mall/controller/clothes/AdminClothesTypeController.java
@@ -335,6 +335,17 @@
    /**
     * 订单列表-修改物流编号
     */
    @GetMapping("printOrder/{id}")
    @ControllerEndpoint(operation = "订单列表-修改物流编号", exceptionMessage = "操作失败")
    public FebsResponse printOrder(@NotNull(message = "{required}") @PathVariable Long id) {
        AdminClothesPrintOrderDto dto = new AdminClothesPrintOrderDto();
        dto.setId(id);
        return clothesTypeService.printOrder(dto);
    }
    /**
     * 订单列表-修改物流编号
     */
    @PostMapping("deliverGoodsUpdate")
    @ControllerEndpoint(operation = "订单列表-修改物流编号", exceptionMessage = "操作失败")
    public FebsResponse deliverGoodsUpdate(@Valid AdminClothesDeliverGoodsDto dto) {
src/main/java/cc/mrbird/febs/mall/dto/clothes/AdminClothesPrintOrderDto.java
New file
@@ -0,0 +1,9 @@
package cc.mrbird.febs.mall.dto.clothes;
import lombok.Data;
@Data
public class AdminClothesPrintOrderDto {
    private Long id;
}
src/main/java/cc/mrbird/febs/mall/service/ClothesTypeService.java
@@ -125,4 +125,6 @@
    List<ClothesArt> allArt(Long typeId);
    FebsResponse socialMuseUpdate(ClothesSocialMuse dto);
    FebsResponse printOrder(AdminClothesPrintOrderDto dto);
}
src/main/java/cc/mrbird/febs/mall/service/impl/ApiClothesSocialServiceImpl.java
@@ -125,7 +125,7 @@
                        Wrappers.lambdaQuery(ClothesSocialFollow.class)
                                .select(ClothesSocialFollow::getId, ClothesSocialFollow::getSourceId)
                                .in(ClothesSocialFollow::getSourceId, socialIds)
                                .eq(ClothesSocialFollow::getType, SocialTypeEnum.LIKE.getValue())
                                .eq(ClothesSocialFollow::getSourceType, SocialSourceTypeEnum.SOCIAL.getValue())
                );
                Map<Long, Long> likeCountBySocialIdMap = new HashMap<>();
@@ -240,10 +240,13 @@
                }
                apiSocialMuseVo.setTotalAmount(totalAmount.setScale(2, RoundingMode.DOWN));
                apiSocialInfoVo.setMuse(apiSocialMuseVo);
                List<ClothesSocialFollow> clothesSocialFollows = clothesSocialFollowMapper.selectList(
                        Wrappers.lambdaQuery(ClothesSocialFollow.class)
                                .select(ClothesSocialFollow::getType)
                                .eq(ClothesSocialFollow::getSourceId, socialId)
                                .eq(ClothesSocialFollow::getSourceType, SocialSourceTypeEnum.SOCIAL.getValue())
                );
                if (CollUtil.isNotEmpty(clothesSocialFollows)){
@@ -456,6 +459,7 @@
                    if(ObjectUtil.isNotNull(clothesSize)){
                        record.setSizeId(sizeId);
                        record.setSizeName(clothesSize.getName());
                        record.setSizeImage(clothesSize.getImage());
                        record.setSizePrice(clothesSize.getPrice());
                    }
                }
@@ -473,6 +477,7 @@
                    ApiClothesPatternRemarkVo vo = new ApiClothesPatternRemarkVo();
                    ClothesPattern pattern = clothesPatternMapper.selectById(patternRemark.getPatternId());
                    vo.setPatternName(pattern.getName());
                    vo.setPatternImage(pattern.getImage());
                    vo.setPatternPrice(pattern.getPrice());
                    vo.setPatternId(pattern.getId());
                    vo.setPatternRemark(patternRemark.getRemark());
@@ -497,6 +502,7 @@
                    ClothesLocation clothesLocation = clothesLocationMapper.selectById(locationRemark.getLocationId());
                    vo.setLocationName(clothesLocation.getName());
                    vo.setLocationRemark(locationRemark.getRemark());
                    vo.setLocationImage(clothesLocation.getImage());
                    vo.setLocationPrice(clothesLocation.getPrice());
                    vo.setLocationId(clothesLocation.getId());
                    locationRemarkList.add(vo);
@@ -514,6 +520,7 @@
                    ClothesArt clothesArt = clothesArtMapper.selectById(artId);
                    if (ObjectUtil.isNotNull(clothesArt)){
                        record.setArtId(artId);
                        record.setArtImage(clothesArt.getImage());
                        record.setArtName(clothesArt.getName());
                        record.setArtPrice(clothesArt.getPrice());
                    }
@@ -528,6 +535,7 @@
                    ClothesCloth clothesCloth = clothesClothMapper.selectById(clothId);
                    if (ObjectUtil.isNotNull(clothesCloth)){
                        record.setClothId(clothId);
                        record.setClothImage(clothesCloth.getImage());
                        record.setClothName(clothesCloth.getName());
                        record.setClothPrice(clothesCloth.getPrice());
                    }
@@ -566,7 +574,7 @@
        entity.setComment(dto.getComment());
        ClothesSocialComment clothesSocialComment = clothesSocialCommentMapper.selectById(commentId);
        if(ObjectUtil.isNotNull(clothesSocialComment)){
            entity.setParentId(clothesSocialComment.getParentId());
            entity.setParentId(clothesSocialComment.getId());
            entity.setCommentId(clothesSocialComment.getId());
        }
        clothesSocialCommentMapper.insert(entity);
src/main/java/cc/mrbird/febs/mall/service/impl/ClothesTypeServiceImpl.java
@@ -3,6 +3,7 @@
import cc.mrbird.febs.common.entity.FebsResponse;
import cc.mrbird.febs.common.entity.QueryRequest;
import cc.mrbird.febs.common.enumerates.*;
import cc.mrbird.febs.common.exception.FebsException;
import cc.mrbird.febs.common.properties.XcxProperties;
import cc.mrbird.febs.common.utils.SpringContextHolder;
import cc.mrbird.febs.common.utils.excl.ExcelSheetPO;
@@ -23,6 +24,7 @@
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@@ -41,6 +43,7 @@
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;
@@ -63,11 +66,13 @@
    private final ClothesTypePatternMapper clothesTypePatternMapper;
    private final ClothesTypeLocationMapper clothesTypeLocationMapper;
    private final ClothesOrderMapper clothesOrderMapper;
    private final ClothesOrderItemMapper clothesOrderItemMapper;
    private final MallExpressInfoMapper mallExpressInfoMapper;
    private final ClothesSocialMapper clothesSocialMapper;
    private final ClothesSocialFileMapper clothesSocialFileMapper;
    private final ClothesSocialMuseMapper clothesSocialMuseMapper;
    private final ClothesSocialCategoryMapper clothesSocialCategoryMapper;
    private final ClothesMemberStatureMapper clothesMemberStatureMapper;
    private final ClothesPatternRemarkMapper clothesPatternRemarkMapper;
    private final ClothesLocationRemarkMapper clothesLocationRemarkMapper;
@@ -1148,4 +1153,90 @@
        return new FebsResponse().success().message("操作成功");
    }
    @Override
    public FebsResponse printOrder(AdminClothesPrintOrderDto dto) {
        HashMap<String, Object> objectObjectHashMap = new HashMap<>();
        ClothesOrder order = clothesOrderMapper.selectById(dto.getId());
        if (ObjectUtil.isNotNull(order)){
            objectObjectHashMap.put("orderNo", order.getOrderNo());
        }
        ClothesType clothesType = clothesTypeMapper.selectById(order.getTypeId());
        if (ObjectUtil.isNotNull(clothesType)) {
            objectObjectHashMap.put("typeName", clothesType.getName());
            objectObjectHashMap.put("typeFront", clothesType.getImageFront());
            objectObjectHashMap.put("typeBack", clothesType.getImageBack());
        }
        List<ClothesOrderItem> clothesOrderItems = clothesOrderItemMapper.selectList(
                Wrappers.lambdaQuery(ClothesOrderItem.class)
                        .eq(ClothesOrderItem::getOrderId, order.getId())
        );
        if(CollUtil.isNotEmpty(clothesOrderItems)){
            for (ClothesOrderItem item : clothesOrderItems){
                if (ClothesOrderItemEnum.CLOTH.getCode() == item.getType()) {
                    ClothesCloth cloth = clothesClothMapper.selectById(item.getItemId());
                    if (ObjectUtil.isNotNull(cloth)) {
                        objectObjectHashMap.put("clothName", cloth.getName());
                        objectObjectHashMap.put("clothCode", cloth.getCode());
                    }
                    continue;
                } else if (ClothesOrderItemEnum.SIZE.getCode() == item.getType()) {
                    ClothesSize size = clothesSizeMapper.selectById(item.getItemId());
                    if (ObjectUtil.isNotNull(size)) {
                        objectObjectHashMap.put("sizeName", size.getName());
                        objectObjectHashMap.put("sizeCode", size.getCode());
                    }
                    continue;
                } else if (ClothesOrderItemEnum.LOCATION.getCode() == item.getType()) {
                    ClothesLocation location = clothesLocationMapper.selectById(item.getItemId());
                    if (ObjectUtil.isNotNull(location)) {
                        objectObjectHashMap.put("locationName", location.getName());
                        objectObjectHashMap.put("locationCode", location.getCode());
                        JSON parse = JSONUtil.parse(item.getRemark());
                        objectObjectHashMap.put("locationText", parse.getByPath("text", String.class));
                        objectObjectHashMap.put("locationImage", parse.getByPath("file", String.class));
                    }else{
                        objectObjectHashMap.put("locationName", "");
                        objectObjectHashMap.put("locationCode", "");
                        objectObjectHashMap.put("locationText", "");
                        objectObjectHashMap.put("locationImage", "");
                    }
                    continue;
                } else if (ClothesOrderItemEnum.PATTERN.getCode() == item.getType()) {
                    ClothesPattern pattern = clothesPatternMapper.selectById(item.getItemId());
                    if (ObjectUtil.isNotNull(pattern)) {
                        objectObjectHashMap.put("patternName", pattern.getName());
                        objectObjectHashMap.put("patternCode", pattern.getCode());
                        JSON parse = JSONUtil.parse(item.getRemark());
                        objectObjectHashMap.put("patternText", parse.getByPath("text", String.class));
                        objectObjectHashMap.put("patternImage", parse.getByPath("file", String.class));
                    }else{
                        objectObjectHashMap.put("patternName", "");
                        objectObjectHashMap.put("patternCode", "");
                        objectObjectHashMap.put("patternText", "");
                        objectObjectHashMap.put("patternImage", "");
                    }
                    continue;
                } else if (ClothesOrderItemEnum.ART.getCode() == item.getType()) {
                    ClothesArt art = clothesArtMapper.selectById(item.getItemId());
                    if (ObjectUtil.isNotNull(art)) {
                        objectObjectHashMap.put("artName", art.getName());
                        objectObjectHashMap.put("artCode", art.getCode());
                    }
                    continue;
                } else if (ClothesOrderItemEnum.CUSTOMIZE.getCode() == item.getType()) {
                    ClothesMemberStature clothesMemberStature = clothesMemberStatureMapper.selectById(item.getItemId());
                    if (ObjectUtil.isNotNull(clothesMemberStature)) {
                        objectObjectHashMap.put("statureName", clothesMemberStature.getName());
                    }
                    continue;
                } else {
                    continue;
                }
            }
        }
        return new FebsResponse().success().data(objectObjectHashMap);
    }
}
src/main/java/cc/mrbird/febs/mall/vo/clothes/ApiAllCommentVo.java
@@ -31,4 +31,7 @@
    @ApiModelProperty(value = "评论数量")
    private Integer commentCnt = 0;
    @ApiModelProperty(value = "点赞数量")
    private Integer likeCnt = 0;
}
src/main/java/cc/mrbird/febs/mall/vo/clothes/ApiClothesLocationRemarkVo.java
@@ -15,6 +15,8 @@
    private Long locationId;
    @ApiModelProperty(value = "反面图案名称")
    private String locationName;
    @ApiModelProperty(value = "反面图案")
    private String locationImage;
    @ApiModelProperty(value = "反面图案价格")
    private BigDecimal locationPrice = BigDecimal.ZERO;
    @ApiModelProperty(value = "反面自定义内容")
src/main/java/cc/mrbird/febs/mall/vo/clothes/ApiClothesPatternRemarkVo.java
@@ -15,6 +15,8 @@
    private Long patternId;
    @ApiModelProperty(value = "正面图案名称")
    private String patternName;
    @ApiModelProperty(value = "正面图案")
    private String patternImage;
    @ApiModelProperty(value = "正面图案价格")
    private BigDecimal patternPrice = BigDecimal.ZERO;
    @ApiModelProperty(value = "正面自定义内容")
src/main/java/cc/mrbird/febs/mall/vo/clothes/ApiClothesSocialMuseVo.java
@@ -28,6 +28,8 @@
    private Long artId;
    @ApiModelProperty(value = "工艺名称")
    private String artName;
    @ApiModelProperty(value = "工艺图片")
    private String artImage;
    @ApiModelProperty(value = "工艺价格")
    private BigDecimal artPrice = BigDecimal.ZERO;
@@ -35,6 +37,8 @@
    private Long sizeId;
    @ApiModelProperty(value = "尺码名称")
    private String sizeName;
    @ApiModelProperty(value = "尺码图片")
    private String sizeImage;
    @ApiModelProperty(value = "尺码价格")
    private BigDecimal sizePrice = BigDecimal.ZERO;
@@ -42,6 +46,8 @@
    private Long clothId;
    @ApiModelProperty(value = "布料名称")
    private String clothName;
    @ApiModelProperty(value = "布料图片")
    private String clothImage;
    @ApiModelProperty(value = "布料价格")
    private BigDecimal clothPrice = BigDecimal.ZERO;
src/main/resources/mapper/modules/ClothesSocialCommentMapper.xml
@@ -8,23 +8,24 @@
        b.avatar as memberAvatar,
        a.id as commentId,
        a.comment as comment,
               (select count(id) from clothes_social_follow where source_id = c.id and source_option_id = a.id and source_type = 2) as likeCnt,
        a.created_time as createdTime
        from clothes_social_comment a
        left join mall_member b on a.member_id = b.id
        left join clothes_social c on a.social_id = b.id
        left join clothes_social c on a.social_id = c.id
        <where>
            and a.show_state = 1
            and a.social_id = #{record.socialId}
            <if test="record != null">
                <if test="record.parentId != null">
                <if test="record.parentId != 0">
                    and a.parent_id = #{record.parentId}
                </if>
                <if test="record.parentId == null">
                <if test="record.parentId == 0">
                    and a.parent_id is null
                </if>
            </if>
        </where>
        order bya.created_time asc
        order by a.created_time desc
    </select>
    <select id="selectSocialCommentListInPage" resultType="cc.mrbird.febs.mall.vo.clothes.AdminClothesSocialCommentVo">
src/main/resources/templates/febs/views/modules/clothesType/orderList.html
@@ -171,7 +171,7 @@
                    febs.alert.warn('请选择订单');
                    return;
                }
                printSelect(data)
                printSelectData(ids)
            }
            if (layEvent === 'deliverGoods') {
@@ -300,7 +300,7 @@
                    febs.alert.warn('请选择待发货的订单');
                    return;
                }
                window.location.href = ctx + "admin/order/exportOrderList?ids="+ids;
                window.location.href = ctx + "admin/clothesType/exportOrderList?ids="+ids;
            }
        });
@@ -310,46 +310,100 @@
         * [自定义打印选中行数据]
         * @param  {[type]}  allData [传入选中行]
         */
        function printSelect(allData) {
       function printSelectData(allData) {
           let orderId = allData;
           console.log(orderId);
            $.ajax({
                url: '/admin/clothesType/printOrder/'+orderId,
                type: "get",
                contentType: 'application/json',
                success(res) {
                    console.log(res);
                    printSelect(res.data);
                },
                error(xhr, status, error) {
                    console.error("AJAX 请求失败:", error);
                    alert("请求失败,请重试");
                }
            });
        }
        function printSelect(data) {
            //用于包含内容
            var v = document.createElement("div");
            //页面头部,导入css  ,media="print"表示打印时使用该样式
            var f = ["<head>", "<style>", "div{font-size:8px;}", ".main{width:100%;}",
                ".main div{width:100%;display:inline-block;}", "</style>", "</head>"
            ].join("");
            var contentHtml = "";
            for (let i = 0; i < allData.length; i++) {
                let data = allData[i]
                var template =
                    "<div class='main'>" +
                    "<table cellspacing=\"0\" width=\"100%\" style=\"border-collapse: separate; border-spacing: 0px;\">" +
                    "<tr>" +
                    "<td style='width: 50%;'>" +
                    "<img src='" + data.img + "' style='width: 100%;'/>" +
                    "</td>" +
                    "<td style='width: 50%;'>" +
                    "<img src='" + data.img + "' style='width: 100%;'/>" +
                    "</td>" +
                    "</tr>" +
                    "</table>" +
                    "<div style='text-align: center;font-size: 10px;font-weight: bold;margin-bottom: 10px'>订单编号:" + data.orderNo + "</div>" +
                    "</div>"
            console.log(data);
            var template =
                "<div class='main'>" +
                "<div style='text-align: center;font-size: 30px;font-weight: bold;margin-bottom: 10px'>订单编号:" + data.orderNo + "</div>" +
                "<div style='font-size: 30px;font-weight: bold;'>类型:" + data.typeName + "</div>" +
                "<div style='font-size: 30px;font-weight: bold;'>布料:" + data.clothName + "</div>" +
                "<div style='font-size: 30px;font-weight: bold;'>编码:" + data.clothCode + "</div>" +
                "<div style='font-size: 30px;font-weight: bold;'>尺码:" + data.sizeName + "</div>" +
                "<div style='font-size: 30px;font-weight: bold;'>编码:" + data.sizeCode + "</div>" +
                "<div style='font-size: 30px;font-weight: bold;'>工艺:" + data.artName + "</div>" +
                "<div style='font-size: 30px;font-weight: bold;'>编码:" + data.artCode + "</div>" +
                "<div style='font-size: 30px;font-weight: bold;'>正面图案:" + data.patternName + "</div>" +
                "<div style='font-size: 30px;font-weight: bold;'>编码:" + data.patternCode + "</div>" +
                "<div style='font-size: 30px;font-weight: bold;'>文案:" + data.patternText + "</div>" +
                "<div class='print-images' style='font-size: 30px;font-weight: bold;'>图片:" +
                    "<img style='width: 200px; height: 200px; max-width: 80%; margin-top: 5px;' src="+ data.patternImage+">" +
                "</div>" +
                contentHtml += template;
            }
                "<div style='font-size: 30px;font-weight: bold;'>反面图案:" + data.locationName + "</div>" +
                "<div style='font-size: 30px;font-weight: bold;'>编码:" + data.locationCode + "</div>" +
                "<div style='font-size: 30px;font-weight: bold;'>文案:" + data.locationText + "</div>" +
                "<div class='print-images' style='font-size: 30px;font-weight: bold;'>图片:" +
                    "<img style='width: 200px; height: 200px; max-width: 80%; margin-top: 5px;' src="+ data.locationImage+">" +
                "</div>" +
                "<div class='print-images' style='font-size: 30px;font-weight: bold;'>正面:" +
                    "<img style='width: 200px; height: 200px; max-width: 80%; margin-top: 5px;' src="+ data.typeFront+">" +
                "</div>" +
                "<div class='print-images' style='font-size: 30px;font-weight: bold;'>反面:" +
                    "<img style='width: 200px; height: 200px; max-width: 80%; margin-top: 5px;' src="+ data.typeBack+">" +
                "</div>" +
                "</div>"
            //contentHtml为已拼凑好的内容
            $(v).append(contentHtml)
            v.innerHTML = template;
            //新建窗口
            var h = window.open("打印窗口", "_blank");
            //写入拼凑内容
            h.document.write(f + $(v).prop("outerHTML"));
            h.document.close();
            //在新窗口的 document 中查找图片
            ensureImagesLoaded(h.document, '.print-images img')
                .then(() => h.print())
                .catch(() => layer.msg('部分图片加载失败'));
            //调用打印
            h.print();
            //关闭页面
            h.close();
        }
        function ensureImagesLoaded(doc, selector) {
            var imgs = $(selector, doc); // 👈 在指定文档中查找
            var promises = [];
            imgs.each(function() {
                var img = this;
                var promise = new Promise(function(resolve, reject) {
                    if (img.complete && img.naturalWidth !== 0) {
                        resolve();
                    } else {
                        $(img).on('load', resolve).on('error', reject);
                    }
                });
                promises.push(promise);
            });
            return Promise.all(promises);
        }
        function refundOrder(id) {
            febs.get(ctx + 'admin/clothesType/refundOrder/' + id, null, function () {
                febs.alert.success('操作成功');