Forráskód Böngészése

Merge branch 'test' of maopiao/mp-ui-pc into master

kk 2 éve
szülő
commit
a30386eeab

+ 27 - 0
src/api/admin/salesite.js

@@ -66,3 +66,30 @@ export function updateSaleSiteStatus(data) {
     data: data
   })
 }
+
+// 下载导入模板
+export function salesiteDownload() {
+  return request({
+    url: '/api/v1/mp/admin/salesite/template/download',
+    method: 'post',
+  })
+}
+
+/**
+ * Post 方式上传文件
+ */
+export function salesiteImport(data, config = {}) {
+  var formData  = new FormData()
+  Object.keys(data).forEach(key => {
+    formData.append(key, data[key])
+  })
+  return request({
+    url: `/api/v1/mp/admin/salesite/import`,
+    method: 'post',
+    data: formData ,
+    ...config,
+    headers: {
+      'Content-Type': 'multipart/form-data'
+    }
+  })
+}

+ 57 - 0
src/api/business/exchangeCode.js

@@ -0,0 +1,57 @@
+import request from '@/utils/request'
+
+// 查询分类列表, 支持翻页
+export function goodsExchangeList(urlParams, data) {
+  return request({
+    url: '/api/v1/mp/admin/CdKey/list',
+    method: 'post',
+    data,
+    urlParams
+  })
+}
+
+// 添加兑换码组
+export function goodsExchangeCreate(data) {
+  return request({
+    url: '/api/v1/mp/admin/CdKey/create',
+    method: 'post',
+    data
+  })
+}
+
+// 查询兑换码组详情
+export function getExchangeCode(data) {
+  return request({
+    url: `/api/v1/mp/admin/CdKey/detail/${data}`,
+    method: 'post',
+  })
+}
+
+// 查看兑换码详情
+export function getExchangeCodelist(urlParams, data) {
+  return request({
+    url: `/api/v1/mp/admin/CdKey/exchangeDetail/${data}`,
+    method: 'post',
+    urlParams
+  })
+}
+
+
+// 兑换码激活
+export function activateExchangeCode(data) {
+  return request({
+    url: `/api/v1/mp/admin/CdKey/activate`,
+    method: 'post',
+    data
+  })
+}
+
+// 导出
+export function exportCode(data) {
+  return request({
+    url: '/api/v1/mp/admin/CdKey/export',
+    method: 'post',
+    timeout: 15 * 60 * 1000,
+    data
+  })
+}

+ 19 - 0
src/router/index.js

@@ -192,6 +192,25 @@ export const constantRoutes = [
       }
     ],
   },
