xdd 2 місяців тому
батько
коміт
62e4e3dae5
2 змінених файлів з 337 додано та 47 видалено
  1. 16 2
      src/api/recharge/template.js
  2. 321 45
      src/views/user/rechargeTemplate/index.vue

+ 16 - 2
src/api/recharge/template.js

@@ -4,8 +4,8 @@ import request from '@/utils/request'
 export function listRechargeTemplate(query) {
   return request({
     url: '/recharge-templates/list',
-    method: 'get',
-    params: query
+    method: 'post',
+    data: query
   })
 }
 
@@ -53,3 +53,17 @@ export function updateRechargeTemplateStatus(id, status) {
     }
   })
 }
+
+
+/**
+ * 获取优惠券列表
+ * @param {Object} query 查询参数
+ * @returns {Promise} 请求结果
+ */
+export function getCouponList(query) {
+  return request({
+    url: '/recharge-templates/getCouponList',
+    method: 'get',
+    params: query
+  })
+}

+ 321 - 45
src/views/user/rechargeTemplate/index.vue

@@ -94,6 +94,12 @@
           <el-tag v-else type="info" size="mini">否</el-tag>
         </template>
       </el-table-column>
+      <el-table-column label="绑定优惠券" align="center" width="100">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.couponCount" type="primary" size="mini">{{ scope.row.couponCount }}张</el-tag>
+          <el-tag v-else type="info" size="mini">无</el-tag>
+        </template>
+      </el-table-column>
       <el-table-column label="有效期" align="center" width="180">
         <template slot-scope="scope">
           <span v-if="scope.row.startTime && scope.row.endTime">
@@ -211,8 +217,27 @@
         </el-row>
         <el-row>
           <el-col :span="24">
-            <el-form-item label="图标URL" prop="iconUrl">
-              <el-input v-model="form.iconUrl" placeholder="请输入图标URL" />
+            <el-form-item label="图标" prop="iconUrl">
+              <el-upload
+                class="avatar-uploader"
+                :action="uploadFileUrl"
+                :headers="headers"
+                :show-file-list="false"
+                :on-success="handleIconSuccess"
+                :before-upload="beforeIconUpload"
+                :on-error="handleIconError"
+              >
+                <img v-if="form.iconUrl" :src="form.iconUrl" class="avatar" />
+                <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+              </el-upload>
+              <div class="el-upload__tip">
+                <div v-if="form.iconUrl" style="margin-top: 10px;">
+                  <el-button size="mini" type="danger" icon="el-icon-delete" @click="handleIconRemove">移除</el-button>
+                </div>
+                <div style="color: #999; font-size: 12px; margin-top: 5px;">
+                  只能上传jpg/png文件,且不超过2MB
+                </div>
+              </div>
             </el-form-item>
           </el-col>
         </el-row>
@@ -237,6 +262,41 @@
             </el-form-item>
           </el-col>
         </el-row>
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="绑定优惠券" prop="couponIdList">
+              <el-select
+                v-model="form.couponIdList"
+                multiple
+                filterable
+                remote
+                reserve-keyword
+                placeholder="请输入优惠券名称搜索"
+                :remote-method="remoteCouponSearch"
+                :loading="couponLoading"
+                style="width: 100%"
+                @focus="handleCouponFocus"
+                @clear="handleCouponClear"
+                clearable
+              >
+                <el-option
+                  v-for="item in couponOptions"
+                  :key="item.couponId"
+                  :label="`${item.title}(¥${item.limitTime})`"
+                  :value="item.couponId"
+                >
+                  <span>{{ item.title }}</span>
+                  <span style="float: right; color: #8492a6; font-size: 13px">
+                    ¥{{ item.price }}
+                  </span>
+                </el-option>
+              </el-select>
+              <div class="el-form-item__tip" style="margin-top: 5px; color: #999; font-size: 12px;">
+                已选择 {{ form.couponIdList ? form.couponIdList.length : 0 }} 张优惠券
+              </div>
+            </el-form-item>
+          </el-col>
+        </el-row>
       </el-form>
       <div slot="footer" class="dialog-footer">
         <el-button type="primary" @click="submitForm">确 定</el-button>
@@ -249,6 +309,7 @@
       <el-descriptions :column="2" border>
         <el-descriptions-item label="模板名称">{{ detailData.templateName }}</el-descriptions-item>
         <el-descriptions-item label="储值金额">¥{{ detailData.rechargeAmount }}</el-descriptions-item>
