1
luofl
2025-04-03 58e344a0c14692fce547d64ea9295f866754fe63
1
8个文件已修改
1020 ■■■■■ 已修改文件
cloud-server-management/src/main/java/com/dsh/course/feignClient/activity/model/THuiminCard.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/code/CommontController.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/code/THuiminCardController.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-management/src/main/webapp/WEB-INF/view/system/tHuiminCard/tHuiminCard.html 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-management/src/main/webapp/WEB-INF/view/system/tHuiminCard/tHuiminCard_add.html 346 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-management/src/main/webapp/WEB-INF/view/system/tHuiminCard/tHuiminCard_detail.html 548 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-management/src/main/webapp/static/modular/system/tHuiminCard/tHuiminCard2.js 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 47 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-management/src/main/java/com/dsh/course/feignClient/activity/model/THuiminCard.java
@@ -91,17 +91,20 @@
     *有效期 不填表示永久
     */
    @TableField("endTime")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",  timezone = "GMT+8")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date endTime;
    /**
     *有效期结束时间 不填表示永久
     *有效期开始时间
     */
    @TableField("startTime")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",  timezone = "GMT+8")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date startTime;
    /**
     *可使用时间段,周,多个逗号分隔
     */
@@ -112,11 +115,13 @@
     */
    @TableField("useTimes")
    private String useTimes;
    /**
     *不可用时间段,yyyy-MM-dd HH:mm:ss,多个逗号分隔
     */
    @TableField("unUseTimes")
    private String unUseTimes;
//    /**
//     *不可用时间段,yyyy-MM-dd HH:mm:ss,多个逗号分隔
//     */
//    @TableField("unUseTimes")
//    private String unUseTimes;
    /**
     *使用范围1门店2场地
     */
cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/code/CommontController.java
@@ -2,18 +2,23 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.dsh.guns.modular.system.model.TCity;
import com.dsh.guns.modular.system.model.TOperator;
import com.dsh.guns.modular.system.service.ICityService;
import com.dsh.guns.modular.system.service.TOperatorService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/base")
public class CommontController {
    @Autowired
    private ICityService cityService;
    @Autowired
    private TOperatorService operatorService;
    /**
@@ -30,8 +35,22 @@
     */
    @RequestMapping("/region/getCity")
    public List<TCity> getCity() {
        List<Integer> ids = cityService.list(new LambdaQueryWrapper<TCity>()
                        .eq(TCity::getParentId, 0))
                .stream()
                .map(TCity::getId)
                .collect(Collectors.toList());
        return cityService.list(new LambdaQueryWrapper<TCity>()
                .in(TCity::getParentId, ids)
                .isNotNull(TCity::getCitycode));
    }
    /**
     * 获取所有的运营商
     */
    @RequestMapping("/operator/getOperator")
    public List<TOperator> getOperator() {
        return operatorService.list();
    }
}
cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/code/THuiminCardController.java
@@ -67,20 +67,18 @@
     */
    @RequestMapping("/tHuiminCard_detail/{id}")
    public String tHuiminCardDetail(@PathVariable("id") Integer id) {
        THuiminCard byId = huiminCardClient.getById(id);
        Date startTime = byId.getStartTime();
        if (startTime != null){
            byId.setStartTimeStr(DateUtil.format(startTime, "yyyy-MM-dd HH:mm:ss"));
        }
        Date endTime = byId.getEndTime();
        if (endTime != null){
            byId.setEndTimeStr(DateUtil.format(endTime, "yyyy-MM-dd HH:mm:ss"));
        }
        String jsonString = JSONObject.toJSONString(byId);
        setAttr("tHuiminCard", jsonString);
        return PREFIX + "tHuiminCard_detail.html";
    }
    /**
     * 获取惠民卡详情
     */
    @RequestMapping("/getDetail")
    @ResponseBody
    public THuiminCard getDetail(Integer id) {
        return huiminCardClient.getById(id);
    }
    /**
     * 获取惠民卡列表
cloud-server-management/src/main/webapp/WEB-INF/view/system/tHuiminCard/tHuiminCard.html
@@ -39,16 +39,18 @@
                </el-form>
                <div class="row">
                    <div class="col-sm-12">
                        <el-button type="primary" size="mini" v-on:click="handleAdd" icon="el-icon-circle-plus-outline">添加</el-button>
                        <el-button type="primary" size="mini" v-on:click="handleEdit" icon="el-icon-edit">编辑</el-button>
                        <el-button type="primary" size="mini" v-on:click="handleDelete" icon="el-icon-delete">删除</el-button>
                        <el-button type="primary" size="mini" v-on:click="handleShelves(1)" icon="el-icon-upload2">上架</el-button>
                        <el-button type="primary" size="mini" v-on:click="handleShelves(2)" icon="el-icon-download">下架</el-button>
                        <el-button type="primary" size="mini" v-on:click="handleViewDetail" icon="el-icon-tickets">查看详情</el-button>
                        <el-button type="primary" size="medium" style="background-color:#1ab394;color: #ffffff;border:#1ab394;" v-on:click="handleSearch" icon="el-icon-search">搜索</el-button>
                        <el-button type="primary" size="medium" style="background-color:#1ab394;color: #ffffff;border:#1ab394;" v-on:click="handleAdd" icon="el-icon-circle-plus-outline">添加</el-button>
                        <el-button type="primary" size="medium" style="background-color:#1ab394;color: #ffffff;border:#1ab394;"  v-on:click="handleEdit" icon="el-icon-edit">编辑</el-button>
                        <el-button type="primary" size="medium" style="background-color:#1ab394;color: #ffffff;border:#1ab394;"  v-on:click="handleDelete" icon="el-icon-delete">删除</el-button>
                        <el-button type="primary" size="medium" style="background-color:#1ab394;color: #ffffff;border:#1ab394;"  v-on:click="handleShelves(1)" icon="el-icon-upload2">上架</el-button>
                        <el-button type="primary" size="medium" style="background-color:#1ab394;color: #ffffff;border:#1ab394;"  v-on:click="handleShelves(2)" icon="el-icon-download">下架</el-button>
                        <el-button type="primary" size="medium" style="background-color:#1ab394;color: #ffffff;border:#1ab394;"  v-on:click="handleViewDetail" icon="el-icon-tickets">查看详情</el-button>
                    </div>
                </div>
                <el-table
                        :data="tableData"
                        :v-loading="loading"
                        stripe
                        style="width: 100%"
                        v-on:selection-change="handleSelectionChange">
cloud-server-management/src/main/webapp/WEB-INF/view/system/tHuiminCard/tHuiminCard_add.html
@@ -24,7 +24,7 @@
        <!-- 封面图片 -->
        <el-row>
            <el-form-item label="封面图片2" prop="cover">
            <el-form-item label="封面图片" prop="cover">
                <el-col :span="12">
                    <div class="upload-area text-center">
                        <el-upload
@@ -122,9 +122,13 @@
        <!-- 有效期 -->
        <el-form-item label="有效期">
            <el-date-picker
                    v-model="huiminCard.endTime"
                    type="date"
                    placeholder="选择日期">
                    v-model="periodOfValidity"
                    format="yyyy-MM-dd HH:mm:ss"
                    value-format="yyyy-MM-dd HH:mm:ss"
                    type="datetimerange"
                    start-placeholder="开始日期"
                    end-placeholder="结束日期"
                    :default-time="['12:00:00']">
            </el-date-picker>
        </el-form-item>
@@ -133,7 +137,7 @@
        <el-form-item label="可用时间" prop="weeks">
            <el-card
                    shadow="never"
                    v-for="(weekGroup, groupIndex) in huiminCard.weeks"
                    v-for="(weekGroup, groupIndex) in weeks"
                    :key="'weekGroup_' + groupIndex">
                <div slot="header"
                     style="display: flex;
@@ -199,13 +203,15 @@
        <!-- 不可用时间 -->
        <el-form-item label="不可用时间" prop="unUseTimes">
            <el-button type="text" v-on:click="addUnUseTime()">添加</el-button>
            <div v-for="(item, dayIndex) in times"
            <div v-for="(item, dayIndex) in huiminCard.unUseTimes"
                 :key="dayIndex"
                 class="date-picker-item mb-2">
                <el-date-picker
                        type="datetime"
                        placeholder="选择日期"
                        v-model="item.date">
                        v-model="item.date"
                        type="datetimerange"
                        start-placeholder="开始日期"
                        end-placeholder="结束日期"
                        :default-time="['12:00:00']">
                </el-date-picker>
                <button
                        type="button"
@@ -323,7 +329,7 @@
                <el-row :gutter="10">
                    <el-col :span="6">
                        <el-form-item label="所在省">
                            <el-select v-model="storeForm.provinceCode" size="mini" filterable placeholder="请选择">
                            <el-select v-model="storeForm.provinceCode" size="mini" clearable filterable placeholder="请选择">
                                <el-option
                                        v-for="item in provinces"
                                        :key="item.code"
@@ -334,8 +340,8 @@
                        </el-form-item>
                    </el-col>
                    <el-col :span="6">
                        <el-form-item label="所在市2">
                            <el-select v-model="storeForm.cityCode" size="mini" filterable placeholder="请选择">
                        <el-form-item label="所在市">
                            <el-select v-model="storeForm.cityCode" clearable size="mini" filterable placeholder="请选择">
                                <el-option
                                        v-for="item in cities"
                                        :key="item.citycode"
@@ -347,7 +353,14 @@
                    </el-col>
                    <el-col :span="6">
                        <el-form-item label="所属运营商">
                            <el-input size="mini" v-model="storeForm.operatorId" placeholder="请输入内容"></el-input>
                            <el-select v-model="storeForm.operatorId" clearable size="mini" filterable placeholder="请选择">
                                <el-option
                                        v-for="item in operations"
                                        :key="item.id"
                                        :label="item.name"
                                        :value="item.id">
                                </el-option>
                            </el-select>
                        </el-form-item>
                    </el-col>
                    <el-col :span="6">
@@ -363,47 +376,42 @@
                        </el-button>
                    </el-col>
                </el-row>
                <el-row>
                    <el-col :span="24">
                        <el-table
                                v-loading="tableStoreLoading"
                                :data="tableStoreData"
                                height="250"
                                v-on:selection-change="handleSelectionChange"
                                border>
                            <el-table-column
                                    type="selection"
                                    width="55">
                            </el-table-column>
                            <el-table-column
                                    prop="province"
                                    label="所在省市">
                            </el-table-column>
                            <el-table-column
                                    prop="operatorName"
                                    label="所属运营商">
                            </el-table-column>
                            <el-table-column
                                    prop="storeName"
                                    label="门店名称">
                            </el-table-column>
                            <el-table-column
                                    prop="ids"
                                    label="闸机ID">
                            </el-table-column>
                        </el-table>
                        <el-pagination
                                background
                                layout="prev, pager, next"
                                v-on:pagination="storeList"
                                :page.sync="queryParams.pageNum"
                                :limit.sync="queryParams.pageSize"
                                :total="tableStoreTotal">
                        </el-pagination>
                    </el-col>
                </el-row>
            </el-form>
            <el-table
                    v-loading="tableStoreLoading"
                    :data="tableStoreData"
                    height="250"
                    v-on:selection-change="handleSelectionChange"
                    border>
                <el-table-column
                        type="selection"
                        width="55">
                </el-table-column>
                <el-table-column
                        prop="province"
                        label="所在省市">
                </el-table-column>
                <el-table-column
                        prop="operatorName"
                        label="所属运营商">
                </el-table-column>
                <el-table-column
                        prop="storeName"
                        label="门店名称">
                </el-table-column>
                <el-table-column
                        prop="ids"
                        label="闸机ID">
                </el-table-column>
            </el-table>
            <el-pagination
                    background
                    layout="prev, pager, next"
                    v-on:pagination="storeList"
                    :page.sync="queryParams.pageNum"
                    :limit.sync="queryParams.pageSize"
                    :total="tableStoreTotal">
            </el-pagination>
            <span slot="footer" class="dialog-footer">
                <el-button v-on:click="dialogVisible2 = false">取 消</el-button>
                <el-button type="primary" v-on:click="handleStore">确 定</el-button>
@@ -416,6 +424,59 @@
                :visible.sync="dialogVisible3"
                width="80%"
                :before-close="handleSiteClose">
            <el-form ref="form" :model="siteForm" label-width="80px">
                <el-row :gutter="10">
                    <el-col :span="6">
                        <el-form-item label="所在省">
                            <el-select v-model="siteForm.provinceCode" size="mini" clearable filterable placeholder="请选择">
                                <el-option
                                        v-for="item in provinces"
                                        :key="item.code"
                                        :label="item.name"
                                        :value="item.code">
                                </el-option>
                            </el-select>
                        </el-form-item>
                    </el-col>
                    <el-col :span="6">
                        <el-form-item label="所在市">
                            <el-select v-model="siteForm.cityCode" clearable size="mini" filterable placeholder="请选择">
                                <el-option
                                        v-for="item in cities"
                                        :key="item.citycode"
                                        :label="item.name"
                                        :value="item.citycode">
                                </el-option>
                            </el-select>
                        </el-form-item>
                    </el-col>
                    <el-col :span="6">
                        <el-form-item label="所属运营商">
                            <el-select v-model="siteForm.operatorId" clearable size="mini" filterable placeholder="请选择">
                                <el-option
                                        v-for="item in operations"
                                        :key="item.id"
                                        :label="item.name"
                                        :value="item.id">
                                </el-option>
                            </el-select>
                        </el-form-item>
                    </el-col>
                    <el-col :span="6">
                        <el-form-item label="门店名称">
                            <el-input size="mini" v-model="siteForm.storeName" placeholder="请输入内容"></el-input>
                        </el-form-item>
                    </el-col>
                </el-row>
                <el-row>
                    <el-col :span="24">
                        <el-button v-on:click="siteList" style="background-color:#1ab394;color: #ffffff" size="mini" icon="el-icon-search">
                            搜索
                        </el-button>
                    </el-col>
                </el-row>
            </el-form>
            <el-table
                    v-loading="tableSiteLoading"
@@ -525,17 +586,63 @@
                    operatorId: null,
                    storeName: '',
                },
                siteForm: {
                    provinceCode: null,
                    cityCode: null,
                    operatorId: null,
                    storeName: '',
                },
                weeks: [
                    {
                        days: [ // 每个星期组的星期选项
                            {
                                value: '1',
                                label: '星期一',
                                checked: false,
                            },
                            {
                                value: '2',
                                label: '星期二',
                                checked: false,
                            },
                            {
                                value: '3',
                                label: '星期三',
                                checked: false,
                            },
                            {
                                value: '4',
                                label: '星期四',
                                checked: false,
                            },
                            {
                                value: '5',
                                label: '星期五',
                                checked: false,
                            },
                            {
                                value: '6',
                                label: '星期六',
                                checked: false,
                            },
                            {
                                value: '7',
                                label: '星期日',
                                checked: false,
                            }
                        ],
                    },
                ],
                provinces: [],
                cities: [],
                stores: [],
                operations: [],
                periodOfValidity: null,
                autoUpload: true,//自动上传
                previewImg: '',//模型数据,用于上传图片完成后图片预览
                dialogVisible: false,
                dialogVisible2: false,
                dialogVisible3: false,
                times: [{}],
                banners: [],
                introduces: null,
                multipleSelection1: [],
@@ -556,49 +663,8 @@
                    useWeeks: null,
                    useTimes: null,
                    introduce: null,
                    weeks: [
                        {
                            days: [ // 每个星期组的星期选项
                                {
                                    value: '1',
                                    label: '星期一',
                                    checked: false,
                                },
                                {
                                    value: '2',
                                    label: '星期二',
                                    checked: false,
                                },
                                {
                                    value: '3',
                                    label: '星期三',
                                    checked: false,
                                },
                                {
                                    value: '4',
                                    label: '星期四',
                                    checked: false,
                                },
                                {
                                    value: '5',
                                    label: '星期五',
                                    checked: false,
                                },
                                {
                                    value: '6',
                                    label: '星期六',
                                    checked: false,
                                },
                                {
                                    value: '7',
                                    label: '星期日',
                                    checked: false,
                                }
                            ],
                        },
                    ],
                    unUseTimes: [
                        {date: null}
                        {}
                    ],
                    useScope: '1',
                    useIds: null,
@@ -644,7 +710,7 @@
                            message: '请填写可用时间',
                            trigger: 'blur',
                            validator: (rule, value, callback) => {
                                const everyFalse = this.huiminCard.weeks.every(week =>
                                const everyFalse = this.weeks.every(week =>
                                    week.days.every(day =>
                                        day.checked === false
                                    )
@@ -652,7 +718,7 @@
                                if (everyFalse) {
                                    callback(new Error('请选择可用星期'));
                                }
                                const everyNull = this.huiminCard.weeks.every(obj =>
                                const everyNull = this.weeks.every(obj =>
                                    obj.startTime === null ||
                                    obj.endTime === null
                                );
@@ -725,7 +791,6 @@
            },
            beforeUpload(file) {
                console.log(111111)
                const isLt2M = file.size / 1024 / 1024 < 10;
                if (!isLt2M) {
                    Feng.error('上传图片大小不能超过 10MB!');
@@ -743,7 +808,7 @@
            },
            addWeek() {
                // 新增一个包含默认星期的组
                this.huiminCard.weeks.push({
                this.weeks.push({
                    days: [
                        {
                            value: '1',
@@ -784,14 +849,14 @@
                });
            },
            removeWeek(index) {
                this.huiminCard.weeks.splice(index, 1);
                this.weeks.splice(index, 1);
                console.log(this.weeks)
            },
            addUnUseTime() {
                this.times.push({date: null});
                this.huiminCard.unUseTimes.push({});
            },
            removeUnUseTime(index) {
                this.times.splice(index, 1);
                this.huiminCard.unUseTimes.splice(index, 1);
            },
            storeList() {
                this.tableStoreLoading = true;
@@ -829,6 +894,9 @@
                        Feng.error("请求失败: " + data.responseJSON.message);
                    }
                );
                this.siteForm.pageNum = vm.queryParams.pageNum;
                this.siteForm.pageSize = vm.queryParams.pageSize
                ajax.set(this.siteForm);
                ajax.start();
            },
            handleStoreClose() {
@@ -887,18 +955,21 @@
                    console.log(valid)
                    if (valid) {
                        let data = this.huiminCard;
                        let weeks = data.weeks;
                        var formatWeekAndTime1 = formatWeekAndTime(weeks);
                        data.useTimes = formatWeekAndTime1.useTimes;
                        data.useWeeks = formatWeekAndTime1.useWeeks;
                        data.unUseTimes = formatUnUseTimes(this.times);
                        let weeks = this.weeks;
                        data.useWeeks = JSON.stringify(weeks)
                        data.introduce = UE.getEditor('editor_1').getContent();
                        console.log(data.introduce)
                        //data
                        if (this.periodOfValidity){
                            data.startTime = this.periodOfValidity[0];
                            data.endTime = this.periodOfValidity[1];
                        }
                        console.log(data.startTime)
                        console.log(data.endTime)
                        let vm = this;
                        let ajax = new $ax(Feng.ctxPath + "/tHuiminCard/add",
                            (data) => {
                                window.parent.THuiminCard.table.refresh();
                                window.parent.parentVue.handleSearch();
                                THuiminCardInfoDlg.close();
                            },
                            (data) => {
@@ -936,52 +1007,21 @@
            );
            ajax2.start();
            let ajax3 = new $ax(Feng.ctxPath + "/base/operator/getOperator",
                (data) => {
                    this.operations = data;
                },
                (data) => {
                    Feng.error("请求失败: " + data.responseJSON.message);
                }
            );
            ajax3.start();
        },
    });
    function formatWeekAndTime(data) {
        const weekTimeMap = {};
        data.forEach(item => {
            // 确定时间段(优先使用直接字段)
            const startTime = item.startTime || item.time?.startTime || '';
            const endTime = item.endTime || item.time?.endTime || '';
            const timePair = startTime + ";" + endTime;
            // 遍历days数组,记录每个选中星期对应的时间段
            item.days.forEach(day => {
                if (day.checked && day.value) {
                    weekTimeMap[day.value] = timePair;
                }
            });
        });
        // 按星期数字排序并生成最终字符串
        const sortedWeeks = Object.keys(weekTimeMap).sort((a, b) => a - b);
        const useWeeks = sortedWeeks.join(',');
        const useTimes = sortedWeeks.map(week => weekTimeMap[week]).join(',');
        return {useWeeks, useTimes};
    }
    function formatUnUseTimes(nUseTimes) {
        if (!nUseTimes) {
            return "";
        }
        let dates = [];
        nUseTimes.forEach(item => {
            // 格式化
            const date = item.date;
            const year = date.getFullYear();
            const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始,需要+1
            const day = String(date.getDate()).padStart(2, '0');
            const hours = String(date.getHours()).padStart(2, '0');
            const minutes = String(date.getMinutes()).padStart(2, '0');
            const seconds = String(date.getSeconds()).padStart(2, '0');
            dates.push(year + '-' + month + '-' + day + '-' + hours + ':' + minutes + ':' + seconds)
        });
        return dates.join(',');
    }
</script>
cloud-server-management/src/main/webapp/WEB-INF/view/system/tHuiminCard/tHuiminCard_detail.html
@@ -1,7 +1,8 @@
@layout("/common/_container.html"){
<body>
<div id="app0" class="form-container">
    <el-form :rules="rules" :disabled="huiminCard.id != null && pageType === 'detail'" label-position="left" ref="formRef" label-width="120px" :model="huiminCard" size="small">
    <el-form :rules="rules" :disabled="pageType === 'detail'" label-position="left" ref="formRef" label-width="120px"
             :model="huiminCard" size="small">
        <el-form-item label="惠民卡名称" prop="huiMinName">
            <el-input v-model="huiminCard.huiMinName"></el-input>
        </el-form-item>
@@ -26,20 +27,21 @@
        <el-row>
            <el-form-item label="封面图片" prop="cover">
                <el-col :span="12">
                    <div class="upload-area text-center" style="display: flex">
                    <div class="upload-area text-center">
                        <el-upload
                                :limit="1"
                                class="avatar-uploader"
                                action="/tCouponManage/uploadPic"
                                list-type="picture-card"
                                :file-list="unBuyCoverFileList"
                                :multiple="false"
                                accept="."
                                :on-success="handleUnBuyCoverSuccess"
                                :before-upload="beforeUpload"
                                :on-exceed="handleUnBuyCoverExceed"
                                :on-remove="handleUnBuyCoverRemove">
                            <img :src="huiminCard.unBuyCover" class="avatar">
                            <i class="el-icon-plus avatar-uploader-icon"></i>
                        </el-upload>
                        <span>已购买封面</span>
                        <span>未购买封面</span>
                    </div>
                </el-col>
@@ -50,12 +52,12 @@
                                class="avatar-uploader"
                                action="/tCouponManage/uploadPic"
                                list-type="picture-card"
                                :file-list="buyCoverFileList"
                                :multiple="false"
                                accept="."
                                :on-success="handleBuyCoverSuccess"
                                :before-upload="beforeUpload"
                                :on-remove="handleBuyCoverRemove">
                            <img :src="huiminCard.buyCover" class="avatar">
                            <i class="el-icon-plus avatar-uploader-icon"></i>
                        </el-upload>
                        <span>已购买封面</span>
@@ -95,8 +97,8 @@
                            :limit="5"
                            class="avatar-uploader"
                            action="/tCouponManage/uploadPic"
                            :file-list="bannerFileList"
                            list-type="picture-card"
                            :file-list="banners"
                            accept="."
                            :on-success="handleSuccess"
                            :before-upload="beforeUpload"
@@ -124,16 +126,19 @@
        <!-- 有效期 -->
        <el-form-item label="有效期">
            <el-date-picker
                    v-model="huiminCard.endTime"
                    type="date"
                    placeholder="选择日期">
                    v-model="periodOfValidity"
                    format="yyyy-MM-dd HH:mm:ss"
                    value-format="yyyy-MM-dd HH:mm:ss"
                    type="datetimerange"
                    start-placeholder="开始日期"
                    end-placeholder="结束日期"
                    :default-time="['12:00:00']">
            </el-date-picker>
        </el-form-item>
        <!-- 可用时间 -->
        <el-form-item label="可用时间" prop="weeks">
            <el-button type="text" v-on:click="addWeek()">添加</el-button>
            <el-card
                    shadow="never"
                    v-for="(weekGroup, groupIndex) in weeks"
@@ -202,13 +207,15 @@
        <!-- 不可用时间 -->
        <el-form-item label="不可用时间" prop="unUseTimes">
            <el-button type="text" v-on:click="addUnUseTime()">添加</el-button>
            <div v-for="(item, dayIndex) in times"
            <div v-for="(item, dayIndex) in huiminCard.unUseTimes"
                 :key="dayIndex"
                 class="date-picker-item mb-2">
                <el-date-picker
                        type="datetime"
                        placeholder="选择日期"
                        v-model="item.date">
                        v-model="item.date"
                        type="datetimerange"
                        start-placeholder="开始日期"
                        end-placeholder="结束日期"
                        :default-time="['12:00:00']">
                </el-date-picker>
                <button
                        type="button"
@@ -313,18 +320,72 @@
        <!-- 操作按钮 -->
        <div class="row mt-5">
            <div class="col-sm-9 offset-sm-3">
                <button v-if="pageType === 'edit'" type="button" v-on:click="submitForm('formRef')" class="btn btn-primary px-4">提交保存</button>
                <button type="button" v-if="pageType === 'edit'" v-on:click="submitForm('formRef')" class="btn btn-primary px-4">提交保存</button>
                <button type="button" v-on:click="cancelForm()" class="btn btn-primary px-4">取 消</button>
            </div>
        </div>
        <!-- 选择门店 -->
        <el-dialog
                title="选择门店"
                :visible.sync="dialogVisible2"
                width="80%"
                :before-close="handleStoreClose">
            <el-form ref="form" :model="storeForm" label-width="80px">
                <el-row :gutter="10">
                    <el-col :span="6">
                        <el-form-item label="所在省">
                            <el-select v-model="storeForm.provinceCode" size="mini" clearable filterable
                                       placeholder="请选择">
                                <el-option
                                        v-for="item in provinces"
                                        :key="item.code"
                                        :label="item.name"
                                        :value="item.code">
                                </el-option>
                            </el-select>
                        </el-form-item>
                    </el-col>
                    <el-col :span="6">
                        <el-form-item label="所在市">
                            <el-select v-model="storeForm.cityCode" clearable size="mini" filterable
                                       placeholder="请选择">
                                <el-option
                                        v-for="item in cities"
                                        :key="item.citycode"
                                        :label="item.name"
                                        :value="item.citycode">
                                </el-option>
                            </el-select>
                        </el-form-item>
                    </el-col>
                    <el-col :span="6">
                        <el-form-item label="所属运营商">
                            <el-select v-model="storeForm.operatorId" clearable size="mini" filterable
                                       placeholder="请选择">
                                <el-option
                                        v-for="item in operations"
                                        :key="item.id"
                                        :label="item.name"
                                        :value="item.id">
                                </el-option>
                            </el-select>
                        </el-form-item>
                    </el-col>
                    <el-col :span="6">
                        <el-form-item label="门店名称">
                            <el-input size="mini" v-model="storeForm.storeName" placeholder="请输入内容"></el-input>
                        </el-form-item>
                    </el-col>
                </el-row>
                <el-row>
                    <el-col :span="24">
                        <el-button v-on:click="storeList" style="background-color:#1ab394;color: #ffffff" size="mini"
                                   icon="el-icon-search">
                            搜索
                        </el-button>
                    </el-col>
                </el-row>
            </el-form>
            <el-table
                    v-loading="tableStoreLoading"
                    :data="tableStoreData"
@@ -356,9 +417,10 @@
                    background
                    layout="prev, pager, next"
                    v-on:pagination="storeList"
                    :page.sync="queryParams.pageNum"
                    :limit.sync="queryParams.pageSize"
                    :total="tableStoreTotal">
            </el-pagination>
            <span slot="footer" class="dialog-footer">
                <el-button v-on:click="dialogVisible2 = false">取 消</el-button>
                <el-button type="primary" v-on:click="handleStore">确 定</el-button>
@@ -371,6 +433,63 @@
                :visible.sync="dialogVisible3"
                width="80%"
                :before-close="handleSiteClose">
            <el-form ref="form" :model="siteForm" label-width="80px">
                <el-row :gutter="10">
                    <el-col :span="6">
                        <el-form-item label="所在省">
                            <el-select v-model="siteForm.provinceCode" size="mini" clearable filterable
                                       placeholder="请选择">
                                <el-option
                                        v-for="item in provinces"
                                        :key="item.code"
                                        :label="item.name"
                                        :value="item.code">
                                </el-option>
                            </el-select>
                        </el-form-item>
                    </el-col>
                    <el-col :span="6">
                        <el-form-item label="所在市">
                            <el-select v-model="siteForm.cityCode" clearable size="mini" filterable
                                       placeholder="请选择">
                                <el-option
                                        v-for="item in cities"
                                        :key="item.citycode"
                                        :label="item.name"
                                        :value="item.citycode">
                                </el-option>
                            </el-select>
                        </el-form-item>
                    </el-col>
                    <el-col :span="6">
                        <el-form-item label="所属运营商">
                            <el-select v-model="siteForm.operatorId" clearable size="mini" filterable
                                       placeholder="请选择">
                                <el-option
                                        v-for="item in operations"
                                        :key="item.id"
                                        :label="item.name"
                                        :value="item.id">
                                </el-option>
                            </el-select>
                        </el-form-item>
                    </el-col>
                    <el-col :span="6">
                        <el-form-item label="门店名称">
                            <el-input size="mini" v-model="siteForm.storeName" placeholder="请输入内容"></el-input>
                        </el-form-item>
                    </el-col>
                </el-row>
                <el-row>
                    <el-col :span="24">
                        <el-button v-on:click="siteList" style="background-color:#1ab394;color: #ffffff" size="mini"
                                   icon="el-icon-search">
                            搜索
                        </el-button>
                    </el-col>
                </el-row>
            </el-form>
            <el-table
                    v-loading="tableSiteLoading"
@@ -451,31 +570,8 @@
        margin-bottom: 10px;
    }
    .avatar-uploader .el-upload {
        border: 1px dashed #d9d9d9;
        border-radius: 6px;
        cursor: pointer;
        position: relative;
        overflow: hidden;
    }
    .avatar-uploader .el-upload:hover {
        border-color: #409EFF;
    }
    .avatar-uploader-icon {
        font-size: 28px;
        color: #8c939d;
        width: 178px;
        height: 178px;
        line-height: 178px;
        text-align: center;
    }
    .avatar {
        width: 178px;
        height: 178px;
        display: block;
    input[type=file] {
        display: none;
    }
@@ -497,21 +593,21 @@
        },
        data() {
            return {
                autoUpload: true,//自动上传
                previewImg: '',//模型数据,用于上传图片完成后图片预览
                dialogVisible: false,
                dialogVisible2: false,
                dialogVisible3: false,
                pageType: null,
                times: [
                    {
                    }
                ],
                banners: [],
                introduces: null,
                multipleSelection1: [],
                multipleSelection2: [],
                storeForm: {
                    provinceCode: null,
                    cityCode: null,
                    operatorId: null,
                    storeName: '',
                },
                siteForm: {
                    provinceCode: null,
                    cityCode: null,
                    operatorId: null,
                    storeName: '',
                },
                unBuyCoverFileList: [],
                buyCoverFileList: [],
                bannerFileList: [],
                weeks: [
                    {
                        days: [ // 每个星期组的星期选项
@@ -553,6 +649,20 @@
                        ],
                    },
                ],
                provinces: [],
                cities: [],
                stores: [],
                operations: [],
                periodOfValidity: null,
                autoUpload: true,//自动上传
                previewImg: '',//模型数据,用于上传图片完成后图片预览
                dialogVisible: false,
                dialogVisible2: false,
                dialogVisible3: false,
                banners: [],
                introduces: null,
                multipleSelection1: [],
                multipleSelection2: [],
                huiminCard: {
                    id: null,
                    huiMinName: null,
@@ -570,7 +680,7 @@
                    useTimes: null,
                    introduce: null,
                    unUseTimes: [
                        {date: null}
                        {}
                    ],
                    useScope: '1',
                    useIds: null,
@@ -635,20 +745,6 @@
                            },
                        }
                    ],
                    unUseTimes: [{
                        required: true,
                        message: '请选择可用时间',
                        trigger: 'blur',
                        validator: (rule, value, callback) => {
                            const everyNull = this.times.every(obj =>
                                obj.date === null
                            );
                            if (everyNull) {
                                callback(new Error('请选择可用时间'));
                            }
                            callback();
                        },
                    }],
                    storeIds: [
                        {
                            required: true,
@@ -693,6 +789,9 @@
            handleUnBuyCoverSuccess(res, file) {
                this.huiminCard.unBuyCover = res;
            },
            handleUnBuyCoverExceed() {
                Feng.error('最多上传一张图片');
            },
            handleUnBuyCoverRemove(file, fileList) {
                this.huiminCard.unBuyCover = '';
            },
@@ -703,20 +802,8 @@
                this.huiminCard.buyCover = '';
            },
            handleSuccess(res, file) {
                let banner = this.huiminCard.banner;
                if (banner === null) {
                    this.huiminCard.banner = res;
                } else {
                    let banners = banner.split(',');
                    banners.push({
                        url: res,
                    });
                    this.huiminCard.banner = this.banners.map(item => {
                        return item.url;
                    }).join(',');
                }
                this.banners.push(res)
                this.huiminCard.banner = this.banners.join(',');
            },
            beforeUpload(file) {
@@ -728,18 +815,15 @@
            },
            handleRemove(file, fileList) {
                const fileUrl = file.response;
                // 1.删除 this.banners中的图片地址
                this.banners = this.banners.filter(item => {
                    return item.url !== fileUrl;
                this.banners.forEach((item, index) => {
                    if (item === fileUrl) {
                        this.banners.splice(index, 1);
                    }
                });
                //2.重新给this.huiminCard.banner 赋值
                thi.huiminCard.banner = this.banners.map(item => {
                    return item.url;
                }).join(',');
                this.huiminCard.banner = this.banners.join(',');
            },
            addWeek() {
                // 新增一个包含默认星期的组
                console.log(this.huiminCard)
                this.weeks.push({
                    days: [
                        {
@@ -782,12 +866,13 @@
            },
            removeWeek(index) {
                this.weeks.splice(index, 1);
                console.log(this.weeks)
            },
            addUnUseTime() {
                this.times.push({date: null});
                this.huiminCard.unUseTimes.push({});
            },
            removeUnUseTime(index) {
                this.times.splice(index, 1);
                this.huiminCard.unUseTimes.splice(index, 1);
            },
            storeList() {
                this.tableStoreLoading = true;
@@ -804,6 +889,10 @@
                        Feng.error("请求失败: " + data.responseJSON.message);
                    }
                );
                this.storeForm.pageNum = vm.queryParams.pageNum;
                this.storeForm.pageSize = vm.queryParams.pageSize
                ajax.set(this.storeForm);
                ajax.start();
            },
            siteList() {
@@ -821,6 +910,9 @@
                        Feng.error("请求失败: " + data.responseJSON.message);
                    }
                );
                this.siteForm.pageNum = vm.queryParams.pageNum;
                this.siteForm.pageSize = vm.queryParams.pageSize
                ajax.set(this.siteForm);
                ajax.start();
            },
            handleStoreClose() {
@@ -846,6 +938,8 @@
                this.tableData.splice(index, 1);
            },
            handleSelectStore() {
                this.queryParams.pageNum = 1;
                this.queryParams.pageSize = 10;
                if (this.huiminCard.useScope === '1') {
                    this.dialogVisible2 = true;
                    this.storeList();
@@ -874,20 +968,21 @@
            },
            submitForm(formName) {
                this.$refs[formName].validate(valid => {
                    console.log(valid)
                    if (valid) {
                        let data = this.huiminCard;
                        let weeks = this.weeks;
                        console.log(weeks)
                        const formatWeekAndTime1 = formatWeekAndTime(weeks);
                        data.useTimes = formatWeekAndTime1.useTimes;
                        data.useWeeks = formatWeekAndTime1.useWeeks;
                        data.unUseTimes = formatUnUseTimes(this.times);
                        data.useWeeks = JSON.stringify(weeks)
                        data.introduce = UE.getEditor('editor_1').getContent();
                        //data
                        if (this.periodOfValidity) {
                            data.startTime = this.periodOfValidity[0];
                            data.endTime = this.periodOfValidity[1];
                        }
                        let vm = this;
                        let ajax = new $ax(Feng.ctxPath + "/tHuiminCard/update",
                            (data) => {
                                // 正确调用父页面方法
                                window.parent.parentVue.handleSearch();
                                THuiminCardInfoDlg.close();
                            },
@@ -906,168 +1001,133 @@
            }
        },
        created() {
            // 初始化编辑器
            this.editor = UE.getEditor('editor_1');
            // 设置内容(需在编辑器就绪后调用)
            this.editor.ready(() => {
                this.editor.setContent(this.huiminCard.introduce);
            });
            const rawData = JSON.parse(`${tHuiminCard}`);
            let editor_1 = UE.getEditor('editor_1');
            console.log("rawData",rawData)
            this.weeks = parseWeekAndTime(rawData.useWeeks, rawData.useTimes)
            console.log("rawData.banner",rawData.banner)
            // 将原始数据转换为banner数组
            this.banners = rawData.banner.split(",").map(item => {
                return {
                    url: item
                }
            });
            const urlParams = new URLSearchParams(window.location.search);
            this.pageType = urlParams.get('pageType');
            // 直接获取参数值
            this.pageType = urlParams.get('pageType');
            if (this.pageType === 'edit' || this.pageType === 'detail') {
            // 将原始数据转换为times数组
            this.times = rawData.unUseTimes.split(",").map(item => {
                const formattedDate = item.replace(/(\d{4}-\d{2}-\d{2})-(\d{2}:\d{2}:\d{2})/, "$1T$2");
                return {
                    original: item, // 原始字符串
                    date: new Date(formattedDate) // 转换后的 Date 对象
                };
            });
                // 1. 解析URL路径获取ID
                const pathArray = window.location.pathname.split('/');
                // 获取最后一段路径(13)
                let id = pathArray[pathArray.length - 1]; // 将ID赋值给huiminCard.id
            let url
            if (rawData.useScope == '1'){
                url = Feng.ctxPath + "/tHuiminCard/storeList"
            }else {
                url = Feng.ctxPath + "/tHuiminCard/siteList"
            }
            if (rawData.useIds !== '' && rawData.useIds !== null){
                let vm = this;
                let ajax = new $ax(Feng.ctxPath + url,
                let ajax = new $ax(Feng.ctxPath + "/tHuiminCard/getDetail",
                    (data) => {
                        vm.tableData = data.records; // 使用 vm 替代 this
                        this.periodOfValidity = [data.startTime, data.endTime]
                        this.huiminCard = {
                            ...data,
                            huiMinType: Number(data.huiMinType),
                            startTime: data.startTimeStr,
                            endTime: data.endTimeStr,
                        }
                        // 设置内容(需在编辑器就绪后调用)
                        editor_1.ready(() => {
                            editor_1.setContent(this.huiminCard.introduce);
                        });
                        this.unBuyCoverFileList = [{
                            url: this.huiminCard.unBuyCover,
                            name: 'unBuyCover',
                            status: 'done'
                        }]
                        this.buyCoverFileList = [{
                            url: this.huiminCard.buyCover,
                            name: 'buyCover',
                            status: 'done'
                        }]
                        this.banners = data.banner.split(",");
                        for (let i = 0; i < this.banners.length; i++) {
                            this.bannerFileList.push({
                                url: this.banners[i],
                                name: 'banner' + i,
                                status: 'done'
                            })
                        }
                        this.weeks = JSON.parse(data.useWeeks);
                        if (data.useIds !== '' && data.useIds !== null){
                            let url
                            if (data.useScope == '1'){
                                url = Feng.ctxPath + "/tHuiminCard/storeList"
                            }else {
                                url = Feng.ctxPath + "/tHuiminCard/siteList"
                            }
                            let vm = this;
                            let ajax = new $ax(Feng.ctxPath + url,
                                (data1) => {
                                    vm.tableData = data1.records; // 使用 vm 替代 this
                                },
                                (data1) => {
                                    Feng.error("请求失败: " + data1.responseJSON.message);
                                }
                            );
                            ajax.set("storeIds",data.useIds)
                            ajax.start();
                        }
                    },
                    (data) => {
                        vm.tableStoreLoading = false;
                        Feng.error("请求失败: " + data.responseJSON.message);
                    }
                );
                ajax.set("storeIds",rawData.useIds)
                ajax.set({id: id})
                ajax.start();
                init();
            }
            // // 设置内容(需在编辑器就绪后调用)
            // this.editor.ready(() => {
            //     this.editor.setContent(this.huiminCard.introduce);
            // });
            // 将原始数据转换为tableData数组
            this.huiminCard = {
                ...rawData,
                huiMinType: Number(rawData.huiMinType),
                startTime: rawData.startTimeStr,
                endTime: rawData.endTimeStr,
            }
            const urlParams = new URLSearchParams(window.location.search);
             // 直接获取参数值
            this.pageType = urlParams.get('pageType');
        },
    });
    function formatWeekAndTime(data) {
        const weekTimeMap = {};
        data.forEach(item => {
            // 确定时间段(优先使用直接字段)
            const startTime = item.startTime || item.time?.startTime || '';
            const endTime = item.endTime || item.time?.endTime || '';
            const timePair = startTime + ";" + endTime;
            // 遍历days数组,记录每个选中星期对应的时间段
            item.days.forEach(day => {
                if (day.checked && day.value) {
                    weekTimeMap[day.value] = timePair;
                }
            });
        });
        // 按星期数字排序并生成最终字符串
        const sortedWeeks = Object.keys(weekTimeMap).sort((a, b) => a - b);
        const useWeeks = sortedWeeks.join(',');
        const useTimes = sortedWeeks.map(week => weekTimeMap[week]).join(',');
        return {useWeeks, useTimes};
    }
    function parseWeekAndTime(useWeeks, useTimes) {
        // 将字符串按逗号分割成数组
        const weeks = useWeeks.split(',').filter(Boolean); // 去除空值
        const times = useTimes.split(',').filter(Boolean);
        // 确保星期和时间段的数量一致
        if (weeks.length !== times.length) {
            throw new Error("星期和时间段的数量不匹配");
        }
        // 定义完整的 days 数组模板
        const fullDays = [
            { value: '1', label: '星期一', checked: false },
            { value: '2', label: '星期二', checked: false },
            { value: '3', label: '星期三', checked: false },
            { value: '4', label: '星期四', checked: false },
            { value: '5', label: '星期五', checked: false },
            { value: '6', label: '星期六', checked: false },
            { value: '7', label: '星期日', checked: false }
        ];
        // 构造还原的数据结构
        const result = [];
        weeks.forEach((week, index) => {
            const [startTime, endTime] = times[index].split(';'); // 分割时间段
            // 查找是否已有相同时间段的项,如果有则复用
            let existingItem = result.find(item =>
                item.startTime === startTime && item.endTime === endTime
            );
            if (!existingItem) {
                // 如果没有找到,则创建新项
                existingItem = {
                    startTime,
                    endTime,
                    days: JSON.parse(JSON.stringify(fullDays)) // 深拷贝完整 days 数组
                };
                result.push(existingItem);
    function init() {
        let ajax = new $ax(Feng.ctxPath + "/base/region/getProvince",
            (data) => {
                this.provinces = data;
            },
            (data) => {
                Feng.error("请求失败: " + data.responseJSON.message);
            }
        );
        ajax.start();
            // 更新当前星期的 checked 状态
            const dayToUpdate = existingItem.days.find(day => day.value === week);
            if (dayToUpdate) {
                dayToUpdate.checked = true;
        let ajax2 = new $ax(Feng.ctxPath + "/base/region/getCity",
            (data) => {
                this.cities = data;
            },
            (data) => {
                Feng.error("请求失败: " + data.responseJSON.message);
            }
        });
        );
        ajax2.start();
        return result;
    }
    function formatUnUseTimes(nUseTimes) {
        if (!nUseTimes) {
            return "";
        }
        let dates = [];
        nUseTimes.forEach(item => {
            // 格式化
            const date = item.date;
            const year = date.getFullYear();
            const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始,需要+1
            const day = String(date.getDate()).padStart(2, '0');
            const hours = String(date.getHours()).padStart(2, '0');
            const minutes = String(date.getMinutes()).padStart(2, '0');
            const seconds = String(date.getSeconds()).padStart(2, '0');
            dates.push(year + '-' + month + '-' + day + '-' + hours + ':' + minutes + ':' + seconds)
        });
        return dates.join(',');
        let ajax3 = new $ax(Feng.ctxPath + "/base/operator/getOperator",
            (data) => {
                this.operations = data;
            },
            (data) => {
                Feng.error("请求失败: " + data.responseJSON.message);
            }
        );
        ajax3.start();
    }
cloud-server-management/src/main/webapp/static/modular/system/tHuiminCard/tHuiminCard2.js
@@ -8,6 +8,7 @@
                dateRange: [],
                status: ''
            },
            loading: false,
            currentPage: 1,
            pageSize: 10,
            total: 800,
@@ -19,11 +20,12 @@
    methods: {
        handleSearch() {
            console.log('搜索条件:', this.query)
            // 修复方案:使用箭头函数 + 字段校验
            this.loading = true;
            const vm = this; // 保留Vue实例引用
            let ajax = new $ax(Feng.ctxPath + "/tHuiminCard/list",
                (data) => { // 改用箭头函数
                    console.log('原始数据:', data);
                    this.loading = false;
                    if(data.rows && Array.isArray(data.rows)){
                        vm.tableData = data.rows;
                        vm.total = data.total;
@@ -33,6 +35,7 @@
                    }
                },
                (data) => {
                    this.loading = false;
                    Feng.error("搜索失败: " + (data.responseJSON?.message || '服务器异常')); // 错误提示优化
                });
package.json
@@ -1,6 +1,43 @@
{
  "dependencies": {
    "html2canvas": "^1.4.1",
    "jspdf": "^2.5.1"
[
  {
    "days": [
      {
        "value": "1",
        "label": "星期一",
        "checked": true
      },
      {
        "value": "2",
        "label": "星期二",
        "checked": true
      },
      {
        "value": "3",
        "label": "星期三",
        "checked": true
      },
      {
        "value": "4",
        "label": "星期四",
        "checked": false
      },
      {
        "value": "5",
        "label": "星期五",
        "checked": false
      },
      {
        "value": "6",
        "label": "星期六",
        "checked": false
      },
      {
        "value": "7",
        "label": "星期日",
        "checked": false
      }
    ],
    "startTime": "00:00",
    "endTime": "23:00"
  }
}
]