+  {
+    path: '/exchange',
+    component: Layout,
+    hidden: true,
+    children: [
+      {
+        path: 'addCode',
+        component: (resolve) => require(['@/views/business/exchange/addCode'], resolve),
+        name: 'ExchangeAdd',
+        meta: { title: '添加兑换码', activeMenu: '/goods/exchange' }
+      },
+      {
+        path: 'detailCode',
+        component: (resolve) => require(['@/views/business/exchange/addCode'], resolve),
+        name: 'ExchangeDetail',
+        meta: { title: '查看兑换码', activeMenu: '/goods/exchange' }
+      }
+    ],
+  },
   {
     path: '/coupon',
     component: Layout,

+ 336 - 0
src/views/business/exchange/addCode.vue

@@ -0,0 +1,336 @@
+<template>
+  <div class="app-container goods-add">
+    <el-divider content-position="left">基础信息</el-divider>
+    <el-form ref="addItem" :rules="rules" :model="addData" label-width="120px">
+      <el-row :gutter="10">
+        <el-row :gutter="10">
+          <el-col :span="7">
+            <el-form-item label="兑换码名称:" prop="title">
+              <el-input v-model="addData.title" placeholder="请输入兑换码名称" :disabled="id?true:false" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="10">
+          <el-col :span="7">
+            <el-form-item label="门店:" prop="channelId">
+              <el-select v-model="addData.channelId" placeholder="请选择门店" style="width: 100%;" :disabled="id?true:false" filterable :filter-method="dataFilter">
+                <el-option v-for="(item) in siteList" :key="item.channelId" :label="item.name" :value="item.channelId">
+                  <div>
+                    <span style="float: left;">{{item.name}} </span>
+                    <span style="float: right;">{{item.mobile}}</span>
+                  </div>
+                </el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="10">
+          <el-col :span="7">
+            <el-form-item label="兑换码数量:" prop="quantity">
+              <el-input v-model="addData.quantity" placeholder="请输入兑换码数量" :disabled="id?true:false" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="6" v-if="id?true:false">
+            <div class="clk" @click="toCodelist()">
+              查看
+            </div>
+          </el-col>
+        </el-row>
+        <el-row :gutter="10">
+          <el-col :span="7">
+            <el-form-item label="有效期:" prop="validityPeriod">
+              <el-select v-model="addData.validityPeriod" placeholder="请选择有效期" style="width: 100%;" :disabled="id?true:false">
+                <el-option label="三个月" value="threeMoths"></el-option>
+                <el-option label="六个月" value="sixMonths"></el-option>
+                <el-option label="永久" value="forever"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-row>
+      <el-divider content-position="left">商品设置</el-divider>
+      <el-row :gutter="10">
+        <el-col :span="22">
+          <el-form-item label="" prop="goodsList">
+            <!-- 奖级列表 -->
+            <code-list ref="awards" :id="id?id:''" v-model="goodsList" @handleCommand="handleCommand" @close="close" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+
+    <el-row v-if="!id">
+      <el-col :span="24" style="text-align: center">
+        <el-button type="info" @click="$router.replace('/marketing/marketing')">取消</el-button>
+        <el-button type="primary" @click="update()">保存</el-button>
+      </el-col>
+    </el-row>
+
+    <!-- 添加商品 -->
+    <goods-add :dialog-visible="goodsTableVisible" @close="close" @confirmGoods="confirmGoods" v-if="goodsTableVisible" />
+    <!-- 添加券 -->
+    <coupon-add :dialog-visible="couponTableVisible" @close="close" @confirmCoupon="confirmCoupon" v-if="couponTableVisible" />
+    <!-- 添加券包 -->
+    <coupon-pkg-add :dialog-visible="couponPkgTableVisible" @close="close" @confirmCouponPkg="confirmCouponPkg" v-if="couponPkgTableVisible" />
+    <!-- 添加盲豆 -->
+    <coin-add :dialog-visible="coinTableVisible" @close="close" @confirmCoin="confirmCoin" v-if="coinTableVisible" />
+
+    <!--  查询兑换码 -->
+    <exchange-code-list v-if="exchangeCodeShow" @cancel="exchangeCodeShow = false" :exchangeCodeShow="exchangeCodeShow" :id="id" />
+  </div>
+</template>
+
+<script>
+import { publicFileGetUrl } from "@/api/common";
+import { getExchangeCode, goodsExchangeCreate } from '@/api/business/exchangeCode'
+import CodeList from "./components/CodeList"
+import GoodsAdd from "./components/GoodsAdd"
+import CouponAdd from "./components/CouponAdd"
+import CouponPkgAdd from "./components/CouponPkgAdd"
+import CoinAdd from "./components/CoinAdd"
+
+import ExchangeCodeList from "./components/ExchangeCodeList"
+import { listAllSaleSite } from "@/api/admin/salesite";
+export default {
+  name: 'ExchangeAdd',
+  components: {
+    CodeList,
+    GoodsAdd,
+    CouponAdd,
+    CouponPkgAdd,
+    CoinAdd,
+    ExchangeCodeList
+  },
+  data() {
+    return {
+      id: this.$route.query.id,
+      siteList: [],//门店列表
+      siteCopyList: [],//门店列表
+      addData: {
+        title: '',//兑换码名称
+        channelId: '',//门店
+        siteName: '',//门店名称
+        type: '',//
+        quantity: '',//数量
+        goodsList: [],//兑换码关联商品
+      },
+      rules: {
+        title: [{ required: true, message: '请输入兑换码名称', trigger: ["blur", "change"] }],
+        channelId: [{ required: true, message: '请选择门店', trigger: 'blur' }],
+        validityPeriod: [{ required: true, message: '请选择有效期', trigger: 'blur' }],
+        quantity: [
+          { required: true, message: "请输入兑换码", trigger: ["blur", "change"] },
+          { pattern: /^[1-9]\d*$/, message: "请输入正确的数字", trigger: ["blur", "change"] }]
+      },
+      // 列表
+      goodsList: [],
+      goodsTableVisible: false, // 添加商品弹框
+      couponTableVisible: false, // 添加卡券弹框
+      couponPkgTableVisible: false, // 添加券包弹框
+      coinTableVisible: false, // 添加盲豆弹框
+      pageParams: {
+        pageNum: 1,
+        pageSize: 10,
+      },
+
+      exchangeCodeShow: false,
+    }
+  },
+  computed: {
+    marketingPicUrl: {
+      get() {
+        return this.addData.picUrl ? this.addData.picUrl.split(',').map(item => {
+          return {
+            fileName: item
+          }
+        }) : []
+      },
+      set(val) {
+        this.$set(this.addData, 'picUrl', val.map(item => {
+          return item.fileName
+        }).toString())
+      }
+    },
+  },
+  created() {
+    if (this.id) {
+      getExchangeCode(this.id).then(res => {
+        const { channelId, quantity, title, siteName, validityPeriod, goodsList, id } = res.data
+        this.addData = { channelId, quantity, title, siteName, validityPeriod: JSON.parse(validityPeriod).value, goodsList, id }
+        if (goodsList) {
+          goodsList.forEach((item) => {
+            item.type = item.type && JSON.parse(item.type).value
+            item.picUrl = publicFileGetUrl + item.picUrl.split(',')[0]
+          });
+          this.$nextTick(() => {
+            this.$refs.awards.add(3, goodsList)
+          })
+          this.goodsList = goodsList
+        }
+      })
+    }
+  },
+  mounted() {
+    this.getSaleSiteList()
+  },
+  methods: {
+    // 获取门店下拉列表
+    getSaleSiteList() {
+      listAllSaleSite({}).then(response => {
+        this.siteList = response.data || [];
+        this.siteCopyList = response.data || [];
+      });
+    },
+    dataFilter(val) {
+      if (val) { //val存在
+        this.siteList = this.siteCopyList.filter((item) => {
+          if (!!~item.mobile.indexOf(val) || !!~item.mobile.toUpperCase().indexOf(val.toUpperCase())
+            || !!~item.name.indexOf(val) || !!~item.name.indexOf(val)) {
+            return true
+          }
+        })
+      } else { //val为空时,还原数组
+        this.siteList = this.siteCopyList;
+      }
+    },
+    // 保存
+    update() {
+      this.$refs.addItem.validate((valid, items) => {
+        if (valid) {
+          if (this.goodsList.length < 1) {
+            this.msgError('请至少设置一个商品!')
+            return;
+          }
+          // 判断没有设置奖级数量
+          let prizeIndexThree = this.goodsList.findIndex((item) => {
+            return !item.quantity && item.quantity != 0;
+          });
+          if (prizeIndexThree != -1) {
+            this.$message.error(
+              `请设置"${this.goodsList[prizeIndexThree].title}"的数量!`
+            );
+            return;
+          }
+
+          let goodsTotal = 0;
+          this.goodsList.forEach((item) => {
+            goodsTotal += item.quantity;
+          });
+          if (this.addData.quantity != goodsTotal) {
+            this.$message.error("兑换码数量不一致!");
+            return;
+          }
+          this.goodsList = this.goodsList.map((item) => {
+            return {
+              ...item,
+              refId: item.refId || item.goodsId || item.couponId || item.id,
+            }
+          });
+
+          const { channelId, quantity, siteName, validityPeriod, title } = this.addData
+          goodsExchangeCreate({
+            channelId,
+            quantity,
+            siteName,
+            validityPeriod,
+            title,
+            goodsList: this.goodsList,
+            id: this.addData.id ? this.addData.id : "",
+          }).then(res => {
+            if (res.code === 0) {
+              this.$message({
+                message: this.addData.id ? '修改成功!' : '添加成功!',
+                type: 'success'
+              })
+              this.$store.dispatch('tagsView/delView', this.$route)
+              this.$router.go(-1)
+            }
+          })
+        } else {
+          if (items && Object.keys(items).length > 0) {
+            this.$message({
+              message: items[Object.keys(items)[0]][0].message,
+              type: 'warning'
+            })
+          }
+        }
+      })
+    },
+
+    toCodelist() {
+      this.exchangeCodeShow = true
+    },
+
+
+    // 添加奖品种类
+    handleCommand(e) {
+      if (e == "goods") {
+        this.goodsTableVisible = true;
+      } else if (e == "coupon") {
+        this.couponTableVisible = true;
+      } else if (e == "coupon_pkg") {
+        this.couponPkgTableVisible = true;
+      } else if (e == "coin") {
+        this.coinTableVisible = true;
+      }
+    },
+
+    // 关闭弹框
+    close() {
+      this.goodsTableVisible = false;
+      this.couponTableVisible = false;
+      this.couponPkgTableVisible = false;
+      this.coinTableVisible = false;
+    },
+
+    // 确认选中商品
+    confirmGoods(arr) {
+      this.$refs.awards.add(1, arr)
+    },
+
+    // 确认选中卡券
+    confirmCoupon(arr) {
+      this.$refs.awards.add(1, arr)
+    },
+
+    // 确认选中券包
+    confirmCouponPkg(arr) {
+      this.$refs.awards.add(1, arr)
+    },
+
+    // 确认输入盲豆
+    confirmCoin(obj) {
+      this.$refs.awards.add(2, obj)
+    },
+
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.goods-add {
+  .tip {
+    font-size: 12px;
+    color: #999;
+  }
+
+  .el-divider {
+    .is-left {
+      color: #409eff;
+      font-size: 20px;
+      font-weight: bolder;
+      left: 10px;
+    }
+  }
+}
+.clk {
+  display: inline-block;
+  line-height: 36px;
+  color: rgb(0, 114, 255);
+  font-size: 16px;
+  cursor: pointer;
+}
+.clk:hover {
+  color: rgb(64, 146, 255);
+}
+</style>

+ 151 - 0
src/views/business/exchange/components/CodeList.vue

@@ -0,0 +1,151 @@
+<template>
+  <div>
+    <div class="prize">
+      <div class="prize-table">
+        <el-table :data="goodsList" class="el-table">
+          <el-table-column label="商品图片">
+            <template slot-scope="scope">
+              <el-image style="width: 70px; height: 70px" :src="scope.row.picUrl" :preview-src-list="[scope.row.picUrl]">
+              </el-image>
+            </template>
+          </el-table-column>
+          <el-table-column label="商品名称" prop="title">
+            <template slot-scope="scope">
+              <div v-if="scope.row.type == 'coin' && scope.row.value >= 0">盲豆 x{{scope.row.value}}</div>
+              <div v-else>{{scope.row.title}}</div>
+            </template>
+          </el-table-column>
+          <el-table-column label="商品类型">
+            <template slot-scope="scope">
+              <div v-if="scope.row.type == 'goods'">商品</div>
+              <div v-if="scope.row.type == 'coupon'">券</div>
+              <div v-if="scope.row.type == 'coupon_pkg'">券包</div>
+              <div v-if="scope.row.type == 'coin'">盲豆</div>
+            </template>
+          </el-table-column>
+          <!-- 商品价格 -->
+          <!-- 商品成本 -->
+          <!-- 商品数量 -->
+          <el-table-column label="兑换码数量" prop="quantity" align="center">
+             <template slot-scope="scope">
+               <div>
+                 <el-input-number
+                   v-model="scope.row.quantity"
+                   controls-position="right"
+                   @change="handleChange($event)"
+                   :min="1"
+                   size="small"
+                   :disabled="id?true:false"
+                 ></el-input-number>
+               </div>
+             </template>
+           </el-table-column>
+          <el-table-column label="操作" align="center" v-if="!id">
+            <template slot-scope="scope">
+              <el-button size="mini" type="text" @click="handleDel(scope.$index)">删除</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+      <div class="prize-btn" v-if="!id">
+        <el-dropdown @command="handleCommand($event)">
+          <el-button type="primary" size="small">
+            添加商品<i class="el-icon-arrow-down el-icon--right"></i>
+          </el-button>
+          <el-dropdown-menu slot="dropdown">
+            <el-dropdown-item command="goods">商品</el-dropdown-item>
+            <el-dropdown-item command="coupon">券</el-dropdown-item>
+            <el-dropdown-item command="coupon_pkg">券包</el-dropdown-item>
+            <el-dropdown-item command="coin">盲豆</el-dropdown-item>
+          </el-dropdown-menu>
+        </el-dropdown>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+export default {
+  name: "AwardList",
+  props: {
+    id: {
+      type: [String,Number],
+      default: false,
+    },
+  },
+  data() {
+    return {
+      // 奖级列表
+      goodsList: [
+        // {
+        //   createTime: "",
+        //   groupId: 1,
+        //   id: 0,
+        //   isDeleted: 0,
+        //   picUrl: "",
+        //   quantity: 0,
+        //   refId: "",
+        //   title: "",
+        //   type: "",
+        //   updateTime: "",
+        //   value: 0,
+        // },
+      ],
+    };
+  },
+  methods: {
+    // 添加奖品
+    add(type, item) {
+      if (type == 1) {
+        item.forEach((res)=>{
+          this.goodsList = this.goodsList.concat(res);
+        })
+      } else if (type == 2) {
+        this.goodsList.push(item);
+      } else if (type == 3) {
+        this.goodsList = item
+      }
+      this.$emit('input', this.goodsList)
+      this.$emit('close')
+    },
+    // 选择奖品种类
+    handleCommand(e) {
+      this.$emit('handleCommand', e)
+    },
+
+    // 改变奖品数量
+    handleChange(e) {
+      this.$forceUpdate();
+    },
+
+    // 奖级商品删除
+    handleDel(index) {
+      this.goodsList.splice(index, 1);
+    },
+
+  },
+};
+</script>
+<style lang="scss" scoped>
+.prize {
+  width: 100%;
+  margin-bottom: 50px;
+  background: #f9f9f9;
+  border: 1px solid #bbbbbb;
+  font-size: 14px;
+  &-top {
+    padding: 10px 20px;
+    margin-bottom: 10px;
+    display: flex;
+    align-content: center;
+    justify-content: space-around;
+    border-bottom: 1px solid #bbbbbb;
+    div {
+      line-height: 36px;
+    }
+  }
+  &-btn {
+    border-top: 1px solid #bbbbbb;
+    padding: 10px;
+  }
+}
+</style>

+ 94 - 0
src/views/business/exchange/components/CoinAdd.vue

@@ -0,0 +1,94 @@
+<template>
+  <div>
+    <el-dialog
+      title="添加盲豆奖品"
+      :visible.sync="dialogVisible"
+      :before-close="close"
+      width="500px"
+    >
+      <el-form
+        :model="coinForm"
+        :rules="coinRules"
+        ref="coinForm"
+        label-width="100px"
+      >
+        <el-form-item label="盲豆数量" prop="quantity">
+          <el-input
+            v-model="coinForm.quantity"
+            size="small"
+            placeholder="请输入盲豆数量"
+            style="width: 200px"
+          />
+        </el-form-item>
+      </el-form>
+      <div class="dialog-btn">
+        <el-button size="small" @click="close"> 取 消 </el-button>
+        <div class="ge"></div>
+        <el-button type="primary" size="small" @click="confirmCoin">
+          确 认
+        </el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+<script>
+import { publicFileGetUrl } from "@/api/common";
+export default {
+  name: "CoinAdd",
+  props: {
+    dialogVisible: {
+      type: Boolean,
+      default: false,
+    },
+  },
+  data() {
+    return {
+      coinForm: { quantity: "" },
+      coinRules: {
+        quantity: [
+          { required: true, message: "请输入数量", trigger: "blur" },
+          {
+            pattern: /^([1-9]\d*)$/,
+            message: "请输入合法的数字",
+            trigger: ["blur", "change"],
+          },
+        ],
+      },
+    };
+  },
+  methods: {
+    // 确认输入盲豆
+    confirmCoin() {
+      let coin = {
+        type: "coin",
+        // quantity: 1,
+        title: `盲豆 x${this.coinForm.quantity}`,
+        picUrl: publicFileGetUrl + "md.jpeg",
+        value: this.coinForm.quantity,
+        sortWeight: 100
+      };
+      this.$refs["coinForm"].validate((valid) => {
+        if (valid) {
+          this.$emit("confirmCoin", coin);
+        } else {
+          return false;
+        }
+      });
+    },
+    close() {
+      this.$emit("close");
+    },
+  },
+};
+</script>
+<style lang="scss" scoped>
+.dialog-btn {
+  display: flex;
+  align-content: center;
+  justify-content: flex-end;
+  padding: 40px 0 0;
+  .ge {
+    width: 40px;
+  }
+}
+</style>

+ 194 - 0
src/views/business/exchange/components/CouponAdd.vue

@@ -0,0 +1,194 @@
+<template>
+  <div>
+    <el-dialog
+      title="添加券奖品"
+      width="1000px"
+      :visible.sync="dialogVisible"
+      :before-close="close"
+    >
+      <div class="dialog-search">
+        <div>券名称:</div>
+        <el-input
+          v-model="couponTitle"
+          placeholder="请输入券名称"
+          clearable
+          size="small"
+          style="width: 240px"
+          @keyup.enter.native="getCouponList"
+        />
+        <div class="ge"></div>
+        <el-button
+          type="primary"
+          icon="el-icon-search"
+          size="mini"
+          @click="getCouponList"
+          >查询</el-button
+        >
+      </div>
+      <el-table
+        v-loading="loading"
+        :data="couponList"
+        row-key="couponId"
+        @selection-change="handleSelectionCoupon"
+        class="el-table"
+      >
+        <el-table-column
+          type="selection"
+          width="55"
+          align="center"
+          fixed="left"
+          :reserve-selection="true"
+        />
+        <!--  -->
+        <el-table-column label="券ID" prop="couponId" />
+        <el-table-column label="券图片">
+          <template slot-scope="scope">
+            <div>
+              <el-image
+                style="width: 100px; height: 100px"
+                :src="scope.row.picUrl"
+                :preview-src-list="[scope.row.picUrl]"
+              >
+              </el-image>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="券名称" prop="title" min-width="85" />
+        <el-table-column label="使用场景" min-width="85">
+          <template slot-scope="scope">
+            <div>{{ scope.row.type.desc }}</div>
+          </template>
+        </el-table-column>
+        <el-table-column label="券价格" min-width="85">
+          <template slot-scope="scope">
+            <div>¥{{ $numberFormat(scope.row.discount) }}</div>
+          </template>
+        </el-table-column>
+        <el-table-column label="门店承担比例" min-width="85">
+          <template slot-scope="scope">
+            <div>{{ scope.row.channelSharedRate }}%</div>
+          </template>
+        </el-table-column>
+        <el-table-column label="有效期限" min-width="85">
+          <template slot-scope="scope">
+            <div>领取后{{ scope.row.dueDays }}天有效</div>
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination
+        v-show="couponTotal > 0"
+        :total="couponTotal"
+        :page.sync="pageParams.pageNum"
+        :limit.sync="pageParams.pageSize"
+        @pagination="getCouponList"
+      />
+      <div class="dialog-btn">
+        <el-button size="small" @click="close"> 取 消 </el-button>
+        <div class="ge"></div>
+        <el-button type="primary" size="small" @click="confirmCoupon">
+          确 认
+        </el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+<script>
+import { publicFileGetUrl } from "@/api/common";
+import { getCouponList } from "@/api/business/coupon";
+export default {
+  name: "CouponAdd",
+  props: {
+    dialogVisible: {
+      type: Boolean,
+      default: false,
+    },
+  },
+  data() {
+    return {
+      loading: false,
+      couponTitle: "", // 券名称
+      couponList: [], // 卡券列表
+      couponTotal: 0, // 卡券总数
+      selectCouponList: [], // 选中卡券
+      pageParams: {
+        pageNum: 1,
+        pageSize: 10,
+      },
+    };
+  },
+  created() {
+    this.getCouponList();
+  },
+  methods: {
+    // 卡券列表
+    getCouponList() {
+      this.loading = true;
+      getCouponList(
+        "pageNum=" +
+          this.pageParams.pageNum +
+          "&pageSize=" +
+          this.pageParams.pageSize +
+          "&",
+        { title: this.couponTitle, status: "on" }
+      ).then((res) => {
+        this.couponList = res.rows.map((item) => {
+          return {
+            ...item,
+            type: JSON.parse(item.type),
+            useArea: JSON.parse(item.useArea),
+            picUrl: publicFileGetUrl + item.picUrl,
+          };
+        });
+        this.couponTotal = res.total;
+        this.loading = false;
+      });
+    },
+
+    // 选中卡券
+    handleSelectionCoupon(e) {
+      this.selectCouponList = e.map((item) => {
+        return {
+          type: "coupon",
+          // quantity: 1,
+          couponId: item.couponId,
+          picUrl: item.picUrl,
+          title: item.title,
+          sortWeight: 100
+        };
+      });
+    },
+
+    // 确认选中卡券
+    confirmCoupon() {
+      if(!this.selectCouponList.length) {
+        this.msgInfo('请选择券')
+        return
+      }
+      this.$emit("confirmCoupon", this.selectCouponList);
+    },
+
+    close() {
+      this.$emit("close");
+    },
+  },
+};
+</script>
+<style lang="scss" scoped>
+.dialog-search {
+  display: flex;
+  line-height: 32px;
+  margin-bottom: 20px;
+  .ge {
+    width: 40px;
+  }
+}
+.dialog-btn {
+  display: flex;
+  align-content: center;
+  justify-content: flex-end;
+  padding: 40px 0 0;
+  .ge {
+    width: 40px;
+  }
+}
+</style>

+ 160 - 0
src/views/business/exchange/components/CouponPkgAdd.vue

@@ -0,0 +1,160 @@
+<template>
+  <div>
+    <el-dialog
+      title="添加券包奖品"
+      width="1000px"
+      :visible.sync="dialogVisible"
+      :before-close="close"
+    >
+      <div class="dialog-search">
+        <div>券名称:</div>
+        <el-input
+          v-model="title"
+          placeholder="请输入券包名称"
+          clearable
+          size="small"
+          style="width: 240px"
+          @keyup.enter.native="getCouponList"
+        />
+        <div class="ge"></div>
+        <el-button
+          type="primary"
+          icon="el-icon-search"
+          size="mini"
+          @click="getCouponList"
+          >查询</el-button
+        >
+      </div>
+      <el-table
+        v-loading="loading"
+        :data="couponList"
+        row-key="id"
+        @selection-change="handleSelectionCouponPkg"
+        class="el-table"
+      >
+        <el-table-column
+          type="selection"
+          width="55"
+          align="center"
+          fixed="left"
+          :reserve-selection="true"
+        />
+        <el-table-column label="券包编号" prop="id" />
+        <el-table-column label="券包名称" prop="title" min-width="85" />
+        <el-table-column label="优惠券数量" prop="couponNum" />
+        <el-table-column label="总面值" min-width="85">
+          <template slot-scope="scope">
+            <div>¥{{ $numberFormat(scope.row.facePrice) }}</div>
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination
+        v-show="couponPkgTotal > 0"
+        :total="couponPkgTotal"
+        :page.sync="pageParams.pageNum"
+        :limit.sync="pageParams.pageSize"
+        @pagination="getCouponList"
+      />
+      <div class="dialog-btn">
+        <el-button size="small" @click="close"> 取 消 </el-button>
+        <div class="ge"></div>
+        <el-button type="primary" size="small" @click="confirmCouponPkg">
+          确 认
+        </el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+<script>
+import { publicFileGetUrl } from "@/api/common";
+import { getCouponList } from "@/api/business/couponPkg";
+export default {
+  name: "CouponAdd",
+  props: {
+    dialogVisible: {
+      type: Boolean,
+      default: false,
+    },
+  },
+  data() {
+    return {
+      loading: false,
+      title: "", // 券包名称
+      couponList: [], // 券包列表
+      couponPkgTotal: 0, // 券包总数
+      selectCouponPkgList: [], // 选中券包
+      pageParams: {
+        pageNum: 1,
+        pageSize: 10,
+      },
+    };
+  },
+  created() {
+    this.getCouponList();
+  },
+  methods: {
+    // 券包列表
+    getCouponList() {
+      this.loading = true;
+      getCouponList(
+        "pageNum=" +
+          this.pageParams.pageNum +
+          "&pageSize=" +
+          this.pageParams.pageSize +
+          "&",
+        { title: this.title, status: 1 }
+      ).then((res) => {
+        this.couponList = res.rows
+        this.couponPkgTotal = res.total;
+        this.loading = false;
+      });
+    },
+
+    // 选中券包
+    handleSelectionCouponPkg(e) {
+      this.selectCouponPkgList = e.map((item) => {
+        return {
+          type: "coupon_pkg",
+          // quantity: 1,
+          id: item.id,
+          picUrl: publicFileGetUrl + item.picUrl,
+          title: item.title,
+          sortWeight: 100
+        };
+      });
+    },
+
+    // 确认选中券包
+    confirmCouponPkg() {
+      if(!this.selectCouponPkgList.length) {
+        this.msgInfo('请选择券包')
+        return
+      }
+      this.$emit("confirmCouponPkg", this.selectCouponPkgList);
+    },
+
+    close() {
+      this.$emit("close");
+    },
+  },
+};
+</script>
+<style lang="scss" scoped>
+.dialog-search {
+  display: flex;
+  line-height: 32px;
+  margin-bottom: 20px;
+  .ge {
+    width: 40px;
+  }
+}
+.dialog-btn {
+  display: flex;
+  align-content: center;
+  justify-content: flex-end;
+  padding: 40px 0 0;
+  .ge {
+    width: 40px;
+  }
+}
+</style>

+ 113 - 0
src/views/business/exchange/components/ExchangeCodeList.vue

@@ -0,0 +1,113 @@
+<template>
+  <div>
+    <el-dialog title="查看兑换码" :visible.sync="exchangeCodeShow" :before-close="close" width="55%">
+      <span class="span1">已兑数量:{{ cdList.length?cdList[0].cashedQty:'-' }}</span> <span class="span2">未兑数量:{{ cdList.length?cdList[0].remainQty:'-' }}</span>
+      <el-table :data="cdList" style="margin-top: 20px;">
+        <el-table-column property="keyId" label="兑换码Id" min-width="200" align="center"></el-table-column>
+        <el-table-column property="goodsName" label="商品名称" min-width="200" align="center">
+          <template slot-scope="scope">
+            <div v-if="scope.row.type && JSON.parse(scope.row.type).value == 'coin'">
+              {{ scope.row.goodsName + ' x' + scope.row.value }}
+            </div>
+            <div v-else>
+              {{ scope.row.goodsName }}
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品图片">
+            <template slot-scope="scope">
+              <el-image style="width: 70px; height: 70px" :src="scope.row.picUrl" :preview-src-list="[scope.row.picUrl]">
+              </el-image>
+            </template>
+          </el-table-column>
+          <el-table-column property="cdKey" label="兑换码" min-width="200" align="center"></el-table-column>
+        <el-table-column property="status" label="状态" min-width="80" align="center">
+          <template slot-scope="{row}">
+            <div v-if="row.status == 1">
+              已兑换
+            </div>
+            <div v-else style="color: green; font-weight: 500; ">
+              未兑换
+            </div>
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination :total="total" :page.sync="pageParams.pageNum" :limit.sync="pageParams.pageSize" @pagination="getList()" />
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { publicFileGetUrl } from "@/api/common"
+import { getExchangeCodelist } from "@/api/business/exchangeCode";
+export default {
+  props: {
+    exchangeCodeShow: {
+      type: Boolean,
+      default: true
+    },
+    id: {
+      type: [Number, String],
+      default: 0
+    },
+  },
+  data() {
+    return {
+      pageParams: {
+        pageNum: 1,
+        pageSize: 10
+      },
+      loading: false,
+      cdList: [],
+      total: 0,
+    };
+  },
+  mounted() {
+    this.getList()
+  },
+  methods: {
+    close() {
+      this.$emit('cancel')
+    },
+    getList() {
+      if (this.loading) {
+        return
+      }
+      this.loading = true
+      getExchangeCodelist('pageNum=' + this.pageParams.pageNum + '&pageSize=' + this.pageParams.pageSize + '&', this.id).then(res => {
+        this.loading = false
+        if (res.code === 0) {
+          res.rows.forEach(ele => {
+            ele.picUrl = publicFileGetUrl + ele.picUrl.split(',')[0]
+          });
+          this.cdList = res.rows
+          this.total = res.total
+        }
+      }).catch(() => {
+        this.loading = false
+      })
+    },
+
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.span1 {
+  font-size: #666;
+  display: inline-block;
+  position: absolute;
+  top: 60px;
+  font-size: 15px;
+  font-weight: 500;
+}
+.span2 {
+  font-size: #666;
+  display: inline-block;
+  position: absolute;
+  top: 60px;
+  left: 200px;
+  font-size: 15px;
+  font-weight: 500;
+}
+</style>

+ 198 - 0
src/views/business/exchange/components/GoodsAdd.vue

@@ -0,0 +1,198 @@
+<template>
+  <div>
+    <el-dialog
+      title="添加实物商品"
+      width="1000px"
+      :visible.sync="dialogVisible"
+      :before-close="close"
+    >
+      <div class="dialog-search">
+        <div>商品名称:</div>
+        <el-input
+          v-model="goodsTitle"
+          placeholder="请输入商品名称"
+          clearable
+          size="small"
+          style="width: 220px" @clear="pageParams.pageNum = 1;getGoodsList()"
+          @keyup.enter.native="pageParams.pageNum = 1;getGoodsList()"
+        />
+        <div style="margin-left: 20px">商品价格:</div>
+        <el-input style="width: 220px" v-model="queryParams.minValue"  @clear="pageParams.pageNum = 1;getGoodsList()" placeholder="最低价格" clearable @keyup.enter.native="pageParams.pageNum = 1;getGoodsList()"/>
+        <div style="width: 20px;text-align: center">-</div>
+        <el-input style="width: 220px" v-model="queryParams.maxValue"  @clear="pageParams.pageNum = 1;getGoodsList()" placeholder="最高价格" clearable @keyup.enter.native="pageParams.pageNum = 1;getGoodsList()"/>
+      </div>
+      <div class="dialog-search">
+        <div>商品类型:</div>
+        <el-select v-model="queryParams.type" placeholder="请选择商品类型" clearable @change="pageParams.pageNum = 1;getGoodsList()">
+          <el-option label="全部" value=""/>
+          <el-option label="实物商品" value="1"/>
+          <el-option label="卡密商品" value="2"/>
+        </el-select>
+        <div class="ge"></div>
+        <el-button
+          type="primary"
+          icon="el-icon-search"
+          size="mini"
+          @click="getGoodsList()"
+          >查询</el-button
+        >
+      </div>
+      <el-table
+        v-loading="loading"
+        :data="goodsList"
+        row-key="goodsId"
+        @selection-change="handleSelectionGoods"
+        class="el-table"
+      >
+        <el-table-column
+          type="selection"
+          width="55"
+          align="center"
+          fixed="left"
+          :reserve-selection="true"
+        />
+        <el-table-column label="商品ID" prop="goodsId" />
+        <el-table-column label="商品图片">
+          <template slot-scope="{ row }">
+            <div v-if="row.picUrl">
+              <el-image
+                style="width: 100px; height: 100px"
+                :src="row.picUrl.split(',')[0]"
+                :preview-src-list="row.picUrl.split(',')"
+              >
+              </el-image>
+            </div>
+            <p v-else>-</p>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品名称" prop="title" min-width="85" />
+        <el-table-column label="商品类型" min-width="85">
+          <template slot-scope="scope">
+            <div>{{ scope.row.type == 1 ? '实物商品':'卡密商品' }}</div>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品价格" min-width="85">
+          <template slot-scope="scope">
+            <div>¥{{ $numberFormat(scope.row.value) }}</div>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品库存" prop="quantity" width="80" />
+      </el-table>
+      <pagination
+        v-show="goodsTotal > 0"
+        :total="goodsTotal"
+        :page.sync="pageParams.pageNum"
+        :limit.sync="pageParams.pageSize"
+        @pagination="getGoodsList"
+      />
+      <div class="dialog-btn">
+        <el-button size="small" @click="close"> 取 消 </el-button>
+        <div class="ge"></div>
+        <el-button type="primary" size="small" @click="confirmGoods">
+          确 认
+        </el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+<script>
+import { publicFileGetUrl } from "@/api/common";
+import { getGoodsList } from "@/api/business/goods";
+import { accMul } from '@/utils/util'
+export default {
+  name: "GoodsAdd",
+  props: {
+    dialogVisible: {
+      type: Boolean,
+      default: false,
+    },
+  },
+  data() {
+    return {
+      loading: false,
+      goodsTitle: "", // 商品名称
+      queryParams:{},
+
+      goodsList: [], // 商品列表
+      goodsTotal: 0, // 商品总数
+      selectGoodsList: [], // 选中商品
+      pageParams: {
+        pageNum: 1,
+        pageSize: 10,
+      },
+    };
+  },
+  created() {
+    this.getGoodsList();
+  },
+  methods: {
+    // 商品列表
+    getGoodsList() {
+      this.loading = true;
+      getGoodsList(
+        "pageNum=" +
+          this.pageParams.pageNum +
+          "&pageSize=" +
+          this.pageParams.pageSize +
+          "&",
+        { title: this.goodsTitle, type: this.queryParams.type, status: "on", minValue: this.queryParams.minValue?accMul(this.queryParams.minValue, 100):this.queryParams.minValue, maxValue: this.queryParams.maxValue?accMul(this.queryParams.maxValue, 100):this.queryParams.maxValue,}
+      ).then((res) => {
+        this.goodsList = res.rows.map((item) => {
+          return {
+            ...item,
+            picUrl: publicFileGetUrl + item.picUrl.split(",")[0],
+          };
+        });
+        this.goodsTotal = res.total;
+        this.loading = false;
+      });
+    },
+
+    // 选中商品
+    handleSelectionGoods(e) {
+      this.selectGoodsList = e.map((item) => {
+        return {
+          type: "goods",
+          // quantity: 1,
+          goodsId: item.goodsId,
+          picUrl: item.picUrl,
+          title: item.title,
+          sortWeight: 100
+        };
+      });
+    },
+
+    // 确认选中商品
+    confirmGoods() {
+      if(!this.selectGoodsList.length) {
+        this.msgInfo('请选择商品')
+        return
+      }
+      this.$emit("confirmGoods", this.selectGoodsList);
+    },
+
+    close() {
+      this.$emit("close");
+    },
+  },
+};
+</script>
+<style lang="scss" scoped>
+.dialog-search {
+  display: flex;
+  line-height: 32px;
+  margin-bottom: 20px;
+  .ge {
+    width: 20px;
+  }
+}
+.dialog-btn {
+  display: flex;
+  align-content: center;
+  justify-content: flex-end;
+  padding: 40px 0 0;
+  .ge {
+    width: 20px;
+  }
+}
+</style>

+ 323 - 0
src/views/business/exchange/index.vue

@@ -0,0 +1,323 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch">
+
+      <el-form-item label="兑换码名称">
+        <el-input v-model="queryParams.title" placeholder="请输入兑换码名称" @change="pageParams.pageNum = 1;handleQuery()" clearable @keyup.enter.native="pageParams.pageNum = 1;handleQuery()" />
+      </el-form-item>
+      <el-form-item label="创建日期">
+        <el-date-picker v-model="addTimeArr" type="datetimerange" size="small" value-format="timestamp" range-separator="至" start-placeholder="时间选择" end-placeholder="时间选择" @change="addTime">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="激活日期">
+        <el-date-picker v-model="activationTimeArr" type="datetimerange" size="small" value-format="timestamp" range-separator="至" start-placeholder="时间选择" end-placeholder="时间选择" @change="activationTime">
+        </el-date-picker>
+      </el-form-item>
+      <br>
+      <el-form-item label="兑换码数量">
+        <el-input v-model="queryParams.minCdKeyNum" placeholder="最小值" @change="pageParams.pageNum = 1;handleQuery()" clearable @keyup.enter.native="pageParams.pageNum = 1;handleQuery()" />
+      </el-form-item>
+      <el-form-item label="-">
+        <el-input v-model="queryParams.maxCdKeyNum" placeholder="最大值" @change="pageParams.pageNum = 1;handleQuery()" clearable @keyup.enter.native="pageParams.pageNum = 1;handleQuery()" />
+      </el-form-item>
+
+      <el-form-item label="门店">
+        <el-select v-model="queryParams.channelId" placeholder="请选择门店" style="width: 100%;" filterable clearable :filter-method="dataFilter" @change="pageParams.pageNum = 1;handleQuery()">
+          <el-option v-for="(item) in siteList" :key="item.channelId" :label="item.name" :value="item.channelId">
+            <div>
+              <span style="float: left;">{{item.name}} </span>
+              <span style="float: right;">{{item.mobile}}</span>
+            </div>
+          </el-option>
+        </el-select>
+      </el-form-item>
+
+      <el-form-item label="状态">
+        <el-select v-model="queryParams.status" placeholder="请选择状态" clearable @change="pageParams.pageNum = 1;handleQuery()">
+          <el-option :label="item.dictLabel" :value="item.dictValue" v-for="(item, index) in statusList" :key="index" />
+        </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" icon="el-icon-plus" size="mini" @click="$router.push({ path: '/exchange/addCode' })" v-hasPermi="['business:cdKey:add']">创建兑换码</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="infor"
+          plain
+          icon="el-icon-printer"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['business:cdKey:export']"
+          >导出兑换码</el-button
+        >
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList()"></right-toolbar>
+    </el-row>
+    <!-- 列表 -->
+    <el-table ref="table" @select="handleSelect" v-loading="loading" :data="list" class="ticket-table">
+      <el-table-column type="selection" width="55" align="center" fixed="left" />
+      <el-table-column label="兑换码编号" prop="groupId" />
+      <el-table-column label="兑换码名称" prop="title" />
+      <el-table-column label="兑换码数量" prop="quantity" />
+      <el-table-column label="门店名称" prop="siteName" />
+      <el-table-column label="创建日期" prop="createdTime">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createdTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="激活日期" prop="activationTime">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.activationTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="状态" prop="status" align="center">
+        <template slot-scope="{ row }">
+          <el-tag type="warning" v-if="row.status && JSON.parse(row.status).value == 'waiting'">待生成</el-tag>
+          <el-tag type="success" v-if="row.status && JSON.parse(row.status).value == 'noactive'">待激活</el-tag>
+          <el-tag type="" v-if="row.status && JSON.parse(row.status).value == 'activated'">已生效</el-tag>
+          <el-tag type="info" v-if="row.status && JSON.parse(row.status).value == 'invalid'">已失效</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center">
+        <template slot-scope="{ row }">
+          <div>
+            <el-button v-hasPermi="['business:cdKey:query']" type="text" @click="$router.push({ path: '/exchange/detailCode',query: {id: row.groupId} })">查看</el-button>
+            <el-button v-if="row.status && JSON.parse(row.status).value == 'noactive'" v-hasPermi="['business:cdKey:activate']" type="text" @click="setStatus(row)">激活</el-button>
+          </div>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 分页 -->
+    <pagination v-show="total > 0" :total="total" :page.sync="pageParams.pageNum" :limit.sync="pageParams.pageSize" @pagination="getList" />
+
+    <add-code v-if="exchangeShow" :dialog-show="exchangeShow" @close="close" />
+  </div>
+</template>
+<script>
+import { publicFileGetUrl } from "@/api/common";
+import {
+  goodsExchangeList,
+  activateExchangeCode,exportCode,
+} from "@/api/business/exchangeCode";
+import { listAllSaleSite } from "@/api/admin/salesite";
+import AddCode from "./addCode.vue";
+export default {
+  name: "ExchangeCode",
+  components: {
+    AddCode,
+  },
+  data() {
+    return {
+      loading: false,
+      showSearch: true,
+      exportLoading: false,
+      queryParams: {},
+      pageParams: {
+        pageNum: 1,
+        pageSize: 10,
+      },
+      // 总条数
+      total: 0,
+      list: [],
+      exchangeShow: false,
+
+      addTimeArr: [],// 添加时间
+      activationTimeArr: [],//激活时间
+      siteList: [],//门店列表
+      siteCopyList: [],//门店列表
+      statusList: [],//状态下拉选项
+      ids: null,
+    };
+  },
+  created() {
+    this.getList();
+  },
+  mounted() {
+    this.getSaleSiteList()
+    this.getCodeStatus()
+  },
+  methods: {
+    /** 查询字典类型详细 */
+    getCodeStatus() {
+      this.getDicts('cd_key_status').then(res => {
+        this.statusList = res.data
+      })
+    },
+    // 获取门店下拉列表
+    getSaleSiteList() {
+      listAllSaleSite({}).then(response => {
+        this.siteList = response.data || [];
+        this.siteCopyList = response.data || [];
+      });
+    },
+    dataFilter(val) {
+      if (val) { //val存在
+        this.siteList = this.siteCopyList.filter((item) => {
+          if (!!~item.mobile.indexOf(val) || !!~item.mobile.toUpperCase().indexOf(val.toUpperCase())
+            || !!~item.name.indexOf(val) || !!~item.name.indexOf(val)) {
+            return true
+          }
+        })
+      } else { //val为空时,还原数组
+        this.siteList = this.siteCopyList;
+      }
+    },
+    getList() {
+      this.loading = true;
+      goodsExchangeList("pageNum=" +this.pageParams.pageNum +"&pageSize=" +this.pageParams.pageSize +"&",this.queryParams).then((res) => {
+          this.loading = false;
+          if (res.code == 0) {
+            this.total = res.total;
+            this.list = res.rows;
+          }
+        })
+        .catch(() => {
+          this.loading = false;
+        });
+    },
+
+    //搜索
+    handleQuery() {
+      this.siteList = this.siteCopyList;
+      this.pageParams.pageNum = 1;
+      this.getList();
+    },
+
+    // 重置
+    resetQuery() {
+      this.pageParams.pageNum = 1
+      this.queryParams = {}
+      this.addTimeArr = [];
+      this.activationTimeArr = []
+      this.getList();
+    },
+
+    //查看详情
+    toDetail() {
+
+    },
+
+    //激活兑换码
+    setStatus(item) {
+      this.$confirm(
+        `确认激活兑换码 “${item.title}” 吗?`,
+        `激活兑换码`,
+        {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+        }
+      ).then(() => {
+        let data = {
+        groupId: item.groupId,
+        isActive: 1,
+      }
+      activateExchangeCode(data).then((res) => {
+          if (res.code === 0) {
+            this.$message.success("激活成功!");
+            this.getList();
+          }
+        });
+      });
+    },
+
+    //勾选Checkbox时的处理
+    handleSelect(selection, row) {
+      const isSelect = selection.find((item) => item.groupId === row.groupId);
+      this.$refs.table.clearSelection();
+      if (isSelect) {
+        this.$refs.table.toggleRowSelection(row, true);
+        this.ids = row.groupId;
+      } else {
+        this.ids = "";
+      }
+    },
+
+    /** 导出按钮操作 */
+    handleExport() {
+      const groupId = this.ids || [];
+
+      if (groupId.length == 0) {
+        this.$alert("请选择你要导出的兑换码组!", "提示", { type: "warning" });
+      } else {
+        this.$confirm("是否确认导出所选兑换码组?", "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+        })
+          .then(() => {
+            this.vloading = this.$loading({
+              lock: true,
+              text: "正在导出.....",
+              background: "rgba(0, 0, 0, 0.7)",
+            });
+            return exportCode({ groupIdList:[groupId] });
+          })
+          .then((response) => {
+            this.vloading.close();
+            this.download(response.msg);
+            this.exportLoading = false;
+          })
+          .catch(() => {
+            this.vloading.close();
+            this.exportLoading = false;
+          });
+      }
+    },
+
+    // 选择创建时间
+    addTime(e) {
+      if (e) {
+        this.queryParams.createTimeStart = e[0];
+        this.queryParams.createTimeEnd = e[1];
+        this.pageParams.pageNum = 1
+        this.handleQuery();
+      } else {
+        this.queryParams.createTimeStart = "";
+        this.queryParams.createTimeEnd = "";
+        this.pageParams.pageNum = 1
+        this.handleQuery();
+      }
+    },
+
+    //激活时间
+    activationTime(e) {
+      if (e) {
+        this.queryParams.activeTimeStart = e[0];
+        this.queryParams.activeTimeEnd = e[1];
+        this.pageParams.pageNum = 1
+        this.handleQuery();
+      } else {
+        this.queryParams.activeTimeStart = "";
+        this.queryParams.activeTimeEnd = "";
+        this.pageParams.pageNum = 1
+        this.handleQuery();
+      }
+    },
+
+    // 关闭弹框
+    close() {
+      this.exchangeShow = false
+      this.getList();
+    },
+  },
+};
+</script>
+<style lang="scss">
+.ticket-table {
+  thead {
+    .el-checkbox {
+      display: none !important;
+    }
+  }
+}
+</style>

+ 2 - 1
src/views/business/goods/index.vue

@@ -20,7 +20,7 @@
         />
       </el-form-item>
       <el-form-item label="商品类型" prop="type">
-        <el-select v-model="queryParams.type" placeholder="请选择是否支持兑换" clearable
+        <el-select v-model="queryParams.type" placeholder="请选择商品类型" clearable
                    @change="queryParams.pageNum = 1;getList()">
           <el-option label="全部" value=""/>
           <el-option label="实物商品" value="1"/>
@@ -418,6 +418,7 @@ export default {
           type: 'success'
         })
       }).catch(() => {
+        this.$refs.upload.clearFiles();
         this.vloading.close();
       })
     },

+ 2 - 2
src/views/business/salesite/components/Create.vue

@@ -159,8 +159,8 @@
 
       </flexbox>
       <flexbox class="ygp-form-items" align="flex-start" justify="flex-start">
-         <el-form-item label="认证状态" prop="certifyStatus" style="width: 50%;">
-          <el-checkbox v-model="form.certifyStatus">已认证</el-checkbox>
+         <el-form-item label="信息状态" prop="certifyStatus" style="width: 50%;">
+          <el-checkbox v-model="form.certifyStatus">已补充</el-checkbox>
          </el-form-item>
       </flexbox>
     </el-form>

+ 1 - 1
src/views/business/salesite/components/Detail.vue

@@ -76,7 +76,7 @@
          class="ygp-form-items"
          align="flex-start"
          justify="flex-start">
-         <el-form-item label="认证状态" style="width: 100%;margin-bottom:5px;" >
+         <el-form-item label="信息状态" style="width: 100%;margin-bottom:5px;" >
            <span :class="loading?'el-icon-loading':''"></span>
            {{detail.certifyStatus && JSON.parse(detail.certifyStatus).desc}}
          </el-form-item>

+ 139 - 3
src/views/business/salesite/index.vue

@@ -112,6 +112,16 @@
         >导出门店</el-button
         >
       </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-upload2"
+          size="mini"
+          @click="handleImport"
+          v-hasPermi="['business:salesite:import']"
+          >批量导入门店</el-button>
+      </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
@@ -139,7 +149,7 @@
           {{ parseTime(row.createdTime) }}
         </template>
       </el-table-column>
-      <el-table-column label="认证状态" prop="certifyStatus" >
+      <el-table-column label="信息状态" prop="certifyStatus" >
         <template slot-scope="{ row }">
              <span v-if="getValue(row.certifyStatus) == 'y'" style="color: blue;"> {{getDesc(row.certifyStatus)}}</span>
              <span v-if="getValue(row.certifyStatus) == 'n'" style="color: red;"> {{getDesc(row.certifyStatus)}}</span>
@@ -193,6 +203,41 @@
         </template>
       </el-table-column>
     </el-table>
+   <!--    导入门店-->
+   <el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body :before-close="openSwitch">
+      1.请下载Excel模版,填写门店
+      <br><br>
+      &emsp;&emsp;<a style="color: #1890FF;" @click="downloadExcel">下载Excel模版</a>
+      <br><br>
+      2.上传Excel
+      <div style="padding-top: 20px; text-align: center">
+        <el-upload
+          ref="upload"
+          :limit="1"
+          :data="reqData"
+          accept=".xlsx, .xls"
+          :headers="upload.headers"
+          :action="upload.url"
+          :disabled="upload.isUploading"
+          :on-progress="handleFileUploadProgress"
+          :on-success="handleFileSuccess"
+          :auto-upload="false"
+          :http-request="reqUploadFile"
+          :on-exceed="exceedMax"
+          drag
+        >
+          <i class="el-icon-upload"></i>
+          <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
+          <div class="el-upload__tip text-center" slot="tip">
+            <span>仅允许导入 xls xlsx 格式文件。</span>
+          </div>
+        </el-upload>
+      </div>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="openSwitch()">取 消</el-button>
+        <el-button type="primary" @click="submitFileForm">确 定</el-button>
+      </div>
+    </el-dialog>
 
     <pagination
       v-show="total>0"
@@ -224,7 +269,7 @@
 <script>
 import { listAllChannel} from "@/api/admin/channel";
 import { listAreaByPid} from "@/api/admin/area";
-import { listSaleSite, updateSaleSiteStatus,salesiteOrderExport } from "@/api/admin/salesite";
+import { listSaleSite, updateSaleSiteStatus,salesiteOrderExport,salesiteDownload,salesiteImport } from "@/api/admin/salesite";
 import SiteCreate from './components/Create'
 import AddSiteCreate from './components/AddCreate'
 import SiteDetail from './components/Detail'
@@ -288,6 +333,15 @@ export default {
       // 表单参数
       form: {},
 
+      // 用户导入参数
+      upload: {
+        open: false,// 是否显示弹出层(用户导入)
+        title: "",// 弹出层标题(用户导入)
+        isUploading: false,// 是否禁用上传
+        url: "",// 上传的地址
+        headers: {},//请求头
+      },
+      reqData: {},
     };
   },
   mounted() {
@@ -487,7 +541,89 @@ export default {
         }).catch(function() {
            row.statusV = row.statusV === "1" ? "2" : "1";
         });
-    }
+    },
+    //下载excel模版表格
+    downloadExcel() {
+      salesiteDownload().then(response => {
+        this.download(response.msg);
+      })
+    },
+
+    handleImport() {
+      this.upload.title = "批量导入门店";
+      this.upload.open = true;
+    },
+    openSwitch() {
+      this.upload.open = false
+      this.$refs.upload.clearFiles();
+    },
+    // 提交上传文件
+    submitFileForm() {
+      this.$refs.upload.submit();
+    },
+
+    // 自定义文件上传的实现
+    reqUploadFile(param) {
+      var data = this.reqData || {}
+      var params = {
+        file: param.file,
+        ...data
+      }
+      this.vloading = this.$loading({
+        lock: true,
+        text: "正在批量导入门店.....",
+        background: "rgba(0, 0, 0, 0.7)",
+      });
+      salesiteImport(params).then(response => {
+        this.vloading.close();
+        this.$refs.upload.clearFiles();
+        console.log(response,'response')
+        if(response.data && response.data.length){
+          let data1 = `<tr><th>手机号</th><th>门店名称</th><th>佣金比例(%)</th><th>上级渠道(手机号)</th><th>错误信息</th></tr>`
+          let data2 = ''
+          for (let i = 0; i < response.data.length; i++) {
+            let h = response.data[i]
+            data2 += '<tr><td>' + h.mobile +'</td><td>'+ h.name + '</td><td>'+ h.commRate + '%</td><td>'+ h.parentsMobile +'</td><td>'+ h.errorReason +'</td></tr>'
+          }
+          let data = '<table style="width:668px"><thead>'+ data1+'</thead><tbody>'+data2+'</tbody></table>'
+          this.$alert(data, response.msg, { dangerouslyUseHTMLString: true, customClass:'custom-alert' });
+        }else{ 
+          this.upload.open = false;
+          this.upload.isUploading = false;
+          this.$message({
+            message: '导入成功',
+            type: 'success'
+          })
+          this.getList()
+        }
+      }).catch(response => {
+        this.$refs.upload.clearFiles();
+        this.vloading.close();
+      })
+    },
+    // 文件上传中处理
+    handleFileUploadProgress(event, file, fileList) {
+      this.upload.isUploading = true;
+    },
+    // 文件上传成功处理
+    handleFileSuccess(response, file, fileList) {
+      this.upload.open = false;
+      this.upload.isUploading = false;
+      this.getList();
+    },
+    // 超出限制时的提示
+    exceedMax() {
+      this.$message({
+        message: '请移除已有文件后再进行上传',
+        type: 'warning'
+      })
+    },
   }
 };
 </script>