+        ```vue
         <el-descriptions-item label="赠送金额">¥{{ detailData.bonusAmount || 0 }}</el-descriptions-item>
         <el-descriptions-item label="限购次数">{{ detailData.purchaseLimit || '不限制' }}</el-descriptions-item>
         <el-descriptions-item label="排序序号">{{ detailData.sortOrder }}</el-descriptions-item>
@@ -269,10 +330,21 @@
           </span>
           <span v-else>永久有效</span>
         </el-descriptions-item>
-        <el-descriptions-item label="图标URL" :span="2">{{ detailData.iconUrl || '无' }}</el-descriptions-item>
+        <el-descriptions-item label="图标" :span="2">
+          <img v-if="detailData.iconUrl" :src="getImageUrl(detailData.iconUrl)" style="max-height: 100px;" />
+          <span v-else>无</span>
+        </el-descriptions-item>
         <el-descriptions-item label="详情链接" :span="2">{{ detailData.detailUrl || '无' }}</el-descriptions-item>
         <el-descriptions-item label="描述文案" :span="2">{{ detailData.shortDesc || '无' }}</el-descriptions-item>
         <el-descriptions-item label="权益详情" :span="2">{{ detailData.benefitDetails || '无' }}</el-descriptions-item>
+        <el-descriptions-item label="绑定优惠券" :span="2">
+          <div v-if="detailData.coupons && detailData.coupons.length > 0">
+            <el-tag v-for="(coupon, index) in detailData.coupons" :key="index" type="success" style="margin-right: 5px; margin-bottom: 5px;">
+              {{ coupon.title }} (¥{{ coupon.price }})
+            </el-tag>
+          </div>
+          <span v-else>无</span>
+        </el-descriptions-item>
       </el-descriptions>
       <div slot="footer" class="dialog-footer">
         <el-button @click="detailOpen = false">关 闭</el-button>
@@ -282,7 +354,17 @@
 </template>
 
 <script>
-import { listRechargeTemplate, getRechargeTemplate, delRechargeTemplate, addRechargeTemplate, updateRechargeTemplate, updateRechargeTemplateStatus } from "@/api/recharge/template";
+import {
+  listRechargeTemplate,
+  getRechargeTemplate,
+  delRechargeTemplate,
+  addRechargeTemplate,
+  updateRechargeTemplate,
+  updateRechargeTemplateStatus,
+  getCouponList
+} from "@/api/recharge/template";
+import { getToken } from "@/utils/auth";
+import { parseTime } from "@/utils/common";
 
 export default {
   name: "RechargeTemplate",
@@ -336,13 +418,32 @@ export default {
         sortOrder: [
           { required: true, message: "排序序号不能为空", trigger: "blur" }
         ]
-      }
+      },
+      // 上传参数
+      uploadFileUrl: process.env.VUE_APP_BASE_API + "/common/upload", // 上传的图片服务器地址
+      headers: {
+        Authorization: "Bearer " + getToken()
+      },
+      // 优惠券相关
+      couponOptions: [],
+      couponLoading: false,
+      couponSearchTimer: null // 搜索防抖定时器
     };
   },
   created() {
     this.getList();
   },
+  beforeDestroy() {
+    // 组件销毁时清理定时器
+    if (this.couponSearchTimer) {
+      clearTimeout(this.couponSearchTimer);
+    }
+  },
   methods: {
+    parseTime,
+    handleIconRemove(){
+      this.form.iconUrl = null;
+    },
     /** 查询充值模板列表 */
     getList() {
       this.loading = true;
@@ -352,70 +453,59 @@ export default {
         this.loading = false;
       });
     },
-    // 取消按钮
-    cancel() {
-      this.open = false;
-      this.reset();
-    },
-    // 表单重置
-    reset() {
-      this.form = {
-        id: null,
-        templateName: null,
-        rechargeAmount: null,
-        bonusAmount: null,
-        benefitDetails: null,
-        status: 1,
-        sortOrder: 0,
-        startTime: null,
-        endTime: null,
-        userType: null,
-        purchaseLimit: null,
-        tag: null,
-        shortDesc: null,
-        detailUrl: null,
-        iconUrl: null,
-        isDefault: 0
-      };
-      this.validTime = [];
-      this.resetForm("form");
-    },
+
     /** 搜索按钮操作 */
     handleQuery() {
       this.queryParams.pageNum = 1;
       this.getList();
     },
+
     /** 重置按钮操作 */
     resetQuery() {
       this.resetForm("queryForm");
       this.handleQuery();
     },
+
     // 多选框选中数据
     handleSelectionChange(selection) {
-      this.ids = selection.map(item => item.id)
-      this.single = selection.length!==1
-      this.multiple = !selection.length
+      this.ids = selection.map(item => item.id);
+      this.single = selection.length !== 1;
+      this.multiple = !selection.length;
     },
+
     /** 新增按钮操作 */
     handleAdd() {
       this.reset();
+      this.loadDefaultCoupons(); // 新增时加载默认选项
       this.open = true;
       this.title = "添加充值模板";
     },
+
     /** 修改按钮操作 */
     handleUpdate(row) {
       this.reset();
-      const id = row.id || this.ids
+      const id = row.id || this.ids;
       getRechargeTemplate(id).then(response => {
         this.form = response.data;
+
         // 设置有效期时间范围
         if (this.form.startTime && this.form.endTime) {
           this.validTime = [this.form.startTime, this.form.endTime];
         }
+
+        // 如果已有绑定的优惠券,加载到选项中
+        if (this.form.couponIdList && this.form.couponIdList.length > 0) {
+          this.loadSelectedCoupons(this.form.couponIdList);
+        } else {
+          // 没有已选择的优惠券时,加载默认选项
+          this.loadDefaultCoupons();
+        }
+
         this.open = true;
         this.title = "修改充值模板";
       });
     },
+
     /** 详情按钮操作 */
     handleDetail(row) {
       const id = row.id;
@@ -424,6 +514,7 @@ export default {
         this.detailOpen = true;
       });
     },
+
     /** 提交按钮 */
     submitForm() {
       this.$refs["form"].validate(valid => {
@@ -439,13 +530,13 @@ export default {
 
           if (this.form.id != null) {
             updateRechargeTemplate(this.form).then(response => {
-              this.$modal.msgSuccess("修改成功");
+              this.$message.success("修改成功");
               this.open = false;
               this.getList();
             });
           } else {
             addRechargeTemplate(this.form).then(response => {
-              this.$modal.msgSuccess("新增成功");
+              this.$message.success("新增成功");
               this.open = false;
               this.getList();
             });
@@ -453,27 +544,212 @@ export default {
         }
       });
     },
+
     /** 删除按钮操作 */
     handleDelete(row) {
       const ids = row.id || this.ids;
-      this.$modal.confirm('是否确认删除充值模板编号为"' + ids + '"的数据项?').then(function() {
+      this.$confirm('是否确认删除充值模板编号为"' + ids + '"的数据项?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
         return delRechargeTemplate(ids);
       }).then(() => {
         this.getList();
-        this.$modal.msgSuccess("删除成功");
+        this.$message.success("删除成功");
       }).catch(() => {});
     },
+
     /** 状态修改 */
     handleStatusChange(row) {
       let text = row.status === 1 ? "启用" : "停用";
-      this.$modal.confirm('确认要"' + text + '""' + row.templateName + '"模板吗?').then(function() {
+      this.$confirm('确认要"' + text + '""' + row.templateName + '"模板吗?').then(() => {
         return updateRechargeTemplateStatus(row.id, row.status);
       }).then(() => {
-        this.$modal.msgSuccess(text + "成功");
-      }).catch(function() {
+        this.$message.success(text + "成功");
+      }).catch(() => {
         row.status = row.status === 0 ? 1 : 0;
       });
-    }
+    },
+
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+
+    // 表单重置
+    reset() {
+      // 清理搜索定时器
+      if (this.couponSearchTimer) {
+        clearTimeout(this.couponSearchTimer);
+        this.couponSearchTimer = null;
+      }
+
+      this.form = {
+        id: null,
+        templateName: null,
+        rechargeAmount: null,
+        bonusAmount: null,
+        benefitDetails: null,
+        status: 1,
+        sortOrder: 0,
+        startTime: null,
+        endTime: null,
+        userType: null,
+        purchaseLimit: null,
+        tag: null,
+        shortDesc: null,
+        detailUrl: null,
+        iconUrl: null,
+        isDefault: 0,
+        couponIdList: []
+      };
+      this.validTime = [];
+      this.resetForm("form");
+      this.couponOptions = [];
+    },
+
+    // 优惠券下拉框获得焦点时
+    handleCouponFocus() {
+      // 如果没有选项且没有已选择的优惠券,加载默认选项
+      if (this.couponOptions.length === 0 && (!this.form.couponIdList || this.form.couponIdList.length === 0)) {
+        this.loadDefaultCoupons();
+      }
+    },
+
+    // 清空优惠券选择
+    handleCouponClear() {
+      this.form.couponIdList = [];
+    },
+
+    // 加载默认优惠券列表
+    loadDefaultCoupons() {
+      this.couponLoading = true;
+      getCouponList({
+        pageSize: 20,
+        pageNum: 1,
+        status: 1 // 只查询有效的优惠券
+      }).then(response => {
+        this.couponOptions = response.data.list || [];
+        this.couponLoading = false;
+      }).catch(() => {
+        this.couponLoading = false;
+        this.couponOptions = [];
+      });
+    },
+
+    // 远程搜索优惠券(添加防抖)
+    remoteCouponSearch(query) {
+      // 清除之前的定时器
+      if (this.couponSearchTimer) {
+        clearTimeout(this.couponSearchTimer);
+      }
+
+      // 设置新的定时器,300ms后执行搜索
+      this.couponSearchTimer = setTimeout(() => {
+        if (query && query.trim() !== '') {
+          this.couponLoading = true;
+          getCouponList({
+            couponName: query.trim(),
+            pageSize: 50, // 增加搜索结果数量
+            pageNum: 1,
+            status: 1 // 只查询有效的优惠券
+          }).then(response => {
+            this.couponOptions = response.data.list || [];
+            this.couponLoading = false;
+          }).catch(() => {
+            this.couponLoading = false;
+            this.couponOptions = [];
+            this.$message.error('搜索优惠券失败');
+          });
+        } else {
+          // 如果搜索为空,加载默认选项
+          this.loadDefaultCoupons();
+        }
+      }, 300);
+    },
+
+    // 加载已选择的优惠券
+    loadSelectedCoupons(couponIds) {
+      if (couponIds && couponIds.length > 0) {
+        this.couponLoading = true;
+        getCouponList({
+          couponIds: couponIds.join(',')
+        }).then(response => {
+          // 合并已选择的优惠券到选项中,避免重复
+          const selectedCoupons = response.data.list || [];
+          const existingIds = this.couponOptions.map(item => item.couponId);
+
+          selectedCoupons.forEach(coupon => {
+            if (!existingIds.includes(coupon.couponId)) {
+              this.couponOptions.push(coupon);
+            }
+          });
+
+          this.couponLoading = false;
+        }).catch(() => {
+          this.couponLoading = false;
+        });
+      }
+    },
+
+    // 获取完整的图片URL
+    getImageUrl(url) {
+      if (!url) return '';
+      // 如果已经是完整URL,直接返回
+      if (url.startsWith('http://') || url.startsWith('https://')) {
+        return url;
+      }
+      // 如果是相对路径,拼接基础URL
+      return process.env.VUE_APP_BASE_API + url;
+    },
+
+    // 图标上传前校验
+    beforeIconUpload(file) {
+      const isJPG = file.type === 'image/jpeg';
+      const isPNG = file.type === 'image/png';
+      const isGIF = file.type === 'image/gif';
+      const isWebP = file.type === 'image/webp';
+      const isLt2M = file.size / 1024 /1024 < 2; // 限制大小为2MB
+      if (!isJPG && !isPNG && !isGIF && !isWebP) {
+        this.$message.error('上传头像图片只能是 JPG、PNG、GIF 或 WebP 格式!');
+      }
+      if (!isLt2M) {
+        this.$message.error('上传头像图片大小不能超过 2MB!');
+      }
+      return (isJPG || isPNG || isGIF || isWebP) && isLt2M;
+    },
+
+    // 图标上传成功后处理
+    handleIconUploadSuccess(response, file) {
+      if (response && response.url) {
+        this.form.iconUrl = response.url; // 赋值上传后的图片URL
+      } else {
+        this.$message.error('图标上传失败,请重试');
+      }
+    },
+
+    // 图标上传失败处理
+    handleIconUploadError() {
+      this.$message.error('图标上传失败,请重试');
+    },
+    handleIconSuccess(response, file) {
+      // 处理图标上传成功的逻辑
+      this.form.iconUrl = response.url; // 假设返回的数据结构有URL
+      this.$message.success('图标上传成功!');
+    },
+    handleIconError(err, file) {
+      // 处理图标上传失败的逻辑
+      this.$message.error('图标上传失败,请重试.');
+    },
   }
 };
 </script>
+
+<style scoped>
+.dialog-footer {
+  text-align: right;
+}
+</style>
+