mitao
2025-04-10 7b184999cf6ed7eb6f5fd065d637a519a854385b
修改bug
16个文件已修改
555 ■■■■■ 已修改文件
cloud-server-activity/src/main/java/com/dsh/activity/controller/HuiminAgreementController.java 70 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-activity/src/main/java/com/dsh/activity/controller/PayHuiminController.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-activity/src/main/java/com/dsh/activity/entity/HuiminPayQuery.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-activity/src/main/java/com/dsh/activity/entity/THuiminAgreement.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-activity/src/main/java/com/dsh/activity/model/response/SalesDetailVO.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-activity/src/main/java/com/dsh/activity/service/impl/PayHuiminServiceImpl.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-activity/src/main/resources/mapper/PayHuiminMapper.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-management/src/main/java/com/dsh/course/feignClient/activity/PayHuiminClient.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-management/src/main/java/com/dsh/course/feignClient/activity/model/HuiminPayQuery.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-management/src/main/java/com/dsh/course/feignClient/activity/model/THuiminAgreement.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-management/src/main/java/com/dsh/course/feignClient/activity/model/THuiminAgreementSetting.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/code/THuiminAgreementController.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/code/TPayHuiminController.java 68 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-management/src/main/java/com/dsh/guns/modular/system/model/SalesDetailVO.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-management/src/main/webapp/WEB-INF/view/system/tHuiminAgreement/tHuiminAgreement_add.html 290 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-management/src/main/webapp/static/modular/system/tPayHuimin/tPayHuimin.js 50 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-activity/src/main/java/com/dsh/activity/controller/HuiminAgreementController.java
@@ -55,7 +55,7 @@
            //查询协议配置
            List<THuiminAgreementSetting> tHuiminAgreementSettingList = huiminAgreementSettingService.list(new LambdaQueryWrapper<THuiminAgreementSetting>()
                    .eq(THuiminAgreementSetting::getAgreementId, huiminAgreement.getId()));
            huiminAgreement.setTHuiminAgreementSettingList(tHuiminAgreementSettingList);
            huiminAgreement.setSettingList(tHuiminAgreementSettingList);
        }
        return huiminAgreement;
    }
