Преглед на файлове

Merge remote-tracking branch 'origin/金牛明医' into 金牛明医

yh преди 2 месеца
родител
ревизия
2d1fb18d07

+ 19 - 1
src/api/his/adv.js

@@ -50,4 +50,22 @@ export function exportAdv(query) {
     method: 'get',
     params: query
   })
-}
+}
+
+// 统计
+export function statistics(query) {
+  return request({
+    url: '/adv/profit/statistics',
+    method: 'get',
+    params: query
+  })
+}
+
+// 统计导出
+export function exportCommission(query) {
+  return request({
+    url: '/adv/profit/exportCommission',
+    method: 'get',
+    params: query
+  })
+}

+ 53 - 0
src/api/his/consecutiveWithdrawRecord.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询连续提现记录列表
+export function listRecord(query) {
+  return request({
+    url: '/his/consecutiveWithdrawRecord/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询连续提现记录详细
+export function getRecord(id) {
+  return request({
+    url: '/his/consecutiveWithdrawRecord/' + id,
+    method: 'get'
+  })
+}
+
+// 新增连续提现记录
+export function addRecord(data) {
+  return request({
+    url: '/his/record',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改连续提现记录
+export function updateRecord(data) {
+  return request({
+    url: '/his/record',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除连续提现记录
+export function delRecord(id) {
+  return request({
+    url: '/his/consecutiveWithdrawRecord/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出连续提现记录
+export function exportRecord(query) {
+  return request({
+    url: '/his/consecutiveWithdrawRecord/export',
+    method: 'get',
+    params: query
+  })
+}

+ 27 - 0
src/api/his/integralRedPacketLog.js

@@ -0,0 +1,27 @@
+import request from '@/utils/request'
+
+// 查询积分佣金红包记录列表
+export function listLog(query) {
+  return request({
+    url: '/his/integralRedPacketLog/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询积分佣金红包记录详细
+export function getLog(logId) {
+  return request({
+    url: '/his/integralRedPacketLog/' + logId,
+    method: 'get'
+  })
+}
+
+// 导出积分佣金红包记录
+export function exportLog(query) {
+  return request({
+    url: '/his/integralRedPacketLog/export',
+    method: 'get',
+    params: query
+  })
+}

+ 62 - 0
src/api/his/withdrawDetail.js

@@ -0,0 +1,62 @@
+import request from '@/utils/request'
+
+// 查询广告分佣列表
+export function listProfit(query) {
+  return request({
+    url: '/adv/profit/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询广告分佣详细
+export function getProfit(id) {
+  return request({
+    url: '/adv/profit/' + id,
+    method: 'get'
+  })
+}
+
+// 新增广告分佣
+export function addProfit(data) {
+  return request({
+    url: '/adv/profit',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改广告分佣
+export function updateProfit(data) {
+  return request({
+    url: '/adv/profit',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除广告分佣
+export function delProfit(id) {
+  return request({
+    url: '/adv/profit/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出广告分佣
+export function exportProfit(query) {
+  return request({
+    url: '/adv/profit/export',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询用户可提现 和 已提现总金额
+export function getWithFinishAndMayWithdraw(query) {
+  return request({
+    url: '/adv/profit/getWithFinishAndMayWithdraw',
+    method: 'get',
+    params: query
+  })
+}

+ 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>

+ 227 - 0
src/views/his/statistics/commission.vue

@@ -0,0 +1,227 @@
+<template>
+  <div class="app-container">
+    <div class="app-content">
+      <div class="title">分佣统计</div>
+
+      <el-form class="search-form" :inline="true">
+        <!-- 快捷时间选择 -->
+        <el-form-item>
+          <el-select v-model="value" placeholder="请选择日期" @change="handleTypeChange">
+            <el-option
+              v-for="item in options"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value">
+            </el-option>
+          </el-select>
+        </el-form-item>
+
+        <!-- 自定义时间范围 -->
+        <el-form-item v-if="value === '0'">
+          <el-date-picker
+            v-model="dateRange"
+            type="daterange"
+            range-separator="至"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            value-format="yyyy-MM-dd"
+            @change="handleDateRangeChange">
+          </el-date-picker>
+        </el-form-item>
+
+        <el-form-item>
+          <el-button type="cyan" icon="el-icon-search" @click="getList">搜索</el-button>
+        </el-form-item>
+      </el-form>
+
+      <div class="data-box">
+        <div class="table-box">
+          <el-button
+            class="export"
+            size="small"
+            @click="handleExport"
+            v-hasPermi="['his:statistics:commissionExport']">
+            导出
+          </el-button>
+
+          <el-table
+            :data="list"
+            border
+            :summary-method="getSummaries"
+            show-summary
+            max-height="500"
+            style="width: 100%;">
+            <el-table-column prop="name" label="公司名称"></el-table-column>
+            <el-table-column prop="amountYuan" label="分佣金额(元)"></el-table-column>
+          </el-table>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { statistics,exportCommission } from "@/api/his/adv";
+import resize from '../../dashboard/mixins/resize'
+
+export default {
+  name: 'Index',
+  mixins: [resize],
+  data() {
+    return {
+      options: [
+        { value: '1', label: '今天' },
+        { value: '2', label: '昨天' },
+        { value: '3', label: '本周' },
+        { value: '4', label: '上周' },
+        { value: '5', label: '本月' },
+        { value: '6', label: '上月' },
+        { value: '7', label: '本季度' },
+        { value: '8', label: '上季度' },
+        { value: '9', label: '本年' },
+        { value: '10', label: '上年' },
+        { value: '0', label: '自定义' }  // 添加自定义选项
+      ],
+      value: '5',
+      dateRange: [],      // 自定义时间范围 [startTime, endTime]
+      startTime: '',      // 开始时间
+      endTime: '',        // 结束时间
+      list: []
+    }
+  },
+
+  created() {
+    this.getList();
+  },
+
+  methods: {
+    // 切换时间类型
+    handleTypeChange(val) {
+      if (val !== '0') {
+        this.dateRange = [];
+        this.startTime = '';
+        this.endTime = '';
+      }
+    },
+
+    // 自定义时间范围变化
+    handleDateRangeChange(val) {
+      if (val && val.length === 2) {
+        this.startTime = val[0];
+        this.endTime = val[1];
+      } else {
+        this.startTime = '';
+        this.endTime = '';
+      }
+    },
+
+    handleExport() {
+      // 校验自定义时间
+      if (this.value === '0' && (!this.startTime || !this.endTime)) {
+        this.$message.warning('请选择自定义时间范围');
+        return;
+      }
+
+      var data = {
+        type: this.value === '0' ? null : this.value,
+        startTime: this.startTime,
+        endTime: this.endTime
+      }
+      exportCommission(data).then((response) => {
+        this.download(response.msg);
+      });
+    },
+
+    getList() {
+      // 校验自定义时间
+      if (this.value === '0' && (!this.startTime || !this.endTime)) {
+        this.$message.warning('请选择自定义时间范围');
+        return;
+      }
+
+      var data = {
+        type: this.value === '0' ? null : this.value,
+        startTime: this.startTime,
+        endTime: this.endTime
+      }
+
+      statistics(data).then((response) => {
+        this.list = response.list;
+      });
+    },
+
+    getSummaries(param) {
+      const { columns, data } = param;
+      const sums = [];
+
+      columns.forEach((column, index) => {
+        if (index === 0) {
+          sums[index] = '总计';
+          return;
+        }
+
+        const values = data.map(item => Number(item[column.property]));
+
+        if (!values.every(value => isNaN(value))) {
+          const sum = values.reduce((prev, curr) => {
+            const value = Number(curr);
+            if (!isNaN(value)) {
+              return prev + curr;
+            } else {
+              return prev;
+            }
+          }, 0);
+
+          // 保留两位小数
+          sums[index] = sum.toFixed(2) + ' 元';
+        } else {
+          sums[index] = '';
+        }
+      });
+
+      return sums;
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.app-container {
+  border: 1px solid #e6e6e6;
+  padding: 12px;
+
+  .app-content {
+    background-color: white;
+
+    .title {
+      padding: 20px 30px 0px 30px;
+      font-size: 18px;
+      font-weight: bold;
+      color: black;
+    }
+
+    .search-form {
+      margin: 20px 30px 0px 30px;
+    }
+
+    .data-box {
+      padding: 30px;
+      background-color: rgb(255, 255, 255);
+      height: 100%;
+
+      .el-select {
+        margin: 5px 10px;
+      }
+
+      .table-box {
+        margin-top: 15px;
+
+        .export {
+          float: right;
+          margin: 10px 0px;
+        }
+      }
+    }
+  }
+}
+</style>

+ 497 - 0
src/views/his/withdrawDetail/index.vue

@@ -0,0 +1,497 @@
+<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="userId">
+        <el-input
+          v-model="queryParams.userId"
+          placeholder="请输入用户id"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="用户昵称" prop="nickName">
+        <el-input
+          v-model="queryParams.nickName"
+          placeholder="请输入用户昵称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="批次单号" prop="outBatchNo">
+        <el-input
+          v-model="queryParams.outBatchNo"
+          placeholder="请输入批次单号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="订单号" prop="batchId">
+        <el-input
+          v-model="queryParams.batchId"
+          placeholder="请输入微信批次单号(订单号)"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="提现金额(元)" label-width="100px">
+        <div class="amount-range">
+          <el-input
+            v-model="queryParams.minAmount"
+            placeholder=""
+            clearable
+            size="small"
+            style="width: 140px"
+            @keyup.enter.native="handleQuery"
+            @input="handleAmountInput('minAmount', $event)"
+          />
+          <span class="separator">-</span>
+          <el-input
+            v-model="queryParams.maxAmount"
+            placeholder=""
+            clearable
+            size="small"
+            style="width: 140px"
+            @keyup.enter.native="handleQuery"
+            @input="handleAmountInput('maxAmount', $event)"
+          />
+        </div>
+      </el-form-item>
+      <!-- 提现时间范围 -->
+      <el-form-item label="提现时间">
+        <el-date-picker
+          v-model="timeRange"
+          type="datetimerange"
+          range-separator="至"
+          start-placeholder="开始时间"
+          end-placeholder="结束时间"
+          :default-time="['00:00:00', '23:59:59']"
+          value-format="yyyy-MM-dd HH:mm:ss"
+          size="small"
+          style="width: 510px"
+        />
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择状态" clearable size="small">
+          <el-option label="发送成功" :value="1" />
+          <el-option label="领取中" value="0" />
+          <el-option label="已取消" :value="-2" />
+          <el-option label="发送失败" :value="-1" />
+
+        </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-form :model="queryParams" ref="totalMoney" :inline="true" v-show="showSearch" label-width="100px">
+      <el-form-item label="可提现总金额" prop="totalMayWithdraw">
+        <el-input
+          v-model="totalMoney.totalMayWithdraw"
+          placeholder=""
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+          disabled
+        />
+      </el-form-item>
+
+      <el-form-item label="已提现总金额" prop="totalWithdrawFinish">
+        <el-input
+          v-model="totalMoney.totalWithdrawFinish"
+          placeholder=""
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+          disabled
+        />
+      </el-form-item>
+      <el-form-item label="领取中金额" prop="withdrawMoney">
+        <el-input
+          v-model="totalMoney.withdrawMoney"
+          placeholder=""
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+          disabled
+        />
+      </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="['his:integralRedPacketLog:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="logList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="日志Id" align="center" prop="logId" />
+      <el-table-column label="用户id" align="center" prop="userId" />
+      <el-table-column label="用户昵称" align="center" prop="nickName" />
+      <el-table-column label="提现金额" align="center" prop="amount" />
+      <el-table-column label="提现时间" align="center" prop="createTime" />
+      <el-table-column label="批次单号" align="center" prop="outBatchNo" width="250px"/>
+      <el-table-column label="微信批次单号" align="center" prop="batchId" />
+      <el-table-column label="状态" align="center" prop="status" >
+        <template slot-scope="{ row }">
+          <el-tag :type="getStatusType(row.status)" size="small">
+            {{ getStatusText(row.status) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="退佣状态" align="center" prop="returnedStatus" >
+        <template slot-scope="{ row }">
+          <span :class="row.returnedStatus === 1 ? 'status-yes' : 'status-no'">
+            {{ row.returnedStatus === 1 ? '是' : '否' }}
+          </span>
+        </template>
+      </el-table-column>
+      <el-table-column label="备注" align="center" prop="remark" />
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+  </div>
+</template>
+
+<script>
+import {
+  listProfit,
+  getProfit,
+  delProfit,
+  addProfit,
+  updateProfit,
+  exportProfit,
+  getWithFinishAndMayWithdraw
+} from "@/api/his/withdrawDetail";
+import { listLog, getLog, delLog, addLog, updateLog, exportLog } from "@/api/his/integralRedPacketLog";
+
+export default {
+  name: "Profit",
+  data() {
+    return {
+      minAmount: undefined,
+      maxAmount: undefined,
+      timeRange: [],
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 广告分佣表格数据
+      logList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      firstLoginTime: null,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userId: null,
+        nickName: null,
+        beginTime:null,
+        endTime:null,
+        minAmount: null,
+        maxAmount: null,
+        outBatchNo: null,
+        batchId: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        adTransId: [
+          { required: true, message: "广告回调唯一交易ID不能为空", trigger: "blur" }
+        ],
+      },
+      // 可提现总金额 和 已提现总金额
+      totalMoney: {
+        totalWithdrawFinish: null,
+        totalMayWithdraw: null,
+        withdrawMoney: null
+      },
+    };
+  },
+  created() {
+    this.getList();
+    this.selectMoney();
+  },
+  methods: {
+    // 金额输入校验(只允许数字和小数点,最多两位小数)
+    handleAmountInput(field, value) {
+      // 移除非数字和非小数点字符
+      let newValue = value.replace(/[^\d.]/g, '')
+
+      // 只允许一个小数点
+      const parts = newValue.split('.')
+      if (parts.length > 2) {
+        newValue = parts[0] + '.' + parts.slice(1).join('')
+      }
+
+      // 限制最多两位小数
+      if (parts[1] && parts[1].length > 2) {
+        newValue = parts[0] + '.' + parts[1].substring(0, 2)
+      }
+
+      // 以0开头但不是0.的情况处理
+      if (newValue.startsWith('0') && newValue.length > 1 && !newValue.startsWith('0.')) {
+        newValue = newValue.substring(1)
+      }
+
+      this.queryParams[field] = newValue === '' ? null : newValue
+    },
+
+
+    getStatusText(status) {
+      const map = {
+        1: '发送成功',
+        '-3': '取消中',
+        '-2': '已取消',
+        '-1': '发送失败',
+        0: '领取中'
+      }
+      return map[status] || '领取中' // 其余状态默认显示领取中
+    },
+    getStatusType(status) {
+      const map = {
+        1: 'success',      // 绿色
+        '-3': 'warning',   // 黄色
+        '-2': 'info',      // 灰色
+        '-1': 'danger'     // 红色
+      }
+      return map[status] || '' // 领取中为默认蓝色/白色
+    },
+    changeLoginTime(){
+      if(this.firstLoginTime!=null){
+        this.queryParams.sTime=this.firstLoginTime[0];
+        this.queryParams.eTime=this.firstLoginTime[1];
+      }else{
+        this.queryParams.sTime=null;
+        this.queryParams.eTime=null;
+      }
+    },
+    /** 查询广告分佣列表 */
+    getList() {
+      this.loading = true;
+      const params = this.queryParams
+      const minAmount = this.queryParams.minAmount ? parseFloat(this.queryParams.minAmount) : null
+      const maxAmount = this.queryParams.maxAmount ? parseFloat(this.queryParams.maxAmount) : null
+
+      // 校验范围逻辑
+      if (minAmount !== null && maxAmount !== null && minAmount > maxAmount) {
+        this.$message.warning('最小金额不能大于最大金额')
+        return
+      }
+
+      if (minAmount !== null) {
+        params.minAmount = minAmount
+      }
+      if (maxAmount !== null) {
+        params.maxAmount = maxAmount
+      }
+      // 时间范围处理
+      if (this.timeRange && this.timeRange.length>0) {
+        params.beginTime = this.timeRange[0]
+        params.endTime = this.timeRange[1]
+      } else {
+        this.timeRange= []
+      }
+      listLog(params).then(response => {
+        this.logList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    /** 查询可提现总金额 和 已提现总金额 */
+    selectMoney() {
+      getWithFinishAndMayWithdraw().then(response => {
+        this.totalMoney.totalMayWithdraw = response.totalMayWithdraw;
+        this.totalMoney.totalWithdrawFinish = response.totalWithdrawFinish;
+        this.totalMoney.withdrawMoney = response.withdrawMoney;
+      })
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        adTransId: null,
+        adTaskId: null,
+        sumMoney: null,
+        userId: null,
+        userMoney: null,
+        companyId: null,
+        companyMoney: null,
+        huyiMoney: null,
+        yunlianMoney: null,
+        createTime: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.selectMoney();
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.queryParams = {
+        userId : null,
+        nickName : null,
+        beginTime : null,
+        endTime : null,
+        minAmount : null,
+        maxAmount : null,
+        outBatchNo : null,
+        batchId : null,
+        pageNum : 1,
+        pageSize : 10,
+      }
+      this.timeRange = [];
+      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 = "添加广告分佣";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getProfit(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改广告分佣";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateProfit(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addProfit(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 delProfit(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+
+      const params = this.queryParams
+      const minAmount = this.queryParams.minAmount ? parseFloat(this.queryParams.minAmount) : null
+      const maxAmount = this.queryParams.maxAmount ? parseFloat(this.queryParams.maxAmount) : null
+
+      // 校验范围逻辑
+      if (minAmount !== null && maxAmount !== null && minAmount > maxAmount) {
+        this.$message.warning('最小金额不能大于最大金额')
+        return
+      }
+
+      if (minAmount !== null) {
+        params.minAmount = minAmount
+      }
+      if (maxAmount !== null) {
+        params.maxAmount = maxAmount
+      }
+      // 时间范围处理
+      if (this.timeRange && this.timeRange.length>0) {
+        params.beginTime = this.timeRange[0]
+        params.endTime = this.timeRange[1]
+      } else {
+        this.timeRange= []
+      }
+      this.$confirm('是否确认导出所有提现数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportLog(params);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
+    }
+  }
+};
+</script>
+<style scoped>
+.amount-range {
+  display: flex;
+  align-items: center;
+}
+.separator {
+  margin: 0 8px;
+  color: #909399;
+}
+</style>

+ 385 - 0
src/views/his/withdrawDetail/lockdownUser.vue

@@ -0,0 +1,385 @@
+<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="userId">
+        <el-input
+          v-model="queryParams.userId"
+          placeholder="请输入用户ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="用户昵称" prop="nickName">
+        <el-input
+          v-model="queryParams.nickName"
+          placeholder="请输入用户昵称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="连续天数" prop="consecutiveDays">
+        <el-input
+          v-model="queryParams.consecutiveDays"
+          placeholder="请输入连续天数"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="开始日期" prop="startDate">
+        <el-date-picker clearable size="small"
+          v-model="queryParams.startDate"
+          type="date"
+          value-format="yyyy-MM-dd"
+          placeholder="选择连续开始日期">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="结束日期" prop="endDate">
+        <el-date-picker clearable size="small"
+          v-model="queryParams.endDate"
+          type="date"
+          value-format="yyyy-MM-dd"
+          placeholder="选择连续结束日期">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="提现次数" prop="withdrawCount">
+        <el-input
+          v-model="queryParams.withdrawCount"
+          placeholder="请输入连续期间提现次数"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="连续金额" prop="totalAmount">
+        <el-input
+          v-model="queryParams.totalAmount"
+          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="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdateUser"
+          v-hasPermi="['his:user:disabledUsers']"
+        >禁用</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="['his:consecutiveWithdrawRecord:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="recordList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="用户ID" align="center" prop="userId" />
+      <el-table-column label="用户昵称" align="center" prop="nickName" />
+      <el-table-column label="连续天数" align="center" prop="consecutiveDays" />
+      <el-table-column label="连续开始日期" align="center" prop="startDate" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.startDate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="连续结束日期" align="center" prop="endDate" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.endDate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="连续期间提现次数" align="center" prop="withdrawCount" />
+      <el-table-column label="连续期间提现总金额" align="center" prop="totalAmount" />
+      <el-table-column label="备注" align="center" prop="remark" />
+    </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="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="用户ID" prop="userId">
+          <el-input v-model="form.userId" placeholder="请输入用户ID" />
+        </el-form-item>
+        <el-form-item label="连续天数" prop="consecutiveDays">
+          <el-input v-model="form.consecutiveDays" placeholder="请输入连续天数" />
+        </el-form-item>
+        <el-form-item label="连续开始日期" prop="startDate">
+          <el-date-picker clearable size="small"
+            v-model="form.startDate"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="选择连续开始日期">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="连续结束日期" prop="endDate">
+          <el-date-picker clearable size="small"
+            v-model="form.endDate"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="选择连续结束日期">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="连续期间提现次数" prop="withdrawCount">
+          <el-input v-model="form.withdrawCount" placeholder="请输入连续期间提现次数" />
+        </el-form-item>
+        <el-form-item label="连续期间提现总金额" prop="totalAmount">
+          <el-input v-model="form.totalAmount" placeholder="请输入连续期间提现总金额" />
+        </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-dialog :title="updateUser.title" :visible.sync="updateUser.open" width="500px" append-to-body>
+      <el-form label-width="80px">
+        <el-form-item label="禁用备注" prop="remark">
+          <el-input v-model="userRemark" placeholder="请输入禁用备注" />
+        </el-form-item>
+
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitUserForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listRecord, getRecord, delRecord, addRecord, updateRecord, exportRecord } from "@/api/his/consecutiveWithdrawRecord";
+import { disabledUsers } from "@/api/his/user";
+
+export default {
+  name: "Record",
+  data() {
+    return {
+      userRemark: "",
+      updateUser:{
+        title:"",
+        open:false
+      },
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      userIds: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 连续提现记录表格数据
+      recordList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userId: null,
+        consecutiveDays: null,
+        startDate: null,
+        endDate: null,
+        withdrawCount: null,
+        totalAmount: null,
+        status: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        userId: [
+          { required: true, message: "用户ID不能为空", trigger: "blur" }
+        ],
+        consecutiveDays: [
+          { required: true, message: "连续天数不能为空", trigger: "blur" }
+        ],
+        startDate: [
+          { required: true, message: "连续开始日期不能为空", trigger: "blur" }
+        ],
+        endDate: [
+          { required: true, message: "连续结束日期不能为空", trigger: "blur" }
+        ],
+        withdrawCount: [
+          { required: true, message: "连续期间提现次数不能为空", trigger: "blur" }
+        ],
+        totalAmount: [
+          { required: true, message: "连续期间提现总金额不能为空", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询连续提现记录列表 */
+    getList() {
+      this.loading = true;
+      listRecord(this.queryParams).then(response => {
+        this.recordList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        userId: null,
+        consecutiveDays: null,
+        startDate: null,
+        endDate: null,
+        withdrawCount: null,
+        totalAmount: null,
+        status: 0,
+        remark: null,
+        createTime: null,
+        updateTime: 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.userIds = selection.map(item => item.userId)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加连续提现记录";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getRecord(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改连续提现记录";
+      });
+    },
+    /** 修改按钮操作 */
+    handleUpdateUser() {
+      this.updateUser.open = true;
+      this.updateUser.title = "禁用用户";
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateRecord(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addRecord(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    submitUserForm(){
+      const params = {userIds: this.userIds,remark: this.userRemark};
+      disabledUsers(params).then(response => {
+        this.msgSuccess("禁用成功");
+        this.updateUser.open = false;
+        this.getList();
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除连续提现记录编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delRecord(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有连续提现记录数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportRecord(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: [] };
           }
         }

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

@@ -1611,6 +1611,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>
@@ -2054,6 +2129,260 @@
               </el-tooltip>
             </el-form-item>
 
+            <!-- 游戏列表区域 -->
+            <el-form-item label="游戏列表" class="game-list-item">
+              <div class="game-list-header">
+                <el-button type="primary" size="small" @click="addGameConfig" icon="el-icon-plus">
+                  新增游戏
+                </el-button>
+                <span class="game-list-tip">最多可添加10个游戏</span>
+              </div>
+
+              <!-- 游戏列表表格 -->
+              <el-table
+                :data="form25.gameList"
+                border
+                style="width: 100%; margin-top: 15px;"
+                v-loading="gameListLoading"
+              >
+                <el-table-column label="序号" width="60" align="center">
+                  <template slot-scope="scope">
+                    <span>{{ scope.$index + 1 }}</span>
+                  </template>
+                </el-table-column>
+
+                <el-table-column label="游戏图片" width="200" align="center">
+                  <template slot-scope="scope">
+                    <div v-if="scope.row.editing">
+                      <ImageUpload
+                        v-model="scope.row.image"
+                        :limit="1"
+                        :file-type='["png", "jpg", "jpeg"]'
+                        :width="30"
+                        :height="30"
+                      />
+                    </div>
+                    <div v-else class="game-image-preview">
+                      <el-image
+                        v-if="scope.row.image"
+                        :src="scope.row.image"
+                        :preview-src-list="[scope.row.image]"
+                        style="width: 50px; height: 50px; border-radius: 4px;"
+                      >
+                        <div slot="error" class="image-slot">
+                          <i class="el-icon-picture-outline"></i>
+                        </div>
+                      </el-image>
+                      <span v-else class="no-image">暂无图片</span>
+                    </div>
+                  </template>
+                </el-table-column>
+
+                <el-table-column label="游戏名称" min-width="150">
+                  <template slot-scope="scope">
+                    <el-input
+                      v-if="scope.row.editing"
+                      v-model="scope.row.name"
+                      placeholder="请输入游戏名称"
+                      size="small"
+                    ></el-input>
+                    <span v-else>{{ scope.row.name || '-' }}</span>
+                  </template>
+                </el-table-column>
+
+                <el-table-column label="游戏链接" min-width="200">
+                  <template slot-scope="scope">
+                    <el-input
+                      v-if="scope.row.editing"
+                      v-model="scope.row.url"
+                      placeholder="请输入游戏链接"
+                      size="small"
+                    ></el-input>
+                    <span v-else class="game-link">{{ scope.row.url || '-' }}</span>
+                  </template>
+                </el-table-column>
+
+                <el-table-column label="排序" width="100" align="center">
+                  <template slot-scope="scope">
+                    <el-input-number
+                      v-if="scope.row.editing"
+                      v-model="scope.row.sort"
+                      :min="0"
+                      :max="999"
+                      size="small"
+                      controls-position="right"
+                      style="width: 80px;"
+                    ></el-input-number>
+                    <span v-else>{{ scope.row.sort || 0 }}</span>
+                  </template>
+                </el-table-column>
+
+                <el-table-column label="状态" width="80" align="center">
+                  <template slot-scope="scope">
+                    <el-switch
+                      v-if="scope.row.editing"
+                      v-model="scope.row.status"
+                      :active-value="1"
+                      :inactive-value="0"
+                      active-color="#13ce66"
+                      inactive-color="#ff4949"
+                    ></el-switch>
+                    <el-tag v-else :type="scope.row.status === 1 ? 'success' : 'info'" size="small">
+                      {{ scope.row.status === 1 ? '启用' : '禁用' }}
+                    </el-tag>
+                  </template>
+                </el-table-column>
+
+                <el-table-column label="操作" width="150" fixed="right" align="center">
+                  <template slot-scope="scope">
+                    <el-button
+                      v-if="!scope.row.editing"
+                      type="text"
+                      size="small"
+                      icon="el-icon-edit"
+                      @click="editGame(scope.$index)"
+                    >编辑</el-button>
+                    <el-button
+                      v-if="scope.row.editing"
+                      type="text"
+                      size="small"
+                      icon="el-icon-check"
+                      @click="saveGame(scope.$index)"
+                    >保存</el-button>
+                    <el-button
+                      v-if="!scope.row.editing"
+                      type="text"
+                      size="small"
+                      icon="el-icon-delete"
+                      class="delete-btn"
+                      @click="deleteGame(scope.$index)"
+                    >删除</el-button>
+                    <el-button
+                      v-if="scope.row.editing"
+                      type="text"
+                      size="small"
+                      icon="el-icon-close"
+                      @click="cancelEdit(scope.$index)"
+                    >取消</el-button>
+                  </template>
+                </el-table-column>
+              </el-table>
+            </el-form-item>
+          </el-card>
+          <el-card class="config-card" shadow="hover">
+            <div class="section-title">
+              <div class="title-icon icon-promotion">
+                <i class="el-icon-bank-card"></i>
+              </div>
+              <div class="title-text">
+                <h3>提现配置</h3>
+                <p class="subtitle">配置APP商家转账配置</p>
+              </div>
+            </div>
+
+            <el-divider></el-divider>
+            <el-form-item label="是否开启提现" prop="isOpenWithdraw">
+              <el-radio-group v-model="form25.isOpenWithdraw">
+                <el-radio :label="1" >开</el-radio>
+                <el-radio :label="0">关</el-radio>
+              </el-radio-group>
+            </el-form-item>
+            <el-form-item label="兑换佣金比例" prop="withdrawRatio">
+              <el-input-number
+                v-model="form25.withdrawRatio"
+                :min="100"
+                :step="1"
+                :precision="0"
+                placeholder="1元=多少积分"
+                controls-position="right"
+
+              />
+            </el-form-item>
+
+            <el-form-item label="一次最大提现金额(元)" prop="maxApplicationAmount">
+              <el-input-number
+                v-model="form25.maxApplicationAmount"
+                :min="0.10"
+                :max="999999.99"
+                :precision="2"
+                :step="0.01"
+                placeholder="最大提现金额"
+                controls-position="right"
+
+              />
+            </el-form-item>
+            <el-form-item label="一天允提现次数(次)" prop="withdrawNum">
+              <el-input-number
+                v-model="form25.withdrawNum"
+                :min="0"
+                :max="99"
+                :precision="0"
+                :step="1"
+                placeholder="提现次数"
+                controls-position="right"
+
+              />
+            </el-form-item>
+            <el-form-item label="连续提现封控(天)" prop="limitDayNum">
+              <el-input-number
+                v-model="form25.limitDayNum"
+                :min="1"
+                :max="99"
+                :precision="0"
+                :step="1"
+                placeholder="连续提现几天封控"
+                controls-position="right"
+
+              />
+            </el-form-item>
+            <el-form-item label="连续提现累计金额封控(元)" prop="limitAmount">
+              <el-input-number
+                v-model="form25.limitAmount"
+                :min="0.10"
+                :max="999999.99"
+                :precision="2"
+                :step="0.01"
+                placeholder="连续提现累计金额封控"
+                controls-position="right"
+              />
+            </el-form-item>
+
+            <el-form-item label="红包接口类型" prop="isNew">
+              <el-radio-group v-model="form25.isNew" >
+                <el-radio label="0">商家转账到零钱(旧)</el-radio>
+                <el-radio label="1">商家转账到零钱(新)</el-radio>
+              </el-radio-group>
+            </el-form-item>
+            <el-form-item label="商户号" prop="mchId">
+              <el-input v-model="form25.mchId" placeholder="请输入商户号"></el-input>
+            </el-form-item>
+            <el-form-item label="商户密钥" prop="mchKey">
+              <el-input v-model="form25.mchKey" placeholder="请输入商户密钥" show-password></el-input>
+            </el-form-item>
+            <el-form-item label="p12证书路径" prop="keyPath">
+              <el-input v-model="form25.keyPath" placeholder="请输入p12证书路径"></el-input>
+            </el-form-item>
+            <el-form-item label="apiV3密钥" prop="apiV3Key">
+              <el-input v-model="form25.apiV3Key" placeholder="请输入apiV3密钥" show-password></el-input>
+            </el-form-item>
+            <el-form-item label="公钥ID" prop="publicKeyId">
+              <el-input v-model="form25.publicKeyId" placeholder="请输入公钥ID"></el-input>
+            </el-form-item>
+            <el-form-item label="公钥证书路径" prop="publicKeyPath">
+              <el-input v-model="form25.publicKeyPath" placeholder="请输入公钥证书路径"></el-input>
+            </el-form-item>
+            <el-form-item label="私钥路径" prop="privateKeyPath">
+              <el-input v-model="form25.privateKeyPath" placeholder="请输入私钥路径"></el-input>
+            </el-form-item>
+            <el-form-item label="证书路径" prop="privateCertPath">
+              <el-input v-model="form25.privateCertPath" placeholder="请输入证书路径"></el-input>
+            </el-form-item>
+            <el-form-item label="看课奖励回调地址" prop="notifyUrl">
+              <el-input v-model="form25.notifyUrl" placeholder="请输入回调地址"></el-input>
+            </el-form-item>
+            <el-form-item label="提现回调地址" prop="withdrawalNotifyUrl">
+              <el-input v-model="form25.withdrawalNotifyUrl" placeholder="请输入回调地址"></el-input>
+            </el-form-item>
           </el-card>
 
           <!-- 操作按钮 -->
@@ -2651,6 +2980,185 @@
         </div>
       </el-tab-pane>
 
+
+      <el-tab-pane label="app页面配置" name="app.pageConfig">
+        <el-form
+          ref="form35"
+          :model="form35"
+          label-width="160px"
+        >
+
+          <!-- 主页面 -->
+          <el-divider content-position="left">主页面</el-divider>
+          <el-form-item label="健康页面" prop="mainPage.health">
+            <el-radio v-model="form35.mainPage.health" label="1">显示</el-radio>
+            <el-radio v-model="form35.mainPage.health" label="0">隐藏</el-radio>
+          </el-form-item>
+
+          <el-form-item label="精选页面" prop="mainPage.featured">
+            <el-radio v-model="form35.mainPage.featured" label="1">显示</el-radio>
+            <el-radio v-model="form35.mainPage.featured" label="0">隐藏</el-radio>
+          </el-form-item>
+
+          <el-form-item label="优选页面" prop="mainPage.preferred">
+            <el-radio v-model="form35.mainPage.preferred" label="1">显示</el-radio>
+            <el-radio v-model="form35.mainPage.preferred" label="0">隐藏</el-radio>
+          </el-form-item>
+
+          <!-- 消息子页面 -->
+          <!--           <el-divider content-position="left">消息 - 子页面</el-divider>-->
+
+          <!--           <el-form-item label="消息列表" prop="subPage.message.message">-->
+          <!--             <el-radio v-model="form35.subPage.message.message" label="1">显示</el-radio>-->
+          <!--             <el-radio v-model="form35.subPage.message.message" label="0">隐藏</el-radio>-->
+          <!--           </el-form-item>-->
+
+          <!--           <el-form-item label="通讯录" prop="subPage.message.contacts">-->
+          <!--             <el-radio v-model="form35.subPage.message.contacts" label="1">显示</el-radio>-->
+          <!--             <el-radio v-model="form35.subPage.message.contacts" label="0">隐藏</el-radio>-->
+          <!--           </el-form-item>-->
+
+          <!--           <el-form-item label="搜索" prop="subPage.message.search">-->
+          <!--             <el-radio v-model="form35.subPage.message.search" label="1">显示</el-radio>-->
+          <!--             <el-radio v-model="form35.subPage.message.search" label="0">隐藏</el-radio>-->
+          <!--           </el-form-item>-->
+
+          <!-- 健康子页面 -->
+          <el-divider content-position="left">健康 - 子页面</el-divider>
+
+          <el-form-item label="医疗服务" prop="subPage.health.medicalService">
+            <el-radio v-model="form35.subPage.health.medicalService" label="1">显示</el-radio>
+            <el-radio v-model="form35.subPage.health.medicalService" label="0">隐藏</el-radio>
+          </el-form-item>
+
+          <el-form-item label="健康管理" prop="subPage.health.healthManagement">
+            <el-radio v-model="form35.subPage.health.healthManagement" label="1">显示</el-radio>
+            <el-radio v-model="form35.subPage.health.healthManagement" label="0">隐藏</el-radio>
+          </el-form-item>
+
+          <el-form-item label="名家讲堂" prop="subPage.health.famousLecture">
+            <el-radio v-model="form35.subPage.health.famousLecture" label="1">显示</el-radio>
+            <el-radio v-model="form35.subPage.health.famousLecture" label="0">隐藏</el-radio>
+          </el-form-item>
+
+          <el-form-item label="学习中心" prop="subPage.health.learningCenter">
+            <el-radio v-model="form35.subPage.health.learningCenter" label="1">显示</el-radio>
+            <el-radio v-model="form35.subPage.health.learningCenter" label="0">隐藏</el-radio>
+          </el-form-item>
+
+          <!-- 精选子页面 -->
+          <!-- 精选 - 子页面 -->
+          <el-divider content-position="left">精选 - 子页面</el-divider>
+
+          <!-- 短视频 -->
+          <el-form-item label="短视频">
+            <el-radio
+              v-model="form35.subPage.featured.shortVideo"
+              label="1"
+            >显示</el-radio>
+            <el-radio
+              v-model="form35.subPage.featured.shortVideo"
+              label="0"
+            >隐藏</el-radio>
+
+            <el-input
+              v-model="form35.subPage.featured.shortVideoH5Url"
+              placeholder="请输入短视频 H5 链接"
+              clearable
+              style="margin-top: 8px"
+            />
+          </el-form-item>
+          <!-- 直播 -->
+          <el-form-item label="直播">
+            <el-radio
+              v-model="form35.subPage.featured.live"
+              label="1"
+            >显示</el-radio>
+            <el-radio
+              v-model="form35.subPage.featured.live"
+              label="0"
+            >隐藏</el-radio>
+
+            <el-input
+              v-model="form35.subPage.featured.liveH5Url"
+              placeholder="请输入直播 H5 链接"
+              clearable
+              style="margin-top: 8px"
+            />
+          </el-form-item>
+          <!-- 短剧 -->
+          <el-form-item label="短剧">
+            <el-radio
+              v-model="form35.subPage.featured.shortDrama"
+              label="1"
+            >显示</el-radio>
+            <el-radio
+              v-model="form35.subPage.featured.shortDrama"
+              label="0"
+            >隐藏</el-radio>
+
+            <el-input
+              v-model="form35.subPage.featured.shortDramaH5Url"
+              placeholder="请输入短剧 H5 链接"
+              clearable
+              style="margin-top: 8px"
+            />
+          </el-form-item>
+
+          <!-- 游戏 -->
+          <el-form-item label="游戏">
+            <el-radio
+              v-model="form35.subPage.featured.game"
+              label="1"
+            >显示</el-radio>
+            <el-radio
+              v-model="form35.subPage.featured.game"
+              label="0"
+            >隐藏</el-radio>
+
+            <el-input
+              v-model="form35.subPage.featured.gameH5Url"
+              placeholder="请输入游戏 H5 链接"
+              clearable
+              style="margin-top: 8px"
+            />
+          </el-form-item>
+
+          <!-- 任务广场 -->
+          <el-form-item label="任务广场">
+            <el-radio
+              v-model="form35.subPage.featured.taskSquare"
+              label="1"
+            >显示</el-radio>
+            <el-radio
+              v-model="form35.subPage.featured.taskSquare"
+              label="0"
+            >隐藏</el-radio>
+
+            <el-input
+              v-model="form35.subPage.featured.taskSquareH5Url"
+              placeholder="请输入任务广场 H5 链接"
+              clearable
+              style="margin-top: 8px"
+            />
+          </el-form-item>
+
+          <!-- 优选子页面 -->
+          <el-divider content-position="left">优选 - 子页面</el-divider>
+
+          <el-form-item label="现金 + 积分购买" prop="subPage.preferred.cashAndPointsPurchase">
+            <el-radio v-model="form35.subPage.preferred.cashAndPointsPurchase" label="1">显示</el-radio>
+            <el-radio v-model="form35.subPage.preferred.cashAndPointsPurchase" label="0">隐藏</el-radio>
+          </el-form-item>
+
+          <!-- 提交 -->
+          <div class="footer">
+            <el-button type="primary" @click="submitForm35">提 交</el-button>
+          </div>
+
+        </el-form>
+      </el-tab-pane>
+
     </el-tabs>
 
 
@@ -2679,9 +3187,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',
@@ -2692,6 +3201,9 @@ export default {
   },
   data() {
     return {
+      rewardList: [],
+      spinRewardList: [],
+      grandGiftList: [],
       corpOptions:[],
       citys: [],
       images: [],
@@ -2760,6 +3272,7 @@ export default {
       form23: {},
       form24: {},
       form25: {},
+      gameListLoading: false,
       form26: {
         bloodGlucose: {
           fasting: { normal: '' },
@@ -2847,6 +3360,36 @@ export default {
       },
       form32:{},
       form34:{},
+      form35: {
+        mainPage: {
+          health: "1",
+          featured: "1",
+          preferred: "1"
+        },
+        subPage: {
+          message: {
+            message: "1",
+            contacts: "1",
+            search: "1"
+          },
+          health: {
+            medicalService: "1",
+            healthManagement: "1",
+            famousLecture: "1",
+            learningCenter: "1"
+          },
+          featured: {
+            shortVideo: "1",
+            live: "1",
+            shortDrama: "1",
+            game: "1",
+            taskSquare: "1"
+          },
+          preferred: {
+            cashAndPointsPurchase: "1"
+          }
+        }
+      },
       storeProductScrmColumns:[],
       storeScrmColumns: [],
       photoArr: [],
@@ -2919,11 +3462,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
+    })
+    listReward({"rewardType": 4}).then(response => {
+      const {rows} = response
+      this.spinRewardList = rows
     })
-    getStoreColumns().then( response => {
-      this.storeScrmColumns = response.data
+    listReward({"rewardType": 6}).then(response => {
+      const {rows} = response
+      this.grandGiftList = rows
     })
   },
   watch: {
@@ -2946,6 +3501,119 @@ export default {
     },
   },
   methods: {
+    /**
+     * 新增游戏配置
+     */
+    addGameConfig() {
+      if (!this.form25.gameList) {
+        this.$set(this.form25, 'gameList', [])
+      }
+
+      // 限制最多10个游戏
+      if (this.form25.gameList.length >= 10) {
+        this.$message.warning('最多只能添加10个游戏')
+        return
+      }
+
+      // 添加新游戏配置
+      this.form25.gameList.push({
+        id: Date.now() + Math.random(), // 临时ID
+        image: '',
+        name: '',
+        url: '',
+        sort: this.form25.gameList.length,
+        status: 1, // 默认启用
+        editing: true // 新增时直接进入编辑状态
+      })
+
+      this.$forceUpdate()
+    },
+
+    /**
+     * 编辑游戏
+     */
+    editGame(index) {
+      // 如果已经有其他行在编辑,先保存或取消
+      const editingIndex = this.form25.gameList.findIndex(item => item.editing)
+      if (editingIndex !== -1 && editingIndex !== index) {
+        this.$confirm('当前有其他游戏正在编辑,是否继续?', '提示', {
+          confirmButtonText: '继续',
+          cancelButtonText: '取消',
+          type: 'warning'
+        }).then(() => {
+          // 取消其他行的编辑状态
+          this.form25.gameList[editingIndex].editing = false
+          // 设置当前行为编辑状态
+          this.$set(this.form25.gameList[index], 'editing', true)
+        }).catch(() => {})
+      } else {
+        this.$set(this.form25.gameList[index], 'editing', true)
+      }
+    },
+
+    /**
+     * 保存游戏
+     */
+    saveGame(index) {
+      const game = this.form25.gameList[index]
+
+      // 验证必填项
+      if (!game.name) {
+        this.$message.error('请输入游戏名称')
+        return
+      }
+      if (!game.url) {
+        this.$message.error('请输入游戏链接')
+        return
+      }
+      if (!game.image) {
+        this.$message.error('请上传游戏图片')
+        return
+      }
+
+      // 验证URL格式
+      const urlPattern = /^(http|https):\/\/[^\s]+$/
+      if (!urlPattern.test(game.url)) {
+        this.$message.error('请输入正确的游戏链接(以http://或https://开头)')
+        return
+      }
+
+      // 保存成功,退出编辑状态
+      this.$set(this.form25.gameList[index], 'editing', false)
+      this.$message.success('保存成功')
+    },
+
+    /**
+     * 取消编辑
+     */
+    cancelEdit(index) {
+      const game = this.form25.gameList[index]
+
+      // 如果是新增但未保存(没有id),直接删除
+      if (!game.id || game.id.toString().includes('.')) {
+        this.form25.gameList.splice(index, 1)
+      } else {
+        this.$set(this.form25.gameList[index], 'editing', false)
+      }
+    },
+
+    /**
+     * 删除游戏
+     */
+    deleteGame(index) {
+      this.$confirm('确定要删除这个游戏吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.form25.gameList.splice(index, 1)
+        // 重新排序
+        this.form25.gameList.forEach((item, idx) => {
+          item.sort = idx
+        })
+        this.$message.success('删除成功')
+      }).catch(() => {})
+    },
 
     // 处理开关配置
     handleSwitchConfig(row) {
@@ -3102,6 +3770,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)
         }
@@ -3264,6 +3938,38 @@ export default {
           this.configKey = response.data.configKey
           this.form34 =JSON.parse(response.data.configValue);
         }
+        if(key=="app.pageConfig"){
+          const defaultForm = this.form35
+          const parsed = response.data && response.data.configValue ? JSON.parse(response.data.configValue) : {}
+          this.form35 = {
+            ...defaultForm,
+            ...parsed,
+            mainPage: {
+              ...defaultForm.mainPage,
+              ...(parsed.mainPage || {})
+            },
+            subPage: {
+              ...defaultForm.subPage,
+              ...(parsed.subPage || {}),
+              message: {
+                ...defaultForm.subPage.message,
+                ...(((parsed.subPage || {}).message) || {})
+              },
+              health: {
+                ...defaultForm.subPage.health,
+                ...(((parsed.subPage || {}).health) || {})
+              },
+              featured: {
+                ...defaultForm.subPage.featured,
+                ...(((parsed.subPage || {}).featured) || {})
+              },
+              preferred: {
+                ...defaultForm.subPage.preferred,
+                ...(((parsed.subPage || {}).preferred) || {})
+              }
+            }
+          }
+        }
       })
     },
     /** 提交按钮 */
@@ -3499,6 +4205,10 @@ export default {
       if (!this.form25.defaultRewardGold){
         this.form25.defaultRewardGold = 100
       }
+      if (!this.form25.isOpenWithdraw){
+        this.form25.isOpenWithdraw = 0
+      }
+
       var param = { configId: this.configId, configKey: this.configKey, configValue: JSON.stringify(this.form25) }
       console.log(param)
       updateConfigByKey(param).then(response => {
@@ -3562,6 +4272,14 @@ export default {
         }
       });
     },
+    submitForm35(){
+      var param={configId:this.configId,configValue:JSON.stringify(this.form35)}
+      updateConfigByKey(param).then(response => {
+        if (response.code === 200) {
+          this.msgSuccess("修改成功");
+        }
+      });
+    },
     submitForm31(){
       var param={configId:this.configId,configKey: this.configKey,configValue:JSON.stringify(this.form34)}
       updateConfigByKey(param).then(response => {
@@ -4030,4 +4748,80 @@ export default {
     padding: 16px;
   }
 }
+
+
+/* 游戏列表样式 */
+.game-list-item {
+  margin-top: 20px;
+}
+
+.game-list-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-bottom: 10px;
+}
+
+.game-list-tip {
+  font-size: 12px;
+  color: #909399;
+}
+
+.game-image-preview {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  min-height: 50px;
+}
+
+.no-image {
+  font-size: 12px;
+  color: #909399;
+}
+
+.game-link {
+  display: inline-block;
+  max-width: 200px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  color: #409EFF;
+  cursor: pointer;
+}
+
+.delete-btn {
+  color: #f56c6c !important;
+}
+
+.delete-btn:hover {
+  color: #f78989 !important;
+}
+
+/* 表格样式优化 */
+::v-deep .el-table .cell {
+  padding-left: 8px;
+  padding-right: 8px;
+}
+
+::v-deep .el-table th {
+  background-color: #f5f7fa;
+  color: #606266;
+}
+
+::v-deep .el-table--border {
+  border-radius: 8px;
+  overflow: hidden;
+}
+
+/* 图片上传组件样式调整 */
+::v-deep .image-upload {
+  width: 60px;
+  height: 60px;
+}
+
+::v-deep .image-upload .el-upload--picture-card {
+  width: 60px;
+  height: 60px;
+  line-height: 64px;
+}
 </style>

+ 58 - 4
src/views/system/config/integralConfig.vue

@@ -167,6 +167,43 @@
           />
         </el-select>
       </el-form-item>
+      <el-form-item label="积分兑换佣金积分类型" prop="integralTypes">
+        <el-select
+          v-model="form11.integralTypes"
+          clearable filterable
+          placeholder="请选择积分类型"
+          multiple
+          size="small">
+          <el-option
+            v-for="item in integralLogTypeOptions"
+            :key="item.dictValue"
+            :label="item.dictLabel"
+            :value="item.dictValue"
+          >
+          </el-option>
+        </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>
 
       <el-row>
         <el-col :span="12">
@@ -222,11 +259,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,
@@ -252,7 +291,8 @@ export default {
         integralCompanyRatio: 0,
         integralHuYiRatio: 0,
         integralYunLianRatio: 0,
-        minimumIntegral: 0
+        minimumIntegral: 0,
+        integralTypes:[]
       },
       saveLoading: false,
     }
@@ -262,17 +302,31 @@ 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(){
       this.saveLoading = true
+      if (!this.form11.integralTypes){
+        this.form11.integralTypes = [];
+      }
       const param={configId:this.configId,configValue:JSON.stringify(this.form11)}
       updateConfigByKey(param).then(response => {
         const {code} = response