+
+<style lang='scss'>
+.custom-alert {
+  width: 700px;
+}
+</style>

+ 24 - 0
src/views/business/ticket/index.vue

@@ -48,6 +48,23 @@
           <el-option label="已停售" value="stop" />
         </el-select>
       </el-form-item>
+      <br>
+      <el-form-item label="销售范围" prop="saleArea">
+        <el-select
+          v-model="queryParams.saleArea"
+          placeholder="请选择销售范围"
+          clearable
+          size="small"
+          @change="pageParams.pageNum = 1;handleQuery()"
+        >
+          <el-option
+              :label="item.dictLabel"
+              :value="item.dictValue"
+              v-for="(item, index) in scopeSalesList"
+              :key="index"
+            />
+        </el-select>
+      </el-form-item>
       <el-form-item>
         <el-button
           type="primary"
@@ -305,6 +322,7 @@ export default {
       list: [],
       ids: [],
       importShow: false,
+      scopeSalesList: [],
     };
   },
   watch: {
@@ -318,8 +336,14 @@ export default {
   },
   created() {
     this.getList();
+    this.getScopeSales()
   },
   methods: {
+    getScopeSales() {
+      this.getDicts("sale_area").then((res) => {
+        this.scopeSalesList = res && res.data;
+      });
+    },
     //切换排序
     sortChannelId(row){
       if (row){

+ 0 - 1
src/views/finance/withdraw/index.vue

@@ -253,7 +253,6 @@ export default {
     // 订单详情
     getDetailInfo() {
       withdrawDetail({ id: this.id }).then(res=>{
-        console.log('res', res)
         if(res.code == 0){
           this.detailInfo = res.data
           this.detailShow = true;