@@ -67,40 +67,42 @@
    @Transactional(rollbackFor = Exception.class)
    public void insert(@RequestBody THuiminAgreement tHuiminAgreement){
        Integer operatorId = tHuiminAgreement.getOperatorId();
        if (tHuiminAgreement.getObjectType().equals(1)) {
            tHuiminAgreement.setOperatorId(null);
        }
        huiminAgreementService.saveOrUpdate(tHuiminAgreement);
        List<THuiminAgreementSetting> tHuiminAgreementSettingList = tHuiminAgreement.getTHuiminAgreementSettingList();
        if (CollUtil.isNotEmpty(tHuiminAgreementSettingList)) {
            if (tHuiminAgreement.getObjectType().equals(2) || tHuiminAgreement.getObjectType().equals(1) && Objects.isNull(operatorId)) {
                //删除之前的协议配置
                huiminAgreementSettingService.remove(new LambdaQueryWrapper<THuiminAgreementSetting>().eq(THuiminAgreementSetting::getAgreementId, tHuiminAgreement.getId()));
                //保存协议配置
                tHuiminAgreementSettingList.forEach(t -> {
                    t.setAgreementId(tHuiminAgreement.getId());
                });
                huiminAgreementSettingService.saveBatch(tHuiminAgreementSettingList);
            } else {
                THuiminAgreement agreement = huiminAgreementService.lambdaQuery()
                        .eq(THuiminAgreement::getOperatorId, operatorId)
                        .last("LIMIT 1").one();
                if (Objects.isNull(agreement)) {
                    agreement = new THuiminAgreement();
                    agreement.setOperatorId(operatorId);
                    huiminAgreementService.save(agreement);
                }
                //删除之前的协议配置
                huiminAgreementSettingService.remove(new LambdaQueryWrapper<THuiminAgreementSetting>()
                        .eq(THuiminAgreementSetting::getAgreementId, agreement.getId()));
                //保存协议配置
                THuiminAgreement finalAgreement = agreement;
                tHuiminAgreementSettingList.forEach(t -> {
                    t.setAgreementId(finalAgreement.getId());
                });
                huiminAgreementSettingService.saveBatch(tHuiminAgreementSettingList);
        //如果是平台账号,需要设置operatorId为null
        List<THuiminAgreementSetting> tHuiminAgreementSettingList = tHuiminAgreement.getSettingList();
        //如果是运营商账号或平台账号默认配置
        if (tHuiminAgreement.getObjectType().equals(2) || tHuiminAgreement.getObjectType().equals(1) && Objects.isNull(operatorId)) {
            if (tHuiminAgreement.getObjectType().equals(1)) {
                tHuiminAgreement.setOperatorId(null);
            }
            huiminAgreementService.saveOrUpdate(tHuiminAgreement);
            //删除之前的协议配置
            huiminAgreementSettingService.remove(new LambdaQueryWrapper<THuiminAgreementSetting>().eq(THuiminAgreementSetting::getAgreementId, tHuiminAgreement.getId()));
            //保存协议配置
            tHuiminAgreementSettingList.forEach(t -> {
                t.setAgreementId(tHuiminAgreement.getId());
            });
        } else {
            //平台配置运营商的协议配置
            THuiminAgreement agreement = huiminAgreementService.lambdaQuery()
                    .eq(THuiminAgreement::getOperatorId, operatorId)
                    .last("LIMIT 1").one();
            if (Objects.isNull(agreement)) {
                agreement = new THuiminAgreement();
                agreement.setOperatorId(operatorId);
            }
            agreement.setStoreNoHuiminCardIntro(tHuiminAgreement.getStoreNoHuiminCardIntro());
            huiminAgreementService.saveOrUpdate(agreement);
            //删除之前的协议配置
            huiminAgreementSettingService.remove(new LambdaQueryWrapper<THuiminAgreementSetting>()
                    .eq(THuiminAgreementSetting::getAgreementId, agreement.getId()));
            //保存协议配置
            THuiminAgreement finalAgreement = agreement;
            tHuiminAgreementSettingList.forEach(t -> {
                t.setAgreementId(finalAgreement.getId());
            });
        }
        if (CollUtil.isNotEmpty(tHuiminAgreementSettingList)) {
            huiminAgreementSettingService.saveBatch(tHuiminAgreementSettingList);
        }
    }
}
cloud-server-activity/src/main/java/com/dsh/activity/controller/PayHuiminController.java
@@ -5,9 +5,6 @@
import com.dsh.activity.entity.HuiminPayQuery;
import com.dsh.activity.model.response.SalesDetailVO;
import com.dsh.activity.service.PayHuiminService;
import com.dsh.activity.util.ResultUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -52,10 +49,10 @@
     * 退款惠民卡
     * @param id
     */
    @GetMapping("/base/tPayHuimin/refund/{id}")
    public ResultUtil<?> refund(@PathVariable("id") Integer id){
    @PostMapping("/base/tPayHuimin/refund")
    public void refund(Integer id){
        try {
            return payHuiminService.refund(id);
            payHuiminService.refund(id);
        } catch (AlipayApiException e) {
            throw new RuntimeException(e);
        }
cloud-server-activity/src/main/java/com/dsh/activity/entity/HuiminPayQuery.java
@@ -1,5 +1,6 @@
package com.dsh.activity.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
@@ -20,12 +21,16 @@
    
    // 时间范围
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date paymentTimeStart; // 支付时间-开始
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date paymentTimeEnd; // 支付时间-结束
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date endTimeStart;     // 结束时间-开始
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date endTimeEnd;     // 结束时间-结束
    // 状态查询
cloud-server-activity/src/main/java/com/dsh/activity/entity/THuiminAgreement.java
@@ -57,14 +57,13 @@
     */
    @TableField("storeNoHuiminCardIntro")
    @ApiModelProperty("门店无惠民卡介绍页")
    private String storeNoHuiminCardIntro;
    @TableField(exist = false)
    private Integer objectType;
    @TableField(exist = false)
    private List<THuiminAgreementSetting> tHuiminAgreementSettingList;
    private List<THuiminAgreementSetting> settingList;
    @Override
    protected Serializable pkVal() {
        return this.id;
cloud-server-activity/src/main/java/com/dsh/activity/model/response/SalesDetailVO.java
@@ -1,5 +1,6 @@
package com.dsh.activity.model.response;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
@@ -17,7 +18,7 @@
    // 关联信息
    private Integer operatorId;
    private String operatorName;        // 所属运营商
    private Integer storeId;
    private String storeIds;
    private String storeName;           // 可用门店
    private Integer appUserId;           // 购买用户ID
    private String userName;            // 购买用户
@@ -26,8 +27,10 @@
    // 时间信息
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date paymentTime;  // 购买时间[1,8](@ref)
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date endTime;      // 有效期
    // 使用信息
cloud-server-activity/src/main/java/com/dsh/activity/service/impl/PayHuiminServiceImpl.java
@@ -123,6 +123,23 @@
     */
    @Override
    public List<SalesDetailVO> exportData(HuiminPayQuery query) {
        return baseMapper.exportData(query);
        List<SalesDetailVO> records = baseMapper.exportData(query);
        if (CollUtil.isNotEmpty(records)){
            List<Integer> appUserIdList = records.stream().map(SalesDetailVO::getAppUserId).collect(Collectors.toList());
            List<AppUser> appUserList = appUserClient.queryAppUserBatch(appUserIdList);
            Map<Integer, AppUser> appUserMap = appUserList.stream().collect(Collectors.toMap(AppUser::getId, appUser -> appUser));
            records.forEach(item->{
                AppUser appUser = appUserMap.get(item.getAppUserId());
                if (Objects.nonNull(appUser)){
                    item.setUserName(appUser.getName());
                    item.setPhone(appUser.getPhone());
                }
                List<TStudent> studentList = studentClient.getStudentByIds(item.getStudentId());
                if (CollUtil.isNotEmpty(studentList)){
                    item.setStudentName(studentList.stream().map(TStudent::getName).collect(Collectors.joining(",")));
                }
            });
        }
        return records;
    }
}
cloud-server-activity/src/main/resources/mapper/PayHuiminMapper.xml
@@ -121,7 +121,7 @@
        thc.huiMinType,
        thc.salesMoney,
        thc.operatorId,
        thc.storeId,
        thc.storeIds,
        tph.appUserId,
        tph.paymentTime,
        thc.endTime,
@@ -136,7 +136,6 @@
        LEFT JOIN t_huimin_card thc ON tph.cardId = thc.id
        LEFT JOIN t_huimin_record thr ON tph.appUserId= thr.appUserId AND tph.cardId= thr.huiminCardId
        <where>
             tph.id IS NOT NULL
            <if test="query.huiMinName !=null and query.huiMinName != ''">
                AND thc.huiMinName LIKE CONCAT('%',#{query.huiMinName},'%')
            </if>
@@ -175,6 +174,7 @@
                </choose>
            </if>
        </where>
        GROUP BY tph.id
        ORDER BY tph.insertTime DESC
    </select>
</mapper>
cloud-server-management/src/main/java/com/dsh/course/feignClient/activity/PayHuiminClient.java
@@ -3,9 +3,7 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dsh.course.feignClient.activity.model.HuiminPayQuery;
import com.dsh.guns.modular.system.model.SalesDetailVO;
import com.dsh.guns.modular.system.util.ResultUtil;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -39,8 +37,8 @@
     * 退款惠民卡
     * @param id
     */
    @GetMapping("/base/tPayHuimin/refund/{id}")
    ResultUtil<?> refund(Integer id);
    @PostMapping("/base/tPayHuimin/refund")
    void refund(Integer id);
    @PostMapping("/base/tPayHuimin/export-data")
    List<SalesDetailVO> exportData(@RequestBody HuiminPayQuery query);
cloud-server-management/src/main/java/com/dsh/course/feignClient/activity/model/HuiminPayQuery.java
@@ -1,5 +1,6 @@
package com.dsh.course.feignClient.activity.model;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
@@ -20,12 +21,16 @@
    
    // 时间范围
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date paymentTimeStart; // 支付时间-开始
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date paymentTimeEnd; // 支付时间-结束
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date endTimeStart;     // 结束时间-开始
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date endTimeEnd;     // 结束时间-结束
    // 状态查询
cloud-server-management/src/main/java/com/dsh/course/feignClient/activity/model/THuiminAgreement.java
@@ -45,7 +45,7 @@
    private String agreementSettings;
    private List<THuiminAgreementSetting> tHuiminAgreementSettingList;
    private List<THuiminAgreementSetting> settingList;
    private Integer objectType;
    @Override
    protected Serializable pkVal() {
cloud-server-management/src/main/java/com/dsh/course/feignClient/activity/model/THuiminAgreementSetting.java
@@ -37,13 +37,11 @@
     * 协议名称
     */
    @TableField("agreementName")
    @JSONField(name = "title")
    private String agreementName;
    /**
     *协议内容
     */
    @TableField("agreementContent")
    @JSONField(name = "content")
    private String agreementContent;
    @Override
cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/code/THuiminAgreementController.java
@@ -60,7 +60,6 @@
        THuiminAgreement huiminAgreement = huiminAgreementClient.selectByObjectType(huiminAgreementQuery);
        model.addAttribute("objectType", objectType);
        model.addAttribute("item", huiminAgreement);
        model.addAttribute("tHuiminAgreementSettingList", Objects.nonNull(huiminAgreement) ? JSONArray.toJSONString(huiminAgreement.getTHuiminAgreementSettingList()) : "");
        //查询运营商列表
        model.addAttribute("operatorList", operatorService.list(new QueryWrapper<TOperator>().eq("state", 1)));
        model.addAttribute("operatorId", operatorId);
@@ -72,23 +71,18 @@
        tHuiminAgreement.setObjectType(UserExt.getUser().getObjectType());
        String agreementSettings = tHuiminAgreement.getAgreementSettings();
        List<THuiminAgreementSetting> tHuiminAgreementSettings = JSONArray.parseArray(agreementSettings, THuiminAgreementSetting.class);
        tHuiminAgreement.setTHuiminAgreementSettingList(tHuiminAgreementSettings);
        tHuiminAgreement.setSettingList(tHuiminAgreementSettings);
        huiminAgreementClient.insert(tHuiminAgreement);
        return SUCCESS_TIP;
    }
    @RequestMapping(value = "/selectAgreementByOperationId")
    @ResponseBody
    public ResultUtil<String> selectAgreementByOperationId(Integer operatorId) {
        String tHuiminAgreementSettings = "";
    public ResultUtil<THuiminAgreement> selectAgreementByOperationId(Integer operatorId) {
        HuiminAgreementQuery huiminAgreementQuery = new HuiminAgreementQuery();
        huiminAgreementQuery.setOperatorId(operatorId);
        huiminAgreementQuery.setObjectType(Objects.isNull(operatorId) ? 1 : 2);
        THuiminAgreement huiminAgreement = huiminAgreementClient.selectByObjectType(huiminAgreementQuery);
        if (Objects.nonNull(huiminAgreement)) {
            //查询协议配置
            tHuiminAgreementSettings = JSONArray.toJSONString(huiminAgreement.getTHuiminAgreementSettingList());
        }
        return ResultUtil.success(tHuiminAgreementSettings);
        return ResultUtil.success(huiminAgreement);
    }
/*
    *//**
cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/code/TPayHuiminController.java
@@ -8,6 +8,7 @@
import com.dsh.course.feignClient.activity.PayHuiminClient;
import com.dsh.course.feignClient.activity.model.HuiminPayQuery;
import com.dsh.course.feignClient.activity.model.TPayHuimin;
import com.dsh.guns.config.UserExt;
import com.dsh.guns.core.base.controller.BaseController;
import com.dsh.guns.core.common.constant.factory.PageFactory;
import com.dsh.guns.modular.system.model.AppUserByNameAndPhoneDTO;
@@ -25,7 +26,7 @@
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@@ -33,6 +34,7 @@
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -67,8 +69,20 @@
     */
    @RequestMapping("")
    public String index(Model model) {
        Integer objectType = UserExt.getUser().getObjectType();
        Integer operatorId = null;
        if (objectType.equals(2)){
            //查询运营商
            TOperator operator = operatorService.getOne(new QueryWrapper<TOperator>()
                    .eq("userId", UserExt.getUser().getId())
                    .ne("state", 3)
                    .last("LIMIT 1"));
            if (Objects.nonNull(operator)) {
                operatorId = operator.getId();
            }
        }
        //查询运营商列表
        model.addAttribute("operatorList", operatorService.list(new QueryWrapper<TOperator>().eq("state", 1)));
        model.addAttribute("operatorList", operatorService.list(new QueryWrapper<TOperator>().eq(Objects.nonNull(operatorId), "id",operatorId).eq("state", 1)));
        model.addAttribute("storeList", storeService.list(new QueryWrapper<TStore>().eq("state", 1)));
        return PREFIX + "tPayHuimin.html";
    }
@@ -87,6 +101,17 @@
    @RequestMapping(value = "/list")
    @ResponseBody
    public Object list(HuiminPayQuery query) {
        Integer objectType = UserExt.getUser().getObjectType();
        if (objectType.equals(2)){
            //查询运营商
            TOperator operator = operatorService.getOne(new QueryWrapper<TOperator>()
                    .eq("userId", UserExt.getUser().getId())
                    .ne("state", 3)
                    .last("LIMIT 1"));
            if (Objects.nonNull(operator)) {
                query.setOperatorId(Long.valueOf(operator.getId()));
            }
        }
        Page<TPayHuimin> tPayHuiminPage = new PageFactory<TPayHuimin>().defaultPage();
        query.setCurrent(tPayHuiminPage.getCurrent());
        query.setSize(tPayHuiminPage.getSize());
@@ -110,16 +135,20 @@
            List<Integer> operatorIdList = records.stream()
                    .map(SalesDetailVO::getOperatorId)
                    .collect(Collectors.toList());
            List<Integer> storeIdList = records.stream()
                    .map(SalesDetailVO::getStoreId)
                    .collect(Collectors.toList());
            Map<Integer, String> operatorMap = operatorService.listByIds(operatorIdList).stream()
                    .collect(Collectors.toMap(TOperator::getId, TOperator::getName));
            Map<Integer, String> storeMap = storeService.listByIds(storeIdList).stream()
            Map<Integer, String> storeMap = storeService.list().stream()
                    .collect(Collectors.toMap(TStore::getId, TStore::getName));
            records.forEach(item->{
                item.setOperatorName(operatorMap.getOrDefault(item.getOperatorId(),""));
                item.setStoreName(storeMap.getOrDefault(item.getStoreId(),""));
                StringBuilder sb = new StringBuilder();
                Arrays.stream(item.getStoreIds().split(",")).map(Integer::parseInt).forEach(s->{
                    sb.append( storeMap.getOrDefault(s, ""));
                    sb.append(",");
                });
                //sb去除最后一个逗号
                sb.deleteCharAt(sb.length() - 1);
                item.setStoreName(sb.toString());
            });
        }
        return super.packForBT(salesDetailVOPage);
@@ -159,10 +188,11 @@
     * @param id
     * @return
     */
    @GetMapping("/refund/{id}")
    @PostMapping("/refund")
    @ResponseBody
    public ResultUtil<?> refund(@PathVariable("id") Integer id) {
        return payHuiminClient.refund(id);
    public ResultUtil<?> refund(Integer id) {
         payHuiminClient.refund(id);
        return ResultUtil.success();
    }
    /**
@@ -177,16 +207,20 @@
            List<Integer> operatorIdList = records.stream()
                    .map(SalesDetailVO::getOperatorId)
                    .collect(Collectors.toList());
            List<Integer> storeIdList = records.stream()
                    .map(SalesDetailVO::getStoreId)
                    .collect(Collectors.toList());
            Map<Integer, String> operatorMap = operatorService.listByIds(operatorIdList).stream()
                    .collect(Collectors.toMap(TOperator::getId, TOperator::getName));
            Map<Integer, String> storeMap = storeService.listByIds(storeIdList).stream()
            Map<Integer, String> storeMap = storeService.list().stream()
                    .collect(Collectors.toMap(TStore::getId, TStore::getName));
            records.forEach(item -> {
                item.setOperatorName(operatorMap.getOrDefault(item.getOperatorId(), ""));
                item.setStoreName(storeMap.getOrDefault(item.getStoreId(), ""));
            records.forEach(item->{
                item.setOperatorName(operatorMap.getOrDefault(item.getOperatorId(),""));
                StringBuilder sb = new StringBuilder();
                Arrays.stream(item.getStoreIds().split(",")).map(Integer::parseInt).forEach(s->{
                    sb.append( storeMap.getOrDefault(s, ""));
                    sb.append(",");
                });
                //sb去除最后一个逗号
                sb.deleteCharAt(sb.length() - 1);
                item.setStoreName(sb.toString());
            });
        }
        String[] titleArr = {"惠民卡名称", "惠民卡类型", "售卖金额", "所属运营商", "可用门店", "购买用户", "联系电话", "购买时间", "绑定人员", "已用次数", "有效期", "状态"};
cloud-server-management/src/main/java/com/dsh/guns/modular/system/model/SalesDetailVO.java
@@ -1,5 +1,6 @@
package com.dsh.guns.modular.system.model;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
@@ -17,7 +18,7 @@
    // 关联信息
    private Integer operatorId;
    private String operatorName;        // 所属运营商
    private Integer storeId;
    private String storeIds;
    private String storeName;           // 可用门店
    private Integer appUserId;           // 购买用户ID
    private String userName;            // 购买用户
@@ -25,8 +26,10 @@
    
    // 时间信息
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date paymentTime;  // 购买时间[1,8](@ref)
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date endTime;      // 有效期
    
    // 使用信息
cloud-server-management/src/main/webapp/WEB-INF/view/system/tHuiminAgreement/tHuiminAgreement_add.html
@@ -14,21 +14,11 @@
                            <div id="tab-1" class="tab-pane active">
                                <div class="panel-body">
                                    <textarea id="editor_1" type="text/plain" style="width:1200px;height:400px;">${item.addUserRemark!}</textarea>
                                    <!--<div class="row btn-group-m-t">
                                        <div class="col-sm-10 col-sm-offset-5">
                                            <#button btnCss="info" name="保存" id="ensure" icon="fa-check" clickFun=""/>
                                        </div>
                                    </div>-->
                                </div>
                            </div>
                            <div id="tab-2" class="tab-pane">
                                <div class="panel-body">
                                    <textarea type="text/plain" id="editor_2" style="width:1200px;height:400px;"${item.selectUserRemark!}</textarea>
                                    <!--<div class="row btn-group-m-t">
                                        <div class="col-sm-10">
                                            <#button btnCss="info" name="保存" id="ensure" icon="fa-check" clickFun=""/>
                                        </div>
                                    </div>-->
                                </div>
                            </div>
                        </div>
@@ -108,6 +98,12 @@
        editor_2 = UE.getEditor('editor_2');
        editor_3 = UE.getEditor('editor_3');
        // 改用全局方法处理删除
        window.deleteTab = function(counter) {
            console.log("全局删除方法被调用,counter =", counter);
            deleteEditor(parseInt(counter));
        };
        // 绑定添加按钮的点击事件
        $("#agreementAdd").click(function() {
            var title = $("#agreement").val().trim();
@@ -123,27 +119,91 @@
            $("#agreement").val("");
        });
        
        //协议配置回显
        let settingList = '${tHuiminAgreementSettingList}';
        if (settingList != "" && typeof settingList != "undefined"){
            let settingArr = JSON.parse(settingList);
            review(settingArr);
        }
        // 确保编辑器初始化完成后再获取数据
        editor_3.ready(function() {
            console.log("编辑器初始化完成,准备加载数据");
            // 页面初始化时通过AJAX请求获取协议配置数据
            var operatorId = $("#operator").val();
            console.log("页面初始化,当前运营商ID:", operatorId);
            // 调用接口获取协议配置数据(只回显协议配置,不回显门店无惠民卡介绍页)
            var ajax = new $ax(Feng.ctxPath + "/tHuiminAgreement/selectAgreementByOperationId", function(data){
                console.log("获取到的惠民卡数据:", data);
                if (data.data != null){
                    // 只更新协议配置
                    if (data.data.settingList && data.data.settingList.length > 0) {
                        console.log("协议配置数据:", data.data.settingList);
                        review(data.data.settingList);
                    }
                }
            },function(data){
                console.error("获取惠民卡数据失败:", data);
                Feng.error("获取惠民卡数据失败!");
            });
            ajax.set("operatorId", operatorId);
            ajax.start();
        });
        
        //经营商切换事件
        $("#operator").change(function() {
            console.log("运营商切换事件触发,选择的运营商ID:", $("#operator").val());
            // 先主动清空编辑器内容
            if(editor_3 && editor_3.body) {
                editor_3.setContent("");
                console.log("主动清空门店无惠民卡介绍页内容");
            }
            //清空协议配置
            removeAll()
            removeAll();
            //调用接口获取协议配置数据
            //提交信息
            var ajax = new $ax(Feng.ctxPath + "/tHuiminAgreement/selectAgreementByOperationId", function(data){
                if (data.data != "" && data.data != null){
                    console.log("协议配置数据:"+data.data);
                    let settingArr = JSON.parse(data.data);
                    review(settingArr);
                console.log("获取到的惠民卡数据:", data);
                if (data.data != null){
                    // 更新门店无惠民卡介绍页内容
                    try {
                        var introContent = "";
                        // 严格判断内容是否存在且非空
                        if(data.data.storeNoHuiminCardIntro !== null &&
                           data.data.storeNoHuiminCardIntro !== undefined &&
                           data.data.storeNoHuiminCardIntro !== "") {
                            introContent = data.data.storeNoHuiminCardIntro;
                        }
                        // 确保编辑器实例存在且已初始化
                        if(editor_3 && editor_3.body) {
                            // 设置编辑器内容(空内容会清空编辑器)
                            editor_3.setContent(introContent);
                            console.log("已更新门店无惠民卡介绍页内容:", introContent ? "有内容" : "内容为空");
                        } else {
                            console.error("编辑器未准备好,无法设置内容");
                            // 延迟设置内容
                            setTimeout(function() {
                                try {
                                    if(editor_3) {
                                        editor_3.setContent(introContent);
                                        console.log("延迟更新门店无惠民卡介绍页内容成功");
                                    }
                                } catch(e) {
                                    console.error("延迟设置编辑器内容出错:", e);
                                }
                            }, 1000);
                        }
                    } catch(e) {
                        console.error("设置编辑器内容出错:", e);
                    }
                    // 更新协议配置
                    if (data.data.settingList && data.data.settingList.length > 0) {
                        console.log("协议配置数据:", data.data.settingList);
                        review(data.data.settingList);
                    }
                }
            },function(data){
                console.error("获取惠民卡数据失败:", data);
                Feng.error("获取惠民卡数据失败!");
            });
            ajax.set("operatorId",$("#operator").val());
            ajax.start();
@@ -180,7 +240,15 @@
    function review(settingArr){
        if (typeof settingArr !== 'undefined' && settingArr.length > 0) {
            settingArr.forEach(function(item) {
                addNewEditor(item.title, item.content || "");
                // 详细记录每个配置项
                console.log("处理协议配置项:", item);
                // 获取标题和内容,兼容不同字段名
                var title = item.agreementName || item.title || "";
                var content = item.agreementContent || item.content || "";
                console.log("使用标题:", title, "内容长度:", content.length, "内容前20字符:", content.substring(0, 20));
                addNewEditor(title, content);
            });
        }
    }
@@ -188,8 +256,11 @@
    // 添加新的编辑器函数 - 修改为接受内容参数
    function addNewEditor(title, content) {
        editorCounter++;
        var editorId = "dynamic-editor-" + editorCounter;
        var tabId = "agreement-tab-" + editorCounter;
        // 立即捕获当前counter值,防止闭包问题
        var currentCounter = editorCounter;
        var editorId = "dynamic-editor-" + currentCounter;
        var tabId = "agreement-tab-" + currentCounter;
        var isFirstTab = (dynamicEditors.length === 0);
        
        // 如果是第一个编辑器,显示tabs容器
@@ -202,10 +273,15 @@
        $("#agreement-content .tab-pane").removeClass("active");
        
        // 创建新的Tab - 始终设置为激活状态
        var tabHtml = '<li class="active" id="tab-li-' + editorCounter + '">' +
                      '<a data-toggle="tab" href="#' + tabId + '" aria-expanded="true">' + title +
                      ' <i class="fa fa-times-circle delete-tab" data-editor-id="' + editorId + '" ' +
                      'data-tab-id="' + tabId + '" data-counter="' + editorCounter + '"></i></a></li>';
        // 修改删除按钮DOM结构,确保按钮在标题右侧
        var tabHtml = '<li class="active" id="tab-li-' + currentCounter + '" style="position:relative;">' +
                      '<a data-toggle="tab" href="#' + tabId + '" aria-expanded="true" style="padding-right:25px;">' + title + '</a>' +
                      '<span onclick="deleteTab(' + currentCounter + ')" ' +
                      'style="position:absolute;right:5px;top:10px;cursor:pointer;color:#f00;z-index:100;">' +
                      '<i class="fa fa-times-circle"></i></span></li>';
        // 记录创建的按钮信息,辅助调试
        console.log("创建删除按钮, counter =", currentCounter, "title =", title);
        
        // 创建Tab内容 - 始终设置为激活状态
        var contentHtml = '<div id="' + tabId + '" class="tab-pane active">' +
@@ -226,90 +302,134 @@
            autoFloatEnabled: false
        });
        
        // 确保编辑器已准备好
        editor.ready(function() {
            try {
                // 检查编辑器是否已准备好接收内容
                if(editor.body) {
                    // 初始化内容
                    editor.setContent(content || "");
                } else {
                    // 如果编辑器body未准备好,延迟设置内容
                    setTimeout(function() {
                        try {
                            editor.setContent(content || "");
                        } catch(e) {
                            console.error("延迟设置编辑器内容出错:", e);
                        }
                    }, 500);
        // 确保编辑器已准备好,使用立即执行函数捕获当前counter值
        (function(capturedCounter, editorId, tabId, titleText, contentText) {
            editor.ready(function() {
                try {
                    // 检查编辑器是否已准备好接收内容
                    if(editor.body) {
                        // 初始化内容
                        editor.setContent(contentText || "");
                    } else {
                        // 如果编辑器body未准备好,延迟设置内容
                        setTimeout(function() {
                            try {
                                editor.setContent(contentText || "");
                            } catch(e) {
                                console.error("延迟设置编辑器内容出错:", e);
                            }
                        }, 500);
                    }
                    // 存储编辑器实例和标题信息,使用捕获的counter
                    dynamicEditors.push({
                        id: editorId,
                        tabId: tabId,
                        counter: capturedCounter,  // 使用捕获的值,而不是外部变量
                        title: titleText,
                        editor: editor,
                        content: contentText || ""
                    });
                    console.log("编辑器准备完成,添加到dynamicEditors,counter =", capturedCounter);
                    // 不再需要在这里绑定事件,因为已经使用事件委托
                } catch(e) {
                    console.error("编辑器初始化出错:", e);
                }
                // 存储编辑器实例和标题信息
                dynamicEditors.push({
                    id: editorId,
                    tabId: tabId,
                    counter: editorCounter,
                    title: title,
                    editor: editor,
                    content: content || ""
                });
                // 绑定删除按钮事件
                $(".delete-tab[data-editor-id='" + editorId + "']").click(function(e) {
                    e.preventDefault();
                    e.stopPropagation();
                    deleteEditor($(this).data("counter"));
                });
            } catch(e) {
                console.error("编辑器初始化出错:", e);
            }
        });
            });
        })(currentCounter, editorId, tabId, title, content);
        
        // 手动激活新添加的标签页
        $('#agreement-tabs a[href="#' + tabId + '"]').tab('show');
    }
    // 删除编辑器函数
    // 删除编辑器函数 - 优化标签页激活逻辑
    function deleteEditor(counter) {
        // 确保counter是整数
        counter = parseInt(counter);
        var index = -1;
        var isActive = $("#tab-li-" + counter).hasClass("active");
        var nextActive = null;
        
        // 输出当前所有编辑器的counter值,辅助调试
        console.log("当前所有编辑器的counter值:", dynamicEditors.map(function(item) { return item.counter; }));
        console.log("完整的dynamicEditors数组:", JSON.stringify(dynamicEditors.map(function(item) {
            return {
                counter: item.counter,
                title: item.title,
                tabId: item.tabId,
                id: item.id
            };
        })));
        // 查找编辑器索引
        for(var i = 0; i < dynamicEditors.length; i++) {
            if(dynamicEditors[i].counter == counter) {
            console.log("检查编辑器", i, "counter =", dynamicEditors[i].counter, "要删除的counter =", counter);
            // 使用严格的整数比较
            if(parseInt(dynamicEditors[i].counter) === counter) {
                index = i;
                break;
            }
        }
        
        if(index === -1) return;
        // 销毁编辑器实例
        if(dynamicEditors[index].editor) {
            dynamicEditors[index].editor.destroy();
        if(index === -1) {
            console.error("找不到要删除的编辑器:", counter);
            // 尝试遍历DOM查找是否存在该元素
            console.log("尝试检查DOM元素是否存在:", "#tab-li-" + counter);
            console.log("DOM元素存在:", $("#tab-li-" + counter).length > 0);
            return;
        }
        
        // 如果删除的是当前活跃tab,需要激活另一个tab
        console.log("删除编辑器", counter, "索引:", index, "是否当前活跃:", isActive);
        // 确定删除后需要激活哪个标签页
        if(isActive && dynamicEditors.length > 1) {
            // 优先选择下一个,如果没有则选择上一个
            if(index < dynamicEditors.length - 1) {
                nextActive = dynamicEditors[index + 1].tabId;
                console.log("将激活下一个标签页:", nextActive);
            } else {
                nextActive = dynamicEditors[index - 1].tabId;
                console.log("将激活上一个标签页:", nextActive);
            }
        }
        
        // 完全清理DOM元素
        $("#tab-li-" + counter).remove();
        $("#" + dynamicEditors[index].tabId).remove();
        // 如果是当前活跃标签,先激活另一个标签,再删除当前标签
        if(isActive && nextActive) {
            try {
                console.log("先激活其他标签页:", nextActive);
                $('a[href="#' + nextActive + '"]').tab('show');
            } catch(e) {
                console.error("激活其他标签页失败:", e);
            }
        }
        
        // 确保UEditor容器被完全移除
        $("#" + dynamicEditors[index].id).parents(".edui-default").remove();
        $("#" + dynamicEditors[index].id).remove();
        // 销毁编辑器实例
        try {
            if(dynamicEditors[index].editor) {
                dynamicEditors[index].editor.destroy();
            }
        } catch(e) {
            console.error("销毁编辑器出错:", e);
        }
        // 完全清理DOM元素
        try {
            $("#tab-li-" + counter).remove();
            $("#" + dynamicEditors[index].tabId).remove();
            // 确保UEditor容器被完全移除
            $("#" + dynamicEditors[index].id).parents(".edui-default").remove();
            $("#" + dynamicEditors[index].id).remove();
        } catch(e) {
            console.error("清理DOM元素出错:", e);
        }
        
        // 从数组中移除
        dynamicEditors.splice(index, 1);
        console.log("删除后的编辑器列表:", dynamicEditors.map(function(item) { return item.title; }));
        
        // 如果没有编辑器了,清空并隐藏tabs容器
        if(dynamicEditors.length === 0) {
@@ -317,10 +437,8 @@
            // 彻底清空容器内容,确保没有残留
            $("#agreement-tabs").empty();
            $("#agreement-content").empty();
        } else if(nextActive) {
            // 激活下一个tab
            $('a[href="#' + nextActive + '"]').tab('show');
        }
        // 不再需要这个逻辑,因为我们在删除前已经激活了其他标签
    }
    
    //收集动态编辑器内容
@@ -340,11 +458,13 @@
                content = dynamicEditors[i].content || "";
            }
            
            // 使用与后端一致的字段名
            agreements.push({
                title: dynamicEditors[i].title,
                content: content
                agreementName: dynamicEditors[i].title,
                agreementContent: content
            });
        }
        console.log("收集到的协议配置数据:", agreements);
        return agreements;
    };
cloud-server-management/src/main/webapp/static/modular/system/tPayHuimin/tPayHuimin.js
@@ -22,20 +22,46 @@
                }},
            {title: '售卖金额', field: 'salesMoney', visible: true, align: 'center', valign: 'middle'},
            {title: '所属运营商', field: 'operatorName', visible: true, align: 'center', valign: 'middle'},
            {title: '可用门店', field: 'storeName', visible: true, align: 'center', valign: 'middle'},
            {title: '可用门店', field: 'storeName', visible: true, align: 'center', valign: 'middle',
                cellStyle:formatTableUnit,
                formatter :paramsMatter
            },
            {title: '购买用户', field: 'userName', visible: true, align: 'center', valign: 'middle'},
            {title: '联系电话', field: 'phone', visible: true, align: 'center', valign: 'middle'},
            {title: '购买时间', field: 'paymentTime', visible: true, align: 'center', valign: 'middle'},
            {title: '绑定人员', field: 'studentName', visible: true, align: 'center', valign: 'middle'},
            {title: '已用次数', field: 'useTimes', visible: true, align: 'center', valign: 'middle'},
            {title: '有效期', field: 'endTime', visible: true, align: 'center', valign: 'middle'},
            {title: '有效期', field: 'endTime', visible: true, align: 'center', valign: 'middle',formatter:function(value,row,index){
                if (!value){
                    return "永久";
                }else {
                    return value;
                }
                }},
            {title: '状态', field: 'status', visible: true, align: 'center', valign: 'middle',
                formatter:function(value,row,index){
                    return {2: '使用中', 3: '已退款'}[value];
                }}
    ];
};
//表格超出宽度鼠标悬停显示td内容
function paramsMatter(value,row,index) {
    var span=document.createElement("span");
    span.setAttribute("title",value);
    span.innerHTML = value;
    return span.outerHTML;
}
//td宽度以及内容超过宽度隐藏
function formatTableUnit(value, row, index) {
    return {
        css: {
            "white-space": "nowrap",
            "text-overflow": "ellipsis",
            "overflow": "hidden",
            "max-width":"150px"
        }
    }
}
/**
 * 检查是否选中
 */
@@ -113,7 +139,7 @@
}
TPayHuimin.refund = function (){
    if (this.check()) {
        if (TPayHuimin.seItem.refundStatus != 1){
        if (TPayHuimin.seItem.status == 3){
            Feng.error("该商品已退款");
            return;
        }
@@ -150,12 +176,12 @@
    queryData['phone'] = $("#phone").val();
    let paymentTimeStr = $("#paymentTimeStr").val();
    if (paymentTimeStr){
        queryData['paymentTimeStart'] = paymentTimeStr.split('~')[0]+' 00:00:00';
        queryData['paymentTimeStart'] = paymentTimeStr.split('~')[0]+'00:00:00';
        queryData['paymentTimeEnd'] = paymentTimeStr.split('~')[1]+' 23:59:59';
    }
    let endTimeStr = $("#endTimeStr").val();
    if (endTimeStr){
        queryData['endTimeStart'] = endTimeStr.split('~')[0]+' 00:00:00';
        queryData['endTimeStart'] = endTimeStr.split('~')[0]+'00:00:00';
        queryData['endTimeEnd'] = endTimeStr.split('~')[1]+' 23:59:59';
    }
    queryData['status'] = $("#status").val();
@@ -176,22 +202,26 @@
    TPayHuimin.getStaticsData();
};
TPayHuimin.resetSearch = function () {
    var queryData = {};
    $("#huiMinName").val('');
    $("#huiMinType option:first").prop("selected", true);
    $("#operatorId option:first").prop("selected", true);
    $("#useId option:first").prop("selected", true);
    $("#status option:first").prop("selected", true);
    $("#userName").val('');
    $("#phone").val('');
    $("#paymentTimeStr").val('');
    $("#endTimeStr").val('');
    $("#status option:first").prop("selected", true);
    TPayHuimin.search();
    $('#TPayHuiminTable').bootstrapTable('destroy');
    TPayHuimin.initTable();
    TPayHuimin.getStaticsData();
};
$(function () {
TPayHuimin.initTable = function () {
    var defaultColunms = TPayHuimin.initColumn();
    var table = new BSTable(TPayHuimin.id, "/tPayHuimin/list", defaultColunms);
    table.setPaginationType("server");
    TPayHuimin.table = table.init();
    TPayHuimin.getStaticsData();
};
$(function () {
    TPayHuimin.initTable();
});