Browse Source

add:签到抽奖

ct 3 ngày trước cách đây
mục cha
commit
17096f54d9

+ 53 - 0
src/api/reward/reward.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询奖励配置列表
+export function listReward(query) {
+  return request({
+    url: '/course/reward/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询奖励配置详细
+export function getReward(id) {
+  return request({
+    url: '/course/reward/' + id,
+    method: 'get'
+  })
+}
+
+// 新增奖励配置
+export function addReward(data) {
+  return request({
+    url: '/course/reward',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改奖励配置
+export function updateReward(data) {
+  return request({
+    url: '/course/reward',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除奖励配置
+export function delReward(id) {
+  return request({
+    url: '/course/reward/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出奖励配置
+export function exportReward(query) {
+  return request({
+    url: '/course/reward/export',
+    method: 'get',
+    params: query
+  })
+}

+ 44 - 0
src/api/reward/rewardGoods.js

@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询奖励商品列表
+export const listRewardGoods = (query) => request({
+  url: '/reward/rewardGoods/list',
+  method: 'get',
+  params: query
+})
+
+// 查询奖励商品详情
+export const getRewardGoods = (id) => request({
+  url: '/reward/rewardGoods/' + id,
+  method: 'get'
+})
+
+// 新增奖励商品
+export const addRewardGoods = (data) => request({
+  url: '/reward/rewardGoods',
+  method: 'post',
+  data: data
+})
+
+// 修改奖励商品
+export const updateRewardGoods = (data) => request({
+  url: '/reward/rewardGoods',
+  method: 'put',
+  data: data
+})
+
+// 删除奖励商品
+export const delRewardGoods = (id) => request({
+  url: '/reward/rewardGoods/' + id,
+  method: 'delete'
+})
+
+// 根据ids查询列表
+export function getGoodsByIds(query) {
+  return request({
+    url: '/reward/rewardGoods/getByIds',
+    method: 'get',
+    params: query
+  })
+}
+

+ 32 - 0
src/api/reward/rewardGoodsOrder.js

@@ -0,0 +1,32 @@
+import request from '@/utils/request'
+
+// 查询奖励商品订单列表
+export const listRewardGoodsOrder = (query) => request({
+  url: '/reward/rewardGoodsOrder/list',
+  method: 'get',
+  params: query
+})
+
+// 查询奖励商品订单详情
+export const getRewardGoodsOrder = (id) => request({
+  url: '/reward/rewardGoodsOrder/' + id,
+  method: 'get'
+})
+
+// 查询支付信息
+export const getRewardGoodsOrderPayInfo = (orderSn) => request({
+  url: '/reward/rewardGoodsOrder/payment/' + orderSn,
+  method: 'get'
+})
+
+// 查询物流信息
+export const getExpress = (orderId) => request({
+  url: '/reward/rewardGoodsOrder/getExpress/' + orderId,
+  method: 'get'
+})
+
+// 取消订单
+export const cancelOrder = (orderId) => request({
+  url: '/reward/rewardGoodsOrder/cancelOrder/' + orderId,
+  method: 'put'
+})

+ 53 - 0
src/api/reward/rewardRound.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询奖励领取记录列表
+export function listRewardRound(query) {
+  return request({
+    url: '/course/rewardRound/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询奖励领取记录详细
+export function getRewardRound(id) {
+  return request({
+    url: '/course/rewardRound/' + id,
+    method: 'get'
+  })
+}
+
+// 新增奖励领取记录
+export function addRewardRound(data) {
+  return request({
+    url: '/course/rewardRound',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改奖励领取记录
+export function updateRewardRound(data) {
+  return request({
+    url: '/course/rewardRound',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除奖励领取记录
+export function delRewardRound(id) {
+  return request({
+    url: '/course/rewardRound/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出奖励领取记录
+export function exportRewardRound(query) {
+  return request({
+    url: '/course/rewardRound/export',
+    method: 'get',
+    params: query
+  })
+}

+ 209 - 0
src/views/components/course/rewardGoodsComponent.vue

@@ -0,0 +1,209 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="商品ID" prop="goodsId">
+        <el-input
+          v-model="queryParams.goodsId"
+          placeholder="请输入商品ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="商品名称" prop="goodsName">
+        <el-input
+          v-model="queryParams.goodsName"
+          placeholder="请输入商品名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="所属店铺" prop="storeId">
+        <el-select v-model="queryParams.storeId" placeholder="请选择店铺" clearable size="small">
+          <el-option
+            v-for="dict in storeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="商品编码" prop="storeGoodsSn">
+        <el-input
+          v-model="queryParams.storeGoodsSn"
+          placeholder="请输入商品编码"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table v-loading="loading" border :data="goodsList">
+      <el-table-column label="商品ID" align="center" prop="goodsId" />
+      <el-table-column label="商品图片" align="center" prop="goodsImg" width="120">
+        <template slot-scope="scope">
+          <el-popover
+            placement="right"
+            title=""
+            trigger="hover"
+          >
+            <img slot="reference" :src="scope.row.goodsImg" width="100">
+            <img :src="scope.row.goodsImg" style="max-width: 150px;">
+          </el-popover>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="商品名称" align="center" prop="goodsName" show-overflow-tooltip />
+      <el-table-column label="所属店铺" align="center" prop="storeName" />
+      <el-table-column label="商品编码" align="center" prop="storeGoodsSn" />
+      <el-table-column label="原价" align="center" prop="opPrice" />
+      <el-table-column label="单价" align="center" prop="price" />
+      <el-table-column label="库存" align="center" prop="stock" />
+      <el-table-column label="状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="排序" align="center" prop="sort" />
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180"/>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="180" fixed="right">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            @click="selectGoods(scope.row)"
+          >选择
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
+</template>
+
+<script>
+import { listRewardGoods } from "@/api/reward/rewardGoods";
+import { listStore } from '@/api/his/storeProduct'
+
+export default {
+  name: "RewardGoods",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 奖励商品表格数据
+      goodsList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 图片数组
+      imageArr: [],
+      // 轮播图
+      photoArr: [],
+      // 店铺选项
+      storeOptions: [],
+      // 状态选项
+      statusOptions: [],
+      activeName: '1',
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        goodsId: null,
+        goodsName: null,
+        storeId: null,
+        storeGoodsSn: null,
+        status: 1
+      },
+    };
+  },
+  created() {
+    this.getStoreList();
+    this.getList();
+    this.getDicts("sys_spec_show").then(response => {
+      this.statusOptions = response.data;
+    });
+  },
+  methods: {
+    selectGoods(row) {
+      this.$emit("select-goods", {"id": row.goodsId, "name": row.goodsName });
+    },
+    handleClick(tab) {
+      this.queryParams.status = tab.name
+      this.getList()
+    },
+    getStoreList() {
+      listStore().then(response => {
+        const {rows} = response
+        this.storeOptions = rows
+      });
+    },
+    /** 查询奖励商品列表 */
+    getList() {
+      this.loading = true;
+      listRewardGoods(this.queryParams).then(response => {
+        this.goodsList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+  }
+};
+</script>
+
+<style scoped>
+.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: 150px;
+  height: 150px;
+  line-height: 150px;
+  text-align: center;
+}
+</style>

+ 187 - 0
src/views/components/his/couponComponent.vue

@@ -0,0 +1,187 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="标题" prop="title">
+        <el-input
+          v-model="queryParams.title"
+          placeholder="请输入标题"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="有效期" prop="limitTime">
+        <el-date-picker v-model="limitTime" size="small" style="width: 220px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="change"></el-date-picker>
+      </el-form-item>
+      <el-form-item label="面额" prop="price">
+        <el-input
+          v-model="queryParams.price"
+          placeholder="请输入面额"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" border :data="couponList">
+      <el-table-column label="优惠券名称" align="center" prop="title" width="120px"/>
+      <el-table-column label="面额" align="center" prop="price" />
+      <el-table-column label="折扣" align="center" prop="rate" />
+      <el-table-column label="数量" align="center" prop="number" />
+      <el-table-column label="卷类型 " align="center" prop="couponType" width="120px">
+        <template slot-scope="scope">
+          <dict-tag :options="couponTypeOptions" :value="scope.row.couponType"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="最低消费金额可用" align="center" prop="minPrice" />
+      <el-table-column label="剩余数量" align="center" prop="remainNumber" />
+      <el-table-column label="有效期" align="center" prop="limitTime" width="180"/>
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180"/>
+      <el-table-column label="更改时间" align="center" prop="updateTime" width="180"/>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="150px">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            @click="selectCoupon(scope.row)"
+          >选择
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
+</template>
+
+<script>
+import { listCoupon } from "@/api/his/coupon";
+export default {
+  name: "CouponComponent",
+  data() {
+    return {
+      limitTime:[],
+      // 遮罩层
+      loading: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 优惠券表格数据
+      couponList: [],
+      statusOptions: [],
+      // 卷类型 1代金券 字典
+      couponTypeOptions: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        title: null,
+        limitTime: null,
+        price: null,
+        number: null,
+        couponType: 7,
+        minPrice: null,
+        remainNumber: null,
+        sTime:null,
+        eTime:null
+      },
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("sys_coupon_type").then(response => {
+      this.couponTypeOptions = response.data;
+    });
+    this.getDicts("sys_company_status").then(response => {
+      this.statusOptions = response.data;
+    });
+  },
+  methods: {
+    selectCoupon(row) {
+      this.$emit("select-coupon", {"id": row.couponId, "name": row.title });
+    },
+    /** 查询优惠券列表 */
+    getList() {
+      this.loading = true;
+      listCoupon(this.queryParams).then(response => {
+        this.couponList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        couponId: null,
+        title: null,
+        createTime: null,
+        limitTime: null,
+        price: null,
+        number: null,
+        couponType: null,
+        minPrice: null,
+        remainNumber: null,
+        status:"1",
+        rate:0,
+        limitDay:1,
+        limitCount:1,
+        limitType:null,
+        cateIds:null,
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.limitTime=null;
+      this.queryParams.sTime=null;
+      this.queryParams.eTime=null;
+      this.handleQuery();
+    },
+    change(){
+      if(this.limitTime!=null){
+        this.queryParams.sTime=this.limitTime[0];
+        this.queryParams.eTime=this.limitTime[1];
+      }else{
+        this.queryParams.sTime=null;
+        this.queryParams.eTime=null;
+      }
+    },
+  }
+};
+</script>
+<style scoped>
+::v-deep .el-table--scrollable-x .el-table__body-wrapper {
+  height: 70vh;
+}
+</style>

+ 3 - 3
src/views/his/coupon/index.vue

@@ -209,7 +209,7 @@
             ></el-option>
           </el-select>
         </el-form-item>
-        <el-form-item label="可用分类" prop="cateIds" v-show="form.couponType==5||form.couponType==6">
+        <el-form-item label="可用分类" prop="cateIds" v-show="form.couponType==5||form.couponType==6||form.couponType==7">
           <el-select v-model="form.cateIds" multiple placeholder="请选择可用分类">
             <el-option
               v-for="dict in cateIdsOptions"
@@ -219,10 +219,10 @@
             ></el-option>
           </el-select>
         </el-form-item>
-        <el-form-item label="面额" prop="price" v-if="form.couponType==1||form.couponType==5||form.couponType==6">
+        <el-form-item label="面额" prop="price" v-if="form.couponType==1||form.couponType==5||form.couponType==6||form.couponType==7">
           <el-input-number v-model="form.price"  :min="0"  label="请输入面额"></el-input-number>
         </el-form-item>
-        <el-form-item label="最低消费" prop="minPrice" v-if="form.couponType==1||form.couponType==5||form.couponType==6">
+        <el-form-item label="最低消费" prop="minPrice" v-if="form.couponType==1||form.couponType==5||form.couponType==6||form.couponType==7">
            <el-input-number v-model="form.minPrice"  :min="0"  label="请输入最低消费金额可用"></el-input-number>
         </el-form-item>
         <el-form-item label="打折百分比" prop="rate" v-if="form.couponType==4">

+ 114 - 0
src/views/his/reward/goodsDetail.vue

@@ -0,0 +1,114 @@
+<template>
+  <div style="background-color: #f0f2f5; padding-bottom: 20px; min-height: 100%; " >
+    <div style="padding: 20px; background-color: #fff;">
+      商品详情
+    </div>
+
+    <div class="content" v-if="item!=null">
+      <div class="desct">
+        商品信息
+      </div>
+      <el-descriptions title="" :column="3" border>
+        <el-descriptions-item label="店铺名称"  >
+          <span>{{item.storeName}}</span>
+        </el-descriptions-item>
+        <el-descriptions-item label="商品编码" >
+          <span>{{item.storeGoodsSn}}</span>
+        </el-descriptions-item>
+        <el-descriptions-item label="商品图片" >
+          <el-image v-if="item.goodsImg != null"
+                    style="width: 100px"
+                    :src="item.goodsImg"
+                    :preview-src-list="[item.goodsImg]">
+          </el-image>
+        </el-descriptions-item>
+        <el-descriptions-item label="商品名称" >
+          <span>{{item.goodsName}}</span>
+        </el-descriptions-item>
+        <el-descriptions-item label="商品介绍"  >
+          <span>{{item.goodsIntroduce}}</span>
+        </el-descriptions-item>
+        <el-descriptions-item label="商品价格" >
+          <span>{{item.price}}</span>
+        </el-descriptions-item>
+        <el-descriptions-item label="商品原价" >
+          <span>{{item.opPrice}}</span>
+        </el-descriptions-item>
+        <el-descriptions-item label="库存" >
+          <span>{{item.stock}}</span>
+        </el-descriptions-item>
+        <el-descriptions-item label="排序" >
+          <span>{{item.sort}}</span>
+        </el-descriptions-item>
+        <el-descriptions-item label="状态" >
+          <dict-tag :options="statusOptions" :value="item.status"/>
+        </el-descriptions-item>
+        <el-descriptions-item label="创建时间" >
+          <span>{{item.createTime}}</span>
+        </el-descriptions-item>
+        <el-descriptions-item label="更新时间" >
+          <span>{{item.updateTime}}</span>
+        </el-descriptions-item>
+        <el-descriptions-item label="备注" >
+          <span>{{item.remark}}</span>
+        </el-descriptions-item>
+      </el-descriptions>
+    </div>
+
+    <div class="content" v-if="item!=null">
+      <div class="desct">
+        商品描述
+      </div>
+      <span v-html="item.goodsDesc"></span>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getRewardGoods } from '@/api/reward/rewardGoods'
+
+export default {
+  name: "GoodsDetail",
+  data() {
+    return {
+      item: {},
+      statusOptions: null
+    }
+  },
+  created() {
+    this.getDicts("sys_spec_show").then(response => {
+      this.statusOptions = response.data;
+    });
+  },
+  methods: {
+    getDetails(id) {
+      getRewardGoods(id).then(response => {
+        this.item = response.data;
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.el-descriptions-item__content {
+  max-width: 150px;
+  min-width: 100px;
+}
+.content{
+  height: 100%;
+  background-color: #fff;
+  padding: 0px 20px 20px;
+
+  margin: 20px;
+}
+.el-descriptions-item__label.is-bordered-label{
+  font-weight: normal;
+}
+.desct {
+  padding-top: 20px;
+  padding-bottom: 20px;
+  color: #524b4a;
+  font-weight: bold;
+}
+</style>

+ 309 - 0
src/views/his/reward/goodsOrderDetail.vue

@@ -0,0 +1,309 @@
+<template>
+  <div style="background-color: #f0f2f5; padding-bottom: 20px; min-height: 100%;">
+    <div style="padding: 20px; background-color: #fff;">
+      订单详情
+    </div>
+
+    <div class="contentx" v-if="item != null">
+      <div class="desct"></div>
+      <div class="order-status">
+        <el-steps :active="getActiveStep(item.status)" align-center finish-status="success">
+          <el-step title="待支付"></el-step>
+          <el-step title="已支付"></el-step>
+          <el-step title="已发货"></el-step>
+          <el-step title="已完成"></el-step>
+          <el-step title="已取消" v-if="item.status === -1"></el-step>
+        </el-steps>
+      </div>
+
+      <el-card shadow="never" style="margin-top: 15px">
+        <div class="operate-container">
+          <span style="margin-left: 20px">订单状态:
+            <el-tag prop="status" v-for="(ite, index) in orderStatusOptions" v-if="item.status == ite.dictValue">{{ite.dictLabel}}</el-tag>
+          </span>
+        </div>
+        <div class="desct">
+          基本信息
+        </div>
+        <el-descriptions title="" :column="3" border>
+          <el-descriptions-item label="订单ID">
+            <span>{{ item.orderId }}</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="订单编号">
+            <span>{{ item.orderSn }}</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="订单状态">
+            <dict-tag :options="orderStatusOptions" :value="item.status"/>
+          </el-descriptions-item>
+          <el-descriptions-item label="所属店铺">
+            <span>{{ item.storeName }}</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="下单用户">
+            <span>{{ item.nickName }}</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="收货人">
+            <span>{{ item.userName }}</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="订单金额">
+            <span class="color-danger">¥{{ item.orderMoney }}</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="支付金额">
+            <span class="color-danger">¥{{ item.payMoney }}</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="快递单号">
+            <span>{{ item.deliverySn || '-' }}</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="下单时间">
+            <span>{{ item.createTime }}</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="支付时间">
+            <span v-if="item.payTime">{{ item.payTime }}</span>
+            <span v-else>-</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="备注">
+            <span>{{ item.remark || '-' }}</span>
+          </el-descriptions-item>
+        </el-descriptions>
+      </el-card>
+    </div>
+
+    <div class="contentx" style="padding-bottom: 70px;" v-if="item != null">
+      <div class="desct">
+        商品信息
+      </div>
+      <el-table border v-if="item.goodsJson" :data="[JSON.parse(item.goodsJson)]" size="small" style="width: 100%;margin-top: 20px">
+        <el-table-column label="商品图片" min-width="150" align="center">
+          <template slot-scope="scope">
+            <el-image
+              v-if="scope.row.goodsImg"
+              style="height: 80px"
+              :src="scope.row.goodsImg"
+              :preview-src-list="[scope.row.goodsImg]"
+              fit="cover">
+            </el-image>
+            <span v-else>-</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品编码" min-width="200" align="center">
+          <template slot-scope="scope">
+            <span>{{ scope.row.storeGoodsSn || '-' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品名称" min-width="300" align="center">
+          <template slot-scope="scope">
+            <span>{{ scope.row.goodsName || '-' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品原价" min-width="150" align="center">
+          <template slot-scope="scope">
+            <span>¥{{ (scope.row.opPrice || 0).toFixed(2) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品单价" min-width="150" align="center">
+          <template slot-scope="scope">
+            <span>¥{{ (scope.row.price || 0).toFixed(2) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="购买数量" min-width="120" align="center">
+          <template slot-scope="scope">
+            <span>1</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品总价" min-width="150" align="center">
+          <template slot-scope="scope">
+            <span class="color-danger">¥{{ scope.row.price.toFixed(2) }}</span>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div style="float: right;margin: 20px" v-if="item.payMoney != null">
+        合计:<span class="color-danger">¥{{ (item.payMoney || 0).toFixed(2) }}</span>
+      </div>
+    </div>
+
+    <div class="contentx" v-if="item != null">
+      <div class="desct">
+        支付信息
+      </div>
+      <el-table
+        border
+        :data="payList"
+        size="small"
+        style="width: 100%;margin-top: 20px">
+        <el-table-column label="支付单号" align="center" prop="payCode" />
+        <el-table-column label="支付金额" align="center" prop="payMoney">
+          <template slot-scope="scope">
+            <span>¥{{ scope.row.payMoney.toFixed(2) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="支付方式" align="center" prop="payTypeCode" />
+        <el-table-column label="外部订单号" align="center" prop="tradeNo" />
+        <el-table-column label="创建时间" align="center" prop="createTime" />
+        <el-table-column label="支付时间" align="center" prop="payTime" />
+      </el-table>
+    </div>
+
+    <div class="contentx" v-if="item != null">
+      <div class="desct">
+        物流信息
+      </div>
+      <el-table
+        border
+        :data="expressList"
+        size="small"
+        style="width: 100%;margin-top: 20px">
+        <el-table-column label="操作时间" align="center" prop="AcceptTime" />
+        <el-table-column label="位置" align="center" prop="Location" />
+        <el-table-column label="描述" align="center" prop="AcceptStation" />
+      </el-table>
+    </div>
+
+    <div class="contentx" v-if="item != null">
+      <div class="desct">
+        操作记录
+      </div>
+      <el-timeline>
+        <el-timeline-item
+          v-for="(activity, index) in orderLogs"
+          :key="index"
+          :timestamp="parseTime(activity.createTime, '{y}-{m}-{d} {h}:{i}:{s}')"
+        >
+          {{ activity.content }}
+          <el-tag size="mini" style="margin-left: 10px;">{{ activity.operator }}</el-tag>
+        </el-timeline-item>
+      </el-timeline>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getExpress, getRewardGoodsOrder, getRewardGoodsOrderPayInfo } from '@/api/reward/rewardGoodsOrder'
+import Template from '@/views/his/complaint/template.vue'
+ 
+export default {
+  name: "GoodsOrderDetail",
+  components: { Template },
+  data() {
+    return {
+      item: null,
+      orderStatusOptions: [],
+      payStatusOptions: [],
+      payList: [],
+      expressList: [],
+      orderLogs: []
+    }
+  },
+  created() {
+    this.getDicts("sys_reward_order_status").then(response => {
+      this.orderStatusOptions = response.data;
+    });
+    this.getDicts("sys_reward_pay_status").then(response => {
+      this.payStatusOptions = response.data;
+    });
+  },
+  methods: {
+    getDetails(id) {
+      getRewardGoodsOrder(id).then(response => {
+        this.item = response.data;
+
+        // 初始化支付信息
+        this.payList = [];
+        if (this.item.payMoney && this.item.payMoney > 0) {
+          getRewardGoodsOrderPayInfo(this.item.orderSn).then(res => {
+            this.payList = res.data;
+          })
+        }
+
+        // 物流信息
+        this.expressList = []
+        if (this.item.deliverySn) {
+          getExpress(this.item.orderId).then(response => {
+            const data = response.data
+            this.expressList = data?.Traces || []
+          });
+        }
+
+        // 模拟操作记录,实际应该从后端获取
+        this.orderLogs = [
+          {
+            content: '订单创建',
+            operator: '系统',
+            createTime: this.item.createTime
+          }
+        ];
+        if (this.item.payTime) {
+          this.orderLogs.push({
+            content: '订单支付成功',
+            operator: '系统',
+            createTime: this.item.payTime
+          });
+        }
+        if (this.item.deliveryTime) {
+          this.orderLogs.push({
+            content: '订单已发货',
+            operator: '系统',
+            createTime: this.item.deliveryTime
+          });
+        }
+        if (this.item.finishTime) {
+          this.orderLogs.push({
+            content: '订单已完成',
+            operator: '系统',
+            createTime: this.item.finishTime
+          });
+        }
+        if (this.item.cancelTime) {
+          this.orderLogs.push({
+            content: '订单已取消',
+            operator: '系统',
+            createTime: this.item.cancelTime
+          });
+        }
+      })
+    },
+    getActiveStep(status) {
+      // 根据订单状态返回当前步骤
+      const statusMap = {
+        '1': 0, // 待支付
+        '2': 1, // 已支付
+        '3': 2, // 已发货
+        '4': 3, // 已完成
+        '-1': 4  // 已取消
+      };
+      return statusMap[status] || 0;
+    }
+  }
+}
+</script>
+
+<style scoped>
+.contentx {
+  height: 100%;
+  background-color: #fff;
+  padding: 0px 20px 20px;
+  margin: 20px;
+}
+
+.desct {
+  padding-top: 20px;
+  padding-bottom: 20px;
+  color: #524b4a;
+  font-weight: bold;
+}
+
+.color-warning {
+  color: #e6a23c;
+  font-weight: bold;
+}
+
+.el-descriptions-item__content {
+  max-width: 150px;
+  min-width: 100px;
+}
+
+.operate-container {
+  background: #F2F6FC;
+  height: 60px;
+  margin: -20px -20px 0;
+  line-height: 60px;
+}
+</style>

+ 1606 - 0
src/views/his/reward/index.vue

@@ -0,0 +1,1606 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="奖励名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入奖励名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="奖励描述" prop="description">
+        <el-input
+          v-model="queryParams.description"
+          placeholder="请输入奖励描述"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="奖励类型" prop="rewardType">
+        <el-select v-model="queryParams.rewardType" placeholder="请选择奖励类型" clearable size="small">
+          <el-option
+            v-for="item in typeOptions"
+            :key="item.dictValue"
+            :label="item.dictLabel"
+            :value="item.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['course:reward:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['course:reward:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['course:reward:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['course:reward:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="rewardList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="主键ID" align="center" prop="id" />
+      <el-table-column label="奖励名称" align="center" prop="name" />
+      <el-table-column label="奖励描述" align="center" prop="description" />
+      <el-table-column label="奖励类型" align="center" prop="rewardType">
+        <template slot-scope="scope">
+          <dict-tag :options="typeOptions" :value="scope.row.rewardType"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="期望值" align="center" prop="expectedValue" />
+      <el-table-column label="实际奖励内容" align="center" prop="actualRewards">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-view"
+            @click="handleViewReward(scope.row)"
+          >查看详情</el-button>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['course:reward:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['course:reward:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改奖励配置对话框 -->
+    <el-dialog :title="title" :visible.sync="open" :width="width" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="奖励名称" prop="name">
+          <el-input v-model="form.name" placeholder="请输入奖励名称" @input="updateRewardItemsName" />
+        </el-form-item>
+        <el-form-item label="奖励类型" prop="rewardType">
+          <el-select v-model="form.rewardType" placeholder="请选择奖励类型" @change="handleRewardTypeChange">
+            <el-option
+              v-for="item in typeOptions"
+              :key="item.dictValue"
+              :label="item.dictLabel"
+              :value="item.dictValue"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="期望值" prop="expectedValue">
+          <el-input-number :min="0" :precision="2" :step="1" v-model="form.expectedValue" placeholder="期望值" />
+        </el-form-item>
+        <el-form-item v-if="form.rewardType === '1'" label="宝箱图片">
+          <div class="image-upload-group">
+            <div class="image-upload-item">
+              <span>关闭图片</span>
+              <el-upload
+                v-model="form.closeChestUrl"
+                class="avatar-uploader"
+                :action="uploadUrl"
+                :show-file-list="false"
+                :on-success="handleSuccessClose"
+                :before-upload="beforeUpload">
+                <img v-if="form.closeChestUrl" :src="form.closeChestUrl" class="avatar">
+                <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+              </el-upload>
+            </div>
+
+            <div class="image-upload-item">
+              <span>开启图片</span>
+              <el-upload
+                v-model="form.openChestUrl"
+                class="avatar-uploader"
+                :action="uploadUrl"
+                :show-file-list="false"
+                :on-success="handleSuccessOpen"
+                :before-upload="beforeUpload">
+                <img v-if="form.openChestUrl" :src="form.openChestUrl" class="avatar">
+                <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+              </el-upload>
+            </div>
+          </div>
+        </el-form-item>
+        <el-form-item v-if="form.rewardType === '2'"
+                      label="红包金额" prop="account">
+          <el-input-number v-model="form.account" :min="0" :step="0.1" style="width: 200px;"></el-input-number>
+        </el-form-item>
+        <el-form-item v-if="form.rewardType === '3'"
+                      label="积分币数" prop="account">
+          <el-input-number v-model="form.account" :min="0" :step="1" style="width: 200px;"></el-input-number>
+        </el-form-item>
+        <el-form-item v-if="form.rewardType === '1'" label="宝箱奖励" prop="rewardItems">
+          <div class="reward-table-container">
+            <div class="table-header">
+              <span>宝箱奖励配置</span>
+              <el-button type="primary" icon="el-icon-plus" size="mini" @click="addRewardItem">添加奖励项</el-button>
+            </div>
+            <el-table :data="form.rewardItems" border size="small">
+              <el-table-column v-if="false" label="奖励名称" >
+                <template slot-scope="scope">
+                  <el-input v-model="scope.row.name" :placeholder="form.name || '请输入奖励名称'"></el-input>
+                </template>
+              </el-table-column>
+              <el-table-column label="奖励模式">
+                <template slot-scope="scope">
+                  <el-select v-model="scope.row.jltype" disabled placeholder="请选择奖励模式" style="width: 100%">
+                    <el-option
+                      v-for="item in jltypeOptions"
+                      :key="item.dictValue"
+                      :label="item.dictLabel"
+                      :value="item.dictValue"
+                    />
+                  </el-select>
+                </template>
+              </el-table-column>
+              <el-table-column label="奖励数量">
+                <template slot-scope="scope">
+                  <el-input-number v-model="scope.row.amount" :min="1" :controls="false" style="width: 100%"></el-input-number>
+                </template>
+              </el-table-column>
+              <el-table-column label="概率" >
+                <template slot-scope="scope">
+                  <el-input v-model="scope.row.probability" placeholder="例如: 20%"></el-input>
+                </template>
+              </el-table-column>
+              <el-table-column  v-if="false" label="唯一序列号" >
+                <template slot-scope="scope">
+                  <el-input v-model="scope.row.code" placeholder="奖励唯一序列号">
+                    <el-button slot="append" icon="el-icon-refresh" @click="generateUUID(scope.row)"></el-button>
+                  </el-input>
+                </template>
+              </el-table-column>
+              <el-table-column label="操作" width="80">
+                <template slot-scope="scope">
+                  <el-button type="danger" icon="el-icon-delete" size="mini" @click="removeRewardItem(scope.$index)"></el-button>
+                </template>
+              </el-table-column>
+            </el-table>
+          </div>
+        </el-form-item>
+
+        <el-form-item v-if="form.rewardType === '4'" label="转盘奖励" prop="rewardItems">
+          <div class="reward-table-container spin-reward">
+            <div class="table-header">
+              <span>转盘奖励配置</span>
+              <el-button type="primary" icon="el-icon-plus" @click="addSpinRewardItem">添加奖励项</el-button>
+            </div>
+            <div class="spin-tips">建议:概率填写为百分比字符串,如 12.5% ,各项之和=100%</div>
+            <el-table :data="form.rewardItems" border stripe>
+              <el-table-column label="图标" align="center" width="72">
+                <template slot-scope="scope">
+                  <el-upload
+                    class="spin-icon-uploader"
+                    :action="uploadUrl"
+                    :show-file-list="false"
+                    :before-upload="beforeUpload"
+                    accept="image/*"
+                    :on-success="(res,file)=>handleSpinIconSuccess(res, scope.row)"
+                  >
+                    <img v-if="scope.row.iconUrl" :src="scope.row.iconUrl" class="spin-icon" />
+                    <i v-else class="el-icon-plus avatar-uploader-icon spin-icon"></i>
+                  </el-upload>
+                </template>
+              </el-table-column>
+              <el-table-column label="奖励名称" align="center">
+                <template slot-scope="scope">
+                  <el-input v-model="scope.row.name" placeholder="请输入奖励名称"></el-input>
+                </template>
+              </el-table-column>
+              <el-table-column label="奖励类型" align="center" width="120">
+                <template slot-scope="scope">
+                  <el-select v-model="scope.row.type" @change="changeType(scope.row)" placeholder="选择类型" style="width: 100%">
+                    <el-option
+                      v-for="opt in spinItemTypeOptions"
+                      :key="opt.dictValue"
+                      :label="opt.dictLabel"
+                      :value="opt.dictValue"
+                    />
+                  </el-select>
+                </template>
+              </el-table-column>
+              <el-table-column label="优惠券" align="center">
+                <template slot-scope="scope">
+                  <el-select
+                    :disabled="scope.row.type !== '4'"
+                    :ref="`customSelect_${scope.row.code}`"
+                    v-model="scope.row.couponId"
+                    placeholder="请选择优惠券"
+                    @click.native.stop="scope.row.type === '4' ? openCouponDrawer(scope.row) : null"
+                    clearable
+                    style="width: 100%;">
+                    <el-option
+                      v-for="item in couponList"
+                      :key="item.id"
+                      :label="item.name"
+                      :value="item.id">
+                    </el-option>
+                  </el-select>
+                </template>
+              </el-table-column>
+              <el-table-column label="商品" align="center">
+                <template slot-scope="scope">
+                  <el-select
+                    :disabled="scope.row.type !== '5'"
+                    :ref="`customSelect_${scope.row.code}`"
+                    v-model="scope.row.goodsId"
+                    placeholder="请选择商品"
+                    @click.native.stop="scope.row.type === '5' ? openGoodsDrawer(scope.row) : null"
+                    clearable
+                    style="width: 100%;">
+                    <el-option
+                      v-for="item in goodsList"
+                      :key="item.id"
+                      :label="item.name"
+                      :value="item.id">
+                    </el-option>
+                  </el-select>
+                </template>
+              </el-table-column>
+              <el-table-column label="奖励数量" align="center" show-overflow-tooltip width="180">
+                <template slot-scope="scope">
+                  <el-input :disabled="scope.row.type === '5'" v-model="scope.row.amount" :controls="false" style="width: 100%"/>
+                </template>
+              </el-table-column>
+              <el-table-column label="概率" align="center" class-name="probability-col" width="120">
+                <template slot-scope="scope">
+                  <el-input v-model="scope.row.probability" placeholder="例如: 10%"></el-input>
+                </template>
+              </el-table-column>
+              <el-table-column v-if="false" label="唯一序列号">
+                <template slot-scope="scope">
+                  <el-input v-model="scope.row.code" placeholder="奖励唯一序列号">
+                    <el-button slot="append" icon="el-icon-refresh" @click="generateUUID(scope.row)"></el-button>
+                  </el-input>
+                </template>
+              </el-table-column>
+              <el-table-column label="操作" align="center" width="80">
+                <template slot-scope="scope">
+                  <el-button type="danger" icon="el-icon-delete" @click="removeRewardItem(scope.$index)"></el-button>
+                </template>
+              </el-table-column>
+            </el-table>
+          </div>
+        </el-form-item>
+
+        <el-form-item v-if="form.rewardType === '5'" label="保底转盘" prop="rewardItems">
+          <div class="reward-table-container spin-reward">
+            <div class="table-header">
+              <span>保底转盘奖励配置</span>
+              <el-button type="primary" icon="el-icon-plus" @click="addSpinRewardItem2">添加奖励项</el-button>
+            </div>
+            <div class="spin-tips">
+              建议:概率填写为百分比字符串,如 12.5% ,各项之和=100%
+              <br/>
+              保底:保底奖励只能有1个且最后5次才能抽中
+            </div>
+            <el-table :data="form.rewardItems" border stripe>
+              <el-table-column label="图标" align="center" width="72">
+                <template slot-scope="scope">
+                  <el-upload
+                    class="spin-icon-uploader"
+                    :action="uploadUrl"
+                    :show-file-list="false"
+                    :before-upload="beforeUpload"
+                    accept="image/*"
+                    :on-success="(res,file)=>handleSpinIconSuccess(res, scope.row)"
+                  >
+                    <img v-if="scope.row.iconUrl" :src="scope.row.iconUrl" class="spin-icon" />
+                    <i v-else class="el-icon-plus avatar-uploader-icon spin-icon"></i>
+                  </el-upload>
+                </template>
+              </el-table-column>
+              <el-table-column label="奖励名称" align="center">
+                <template slot-scope="scope">
+                  <el-input v-model="scope.row.name" placeholder="请输入奖励名称"></el-input>
+                </template>
+              </el-table-column>
+              <el-table-column label="奖励类型" align="center" width="120">
+                <template slot-scope="scope">
+                  <el-select v-model="scope.row.type" @change="changeType(scope.row)" placeholder="选择类型" style="width: 100%">
+                    <el-option
+                      v-for="opt in spinItemTypeOptions"
+                      :key="opt.dictValue"
+                      :label="opt.dictLabel"
+                      :value="opt.dictValue"
+                    />
+                  </el-select>
+                </template>
+              </el-table-column>
+              <el-table-column label="优惠券" align="center">
+                <template slot-scope="scope">
+                  <el-select
+                    :disabled="scope.row.type !== '4'"
+                    :ref="`customSelect_${scope.row.code}`"
+                    v-model="scope.row.couponId"
+                    placeholder="请选择优惠券"
+                    @click.native.stop="scope.row.type === '4' ? openCouponDrawer(scope.row) : null"
+                    clearable
+                    style="width: 100%;">
+                    <el-option
+                      v-for="item in couponList"
+                      :key="item.id"
+                      :label="item.name"
+                      :value="item.id">
+                    </el-option>
+                  </el-select>
+                </template>
+              </el-table-column>
+              <el-table-column label="商品" align="center">
+                <template slot-scope="scope">
+                  <el-select
+                    :disabled="scope.row.type !== '5'"
+                    :ref="`customSelect_${scope.row.code}`"
+                    v-model="scope.row.goodsId"
+                    placeholder="请选择商品"
+                    @click.native.stop="scope.row.type === '5' ? openGoodsDrawer(scope.row) : null"
+                    clearable
+                    style="width: 100%;">
+                    <el-option
+                      v-for="item in goodsList"
+                      :key="item.id"
+                      :label="item.name"
+                      :value="item.id">
+                    </el-option>
+                  </el-select>
+                </template>
+              </el-table-column>
+              <el-table-column label="奖励数量" align="center" width="180">
+                <template slot-scope="scope">
+                  <el-input :disabled="scope.row.type === '5'" v-model="scope.row.amount" :controls="false" style="width: 100%"/>
+                </template>
+              </el-table-column>
+              <el-table-column label="概率" align="center" class-name="probability-col" width="120">
+                <template slot-scope="scope">
+                  <el-input v-model="scope.row.probability" placeholder="例如: 10%"></el-input>
+                </template>
+              </el-table-column>
+              <el-table-column label="保底" align="center" width="100">
+                <template slot-scope="scope">
+                  <el-switch
+                    v-model="scope.row.isGuarantee"
+                    active-color="#13ce66">
+                  </el-switch>
+                </template>
+              </el-table-column>
+              <el-table-column v-if="false" label="唯一序列号">
+                <template slot-scope="scope">
+                  <el-input v-model="scope.row.code" placeholder="奖励唯一序列号">
+                    <el-button slot="append" icon="el-icon-refresh" @click="generateUUID(scope.row)"></el-button>
+                  </el-input>
+                </template>
+              </el-table-column>
+              <el-table-column label="操作" align="center" width="80">
+                <template slot-scope="scope">
+                  <el-button type="danger" icon="el-icon-delete" @click="removeRewardItem(scope.$index)"></el-button>
+                </template>
+              </el-table-column>
+            </el-table>
+          </div>
+        </el-form-item>
+
+        <el-form-item v-if="form.rewardType === '6'" label="大礼品" prop="rewardItems">
+          <div class="reward-table-container spin-reward">
+            <div class="table-header">
+              <span>转盘奖励配置</span>
+              <el-button type="primary" icon="el-icon-plus" @click="addSpinRewardItem">添加奖励项</el-button>
+            </div>
+            <div class="spin-tips">建议:概率填写为百分比字符串,如 12.5% ,各项之和=100%</div>
+            <el-table :data="form.rewardItems" border stripe>
+              <el-table-column label="图标" align="center" width="72">
+                <template slot-scope="scope">
+                  <el-upload
+                    class="spin-icon-uploader"
+                    :action="uploadUrl"
+                    :show-file-list="false"
+                    :before-upload="beforeUpload"
+                    accept="image/*"
+                    :on-success="(res,file)=>handleSpinIconSuccess(res, scope.row)"
+                  >
+                    <img v-if="scope.row.iconUrl" :src="scope.row.iconUrl" class="spin-icon" />
+                    <i v-else class="el-icon-plus avatar-uploader-icon spin-icon"></i>
+                  </el-upload>
+                </template>
+              </el-table-column>
+              <el-table-column label="奖励名称" align="center">
+                <template slot-scope="scope">
+                  <el-input v-model="scope.row.name" placeholder="请输入奖励名称"></el-input>
+                </template>
+              </el-table-column>
+              <el-table-column label="奖励类型" align="center" width="120">
+                <template slot-scope="scope">
+                  <el-select v-model="scope.row.type" @change="changeType(scope.row)" placeholder="选择类型" style="width: 100%">
+                    <el-option
+                      v-for="opt in spinItemTypeOptions"
+                      :key="opt.dictValue"
+                      :label="opt.dictLabel"
+                      :value="opt.dictValue"
+                    />
+                  </el-select>
+                </template>
+              </el-table-column>
+              <el-table-column label="优惠券" align="center">
+                <template slot-scope="scope">
+                  <el-select
+                    :disabled="scope.row.type !== '4'"
+                    :ref="`customSelect_${scope.row.code}`"
+                    v-model="scope.row.couponId"
+                    placeholder="请选择优惠券"
+                    @click.native.stop="scope.row.type === '4' ? openCouponDrawer(scope.row) : null"
+                    clearable
+                    style="width: 100%;">
+                    <el-option
+                      v-for="item in couponList"
+                      :key="item.id"
+                      :label="item.name"
+                      :value="item.id">
+                    </el-option>
+                  </el-select>
+                </template>
+              </el-table-column>
+              <el-table-column label="商品" align="center">
+                <template slot-scope="scope">
+                  <el-select
+                    :disabled="scope.row.type !== '5'"
+                    :ref="`customSelect_${scope.row.code}`"
+                    v-model="scope.row.goodsId"
+                    placeholder="请选择商品"
+                    @click.native.stop="scope.row.type === '5' ? openGoodsDrawer(scope.row) : null"
+                    clearable
+                    style="width: 100%;">
+                    <el-option
+                      v-for="item in goodsList"
+                      :key="item.id"
+                      :label="item.name"
+                      :value="item.id">
+                    </el-option>
+                  </el-select>
+                </template>
+              </el-table-column>
+              <el-table-column label="奖励数量" align="center" show-overflow-tooltip width="180">
+                <template slot-scope="scope">
+                  <el-input :disabled="scope.row.type === '5'" v-model="scope.row.amount" :controls="false" style="width: 100%"/>
+                </template>
+              </el-table-column>
+              <el-table-column label="概率" align="center" class-name="probability-col" width="120">
+                <template slot-scope="scope">
+                  <el-input v-model="scope.row.probability" placeholder="例如: 10%"></el-input>
+                </template>
+              </el-table-column>
+              <el-table-column v-if="false" label="唯一序列号">
+                <template slot-scope="scope">
+                  <el-input v-model="scope.row.code" placeholder="奖励唯一序列号">
+                    <el-button slot="append" icon="el-icon-refresh" @click="generateUUID(scope.row)"></el-button>
+                  </el-input>
+                </template>
+              </el-table-column>
+              <el-table-column label="操作" align="center" width="80">
+                <template slot-scope="scope">
+                  <el-button type="danger" icon="el-icon-delete" @click="removeRewardItem(scope.$index)"></el-button>
+                </template>
+              </el-table-column>
+            </el-table>
+          </div>
+        </el-form-item>
+
+        <el-form-item label="状态" prop="status">
+          <el-radio-group v-model="form.status">
+            <el-radio v-for="dict in statusOptions" :key="dict.dictValue" :label="dict.dictValue">{{dict.dictLabel}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="奖励描述" prop="description">
+          <el-input v-model="form.description" type="textarea" placeholder="请输入奖励描述" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+
+    <el-dialog
+      :title="`奖励详情 - ${currentReward.name || '未知奖励'}`"
+      :visible.sync="detailVisible"
+      width="700px"
+      append-to-body
+    >
+      <div class="reward-detail-container">
+        <!-- 基础信息 -->
+        <el-descriptions :column="2" border class="base-info" :label-style="{ width: '120px' }" :content-style="{ width: '200px' }">
+          <el-descriptions-item label="奖励名称">{{ currentReward.name || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="奖励类型">
+            <dict-tag :options="typeOptions" :value="currentReward.rewardType"/>
+          </el-descriptions-item>
+          <el-descriptions-item label="状态">
+            <dict-tag :options="statusOptions" :value="currentReward.status"/>
+          </el-descriptions-item>
+          <el-descriptions-item label="期望值">{{ currentReward.expectedValue || 0 }}</el-descriptions-item>
+          <el-descriptions-item label="描述" :span="2">{{ currentReward.description || '-' }}</el-descriptions-item>
+        </el-descriptions>
+
+        <!-- 奖励内容详情 -->
+        <div class="reward-content">
+          <h4>奖励内容详情</h4>
+
+          <!-- 宝箱类型奖励 -->
+          <div v-if="currentReward.rewardType === 1" class="chest-reward">
+            <el-table :data="parsedRewardItems" size="small" border stripe>
+              <el-table-column label="奖励模式">
+                <template slot-scope="{row}">
+                  <el-select v-model="row.jltype" placeholder="请选择奖励模式" style="width: 100%" disabled>
+                    <el-option
+                      v-for="item in jltypeOptions"
+                      :key="item.dictValue"
+                      :label="item.dictLabel"
+                      :value="item.dictValue"
+                    />
+                  </el-select>
+                </template>
+              </el-table-column>
+              <el-table-column label="数量" prop="amount"  align="center">
+                <template slot-scope="{row}">
+                  {{ row.amount || 1 }}
+                </template>
+              </el-table-column>
+              <el-table-column label="概率" prop="probability" align="center">
+                <template slot-scope="{row}">
+                  <el-tag v-if="row.probability" size="small">{{ row.probability }}</el-tag>
+                  <span v-else>-</span>
+                </template>
+              </el-table-column>
+            </el-table>
+            <div v-if="!parsedRewardItems || parsedRewardItems.length === 0" class="empty-tip">
+              暂无奖励配置
+            </div>
+          </div>
+
+          <!-- 红包类型奖励 -->
+          <div v-else-if="currentReward.rewardType === 2" class="redpacket-reward">
+            <div class="reward-amount">
+              <i class="el-icon-money" style="color: #e6a23c; font-size: 24px;"></i>
+              <span class="amount-text">{{ rewardAmount }} 元</span>
+              <el-tag type="warning" size="small">红包奖励</el-tag>
+            </div>
+          </div>
+
+          <!-- 积分币类型奖励 -->
+          <div v-else-if="currentReward.rewardType === 3" class="points-reward">
+            <div class="reward-amount">
+              <i class="el-icon-coin" style="color: #67c23a; font-size: 24px;"></i>
+              <span class="amount-text">{{ rewardAmount }} 积分币</span>
+              <el-tag type="success" size="small">积分币奖励</el-tag>
+            </div>
+          </div>
+
+          <!-- 转盘类型奖励 -->
+          <div v-else-if="currentReward.rewardType === 4 || currentReward.rewardType === 6" class="chest-reward">
+            <el-table :data="parsedRewardItems" size="small" border stripe>
+              <el-table-column label="图标" prop="iconUrl" align="center" width="80">
+                <template slot-scope="{row}">
+                  <el-image
+                    v-if="row.iconUrl"
+                    :src="row.iconUrl"
+                    :preview-src-list="[row.iconUrl]"
+                    fit="cover"
+                    style="width:32px;height:32px;border:1px solid #ebeef5;border-radius:4px;"
+                  />
+                  <span v-else>-</span>
+                </template>
+              </el-table-column>
+              <el-table-column label="奖品名称" prop="name" align="center" />
+              <el-table-column label="奖品类型" prop="type" align="center">
+                <template slot-scope="{row}">
+                  <el-tag v-if="row.type" size="small">
+                    {{ getSpinItemTypeLabel(row.type) }}
+                  </el-tag>
+                  <span v-else>-</span>
+                </template>
+              </el-table-column>
+              <el-table-column label="数量" prop="amount" align="center">
+                <template slot-scope="{row}">
+                  <span v-if="row.amount">
+                    {{ row.amount }}
+                  </span>
+                  <span v-else>-</span>
+                </template>
+              </el-table-column>
+              <el-table-column label="概率" prop="probability" align="center">
+                <template slot-scope="{row}">
+                  <el-tag v-if="row.probability" size="small">{{ row.probability }}</el-tag>
+                  <span v-else>-</span>
+                </template>
+              </el-table-column>
+            </el-table>
+            <div v-if="!parsedRewardItems || parsedRewardItems.length === 0" class="empty-tip">
+              暂无奖励配置
+            </div>
+          </div>
+
+          <!-- 保底转盘类型奖励 -->
+          <div v-else-if="currentReward.rewardType === 5" class="chest-reward">
+            <el-table :data="parsedRewardItems" size="small" border stripe>
+              <el-table-column label="图标" prop="iconUrl" align="center" width="80">
+                <template slot-scope="{row}">
+                  <el-image
+                    v-if="row.iconUrl"
+                    :src="row.iconUrl"
+                    :preview-src-list="[row.iconUrl]"
+                    fit="cover"
+                    style="width:32px;height:32px;border:1px solid #ebeef5;border-radius:4px;"
+                  />
+                  <span v-else>-</span>
+                </template>
+              </el-table-column>
+              <el-table-column label="奖品名称" prop="name" align="center" />
+              <el-table-column label="奖品类型" prop="type" align="center">
+                <template slot-scope="{row}">
+                  <el-tag v-if="row.type" size="small">
+                    {{ getSpinItemTypeLabel(row.type) }}
+                  </el-tag>
+                  <span v-else>-</span>
+                </template>
+              </el-table-column>
+              <el-table-column label="数量" prop="amount" align="center">
+                <template slot-scope="{row}">
+                  <span v-if="row.amount">
+                    {{ row.amount }}
+                  </span>
+                  <span v-else>-</span>
+                </template>
+              </el-table-column>
+              <el-table-column label="概率" prop="probability" align="center">
+                <template slot-scope="{row}">
+                  <el-tag v-if="row.probability" size="small">{{ row.probability }}</el-tag>
+                  <span v-else>-</span>
+                </template>
+              </el-table-column>
+              <el-table-column label="保底" prop="isGuarantee" align="center">
+                <template slot-scope="{row}">
+                  <el-tag size="small" :type="row.isGuarantee ? 'success' : 'info'">{{ row.isGuarantee ? '是' : '否' }}</el-tag>
+                </template>
+              </el-table-column>
+            </el-table>
+            <div v-if="!parsedRewardItems || parsedRewardItems.length === 0" class="empty-tip">
+              暂无奖励配置
+            </div>
+          </div>
+
+          <!-- 未知类型 -->
+          <div v-else class="unknown-reward">
+            <el-alert type="info" title="未知奖励类型" :closable="false"></el-alert>
+          </div>
+        </div>
+      </div>
+
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="detailVisible = false">关 闭</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 选择优惠券 -->
+    <el-drawer :append-to-body="true" :with-header="false" size="75%" :visible.sync="couponDrawerOpen">
+      <coupon-component @select-coupon="selectCoupon"></coupon-component>
+    </el-drawer>
+
+    <!-- 选择商品 -->
+    <el-drawer :append-to-body="true" :with-header="false" size="75%" :visible.sync="goodsDrawerOpen">
+      <RewardGoodsComponent @select-goods="selectGoods"></RewardGoodsComponent>
+    </el-drawer>
+
+  </div>
+</template>
+
+<script>
+import { listReward, getReward, delReward, addReward, updateReward, exportReward } from "@/api/reward/reward";
+import CouponComponent from '@/views/components/his/couponComponent.vue'
+import RewardGoodsComponent from '@/views/components/course/rewardGoodsComponent.vue'
+import {Loading} from "element-ui";
+import { getByIds } from '@/api/his/coupon'
+import { getGoodsByIds } from '@/api/reward/rewardGoods'
+
+export default {
+  name: "Reward",
+  components: {
+    CouponComponent, RewardGoodsComponent
+  },
+  data() {
+    return {
+      finalQuality:1,
+      uploadUrl: process.env.VUE_APP_BASE_API+"/common/uploadOSS",
+      detailVisible: false,
+      currentReward: {},
+      activeCollapse: [],
+      jltypeOptions: [],
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      rewardList: [],
+      typeOptions: [],
+      // 转盘奖励-奖励类型选项
+      spinItemTypeOptions: [],
+      statusOptions: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      width: '1200px',
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        name: null,
+        description: null,
+        rewardType: null,
+        status: null,
+        expectedValue: null,
+        createId: null,
+        actualRewards: null
+      },
+      // 已选中优惠券列表
+      couponList: [],
+      couponDrawerOpen: false,
+      currentRow: null,
+      // 已选中商品列表
+      goodsList: [],
+      goodsDrawerOpen: false,
+      // 表单参数
+      form: {
+        id: null,
+        name: null,
+        description: null,
+        rewardType: null,
+        status: "1",
+        expectedValue: 0,
+        account: 0,
+        rewardItems: [],
+        openChestUrl:"",
+        closeChestUrl:"",
+
+      },
+      // 表单校验
+      rules: {
+        name: [
+          { required: true, message: "奖励名称不能为空", trigger: "blur" }
+        ],
+        rewardType: [
+          { required: true, message: "奖励类型不能为空", trigger: "change" }
+        ],
+        status: [
+          { required: true, message: "状态 不能为空", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  computed: {
+    // 解析奖励项数据
+    parsedRewardItems() {
+      if (!this.currentReward.actualRewards) return null;
+      try {
+        const parsed = JSON.parse(this.currentReward.actualRewards);
+        return Array.isArray(parsed) ? parsed : null;
+      } catch (e) {
+        console.error("解析奖励内容失败", e);
+        return null;
+      }
+    },
+
+    // 获取红包或积分币金额
+    rewardAmount() {
+      if (!this.currentReward.actualRewards) return 0;
+
+      try {
+        const parsed = JSON.parse(this.currentReward.actualRewards);
+        if (this.currentReward.rewardType === 2) {
+          return parsed.amount || parsed.money || 0;
+        } else if (this.currentReward.rewardType === 3) {
+          return parsed.points || parsed.score || 0;
+        }
+        return 0;
+      } catch (e) {
+        return 0;
+      }
+    }
+  },
+  created() {
+    this.getList();
+    this.getDicts("sys_reward_type").then((response) => {
+      this.typeOptions = response.data;
+    });
+    this.getDicts("sys_user_status").then((response) => {
+      this.statusOptions = response.data;
+    });
+    this.getDicts("sys_reward_spin_type").then((response) => {
+      this.jltypeOptions = response.data;
+    });
+    this.getDicts("spin_reward_type").then((response) => {
+      this.spinItemTypeOptions = response.data;
+    });
+  },
+  methods: {
+    changeType(row) {
+      row.amount = null
+      row.couponId = null
+      row.goodsId = null
+      if (row.type === '5') {
+        row.amount = 1
+      }
+    },
+    openCouponDrawer(row) {
+      this.$nextTick(() => {
+        this.$refs[`customSelect_${row.code}`]?.blur?.()
+      });
+      this.currentRow = row
+      this.couponDrawerOpen = true
+    },
+    selectCoupon(coupon) {
+      this.currentRow.couponId = coupon.id
+      if (!this.couponList.some(item => item.id === coupon.id)) {
+        this.couponList.push(coupon)
+      }
+      this.couponDrawerOpen = false
+    },
+    openGoodsDrawer(row) {
+      this.$nextTick(() => {
+        this.$refs[`customSelect_${row.code}`]?.blur?.()
+      });
+      this.currentRow = row
+      this.goodsDrawerOpen = true
+    },
+    selectGoods(goods) {
+      this.currentRow.goodsId = goods.id
+      if (!this.goodsList.some(item => item.id === goods.id)) {
+        this.goodsList.push(goods)
+      }
+      this.goodsDrawerOpen = false
+    },
+    handleSuccessOpen(res, file) {
+      if(res.code==200){
+        this.form.openChestUrl = res.url;
+      }
+      else{
+        this.msgError(res.msg);
+      }
+    },
+    handleSuccessClose(res, file) {
+      if(res.code==200){
+        this.form.closeChestUrl = res.url;
+      }
+      else{
+        this.msgError(res.msg);
+      }
+      console.log(this.form.closeChestUrl)
+    },
+    beforeUpload(file) {
+      const isPic =
+        file.type === 'image/jpeg' ||
+        file.type === 'image/png' ||
+        file.type === 'image/gif' ||
+        file.type === 'image/jpg'
+      // const isLt2M = file.size / 1024 / 1024 < 2
+      if (!isPic) {
+        this.$message.error('上传图片只能是 JPG、JPEG、PNG、GIF 格式!')
+        return false
+      }
+      return new Promise((resolve, reject) => {
+        if (file.size / 1024 / 1024 > 3) {
+          this.$message.error('上传的图片不能超过3MB');
+          reject();
+          return;
+        }
+        if (file.size / 1024 / 1024 > 1) {
+          const loadingInstance = Loading.service({ text: '图片内存过大正在压缩图片...' });
+          // 文件大于1MB时进行压缩
+          this.compressImage(file).then((compressedFile) => {
+            loadingInstance.close();
+            if (compressedFile.size / 1024 > 500) {
+              this.$message.error('图片压缩后仍大于500KB');
+              reject();
+            } else {
+              // this.$message.success(`图片压缩成功,最终质量为: ${this.finalQuality.toFixed(2)}`);
+              console.log(`图片压缩成功,最终质量为: ${this.finalQuality.toFixed(2)}`);
+              console.log(`最终内存大小为: ${(compressedFile.size/1024).toFixed(2)}KB`);
+              resolve(compressedFile);
+            }
+          }).catch((err) => {
+            loadingInstance.close();
+            console.error(err);
+            reject();
+          });
+        } else {
+          resolve(file);
+        }
+      });
+    },
+    compressImage(file) {
+      return new Promise((resolve, reject) => {
+        const reader = new FileReader();
+        reader.readAsDataURL(file);
+        reader.onload = (event) => {
+          const img = new Image();
+          img.src = event.target.result;
+          img.onload = () => {
+            const canvas = document.createElement('canvas');
+            const ctx = canvas.getContext('2d');
+            const width = img.width;
+            const height = img.height;
+            canvas.width = width;
+            canvas.height = height;
+            ctx.drawImage(img, 0, 0, width, height);
+
+            let quality = 1; // 初始压缩质量
+            let dataURL = canvas.toDataURL('image/jpeg', quality);
+
+            // 逐步压缩,直到图片大小小于500KB并且压缩质量不再降低
+            while (dataURL.length / 1024 > 500 && quality > 0.1) {
+              quality -= 0.01;
+              dataURL = canvas.toDataURL('image/jpeg', quality);
+            }
+            this.finalQuality = quality; // 存储最终的压缩质量
+
+            if (dataURL.length / 1024 > 500) {
+              reject(new Error('压缩后图片仍然大于500KB'));
+              return;
+            }
+
+            const arr = dataURL.split(',');
+            const mime = arr[0].match(/:(.*?);/)[1];
+            const bstr = atob(arr[1]);
+            let n = bstr.length;
+            const u8arr = new Uint8Array(n);
+            while (n--) {
+              u8arr[n] = bstr.charCodeAt(n);
+            }
+            const compressedFile = new Blob([u8arr], { type: mime });
+            compressedFile.name = file.name;
+            resolve(compressedFile);
+          };
+          img.onerror = (error) => {
+            reject(error);
+          };
+        };
+        reader.onerror = (error) => {
+          reject(error);
+        };
+      });
+    },
+    // 查看奖励详情
+    handleViewReward(row) {
+      this.currentReward = { ...row };
+      this.detailVisible = true;
+    },
+
+    // 格式化JSON显示
+    formatJson(json) {
+      if (!json) return '无数据';
+      try {
+        const parsed = JSON.parse(json);
+        return JSON.stringify(parsed, null, 2);
+      } catch (e) {
+        return json;
+      }
+    },
+    /** 查询奖励配置列表 */
+    getList() {
+      this.loading = true;
+      listReward(this.queryParams).then(response => {
+        this.rewardList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        name: null,
+        description: null,
+        rewardType: null,
+        status: "1",
+        expectedValue: 0,
+        account: 0,
+        openChestUrl: "",
+        closeChestUrl:"",
+        rewardItems: []
+      };
+      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
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加奖励配置";
+      // 若选择转盘类型时,默认添加一条配置
+      if (this.form.rewardType === '4') {
+        this.ensureSpinDefaultItem();
+      }
+      if (this.form.rewardType === '5') {
+        this.ensureSpinDefaultItem2();
+      }
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getReward(id).then(response => {
+        this.form = response.data;
+        this.form.status = response.data.status.toString();
+        this.form.rewardType = response.data.rewardType.toString();
+
+        // 解析actualRewards
+        try {
+          const actualRewards = JSON.parse(response.data.actualRewards || "[]");
+          if (this.form.rewardType === '1' || this.form.rewardType === '4' || this.form.rewardType === '5'
+            || this.form.rewardType === '6') {
+            // 宝箱类型
+            this.form.rewardItems = actualRewards.map(item => ({
+              ...item,
+              couponId: item.couponId || null,
+              goodsId: item.goodsId || null,
+            }));
+
+            this.initCouponList(actualRewards.filter(item => item.couponId).map(item => item.couponId).join(","))
+            this.initGoodsList(actualRewards.filter(item => item.goodsId).map(item => item.goodsId).join(","))
+          } else if (this.form.rewardType === '2') {
+            // 红包类型
+            this.form.account = actualRewards.amount || 0;
+          } else if (this.form.rewardType === '3') {
+            // 积分币类型
+            this.form.account = actualRewards.points || 0;
+          }
+        } catch (e) {
+          this.form.rewardItems = [];
+          this.form.account = 0;
+        }
+
+        this.open = true;
+        this.title = "修改奖励配置";
+      });
+    },
+    initCouponList(ids) {
+      if (!ids) {
+        return
+      }
+      getByIds({ids}).then(response => {
+        const {data} = response
+        data.forEach(d => {
+          if (!this.couponList.some(item => item.id === d.couponId)) {
+            this.couponList.push({"id": d.couponId, "name": d.title})
+          }
+        })
+      })
+    },
+    initGoodsList(ids) {
+      if (!ids) {
+        return
+      }
+      getGoodsByIds({ids}).then(response => {
+        const {data} = response
+        data.forEach(g => {
+          if (!this.goodsList.some(item => item.id === g.goodsId)) {
+            this.goodsList.push({"id": g.goodsId, "name": g.goodsName})
+          }
+        })
+      })
+    },
+    // 奖励类型变化处理
+    handleRewardTypeChange(value) {
+      // 清空相关数据
+      this.form.account = 0;
+      this.form.rewardItems = [];
+      this.form.expectedValue = 0
+      // 切换为转盘类型时,默认加入一条配置
+      if (value === '4') {
+        this.ensureSpinDefaultItem();
+      }
+      if (value === '5') {
+        this.ensureSpinDefaultItem2();
+      }
+      if (value === '6') {
+        this.ensureSpinDefaultItem();
+      }
+    },
+    // 更新奖励项名称(当表单名称变化时)
+    updateRewardItemsName() {
+      if (this.form.rewardType === '1' && this.form.rewardItems.length > 0) {
+        // 可选:当表单名称变化时,自动更新所有奖励项的名称
+        // this.form.rewardItems.forEach(item => {
+        //   item.name = this.form.name;
+        // });
+      }
+    },
+    // 添加奖励项
+    addRewardItem() {
+      this.form.rewardItems.push({
+        type: '1',
+        jltype: '1',
+        name: this.form.name || '', // 默认使用表单中的奖励名称
+        couponId: null,
+        amount: 1,
+        probability: '',
+        code: this.generateUUID()
+      });
+    },
+    // 转盘奖励:添加奖励项(包含奖励类型选择)
+    addSpinRewardItem() {
+      this.form.rewardItems.push({
+        type: '2',
+        iconUrl: '',
+        name: '',
+        couponId: null,
+        goodsId: null,
+        amount: '',
+        probability: '',
+        code: this.generateUUID()
+      });
+    },
+    addSpinRewardItem2() {
+      this.form.rewardItems.push({
+        type: '2',
+        isGuarantee: 0,
+        iconUrl: '',
+        name: '',
+        couponId: null,
+        amount: '',
+        probability: '',
+        code: this.generateUUID()
+      });
+    },
+    // 转盘奖励:图标上传成功
+    handleSpinIconSuccess(res, row) {
+      if (res && res.code === 200 && res.url) {
+        this.$set(row, 'iconUrl', res.url);
+      } else {
+        this.msgError(res && res.msg ? res.msg : '图片上传失败');
+      }
+    },
+    // 转盘奖励:确保有一条默认项
+    ensureSpinDefaultItem() {
+      if (!Array.isArray(this.form.rewardItems)) this.form.rewardItems = [];
+      if (this.form.rewardItems.length === 0) {
+        this.addSpinRewardItem();
+      }
+    },
+    ensureSpinDefaultItem2() {
+      if (!Array.isArray(this.form.rewardItems)) this.form.rewardItems = [];
+      if (this.form.rewardItems.length === 0) {
+        this.addSpinRewardItem2();
+      }
+    },
+    // 移除奖励项
+    removeRewardItem(index) {
+      this.form.rewardItems.splice(index, 1);
+    },
+    // 生成UUID
+    generateUUID(item) {
+      if (item) {
+        item.code = this.generateUUIDString();
+      } else {
+        return this.generateUUIDString();
+      }
+    },
+    // 生成UUID字符串
+    generateUUIDString() {
+      return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
+        var r = Math.random() * 16 | 0,
+          v = c == 'x' ? r : (r & 0x3 | 0x8);
+        return v.toString(16);
+      });
+    },
+    // 获取转盘奖励类型标签
+    getSpinItemTypeLabel(type) {
+      const option = this.spinItemTypeOptions.find(item => item.dictValue === type.toString());
+      return option ? option.dictLabel : type;
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          let actualRewards = "";
+          if (this.form.rewardType === '1' || this.form.rewardType === '4' || this.form.rewardType === '5'
+            || this.form.rewardType === '6') {
+            // 宝箱类型,将rewardItems转为JSON
+            actualRewards = JSON.stringify(this.form.rewardItems);
+          } else if (this.form.rewardType === '2') {
+            // 红包类型
+            actualRewards = JSON.stringify({ amount: this.form.account });
+          } else if (this.form.rewardType === '3') {
+            // 积分币类型
+            actualRewards = JSON.stringify({ points: this.form.account });
+          }
+
+          // 设置actualRewards
+          this.form.actualRewards = actualRewards;
+
+          if (this.form.id != null) {
+            updateReward(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addReward(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除奖励配置编号为"' + ids + '"的数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return delReward(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有奖励配置数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportReward(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
+    }
+  }
+};
+</script>
+
+<style scoped>
+.spin-reward .el-table th,
+.spin-reward .el-table td {
+  padding: 6px 8px;
+}
+
+.spin-reward .probability-col .el-input__inner {
+  text-align: center;
+}
+
+.spin-tips {
+  padding: 8px 12px;
+  color: #909399;
+  font-size: 12px;
+  background-color: #fafafa;
+  border-top: 1px solid #ebeef5;
+  border-bottom: 1px solid #ebeef5;
+}
+.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: 120px;
+  height: 120px;
+  display: block;
+}
+.spin-icon-uploader {
+  display: inline-block;
+}
+.spin-icon {
+  width: 32px;
+  height: 32px;
+  object-fit: cover;
+  border: 1px solid #ebeef5;
+  border-radius: 4px;
+}
+.spin-icon-uploader .el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 4px;
+  width: 32px;
+  height: 32px;
+  line-height: 32px;
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+}
+.spin-icon-uploader .el-upload:hover {
+  border-color: #409EFF;
+}
+/* 覆盖全局 .avatar-uploader-icon 的大尺寸,限定在转盘上传器内为 32x32 */
+.spin-icon-uploader .avatar-uploader-icon {
+  width: 32px !important;
+  height: 32px !important;
+  line-height: 32px !important;
+  font-size: 16px !important;
+  color: #8c939d;
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+}
+.reward-table-container {
+  border: 1px solid #ebeef5;
+  border-radius: 4px;
+}
+
+.table-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 15px;
+  background-color: #f5f7fa;
+  border-bottom: 1px solid #ebeef5;
+}
+
+.table-tips {
+  padding: 10px 15px;
+  color: #909399;
+  font-size: 12px;
+  background-color: #f5f7fa;
+}
+.reward-detail-container {
+  max-height: 60vh;
+  overflow-y: auto;
+}
+
+.base-info {
+  margin-bottom: 20px;
+  width: 100%;
+  table-layout: fixed;
+}
+
+.base-info .el-descriptions__label {
+  width: 120px !important;
+  min-width: 120px;
+}
+
+.base-info .el-descriptions__content {
+  width: 200px !important;
+  min-width: 200px;
+}
+
+.reward-content {
+  margin: 20px 0;
+}
+
+.reward-content h4 {
+  margin-bottom: 15px;
+  color: #303133;
+  font-weight: 600;
+}
+
+.chest-reward,
+.redpacket-reward,
+.points-reward {
+  margin: 15px 0;
+}
+
+.reward-amount {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  padding: 15px;
+  background: #f8f9fa;
+  border-radius: 4px;
+}
+
+.amount-text {
+  font-size: 18px;
+  font-weight: bold;
+  color: #409EFF;
+}
+
+.code-text {
+  font-family: monospace;
+  font-size: 12px;
+}
+
+.empty-tip {
+  text-align: center;
+  color: #909399;
+  padding: 20px;
+}
+
+.json-pre {
+  background: #f5f7fa;
+  padding: 12px;
+  border-radius: 4px;
+  font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
+  font-size: 12px;
+  line-height: 1.5;
+  overflow: auto;
+  max-height: 200px;
+  margin: 0;
+}
+
+.raw-data {
+  margin-top: 20px;
+}
+/* 新增样式 */
+.image-upload-group {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 20px;
+}
+
+.image-upload-item {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+}
+
+.image-preview {
+  margin-top: 10px;
+  border: 1px dashed #d9d9d9;
+  padding: 10px;
+  border-radius: 4px;
+}
+
+.image-actions {
+  margin-top: 10px;
+  display: flex;
+  gap: 10px;
+}
+
+.chest-images-preview {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+.chest-images-section {
+  margin: 20px 0;
+}
+
+.chest-images-display {
+  display: flex;
+  gap: 30px;
+  justify-content: center;
+  margin-top: 15px;
+}
+
+.chest-image-item {
+  text-align: center;
+}
+
+.chest-image-item p {
+  margin-bottom: 8px;
+  font-weight: bold;
+}
+</style>

+ 529 - 0
src/views/his/reward/rewardGoods.vue

@@ -0,0 +1,529 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="商品ID" prop="goodsId">
+        <el-input
+          v-model="queryParams.goodsId"
+          placeholder="请输入商品ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="商品名称" prop="goodsName">
+        <el-input
+          v-model="queryParams.goodsName"
+          placeholder="请输入商品名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="所属店铺" prop="storeId">
+        <el-select v-model="queryParams.storeId" placeholder="请选择店铺" clearable size="small">
+          <el-option
+            v-for="dict in storeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="商品编码" prop="storeGoodsSn">
+        <el-input
+          v-model="queryParams.storeGoodsSn"
+          placeholder="请输入商品编码"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['reward:rewardGoods:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['reward:rewardGoods:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['reward:rewardGoods:remove']"
+        >删除</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-tabs type="card" v-model="activeName" @tab-click="handleClick">
+      <el-tab-pane label="已上架" name="1"></el-tab-pane>
+      <el-tab-pane label="待上架" name="0"></el-tab-pane>
+    </el-tabs>
+
+    <el-table v-loading="loading" border :data="goodsList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="商品ID" align="center" prop="goodsId" />
+      <el-table-column label="商品图片" align="center" prop="goodsImg" width="120">
+        <template slot-scope="scope">
+          <el-popover
+            placement="right"
+            title=""
+            trigger="hover"
+          >
+            <img slot="reference" :src="scope.row.goodsImg" width="100">
+            <img :src="scope.row.goodsImg" style="max-width: 150px;">
+          </el-popover>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="商品名称" align="center" prop="goodsName" show-overflow-tooltip />
+      <el-table-column label="所属店铺" align="center" prop="storeName" />
+      <el-table-column label="商品编码" align="center" prop="storeGoodsSn" />
+      <el-table-column label="原价" align="center" prop="opPrice" />
+      <el-table-column label="单价" align="center" prop="price" />
+      <el-table-column label="库存" align="center" prop="stock" />
+      <el-table-column label="状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="排序" align="center" prop="sort" />
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180"/>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="180" fixed="right">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            v-hasPermi="['reward:rewardGoods:query']"
+            @click="handleDetails(scope.row)"
+          >详情
+          </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['reward:rewardGoods:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['reward:rewardGoods:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改奖励商品对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="900px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="商品名称" prop="goodsName">
+          <el-input v-model="form.goodsName" placeholder="请输入奖励名称" />
+        </el-form-item>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="所属店铺" prop="storeId">
+              <el-select v-model="form.storeId" placeholder="请选择店铺">
+                <el-option
+                  v-for="dict in storeOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictLabel"
+                  :value="dict.dictValue"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="商品编码" prop="storeGoodsSn">
+              <el-input v-model="form.storeGoodsSn" placeholder="请输入商品编码" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-form-item label="商品封面" prop="goodsImg">
+          <Material v-model="imageArr" type="image" :num="1" :width="150" :height="150" />
+        </el-form-item>
+
+        <el-form-item label="轮播图" prop="goodsImages">
+          <Material v-model="photoArr" type="image" :num="10" :width="150" :height="150" />
+        </el-form-item>
+
+        <el-form-item label="商品介绍" prop="goodsIntroduce">
+          <el-input v-model="form.goodsIntroduce" type="textarea" placeholder="请输入商品介绍" />
+        </el-form-item>
+
+        <el-form-item label="商品描述" prop="goodsDesc">
+          <Editor ref="myeditor"  @on-text-change="updateText"/>
+        </el-form-item> 
+
+        <el-row>
+          <el-col :span="6">
+            <el-form-item label="库存" prop="stock">
+              <el-input v-model="form.stock"/>
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item label="原价" prop="opPrice">
+              <el-input v-model="form.opPrice"/>
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item label="单价" prop="price">
+              <el-input v-model="form.price"/>
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item label="序号" prop="sort">
+              <el-input v-model="form.sort"/>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-form-item label="状态" prop="status">
+          <el-radio-group v-model="form.status">
+            <el-radio
+              v-for="dict in statusOptions"
+              :key="dict.dictValue"
+              :label="dict.dictValue"
+            >{{ dict.dictLabel }}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-drawer
+      :with-header="false"
+      size="75%"
+      :title="show.title" :visible.sync="show.open">
+      <GoodsDetail  ref="goodsDetail" />
+    </el-drawer>
+  </div>
+</template>
+
+<script>
+import { listRewardGoods, getRewardGoods, delRewardGoods, addRewardGoods, updateRewardGoods } from "@/api/reward/rewardGoods";
+import ImageUpload from '@/components/ImageUpload/index.vue';
+import { listStore } from '@/api/his/storeProduct'
+import Material from '@/components/Material/index.vue'
+import Editor from '@/components/Editor/wang.vue' 
+import GoodsDetail from './goodsDetail.vue'
+
+export default {
+  name: "RewardGoods",
+  components: { GoodsDetail, Material, ImageUpload, Editor },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 奖励商品表格数据
+      goodsList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 图片数组
+      imageArr: [],
+      // 轮播图
+      photoArr: [],
+      // 店铺选项
+      storeOptions: [],
+      // 状态选项
+      statusOptions: [],
+      activeName: '1',
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        goodsId: null,
+        goodsName: null,
+        storeId: null,
+        storeGoodsSn: null,
+        status: 1
+      },
+      // 表单参数
+      form: {
+        goodsName: null,
+        goodsId: null,
+        storeId: null,
+        storeGoodsSn: null,
+        goodsImg: null,
+        goodsImages: null,
+        goodsIntroduce: null,
+        goodsDesc: null,
+        opPrice: 0,
+        price: 0,
+        stock: 0,
+        status: "1",
+        sort: 1,
+        remark: null
+      },
+      // 表单校验
+      rules: {
+        goodsName: [
+          { required: true, message: "商品名称不能为空", trigger: "blur" }
+        ],
+        storeId: [
+          { required: true, message: "店铺不能为空", trigger: "change" }
+        ],
+        storeGoodsSn: [
+          { required: true, message: "商品编码不能为空", trigger: "blur" }
+        ],
+        goodsImg: [
+          { required: true, message: "商品封面不能为空", trigger: "blur" }
+        ],
+        goodsImages: [
+          { required: true, message: "商品轮播图不能为空", trigger: "blur" }
+        ],
+        goodsIntroduce: [
+          { required: true, message: "商品介绍不能为空", trigger: "blur" }
+        ],
+        stock: [
+          { required: true, message: "库存数量不能为空", trigger: "blur" }
+        ],
+        opPrice: [
+          { required: true, message: "原价不能为空", trigger: "blur" }
+        ],
+        price: [
+          { required: true, message: "单价不能为空", trigger: "blur" }
+        ],
+        sort: [
+          { required: true, message: "序号不能为空", trigger: "blur" }
+        ],
+        status: [
+          { required: true, message: "状态不能为空", trigger: "blur" }
+        ]
+      },
+      show: {
+        title: '商品详情',
+        open: false
+      }
+    };
+  },
+  created() {
+    this.getStoreList();
+    this.getList();
+    this.getDicts("sys_spec_show").then(response => {
+      this.statusOptions = response.data;
+    });
+  },
+  watch: {
+    imageArr: function(val) {
+      this.form.goodsImg = val.join(',');
+    },
+    photoArr: function(val) {
+      this.form.goodsImages = val.join(',')
+    }
+  },
+  methods: {
+    handleClick(tab) {
+      this.queryParams.status = tab.name
+      this.getList()
+    },
+    getStoreList() {
+      listStore().then(response => {
+        const {rows} = response
+        this.storeOptions = rows
+      });
+    },
+    /** 查询奖励商品列表 */
+    getList() {
+      this.loading = true;
+      listRewardGoods(this.queryParams).then(response => {
+        this.goodsList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        goodsName: null,
+        goodsId: null,
+        storeId: null,
+        storeGoodsSn: null,
+        goodsImg: null,
+        goodsImages: null,
+        goodsIntroduce: null,
+        goodsDesc: null,
+        opPrice: 0,
+        price: 0,
+        stock: 0,
+        status: "1",
+        sort: 1,
+        remark: null
+      }
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.goodsId)
+      this.single = selection.length !== 1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加奖励商品";
+      this.$nextTick(() => {
+        this.$refs.myeditor.setText("");
+      });
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.goodsId || this.ids
+      getRewardGoods(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改奖励商品";
+        this.$nextTick(() => {
+          this.$refs.myeditor.setText(this.form.goodsDesc);
+        });
+        if (this.form.goodsImg) {
+          this.imageArr = this.form.goodsImg.split(",");
+        }
+        if (this.form.goodsImages) {
+          this.photoArr = this.form.goodsImages.split(",");
+        }
+        this.form.status = this.form.status + ''
+      });
+    },
+    /** 详情 */
+    handleDetails(row) {
+      this.show.open = true
+      setTimeout(() => {
+        this.$refs.goodsDetail.getDetails(row.goodsId)
+      }, 1)
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.goodsId != null) {
+            updateRewardGoods(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addRewardGoods(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.goodsId || this.ids;
+      this.$confirm('是否确认删除奖励商品编号为"' + ids + '"的数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return delRewardGoods(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+    updateText(text) {
+      this.form.goodsDesc = text
+    },
+  }
+};
+</script>
+
+<style scoped>
+.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: 150px;
+  height: 150px;
+  line-height: 150px;
+  text-align: center;
+}
+</style>

+ 318 - 0
src/views/his/reward/rewardGoodsOrder.vue

@@ -0,0 +1,318 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="所属店铺" prop="storeId">
+        <el-select v-model="queryParams.storeId" placeholder="请选择店铺" clearable size="small">
+          <el-option
+            v-for="dict in storeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="会员ID" prop="userId">
+        <el-input
+          v-model="queryParams.userId"
+          placeholder="请输入会员ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="收货人" prop="receiveUserName">
+        <el-input
+          v-model="queryParams.receiveUserName"
+          placeholder="请输入收货人"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="收货电话" prop="receiveUserPhone">
+        <el-input
+          v-model="queryParams.receiveUserPhone"
+          placeholder="请输入收货人电话"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="订单编号" prop="orderSn">
+        <el-input
+          v-model="queryParams.orderSn"
+          placeholder="请输入订单编号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="快递单号" prop="deliverySn">
+        <el-input
+          v-model="queryParams.deliverySn"
+          placeholder="请输入快递单号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="下单时间" prop="createTime">
+        <el-date-picker
+          v-model="queryParams.createTime"
+          size="small"
+          style="width: 240px"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+        ></el-date-picker>
+      </el-form-item>
+      <el-form-item label="支付时间" prop="payTime">
+        <el-date-picker
+          v-model="queryParams.payTime"
+          size="small"
+          style="width: 240px"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+        ></el-date-picker>
+      </el-form-item>
+      <el-form-item label="发货时间" prop="deliveryTime">
+        <el-date-picker
+          v-model="queryParams.deliveryTime"
+          size="small"
+          style="width: 240px"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+        ></el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-tabs type="card" v-model="activeName" @tab-click="handleClick">
+      <el-tab-pane label="全部订单" name=""></el-tab-pane>
+      <el-tab-pane
+        v-for="dict in orderStatusOptions"
+        :key="dict.dictValue"
+        :label="dict.dictLabel"
+        :name="dict.dictValue"
+      ></el-tab-pane>
+    </el-tabs>
+
+    <el-table v-loading="loading" border :data="orderList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="订单ID" align="center" prop="orderId"/>
+      <el-table-column label="订单编号" align="center" prop="orderSn" width="180"/>
+      <el-table-column label="所属店铺" align="center" prop="storeName" show-overflow-tooltip />
+      <el-table-column label="下单用户" align="center" prop="nickName" />
+      <el-table-column label="收货人" align="center" prop="userName" />
+      <el-table-column label="订单金额" align="center" prop="orderMoney" />
+      <el-table-column label="支付金额" align="center" prop="payMoney" />
+      <el-table-column label="订单状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :options="orderStatusOptions" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="下单时间" align="center" prop="createTime" width="180"/>
+      <el-table-column label="支付时间" align="center" prop="payTime" width="180"/>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="150" fixed="right">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            @click="handleDetails(scope.row)"
+            v-hasPermi="['reward:rewardGoodsOrder:query']"
+          >详情</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            @click="handleCancel(scope.row)"
+            v-hasPermi="['reward:rewardGoodsOrder:cancelOrder']"
+            v-if="scope.row.status === 1 || scope.row.status === 2 || scope.row.status === 3"
+          >取消</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <el-drawer
+      :with-header="false"
+      size="75%"
+      :title="show.title"
+      :visible.sync="show.open"
+    >
+      <GoodsOrderDetail ref="goodsOrderDetail" />
+    </el-drawer>
+  </div>
+</template>
+
+<script>
+import { listRewardGoodsOrder, cancelOrder } from '@/api/reward/rewardGoodsOrder'
+import GoodsOrderDetail from './goodsOrderDetail.vue'
+import { listStore } from '@/api/his/storeProduct'
+
+export default { 
+  name: "RewardGoodsOrder",
+  components: { GoodsOrderDetail },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 订单表格数据
+      orderList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 店铺选项
+      storeOptions: [],
+      // 当前激活的tab
+      activeName: "",
+      // 订单状态选项
+      orderStatusOptions: [],
+      // 详情弹窗
+      show: {
+        title: '订单详情',
+        open: false
+      },
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        storeId: null,
+        userId: null,
+        receiveUserName: null,
+        receiveUserPhone: null,
+        orderSn: null,
+        deliverySn: null,
+        status: null,
+        createTime: null,
+        payTime: null,
+        deliveryTime: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {}
+    };
+  },
+  created() {
+    this.getStoreList();
+    this.getList();
+    this.getDicts("sys_reward_order_status").then(response => {
+      this.orderStatusOptions = response.data;
+    });
+  },
+  methods: {
+    getStoreList() {
+      listStore().then(response => {
+        const {rows} = response
+        this.storeOptions = rows
+      });
+    },
+    /** 查询奖励商品订单列表 */
+    getList() {
+      this.loading = true;
+      const { createTime, payTime, deliveryTime, ...restParams } = this.queryParams;
+
+      const params = {
+        ...restParams,
+        ...this.parseDateRanges({ createTime, payTime, deliveryTime })
+      };
+      listRewardGoodsOrder(params).then(response => {
+        this.orderList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    parseDateRanges(dateFields) {
+      const result = {};
+      Object.keys(dateFields).forEach(field => {
+        const dateArray = dateFields[field];
+        const capitalizedField = field.charAt(0).toUpperCase() + field.slice(1);
+
+        if (dateArray && dateArray.length === 2) {
+          result[`s${capitalizedField}`] = dateArray[0] + ' 00:00:00'
+          result[`e${capitalizedField}`] = dateArray[1] + ' 00:00:00'
+        } else {
+          result[`s${capitalizedField}`] = null;
+          result[`e${capitalizedField}`] = null;
+        }
+      });
+      return result;
+    },
+    /** 搜索按钮操作 */
+    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
+    },
+    /** Tab切换 */
+    handleClick(tab) {
+      this.queryParams.status = tab.name;
+      this.getList();
+    },
+    /** 详情操作 */
+    handleDetails(row) {
+      this.show.open = true;
+      setTimeout(() => {
+        this.$refs.goodsOrderDetail.getDetails(row.orderId);
+      }, 100);
+    },
+    /** 取消订单操作 */
+    handleCancel(row) {
+      this.$confirm('确认要取消ID为' + row.orderId + '的订单吗?', '取消订单', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        cancelOrder(row.orderId).then(() => {
+          this.$message.success('订单取消成功');
+          this.getList();
+        })
+      }).catch(() => {});
+    },
+  }
+};
+</script>
+
+<style scoped>
+</style>

+ 232 - 0
src/views/his/reward/rewardRound.vue

@@ -0,0 +1,232 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="奖励类型" prop="rewardType">
+        <el-select v-model="queryParams.rewardType" placeholder="请选择奖励类型" clearable size="small">
+          <el-option
+            v-for="item in typeOptions"
+            :key="item.dictValue"
+            :label="item.dictLabel"
+            :value="item.dictValue"
+          /> 
+        </el-select>
+      </el-form-item>
+
+      <el-form-item label="奖励状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择奖励状态" clearable size="small">
+          <el-option
+            v-for="item in statusOptions"
+            :key="item.dictValue"
+            :label="item.dictLabel"
+            :value="item.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="销售公司" prop="companyId">
+        <el-select v-model="queryParams.companyId"
+                   placeholder="请选择推送公司"
+                   size="small">
+          <!-- 公司选项 -->
+          <el-option
+            v-for="item in companyList"
+            :key="item.companyId"
+            :label="item.companyName"
+            :value="item.companyId"
+          />
+        </el-select>
+      </el-form-item>
+
+      <el-form-item label="创建时间" prop="createTime">
+        <el-date-picker clearable size="small" style="width: 205.4px"
+                        v-model="dateRange"
+                        type="daterange"
+                        value-format="yyyy-MM-dd"
+                        start-placeholder="开始日期" end-placeholder="结束日期"
+        >
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['course:rewardRound:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="rewardRoundList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="领取用户" align="center" prop="userIdByName" />
+      <el-table-column label="奖励类型" align="center" prop="rewardType">
+        <template slot-scope="scope">
+          <dict-tag :options="typeOptions" :value="scope.row.rewardType"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="公司" align="center" prop="companyName" />
+      <el-table-column label="实际领取到的奖励" align="center" prop="actualRewards" />
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180"/>
+      <el-table-column label="奖励状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+<!--      <el-table-column label="看课记录id" align="center" prop="watchId" />-->
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList" 
+    />
+
+  </div>
+</template>
+
+<script>
+import { listRewardRound, getRewardRound, delRewardRound, addRewardRound, updateRewardRound, exportRewardRound } from "@/api/reward/rewardRound";
+import {getCompanyList} from "@/api/company/company";
+
+export default {
+  name: "RewardRound",
+  data() {
+    return {
+      dateRange:[],
+      companyList:[],
+      statusOptions: [],
+      typeOptions: [],
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 奖励领取记录表格数据
+      rewardRoundList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        rewardId: null,
+        rewardConfigId: null,
+        userId: null,
+        rewardType: null,
+        companyId: null,
+        actualRewards: null,
+        receiveTime: null,
+        createId: null,
+        status: null,
+        courseId: null,
+        watchId: null
+      },
+      // 表单参数
+      form: {},
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("sys_reward_type").then((response) => {
+      this.typeOptions = response.data;
+    });
+    this.getDicts("sys_reward_status").then((response) => {
+      this.statusOptions = response.data;
+    });
+    getCompanyList().then(response => {
+      this.companyList = response.data;
+    });
+  },
+  methods: {
+    /** 查询奖励领取记录列表 */
+    getList() {
+      this.loading = true;
+      listRewardRound(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+        this.rewardRoundList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        rewardId: null,
+        rewardConfigId: null,
+        userId: null,
+        rewardType: null,
+        companyId: null,
+        actualRewards: null,
+        receiveTime: null,
+        createId: null,
+        createTime: null,
+        updateTime: null,
+        status: 0,
+        courseId: null,
+        watchId: null
+      };
+      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
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有奖励领取记录数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportRewardRound(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>

+ 15 - 11
src/views/system/config/companyMenuConfig.vue

@@ -127,18 +127,22 @@ export default {
       getConfigByKey(key).then(response => {
         if(key == "companymenu.config"){
           this.getCompanyOptions();
-          console.log(response.data.configId)
-          this.configId=response.data.configId;
-          this.configKey=response.data.configKey;
-          if(response.data.configValue != null) {
-            this.form14 = JSON.parse(response.data.configValue);
-            // 回显选中的菜单
-            this.$nextTick(() => {
-              if (this.form14.menuIds && this.form14.menuIds.length > 0) {
-                this.$refs.menu.setCheckedKeys(this.form14.menuIds);
-              }
-            });
+          if (response.data){
+            this.configId=response.data.configId;
+            this.configKey=response.data.configKey;
+            if(response.data.configValue != null) {
+              this.form14 = JSON.parse(response.data.configValue);
+              // 回显选中的菜单
+              this.$nextTick(() => {
+                if (this.form14.menuIds && this.form14.menuIds.length > 0) {
+                  this.$refs.menu.setCheckedKeys(this.form14.menuIds);
+                }
+              });
+            }
           } else {
+            // 如果没有数据,设置默认值
+            this.configId = null;
+            this.configKey = key;
             this.form14 = { menuIds: [] };
           }
         }

+ 103 - 6
src/views/system/config/config.vue

@@ -1583,6 +1583,81 @@
               inactive-color="#ff4949">
             </el-switch>
           </el-form-item>
+          <el-form-item label="宝箱配置">
+             <div style="display: flex; align-items: center; gap: 10px; width: 100%;">
+               <el-input disabled
+                 v-model="form18.silverPercent"
+                 :min="1"
+                 :max="100"
+                 controls-position="right"
+                 style="width: 120px;"
+               />
+               <span> %</span>
+               <el-select
+                 ref="customSelect2"
+                 v-model="form18.silverBox"
+                 placeholder="请选择宝箱"
+                 clearable
+                 style="width: 100%;">
+                 <el-option
+                   v-for="item in rewardList"
+                   :key="item.id"
+                   :label="item.name"
+                   :value="item.id">
+                 </el-option>
+               </el-select>
+               <el-input disabled
+                 v-model="form18.goldPercent"
+                 :min="1"
+                 :max="100"
+                 controls-position="right"
+                 style="width: 120px; margin-left: 20px;"
+               />
+               <span> %</span>
+               <el-select
+                 ref="customSelect2"
+                 v-model="form18.goldBox"
+                 placeholder="请选择宝箱"
+                 clearable
+                 style="width: 100%;">
+                 <el-option
+                   v-for="item in rewardList"
+                   :key="item.id"
+                   :label="item.name"
+                   :value="item.id">
+                 </el-option>
+               </el-select>
+             </div>
+           </el-form-item>
+           <el-form-item label="转盘配置">
+             <el-select
+               ref="customSelect2"
+               v-model="form18.defaultSpinReward"
+               placeholder="请选择转盘奖励"
+               clearable
+               style="width: 100%;">
+               <el-option
+                 v-for="item in spinRewardList"
+                 :key="item.id"
+                 :label="item.name"
+                 :value="item.id">
+               </el-option>
+             </el-select>
+           </el-form-item>
+           <el-form-item label="大礼品配置">
+             <el-select
+               v-model="form18.defaultGrandGift"
+               placeholder="请选择大礼品奖励"
+               clearable
+               style="width: 100%;">
+               <el-option
+                 v-for="item in grandGiftList"
+                 :key="item.id"
+                 :label="item.name"
+                 :value="item.id">
+               </el-option>
+             </el-select>
+           </el-form-item>
           <div class="line"></div>
           <div style="float:right;margin-right:20px">
             <el-button type="primary" @click="submitForm18">提交</el-button>
@@ -2651,9 +2726,10 @@ import companyMenuConfig from './companyMenuConfig'
 import IntegralConfig from '@/views/system/config/integralConfig.vue'
 import { getCitys } from '@/api/store/city'
 import { listCompany } from '@/api/company/company'
-import { getStoreProductColumns } from '@/api/hisStore/storeProduct'
-import { getStoreColumns } from '@/api/hisStore/store'
+// import { getStoreProductColumns } from '@/api/hisStore/storeProduct'
+// import { getStoreColumns } from '@/api/hisStore/store'
 import {listQwCompany} from "@/api/qw/qwCompany";
+import {listReward} from "@/api/reward/reward";
 
 export default {
   name: 'Config',
@@ -2664,6 +2740,9 @@ export default {
   },
   data() {
     return {
+      rewardList: [],
+      spinRewardList: [],
+      grandGiftList: [],
       corpOptions:[],
       citys: [],
       images: [],
@@ -2891,11 +2970,23 @@ export default {
     this.getDicts('sys_integral_log_type').then(response => {
       this.integralLogTypeOptions = response.data
     })
-    getStoreProductColumns().then( response => {
-      this.storeProductScrmColumns = response.data
+    // getStoreProductColumns().then( response => {
+    //   this.storeProductScrmColumns = response.data
+    // })
+    // getStoreColumns().then( response => {
+    //   this.storeScrmColumns = response.data
+    // })
+    listReward({"rewardType": 1}).then(response => {
+      const {rows, total} = response
+      this.rewardList = rows
     })
-    getStoreColumns().then( response => {
-      this.storeScrmColumns = response.data
+    listReward({"rewardType": 4}).then(response => {
+      const {rows} = response
+      this.spinRewardList = rows
+    })
+    listReward({"rewardType": 6}).then(response => {
+      const {rows} = response
+      this.grandGiftList = rows
     })
   },
   watch: {
@@ -3074,6 +3165,12 @@ export default {
           this.configId = null;
           this.configKey = key;
         }
+        
+        // 如果 response.data 为空,后续逻辑直接返回,避免报错
+        if (!response.data || !response.data.configValue) {
+          return;
+        }
+
         if (key == 'sys.oss.cloudStorage') {
           this.form1 = JSON.parse(response.data.configValue)
         }

+ 37 - 3
src/views/system/config/integralConfig.vue

@@ -159,6 +159,27 @@
           />
         </el-select>
       </el-form-item>
+      <el-card class="box-card" style="margin-bottom: 20px;">
+        <div slot="header" class="clearfix">
+          <span>签到大礼品配置</span>
+        </div>
+        <div class="text">
+          <el-form-item label="大礼品配置">
+            <el-select
+              v-model="form11.defaultGrandGift"
+              placeholder="请选择大礼品奖励"
+              clearable
+              style="width: 100%;">
+              <el-option
+                v-for="item in grandGiftList"
+                :key="item.id"
+                :label="item.name"
+                :value="item.id">
+              </el-option>
+            </el-select>
+          </el-form-item>
+        </div>
+      </el-card>
       <div style="display: flex; justify-content: flex-end;">
         <el-button type="primary" :disabled="saveLoading" :loading="saveLoading" @click="submitForm11">提  交</el-button>
       </div>
@@ -168,11 +189,13 @@
 
 <script>
 import { getConfigByKey, updateConfigByKey } from '@/api/system/config'
+import {listReward} from "@/api/reward/reward";
 
 export default {
   name: "IntegralConfig",
   data() {
     return {
+      grandGiftList: [],
       integralLogTypeOptions: [],
       form11: {
         integralRegister: null,
@@ -203,13 +226,24 @@ export default {
     this.getDicts("sys_integral_log_type").then(response => {
       this.integralLogTypeOptions = response.data;
     });
+    listReward({"rewardType": 6}).then(response => {
+        const {rows} = response
+        this.grandGiftList = rows
+    })
   },
   methods: {
     getConfigByKey(key){
       getConfigByKey(key).then(response => {
-        this.configId=response.data.configId;
-        this.configKey=response.data.configKey;
-        this.form11 =JSON.parse(response.data.configValue);
+        if (response.data) {
+          this.configId=response.data.configId;
+          this.configKey=response.data.configKey;
+          if (response.data.configValue) {
+            this.form11 =JSON.parse(response.data.configValue);
+          }
+        } else {
+          this.configId = null;
+          this.configKey = key;
+        }
       });
     },
     submitForm11(){