huangmp 2 жил өмнө
parent
commit
3f2f3154dd

+ 122 - 0
src/views/modules/promotion/promotion-order-upload.vue

@@ -0,0 +1,122 @@
+<template>
+  <!-- 发货信息,用于导出代发货订单的excel交给快递公司 -->
+  <el-dialog
+    :modal="false"
+    title="请选择excel文件上传"
+    :close-on-click-modal="false"
+    :visible.sync="visible"
+    @close="handleClose"
+    width="38%">
+    <el-upload
+      class="upload-demo"
+      ref="upload"
+      :action="$http.adornUrl('/promotion/promotionOrder/importPromotionOrder')"
+      :headers="{ Authorization: $cookie.get('Authorization_vp'),locale:lang}"
+      :limit="1"
+      name="file"
+      :on-preview="handlePreview"
+      :on-remove="handleRemove"
+      :on-error="uploadFalse"
+      :on-success="uploadSuccess"
+      :file-list="files"
+      :auto-upload="true"
+      :before-upload="beforeAvatarUpload">
+      <div slot="tip" class="el-upload__tip"></div>
+      <el-button slot="trigger" size="small" icon="el-icon-upload2" style="margin-right: 20px">上传</el-button>
+      <el-button size="small" type="primary" @click="submitUpload" :loading="uploading">提 交</el-button>
+    </el-upload>
+  </el-dialog>
+</template>
+<script>
+export default {
+  data () {
+    return {
+      lang: localStorage.getItem('lang') || 'zh_CN',
+      visible: false,
+      uploading: false,
+      files: [],
+    }
+  },
+  methods: {
+    uploadSuccess (detectMatch, file, fileList) {
+      this.files = fileList;
+    },
+    uploadFalse (response) {
+      alert(this.$i18n.t('product.fileUploadFail'))
+    },
+    init () {
+      this.visible = true
+    },
+    // 上传前对文件的大小的判断
+    beforeAvatarUpload (file) {
+      this.upload = true
+      const extension = file.name.split('.')[1] === 'xls'
+      const extension2 = file.name.split('.')[1] === 'xlsx'
+      if (!extension && !extension2) {
+        alert(this.$i18n.t('product.downloadTemplateTips1'))
+        return extension || extension2
+      }
+      return extension || extension2
+    },
+    submitUpload () {
+      this.uploading = true
+      this.$refs.upload.submit()
+      /*let file = this.files[0].raw;
+      let formData = new FormData();
+      formData.append('file', file);
+      this.$http({
+        url: this.$http.adornUrl(`/promotion/promotionOrder/importPromotionOrder`),
+        method: 'POST',
+        data: formData,
+        headers: {
+          'Content-Type': 'multipart/form-data'
+        }
+      }).then(({data}) => {
+        if(data){
+          this.uploading = false;
+          this.visible = false;
+          this.$message({
+            message: "提交成功",
+            type: 'success'
+          })
+          this.$emit("refreshDataList");
+        }else{
+          this.$message({
+            message: "提交失败",
+            type: 'error'
+          })
+        }
+      }).catch((error) => {
+        this.uploading = false;
+      })*/
+    },
+    handleRemove (file) {
+
+    },
+    handlePreview (file) {
+      // debugger
+      // if (file.response.status) {
+      //   alert(this.$i18n.t('product.fileSuccess'))
+      //   this.$emit('refreshDataList')
+      // } else {
+      //   alert(this.$i18n.t('product.fileFail'))
+      // }
+    },
+    handleClose(){
+      this.detectMatch = {};
+      this.files = [];
+    }
+  }
+}
+</script>
+<style scoped>
+.download-btn {
+  margin-left: 12px;
+}
+div >>> .el-dialog__body {
+  padding-top: 10px;
+}
+.upload-demo {
+  display: inline-block;
+}
+</style>

+ 1388 - 0
src/views/modules/promotion/promotion-order-video.vue

@@ -0,0 +1,1388 @@
+<template>
+  <div>
+    <el-dialog
+      title="推广视频"
+      :close-on-click-modal="false"
+      :visible.sync="visible"
+      :append-to-body="true"
+      :modal-append-to-body="false"
+      width="80%"
+      v-if="visible"
+      @close="closeDialog">
+      <div class="mod-home">
+        <div class="operation-bar">
+          <!--        <div class="default-btn primary-btn" @click="addOrUpdateHandle()"-->
+          <!--             v-if="isAuth('print:promotionVideo:save')">{{$t("crud.addTitle")}}</div>-->
+          <div class="default-btn primary-btn" @click="addUpItem">{{$t("crud.addTitle")}}</div>
+        </div>
+        <div class="refund-plate">
+          <el-table
+            highlight-current-row
+            :data="dataList"
+            height="400"
+            show-overflow-tooltip
+            style="width: 100%">
+            <el-table-column
+              prop="id"
+              width="80"
+              label="视频ID">
+            </el-table-column>
+            <el-table-column
+              prop="upName"
+              align="center"
+              label="博主">
+              <template slot-scope="scope">
+                <span>{{scope.row.upId}}</span>
+                <br/>
+                <span>{{scope.row.upName}}</span>
+              </template>
+            </el-table-column>
+            <el-table-column
+              prop="publishPlatform"
+              align="center"
+              label="视频平台">
+              <template slot-scope="scope">
+                <span>{{scope.row.publishPlatform}}</span>
+              </template>
+            </el-table-column>
+            <el-table-column
+              prop="fansNum"
+              align="center"
+              label="粉丝数">
+              <template slot-scope="scope">
+                <span>{{scope.row.fansNum}}</span>
+              </template>
+            </el-table-column>
+            <el-table-column
+              prop="videoUrl"
+              cell-style="{}"
+              label="视频链接">
+              <template slot-scope="scope">
+                <span @click="jumpToLink(scope.row.videoUrl)" style="cursor: pointer;color: #2d8cf0">{{scope.row.videoUrl}}</span>
+              </template>
+            </el-table-column>
+            <el-table-column
+              prop="likeNum"
+              align="center"
+              label="点赞数">
+              <template slot-scope="scope">
+                <span>{{scope.row.likeNum}}</span>
+              </template>
+            </el-table-column>
+            <el-table-column
+              prop="commNum"
+              align="center"
+              label="评论数">
+              <template slot-scope="scope">
+                <span>{{scope.row.commNum}}</span>
+              </template>
+            </el-table-column>
+            <el-table-column align="center" fixed="right" :label="$t('publics.operating')" width="auto">
+              <template slot-scope="scope">
+                <div class="text-btn-con">
+                  <div class="default-btn text-btn" @click="addOrUpdateHandle(scope.row.id)"
+                  >{{$t("crud.updateBtn")}}</div>
+                  <div class="default-btn text-btn" @click.stop="deleteHandle(scope.row.id)"
+                  >{{$t("text.delBtn")}}</div>
+                </div>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+        <div>
+          <el-form :model="dataForm" :rules="dataRule" ref="dataForm" label-width="110px">
+            <el-row v-for="(upItem, index) in videoList" v-if="videoList.length > 0">
+              <el-col :span="5">
+                <el-form-item label="博主ID" :prop="upItem.upId" :rules="{required: true, message: '博主ID必填', trigger: 'blur'}">
+                  <el-input v-model="upItem.upId"size="small"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="5">
+                <el-form-item label="博主昵称" :prop="upItem.upName" :rules="{required: true, message: '博主昵称必填', trigger: 'blur'}">
+                  <el-input v-model="upItem.upName"size="small"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="5">
+                <el-form-item label="视频平台" :prop="upItem.publishPlatform" :rules="{required: true, message: '视频平台必填', trigger: 'blur'}">
+                  <el-select v-model="upItem.publishPlatform" filterable placeholder="请选择">
+                    <el-option
+                      v-for="(item,index) in videoPlatformList"
+                      :key="index"
+                      :label="item.label"
+                      :value="item.value">
+                    </el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="5">
+                <el-form-item label="粉丝数" :prop="upItem.fansNum">
+                  <el-input v-model="upItem.fansNum" size="small" type="number"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="4">
+                <el-button circle @click.prevent="saveVideo(upItem)" type="success" icon="el-icon-check"></el-button>
+                <el-button circle @click.prevent="removeUpItem(upItem)" type="danger" icon="el-icon-delete"></el-button>
+              </el-col>
+            </el-row>
+          </el-form>
+        </div>
+      </div>
+    </el-dialog>
+    <PromotionVideoAddOrUpdate ref="promotionVideoRef" @refreshDataList="getVideoList(dataForm.id)"></PromotionVideoAddOrUpdate>
+  </div>
+
+</template>
+
+<script>
+  import PromotionVideoAddOrUpdate from './promotionVideo-add-or-update'
+export default {
+  data() {
+    return {
+      dataList:[],
+      hotShop: {
+        shopName: null
+      },
+      dataForm:{
+        id: null,
+      },
+      videoList:[],
+      visible: false,
+      videoPlatformList: [
+        {value: '抖音', label: '抖音'},
+        {value: '小红书', label: '小红书'},
+        {value: '视频号', label: '视频号'},
+        {value: '快手', label: '快手'},
+        {value: 'B站', label: 'B站'},
+      ],
+      dataRule: {
+      },
+    }
+  },
+  components: {
+    PromotionVideoAddOrUpdate
+  },
+  created() {
+
+  },
+  methods: {
+    init(promotionOrderId) {
+      this.dataForm.id = promotionOrderId;
+      this.getVideoList(this.dataForm.id)
+    },
+    getVideoList(promotionOrderId){
+      this.$http({
+        url: this.$http.adornUrl(`/promotion/promotionVideo/getVideoByPromotionOrderId/` + promotionOrderId),
+        method: 'GET',
+      }).then(({data}) => {
+        this.visible = true
+        this.dataList = data
+      })
+    },
+    addOrUpdateHandle(videoId){
+      this.addOrUpdateVisible = true
+      this.$nextTick(() => {
+        this.$refs.promotionVideoRef.init(videoId)
+      })
+    },
+    jumpToLink(videoUrl){
+      let regex = /https?:\/\/[^\s]+/g // 匹配URL的正则表达式
+      let url =  videoUrl.match(regex) // 返回所有匹配到的链接
+      window.open(url)
+    },
+    addUpItem(){
+      this.videoList.push({upId:null, upName: null, publishPlatform:null, payAmt:null, fansNum:null})
+    },
+    saveVideo(upItem){
+      upItem.promotionOrderId = this.dataForm.id
+      this.$refs['dataForm'].validate((valid) => {
+        if (valid) {
+          this.$http({
+            url: this.$http.adornUrl('/promotion/promotionVideo'),
+            method: 'post',
+            data: this.$http.adornData(upItem)
+          }).then(({data}) => {
+            this.$message({
+              message: this.$i18n.t('publics.operation'),
+              type: 'success',
+            })
+            this.videoList = [];
+            this.getVideoList(this.dataForm.id)
+          })
+        }
+      })
+    },
+    deleteHandle(videoId){
+      this.$confirm('确定要删除吗?', '请选择', {
+        confirmButtonText: this.$i18n.t('crud.filter.submitBtn'),
+        cancelButtonText: this.$i18n.t('crud.filter.cancelBtn'),
+        type: 'warning'
+      }).then(() => {
+        this.$http({
+          url: this.$http.adornUrl('/promotion/promotionVideo/' + videoId),
+          method: 'delete',
+          data: this.$http.adornData({})
+        }).then(({ data }) => {
+          this.$message({
+            message: this.$i18n.t('publics.operation'),
+            type: 'success',
+          })
+          this.getVideoList(this.dataForm.id)
+        })
+      }).catch(() => { })
+    },
+    removeUpItem(upItem, index){
+      this.videoList.splice(index, 1)
+    },
+    closeDialog() {
+      this.visible = false
+    },
+  }
+}
+</script>
+
+<style lang="scss">
+// e-chart
+#real-time-data-chart canvas {
+  width: 100%;
+  height: 100%;
+  padding: 0 20px !important
+}
+
+.mod-home {
+  .search-bar {
+    .input-row {
+      .select-time-btn {
+        margin-right: 20px;
+        display: inline-block;
+        color: #AAAAAA;
+        font-size: 14px;
+        cursor: pointer;
+
+        &:last-child {
+          margin-right: 0;
+        }
+      }
+
+      .select-time-btn.is-active {
+        color: #155BD4;
+      }
+
+    }
+  }
+
+  // 店铺状态异常提示
+  .shop-inf-imperfect-tips {
+    width: 100%;
+    line-height: 32px;
+    font-size: 14px;
+    color: #333;
+    background: #FFF7DD;
+    border: 1px solid #FFD888;
+    border-radius: 2px;
+    padding: 5px 10px;
+    margin-bottom: 10px;
+
+    .el-icon-warning {
+      font-size: 16px;
+      color: #FFA900;
+      margin-left: 5px;
+      margin-right: 5px;
+    }
+  }
+
+  // font-size: 1em;
+  // line-height: 2em;
+  // .strong {
+  //   margin: 0;
+  //   font-size: 17px;
+  //   font-weight: bold;
+  //   text-align: center;
+  //   margin-bottom: 0.5em;
+  // }
+  // .content {
+  //   font-size: 16px;
+  //   padding: 0 30px;
+  // }
+  // background-color: #F5F6F9;
+  .grap {
+    color: #999999;
+  }
+
+  // 白色背景 标题样式
+  .white-basic {
+    background: #fff;
+    padding: 20px;
+    border-radius: 6px;
+    margin-bottom: 20px;
+
+    .title-basic {
+      font-size: 18px;
+      margin-bottom: 20px;
+      font-weight: bold;
+      line-height: 24px;
+      color: #333333;
+      opacity: 1;
+    }
+  }
+
+  // 今日待办
+  .abeyance-box {
+    display: flex;
+    justify-content: space-between;
+
+    .order-num-item {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-top: 7px;
+      margin-bottom: 14px;
+      background-color: #fff;
+      box-sizing: border-box;
+      border-radius: 4px;
+      // cursor: pointer;
+      .item-box {
+        left: 30px;
+
+        .words {
+          font-size: 16px;
+          font-weight: 400;
+          color: #666;
+        }
+
+        .number {
+          font-size: 24px;
+          font-family: Microsoft YaHei;
+          font-weight: bold;
+          color: #333;
+          margin-top: 10px;
+        }
+
+        .compare {
+          font-size: 14px;
+        }
+      }
+
+      .item-img {
+        position: relative;
+        margin-right: 25px;
+        display: block;
+        width: 60px;
+        height: 60px;
+
+        img {
+          display: block;
+          width: 100%;
+          height: 100%;
+          border-radius: 50%;
+        }
+      }
+    }
+
+    .order-num-item:first-child {
+      margin-left: 30px;
+    }
+
+    .order-num-item:last-child {
+      margin-right: 100px;
+    }
+  }
+
+  // 订单栏项
+  .order-all-num {
+    // display: flex;
+    // justify-content: space-between;
+    .row-bg {
+      display: flex;
+
+      .col-box {
+        display: flex;
+        justify-content: space-between;
+        height: 120px;
+
+      }
+
+      .num-item-box {
+        position: relative;
+        width: calc(20% - 20px);
+        flex: 1;
+        padding-right: 20px;
+        box-sizing: border-box;
+      }
+
+      .num-item-box:last-child {
+        padding-right: 0;
+      }
+
+      .col-box:first-child {
+        // margin-right: 20px;
+        .num-item-box {
+          padding-right: 20px;
+          box-sizing: border-box;
+        }
+      }
+
+      .col-box:last-child {
+        .num-item-box:not(:last-child) {
+          padding-right: 20px;
+          box-sizing: border-box;
+        }
+      }
+    }
+
+    // 基本信息样式
+    .order-num-item {
+      // width: calc((100% - 73px) * 0.2);
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      background-color: #fff;
+      box-sizing: border-box;
+      border-radius: 4px;
+      // &:hover {
+      //   .item-img {
+      //     img {
+      //       position: absolute;
+      //       top: -10px;
+      //     }
+      //   }
+      // }
+      .item-box {
+        position: absolute;
+        z-index: 1;
+        left: 30px;
+
+        .words {
+          font-size: 14px;
+          font-weight: bold;
+          color: #fff;
+        }
+
+        .number {
+          width: 160px;
+          word-break: break-all;
+          font-size: 26px;
+          font-family: Microsoft YaHei;
+          font-weight: bold;
+          color: #fff;
+          margin-top: 10px;
+
+          .text {
+            padding-right: 20px;
+          }
+
+          // .ratio{
+          //   font-size: 12px;
+          //   font-weight: 400;
+          //   color: #FFFFFF;
+          //   opacity: 0.7;
+          // }
+        }
+
+        // .ratio{
+        //   font-size: 12px;
+        //   font-weight: 400;
+        //   color: #FFFFFF;
+        //   opacity: 0.7;
+        // }
+        .seq {
+          display: flex
+        }
+
+        .up {
+          color: #3DD598;
+        }
+
+        .up-icon {
+          display: inline-block;
+          width: 16px;
+          height: 16px;
+          margin: 0 12px 0 4px;
+          background: url('~@/assets/img/home/ic-arrow-narrow-up.png')
+        }
+
+        .down {
+          color: #F0142F;
+        }
+
+        .down-icon {
+          display: inline-block;
+          width: 16px;
+          height: 16px;
+          margin: 0 12px 0 4px;
+          background: url('~@/assets/img/home/ic-arrow-narrow-down.png')
+        }
+
+        .compare {
+          font-size: 14px;
+        }
+      }
+
+      .item-img {
+        position: relative;
+        display: block;
+        width: 100%;
+        // transition: .35s;
+        img {
+          display: block;
+          width: 100%;
+          height: 100%;
+        }
+      }
+    }
+  }
+
+  // 添加公告
+  .introduce {
+    margin-bottom: 10px;
+  }
+
+  .router-link-active {
+    //点击时去掉下划线
+    text-decoration: none;
+  }
+
+  a {
+    text-decoration: none;
+  }
+
+  .title {
+    font-size: 22px;
+    color: #111111;
+    font-weight: bold;
+    padding: 20px;
+  }
+
+  .btn-more {
+    float: right;
+    margin: 10px;
+    margin-top: 0px;
+  }
+
+  .introduce-container {
+    padding: 10px;
+    display: flex;
+    background-color: #b4dff8;
+    margin: 20px 0 10px 0;
+  }
+
+  .introduce-container .text {
+    width: 50%;
+    line-height: 30px;
+    font-size: 22px;
+  }
+
+  // 栏目标题行
+  .title-line {
+    background: #f8f8f8;
+    padding: 12px;
+    font-size: 14px;
+    line-height: 1em;
+  }
+
+  .blue-vertical {
+    display: inline-block;
+    width: 3px;
+    height: 1em;
+    background: #155bd4;
+    margin-right: 0.5em;
+    vertical-align: middle;
+  }
+
+  .title-txt {
+    color: #000;
+    font-weight: bold;
+    margin-right: 1em;
+    vertical-align: middle;
+  }
+
+  .title-time {
+    color: #999999;
+    font-size: 12px;
+    margin-left: 12px;
+    vertical-align: middle;
+  }
+
+  .realtime {
+    // display: flex;
+    margin-top: 20px;
+    padding: 0;
+  }
+
+  /**
+    实时概况
+     */
+  .realtime-situation-box {
+    .real-time-content {
+      display: flex;
+      flex-wrap: wrap;
+      margin-top: 10px;
+      margin-bottom: -12px;
+
+      .item {
+        width: 20%;
+        padding-left: 30px;
+        margin-bottom: 40px;
+
+        .word {
+          margin-bottom: 10px;
+          font-size: 16px;
+          font-weight: 400;
+          color: #999999;
+        }
+
+        .number {
+          font-size: 24px;
+          font-weight: bold;
+          line-height: 31px;
+          color: #333333;
+        }
+      }
+    }
+  }
+
+  .realtime-situation {
+    //左边
+    .realtime-left {
+      height: 100%;
+      // width: calc((100% - 20px) * 0.8);
+      // margin-right: 20px;
+      // .chart-content {
+      //   width: 100%;
+      //   height: 360px;
+      // }
+      background: #fff;
+      border-radius: 4px;
+    }
+
+    .col-item {
+      padding-right: 20px;
+      box-sizing: border-box;
+    }
+
+    // 标题
+    .title {
+      position: relative;
+      display: flex;
+      align-items: center;
+      box-sizing: border-box;
+
+      .t-title {
+        font-size: 18px;
+        font-weight: bold;
+        color: #333;
+      }
+
+      .update-time {
+        font-size: 12px;
+        color: #999999;
+        margin-left: 10px;
+      }
+
+      .t-small-text {
+        font-size: 12px;
+        color: #999;
+      }
+
+      .t-update-time {
+        margin-left: 12px;
+      }
+
+      .t-explain-item::before {
+        display: inline-block;
+        content: '';
+        width: 18px;
+        height: 8px;
+        background: #FF4141;
+        border-radius: 8px;
+        margin-right: 10px;
+      }
+
+      .t-explain-first-item {
+        margin-left: 50px;
+      }
+
+      .t-explain-second-item {
+        margin-left: 40px;
+      }
+
+      .t-red::before {
+        background: #FF4141;
+      }
+
+      .t-dark-green::before {
+        background: #42B983;
+      }
+
+      .t-today-data::before {
+        background: #1890FF;
+      }
+
+      .t-yesterday-data::before {
+        background: #21D59B;
+      }
+
+      .t-pay-amount {
+        position: absolute;
+        right: 0;
+        top: 0;
+        display: flex;
+
+        .t-pay-item {
+          color: #333;
+          text-align: left;
+          margin-right: 30px;
+
+          .tt-title {
+            font-size: 14px;
+          }
+
+          .tt-num {
+            font-size: 20px;
+            font-weight: bold;
+            margin-top: 13px;
+          }
+        }
+
+        .t-today {
+          margin-right: 150px;
+        }
+      }
+    }
+
+    .pay-amount-text {
+      font-weight: bold;
+    }
+
+    .pay-amount-num {
+      font-size: 24px;
+      min-height: 24px;
+      font-weight: 700;
+      margin: 10px 0;
+      line-height: 24px;
+    }
+
+    .pay-amount-tips {
+      color: #9b9b9b;
+    }
+
+    // 图表
+    .realtime-chart-box {
+      left: -10px !important;
+      // margin-top: 10px;
+    }
+
+    .wrapper__summary:nth-child(2) {
+      margin-top: 120px;
+    }
+
+    // 右边
+    .realtime-right {
+      min-width: calc((100% - 20px) * 0.2);
+      min-height: 426px;
+      height: 100%;
+      padding: 20px 0px 0 20px;
+      background-color: #fff;
+      box-sizing: border-box;
+      border-radius: 4px;
+
+      .realtime-right-title {
+        font-size: 18px;
+        font-weight: bold;
+        color: #333;
+        margin-bottom: 45px;
+      }
+
+      .realtime-right-box {
+        display: flex;
+        flex-wrap: wrap;
+        width: 100%;
+        height: 100%;
+
+        .realtime-right-box-left, .realtime-right-box-right {
+          width: 100%;
+          display: flex;
+          justify-content: space-between;
+        }
+
+        .realtime-right-box-right {
+          margin-top: -30px;
+        }
+
+        .order-num-item {
+          width: 100%;
+          display: flex;
+
+          .item-img {
+            margin-right: 30px;
+
+            .words {
+              font-size: 16px;
+              font-weight: 400;
+              color: #666;
+            }
+
+            .number {
+              font-size: 24px;
+              font-family: Microsoft YaHei;
+              font-weight: bold;
+              color: #333;
+              margin: 14px 0;
+            }
+
+            .compare {
+              font-size: 14px;
+            }
+          }
+
+          .item-box {
+            .words {
+              font-size: 16px;
+              font-weight: 400;
+              color: #666;
+            }
+
+            .number {
+              font-size: 26px;
+              font-family: Microsoft YaHei;
+              font-weight: bold;
+              color: #333;
+              margin: 14px 0;
+            }
+
+            .seq {
+              display: flex;
+
+              .value {
+                color: #333333;
+                font-weight: bold;
+                margin-right: 8px;
+              }
+            }
+          }
+        }
+
+        // .order-num-item:nth-child(even){
+        //     margin-left: 86px;
+        // }
+      }
+    }
+
+    .realtime .wrapper__summary {
+      display: flex;
+    }
+
+    .realtime .wrapper__summary .summary__box {
+      display: inline-flex;
+      flex: 1;
+      margin-left: 20px;
+    }
+
+    .realtime .wrapper__summary .summary__item {
+      position: relative;
+      width: 100%;
+    }
+
+    //客户数信息
+    .customer-number-info {
+      margin-left: 60px;
+    }
+
+    .text-tit {
+      font-weight: 600;
+    }
+
+    .text-num {
+      font-size: 24px;
+      min-height: 24px;
+      font-weight: 700;
+      margin: 15px 0;
+      line-height: 24px;
+    }
+
+    .text-tips {
+      color: #9b9b9b;
+    }
+
+    // 客户数icon
+    svg {
+      fill: currentColor;
+      vertical-align: middle;
+    }
+
+    .realtime .wrapper__summary .summary__svg {
+      position: absolute;
+      left: 0;
+      top: 50%;
+      transform: translateY(-50%);
+    }
+  }
+
+  /**
+    整体看板
+     */
+  .whole-plate {
+    margin: 20px 0 20px;
+    min-height: 460px;
+    background-color: #fff;
+    border-radius: 4px;
+
+    // 标题
+    .title {
+      width: 80%;
+      position: relative;
+      display: flex;
+      align-items: center;
+
+      .t-title {
+        font-size: 18px;
+        font-weight: bold;
+        color: #333;
+      }
+
+      .update-time {
+        font-size: 12px;
+        color: #999999;
+        margin-left: 10px;
+      }
+
+      .t-small-text {
+        font-size: 12px;
+        color: #999;
+      }
+
+      .t-update-time {
+        margin-left: 12px;
+      }
+
+      .t-explain-item::before {
+        display: inline-block;
+        content: '';
+        width: 18px;
+        height: 8px;
+        background: #FF4141;
+        border-radius: 8px;
+        margin-right: 10px;
+      }
+
+      .t-explain-first-item {
+        margin-left: 50px;
+      }
+
+      .t-explain-second-item {
+        margin-left: 40px;
+      }
+
+      .t-red::before {
+        background: #FF4141;
+      }
+
+      .t-dark-green::before {
+        background: #42B983;
+      }
+
+      .t-today-data::before {
+        background: #1890FF;
+      }
+
+      .t-yesterday-data::before {
+        background: #21D59B;
+      }
+
+      .t-pay-amount {
+        position: absolute;
+        right: 0;
+        top: 0;
+        display: flex;
+
+        .t-pay-item {
+          color: #333;
+          text-align: left;
+          margin-right: 30px;
+
+          .tt-title {
+            font-size: 14px;
+          }
+
+          .tt-num {
+            font-size: 20px;
+            font-weight: bold;
+            margin-top: 13px;
+          }
+        }
+
+        .t-today {
+          margin-right: 150px;
+        }
+      }
+    }
+
+    .money {
+      width: 20%;
+      display: flex;
+      justify-content: space-between;
+
+      .related-income-item {
+        text-align: center;
+      }
+    }
+
+    .related-income {
+      margin: 20px 0 0 0px;
+      padding-right: 50px;
+      display: flex;
+      flex-wrap: wrap;
+      justify-content: space-between;
+    }
+
+    .item-tit {
+      margin-top: 23px;
+      margin-bottom: 15px;
+    }
+
+    .item-num {
+      height: 24px;
+      line-height: 24px;
+    }
+
+    .item-num-price {
+      font-size: 18px;
+      font-weight: 700;
+    }
+
+    .item-num a {
+      color: #155bd4;
+      text-decoration: none;
+    }
+
+    .integral-plate {
+      margin-top: 15px;
+    }
+  }
+
+  /**
+    退款看板
+     */
+  .refund-plate {
+    display: flex;
+    flex-wrap: wrap;
+    justify-content: space-between;
+    // 上
+    .ranking-box {
+      display: flex;
+      flex-wrap: wrap;
+      flex-direction: column;
+      width: 50%;
+      padding-right: 20px;
+
+      .ranking-left,
+      .refund-rate-box {
+        display: flex;
+        flex-direction: column;
+        width: 100%;
+        background: #fbfbfb;
+        padding: 20px;
+        box-sizing: border-box;
+        border-radius: 4px;
+        height: 574px;
+      }
+
+      .refund-rate-box {
+        height: 396px;
+      }
+
+      .ranking-left {
+        margin-top: 20px;
+        flex: auto
+      }
+
+      .ranking-title {
+        font-weight: bold;
+        color: #333;
+        font-size: 18px;
+        margin-bottom: 20px;
+      }
+
+      .table {
+        width: 100%;
+        border: none;
+        background: #fbfbfb;
+        // border-spacing: 10px 20px;
+        text-align: left;
+
+        .table-tit {
+          cursor: pointer;
+        }
+
+        .table-tit:hover {
+          background-color: lightgoldenrodyellow;
+          color: #000;
+        }
+
+        .table-tit:active {
+          background-color: lightblue;
+          color: #000;
+        }
+
+        tr {
+          border: none;
+          height: 3em;
+          line-height: 1.5em;
+        }
+
+        td {
+          border: none;
+          word-break: break-wrod;
+        }
+
+        .gray {
+          background: #F7F8FA;
+        }
+
+        .table-tit-item {
+          color: #999;
+          text-align: left;
+        }
+
+        .rank {
+          width: 20%;
+        }
+
+        .prod {
+          width: 50%;
+        }
+
+        .ref {
+          width: 20%;
+        }
+
+        .ranks {
+          width: 10%;
+        }
+
+        .prods {
+          width: 50%;
+        }
+
+        .refs {
+          width: 30%;
+        }
+
+        .prop {
+          width: 10%;
+          // text-align: center;
+        }
+      }
+
+      .no-data {
+        height: 60px;
+        line-height: 60px;
+        text-align: center;
+        font-size: 14px;
+        color: #999;
+      }
+
+      .line-clamp-one {
+        display: -webkit-box;
+        -webkit-box-orient: vertical;
+        -webkit-line-clamp: 1;
+        text-overflow: ellipsis;
+        overflow: hidden;
+        /* autoprefixepxr: off */
+        -webkit-box-orient: vertical;
+        word-wrap: break-word;
+        word-break: break-all;
+      }
+
+      .padLeft {
+        padding-left: 20px;
+      }
+
+      .msg-tit {
+        font-weight: bold;
+        color: #333;
+        font-size: 18px;
+        margin-bottom: 15px;
+      }
+    }
+
+    //  下
+    .refund-chart-box {
+      display: flex;
+      flex-wrap: wrap;
+      width: 50%;
+
+      .successed-refund,
+      .ranking-right {
+        display: flex;
+        width: 100%;
+        flex-direction: column;
+        background: #fbfbfb;
+        padding: 20px;
+        box-sizing: border-box;
+        border-radius: 4px;
+      }
+
+      .successed-refund {
+        display: flex;
+        flex-direction: column;
+        width: 100%;
+        background: #fbfbfb;
+        height: 396px;
+        padding: 20px;
+        box-sizing: border-box;
+      }
+
+      .ranking-right {
+        margin-top: 20px;
+      }
+
+      .ranking-title {
+        font-weight: bold;
+        color: #333;
+        font-size: 18px;
+        margin-bottom: 20px;
+      }
+
+      .table {
+        width: 100%;
+        border: none;
+        background: #fbfbfb;
+        // border-spacing: 10px 20px;
+        text-align: left;
+
+        tr {
+          border: none;
+          height: 3em;
+          line-height: 1.5em;
+        }
+
+        td {
+          border: none;
+          word-break: break-wrod;
+        }
+
+        .gray {
+          background: #F7F8FA;
+        }
+
+        .table-tit-item {
+          color: #999;
+          text-align: left;
+        }
+
+        .rank {
+          width: 10%;
+        }
+
+        .prod {
+          width: 50%;
+        }
+
+        .ref {
+          width: 30%;
+        }
+
+        .ranks {
+          width: 20%;
+        }
+
+        .prods {
+          width: 40%;
+        }
+
+        .refs {
+          width: 30%;
+        }
+
+        .prop {
+          width: 10%;
+          // text-align: center;
+        }
+      }
+
+      .msg-tit {
+        font-weight: bold;
+        color: #333;
+        font-size: 18px;
+        margin-bottom: 15px;
+      }
+
+      .padLeft {
+        padding-left: 20px;
+      }
+
+      .msg-price {
+        margin: 6px 0;
+        line-height: 26px;
+        padding: 0;
+        font-size: 24px;
+        font-weight: bold;
+        line-height: 1em;
+      }
+
+      .msg-txt-p {
+        width: 146px;
+      }
+
+      .compare {
+        color: #9b9b9b;
+        display: flex;
+        justify-content: space-between;
+        font-size: 12px;
+        padding: 5px;
+      }
+
+      .compare-left {
+        margin-right: 10px;
+        white-space: nowrap;
+      }
+    }
+
+    .integral-plate canvas {
+      left: -5px !important;
+    }
+
+    .money-padleft {
+      padding-left: 10px;
+    }
+
+    .refund-tip {
+      display: flex;
+      font-size: 14px;
+      font-weight: 400;
+      color: #5A607F;
+    }
+
+    .msg-tit-txt {
+      display: flex;
+      justify-content: space-between;
+    }
+
+    .traffictrendA, .traffictrendB {
+      display: inline-block;
+      width: 10px;
+      height: 10px;
+      border-radius: 6px;
+      margin-right: 4px;
+    }
+
+    .traffictrendA {
+      background: #21D59B;
+    }
+
+    .traffictrendB {
+      margin-left: 40px;
+      background: #0058FF;
+    }
+
+  }
+}
+
+.empty {
+  display: block;
+  height: 200px;
+  line-height: 200px;
+  text-align: center;
+  color: #aaa;
+}
+</style>

+ 121 - 0
src/views/modules/promotion/promotion-video-upload.vue

@@ -0,0 +1,121 @@
+<template>
+  <!-- 发货信息,用于导出代发货订单的excel交给快递公司 -->
+  <el-dialog
+    :modal="false"
+    title="请选择excel文件上传"
+    :close-on-click-modal="false"
+    :visible.sync="visible"
+    @close="handleClose"
+    width="38%">
+    <el-upload
+      class="upload-demo"
+      ref="upload"
+      :action="$http.adornUrl('/promotion/promotionVideo/importPromotionVideo')"
+      :headers="{Authorization: $cookie.get('Authorization_vp'),locale:lang}"
+      :limit="1"
+      name="file"
+      :on-preview="handlePreview"
+      :on-remove="handleRemove"
+      :on-error="uploadFalse"
+      :on-success="uploadSuccess"
+      :file-list="files"
+      :auto-upload="true"
+      :before-upload="beforeAvatarUpload">
+      <div slot="tip" class="el-upload__tip"></div>
+      <el-button slot="trigger" size="small" icon="el-icon-upload2" style="margin-right: 20px">上传</el-button>
+      <el-button size="small" type="primary" @click="submitUpload" :loading="uploading">提 交</el-button>
+    </el-upload>
+  </el-dialog>
+</template>
+<script>
+export default {
+  data () {
+    return {
+      lang: localStorage.getItem('lang') || 'zh_CN',
+      visible: false,
+      uploading: false,
+      files: [],
+    }
+  },
+  methods: {
+    uploadSuccess (detectMatch, file, fileList) {
+      this.files = fileList;
+    },
+    uploadFalse (response) {
+      alert(this.$i18n.t('product.fileUploadFail'))
+    },
+    init () {
+      this.visible = true
+    },
+    // 上传前对文件的大小的判断
+    beforeAvatarUpload (file) {
+      this.upload = true
+      const extension = file.name.split('.')[1] === 'xls'
+      const extension2 = file.name.split('.')[1] === 'xlsx'
+      if (!extension && !extension2) {
+        alert(this.$i18n.t('product.downloadTemplateTips1'))
+        return extension || extension2
+      }
+      return extension || extension2
+    },
+    submitUpload () {
+      this.uploading = true
+      this.$refs.upload.submit()
+      /*let file = this.files[0].raw;
+      let formData = new FormData();
+      formData.append('file', file);
+      this.$http({
+        url: this.$http.adornUrl(`/promotion/promotionOrder/importPromotionOrder`),
+        method: 'POST',
+        data: formData,
+        headers: {
+          'Content-Type': 'multipart/form-data'
+        }
+      }).then(({data}) => {
+        if(data){
+          this.uploading = false;
+          this.visible = false;
+          this.$message({
+            message: "提交成功",
+            type: 'success'
+          })
+          this.$emit("refreshDataList");
+        }else{
+          this.$message({
+            message: "提交失败",
+            type: 'error'
+          })
+        }
+      }).catch((error) => {
+        this.uploading = false;
+      })*/
+    },
+    handleRemove (file) {
+
+    },
+    handlePreview (file) {
+      // debugger
+      // if (file.response.status) {
+      //   alert(this.$i18n.t('product.fileSuccess'))
+      //   this.$emit('refreshDataList')
+      // } else {
+      //   alert(this.$i18n.t('product.fileFail'))
+      // }
+    },
+    handleClose(){
+      this.files = [];
+    }
+  }
+}
+</script>
+<style scoped>
+.download-btn {
+  margin-left: 12px;
+}
+div >>> .el-dialog__body {
+  padding-top: 10px;
+}
+.upload-demo {
+  display: inline-block;
+}
+</style>

+ 374 - 0
src/views/modules/promotion/promotionOrder-add-or-update.vue

@@ -0,0 +1,374 @@
+<template>
+  <el-dialog
+    :title="!dataForm.id ? this.$i18n.t('crud.addTitle') : this.$i18n.t('temp.modify')"
+    :close-on-click-modal="false"
+    :visible.sync="visible"
+    @close="">
+    <el-row>
+      <el-form :model="dataForm" :rules="dataRule" ref="dataForm" label-width="110px">
+        <el-row>
+          <el-col :span="10">
+            <el-form-item label="推广人" prop="tgUserName" :rules="{required: true, message: '推广人必填', trigger: 'blur'}">
+              <el-input v-model="dataForm.tgUserName" size="small"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :span="10" :offset="1">
+            <el-form-item label="推广店铺" prop="shopId" :rules="{required: true, message: '推广店铺必填', trigger: 'blur'}">
+              <el-select v-model="dataForm.shopId" placeholder="推广店铺" style="width: 300px" @change="shopChange"
+                         controls-position="right" :clearable="true">
+                <el-option v-for="(item,index) in shopList" :key="index" :label="item.shopName" :value="item.shopId">
+                </el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="8">
+            <el-form-item label="寄拍/付费" prop="payType" :rules="{required: true, message: '付费类型必填', trigger: 'blur'}">
+              <el-select v-model="dataForm.payType" placeholder="请选择" size="small" style="width: 300px">
+                <el-option :key="0" label="寄拍" value="寄拍"></el-option>
+                <el-option :key="1" label="付费 " value="付费"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="5" :offset="3">
+            <el-form-item label="稿费" prop="payAmt">
+              <el-input v-model="dataForm.payAmt"size="small" type="number" placeholder="寄拍不填"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :span="5">
+            <el-form-item label="结算状态" prop="payType">
+              <el-select v-model="dataForm.settleStatus" placeholder="请选择" size="small">
+                <el-option :key="1" label="待结算" value="待结算"></el-option>
+                <el-option :key="2" label="已结算 " value="已结算"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col  :span="10">
+            <el-form-item label="订单编号" prop="orderNumber" :rules="{required: true, message: '订单号必填', trigger: 'blur'}">
+              <el-input v-model="dataForm.orderNumber" size="small" type="textarea" rows="3" placeholder="多个订单号时需要换行,一个订单号占一行"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col  :span="10" :offset="1">
+            <el-form-item label="备注" prop="remark">
+              <el-input v-model="dataForm.remark" size="small" type="textarea" rows="3"></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-form-item label="收款码" prop="pic">
+            <el-upload
+              :disabled="isView"
+              ref="upload"
+              :multiple="true"
+              :action="$http.adornUrl('/admin/file/simpleUpload')"
+              list-type="picture-card"
+              :headers="{Authorization: $cookie.get('Authorization_vs'),locale:lang}"
+              :on-success="onUploadSuccess"
+              :file-list="fileList"
+              :limit="1"
+              :on-remove="handlePicRemove"
+              :on-preview="handlePicPreview">
+              <i class="el-icon-plus"></i>
+            </el-upload>
+            <div  @paste="pasteImg($event)">
+              <textarea placeholder="点击这里,然后把图片粘贴" style="width: 100%;height: 100px;border: 1px solid #c9c9c9;border-radius: 5px;"></textarea>
+            </div>
+          </el-form-item>
+        </el-row>
+        <div v-if="!dataForm.id">
+          <h3>博主信息</h3>
+          <el-divider></el-divider>
+          <el-row v-for="(upItem, index) in dataForm.videoList" v-if="dataForm.videoList.length > 0">
+            <el-col :span="6">
+              <el-form-item label="博主ID" :prop="'videoList.' + index + '.upId'" :rules="{required: true, message: '博主ID必填', trigger: 'blur'}">
+                <el-select
+                  v-model="upItem.upId"
+                  filterable
+                  remote
+                  reserve-keyword
+                  placeholder="请输入博主ID"
+                  :remote-method="queryUpById"
+                  @change="changeUpById($event, index)"
+                  :loading="queryUpLoading">
+                  <el-option
+                    v-for="item in upList"
+                    :key="item.upId"
+                    :label="item.upId"
+                    :value="item.upId">
+                    <span >{{ item.upId }}|</span>
+                    <span >{{ item.upName }}|</span>
+                    <span >{{ item.publishPlatform }}|</span>
+                    <span >{{ item.tgUserName }}</span>
+                  </el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="5">
+              <el-form-item label="博主昵称" :prop="'videoList.' + index + '.upName'" :rules="{required: true, message: '博主昵称必填', trigger: 'blur'}">
+                <el-select
+                  v-model="upItem.upName"
+                  filterable
+                  remote
+                  reserve-keyword
+                  placeholder="请输入博主昵称"
+                  :remote-method="queryUpByName"
+                  @change="changeUpByName($event, index)"
+                  :loading="queryUpLoading">
+                  <el-option
+                    v-for="item in upList"
+                    :key="item.upName"
+                    :label="item.upName"
+                    :value="item.upName">
+                    <span >{{ item.upId }}|</span>
+                    <span >{{ item.upName }}|</span>
+                    <span >{{ item.publishPlatform }}|</span>
+                    <span >{{ item.tgUserName }}</span>
+                  </el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="5">
+              <el-form-item label="视频平台" :prop="'videoList.' + index + '.publishPlatform'" :rules="{required: true, message: '视频平台必填', trigger: 'blur'}">
+                <el-select v-model="upItem.publishPlatform" filterable placeholder="请选择">
+                  <el-option
+                    v-for="(item,index) in videoPlatformList"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value">
+                  </el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="5">
+              <el-form-item label="粉丝数" :prop="'videoList.' + index + '.fansNum'">
+                <el-input v-model="upItem.fansNum" size="small" type="number"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="3">
+              <el-button circle @click.prevent="removeUpItem(upItem)" type="danger" icon="el-icon-delete"></el-button>
+              <el-button circle @click.prevent="addUpItem()" type="success" icon="el-icon-plus" v-if="index === dataForm.videoList.length - 1"></el-button>
+            </el-col>
+          </el-row>
+          <el-row v-if="dataForm.videoList.length === 0">
+            <el-button circle @click.prevent="addUpItem()" type="success" icon="el-icon-plus"></el-button>
+          </el-row>
+        </div>
+      </el-form>
+    </el-row>
+    <span slot="footer" class="dialog-footer">
+      <el-button class="default-btn" @click="visible = false">{{$t("crud.filter.cancelBtn")}}</el-button>
+      <el-button class="default-btn primary-btn" type="primary" @click="dataFormSubmit()">{{$t("crud.filter.submitBtn")}}</el-button>
+    </span>
+    <el-dialog :visible.sync="imgDialogVisible" :append-to-body="true">
+      <img width="100%" :src="dialogImageUrl" alt="">
+    </el-dialog>
+  </el-dialog>
+</template>
+
+
+<script>
+  import { uploadFile } from '@/utils/httpRequest.js'
+  export default {
+    data () {
+      return {
+        visible: false,
+        lang: localStorage.getItem('lang') || 'zh_CN',
+        dataForm: {
+          id: null,
+          tgUserName: null,
+          upId: null,
+          upName: null,
+          orderNumber: null,
+          shopId: this.$store.state.user.shopId,
+          shopName: null,
+          status: null,
+          promotionVideoId: null,
+          promotionVideo: null,
+          createTime: null,
+          updateTime: null,
+          settleStatus: '待结算',
+          remark: null,
+          payType: null,
+          payAmt: 0,
+          videoList:[{upId:null, upName: null, publishPlatform:null, payAmt:null, fansNum:null}],
+          settleQrCodeImg: null
+        },
+        imgDialogVisible: false,
+        dialogImageUrl: null,
+        shopList: [],
+        fileList:[],
+        resourcesUrl: process.env.VUE_APP_RESOURCES_URL,
+        isView: false,
+        videoPage: {
+          total: 0, // 总页数
+          currentPage: 1, // 当前页数
+          pageSize: 10 // 每页显示多少条
+        },
+        dataRule: {
+        },
+        upList:[{}],
+        videoPlatformList: [
+          {value: '抖音', label: '抖音'},
+          {value: '小红书', label: '小红书'},
+          {value: '视频号', label: '视频号'},
+          {value: '快手', label: '快手'},
+          {value: 'B站', label: 'B站'},
+        ],
+        queryUpLoading: false
+      }
+    },
+    mounted () {
+      this.getShopList();
+      this.getUpList();
+    },
+    methods: {
+      init (id) {
+        this.dataForm.id = id || 0
+        this.visible = true
+        this.$nextTick(() => {
+          this.$refs['dataForm'].resetFields()
+          if (this.dataForm.id) {
+            this.$http({
+              url: this.$http.adornUrl('/promotion/promotionOrder/info/' + this.dataForm.id),
+              method: 'get',
+              params: this.$http.adornParams()
+            }).then(({data}) => {
+              this.dataForm = data
+              if(this.dataForm.settleQrCodeImg) {
+                this.fileList = [];
+                this.fileList.push({url: this.resourcesUrl + this.dataForm.settleQrCodeImg, response: {filePath: this.dataForm.settleQrCodeImg}})
+              }
+            })
+          }
+        })
+      },
+      changeUpById(upId, videoIndex){
+        let up = this.upList.find(item => item.upId === upId)
+        if(up){
+          this.dataForm.videoList[videoIndex].upName = up.upName
+          this.dataForm.videoList[videoIndex].upId = up.upId
+          this.dataForm.videoList[videoIndex].fansNum = up.fansNum
+          this.dataForm.videoList[videoIndex].publishPlatform = up.publishPlatform
+        }
+      },
+      changeUpByName(upName, videoIndex){
+        let up = this.upList.find(item => item.upName === upName)
+        if(up){
+          this.dataForm.videoList[videoIndex].upName = up.upName
+          this.dataForm.videoList[videoIndex].upId = up.upId
+          this.dataForm.videoList[videoIndex].fansNum = up.fansNum
+          this.dataForm.videoList[videoIndex].publishPlatform = up.publishPlatform
+        }
+      },
+      getUpList(upId, upName){
+        this.$http({
+          url: this.$http.adornUrl('/promotion/promotionUp/list'),
+          method: 'get',
+          params: this.$http.adornParams({upId: upId, upName:upName})
+        }).then(({ data }) => {
+          this.upList = data;
+        })
+      },
+      onUploadSuccess(response, file, fileList){
+        this.fileList = fileList;
+      },
+      handlePicRemove(file, fileList){
+        this.fileList = fileList;
+      },
+      handlePicPreview(file){
+        this.dialogImageUrl = file.url
+        let url = file.response.resourcesUrl + file.response.filePath
+        this.videoFlag = this.checkMediaType(url)
+        this.imgDialogVisible = true
+      },
+      queryUpById(upId) {
+        if (upId !== '') {
+          this.queryUpLoading = true
+          this.getUpList(upId, null)
+          this.queryUpLoading = false
+        } else {
+          this.upList = [];
+        }
+      },
+      queryUpByName(upName) {
+        if (upName !== '') {
+          this.queryUpLoading = true
+          this.getUpList(null, upName)
+          this.queryUpLoading = false
+        } else {
+          this.upList = [];
+        }
+      },
+      getShopList() {
+        this.$http({
+          url: this.$http.adornUrl('/shop/shopDetail/getShopList'),
+          method: 'get',
+          params: this.$http.adornParams({shopId: this.shopId})
+        }).then(({ data }) => {
+          if (data) {
+            this.shopList = data
+          }
+        })
+      },
+      shopChange (index) {
+        this.dataForm.shopName = this.shopList[index].shopName
+      },
+      // 表单提交
+      dataFormSubmit () {
+        this.$refs['dataForm'].validate((valid) => {
+          if (valid) {
+            if(this.fileList.length > 0){
+              this.dataForm.settleQrCodeImg = this.fileList[0].response.filePath
+            }
+            this.dataForm.shopName = this.shopList.find(item => item.shopId === this.dataForm.shopId).shopName
+            this.$http({
+              url: this.$http.adornUrl('/promotion/promotionOrder'),
+              method: this.dataForm.id ? 'put' : 'post',
+              data: this.$http.adornData(this.dataForm)
+            }).then(({data}) => {
+              this.$message({
+                message: this.$i18n.t('publics.operation'),
+                type: 'success',
+              })
+              this.visible = false
+              this.$emit('refreshDataList')
+            })
+          }
+        })
+      },
+      addUpItem(){
+        this.dataForm.videoList.push({upId:null, upName: null, publishPlatform:null, payAmt:null, fansNum:null})
+      },
+      removeUpItem(upItem, index){
+        if(this.dataForm.videoList.length === 1){
+          return
+        }
+        this.dataForm.videoList.splice(index, 1)
+      },
+      pasteImg(e) {
+        const { items } = e.clipboardData; // 获取粘贴板文件对象
+        if (items.length) {
+          for (const item of items) {
+            if (item.type.indexOf('image') !== -1) {
+              const file = item.getAsFile(); // 获取图片文件
+              if (file) {
+                uploadFile(
+                  this.$http.adornUrl('/admin/file/simpleUpload'),
+                  file
+                ).then(({ data }) => {
+                  // this.$refs['file'].value = null // 解决上传同一图片不显示bug
+                  // { url: this.resourcesUrl + picArray[i], response: {filePath: picArray[i] }
+                  let obj = {url: data.resourcesUrl + data.filePath, response: {filePath: data.filePath }}
+                  this.fileList.push(obj)
+                })
+              }
+            }
+          }
+        }
+      },
+    }
+  }
+</script>

+ 416 - 0
src/views/modules/promotion/promotionOrder.vue

@@ -0,0 +1,416 @@
+<template>
+  <div class="mod-print-promotionOrder">
+    <!-- 搜索相关区域 -->
+    <div class="search-bar">
+      <el-form :inline="true" :model="searchForm" @keyup.enter.native="getDataList(this.page)" size="small">
+        <div class="input-row">
+          <el-form-item label="订单编号" prop="orderNumber">
+            <el-input v-model="searchForm.orderNumber" :clearable="true" size="small"></el-input>
+          </el-form-item>
+          <el-form-item label="推广人" prop="tgUserName">
+            <el-input v-model="searchForm.tgUserName" :clearable="true"></el-input>
+          </el-form-item>
+          <el-form-item label="博主ID" prop="tgUserName">
+            <el-input v-model="searchForm.upId" :clearable="true"></el-input>
+          </el-form-item>
+          <el-form-item label="博主名称" prop="tgUserName">
+            <el-input v-model="searchForm.upName" :clearable="true"></el-input>
+          </el-form-item>
+          <el-form-item label="推广店铺" prop="shopId">
+            <el-select v-model="searchForm.shopId" placeholder="推广店铺"
+                       controls-position="right" :clearable="true" style="width: 295px">
+              <el-option v-for="item in shopList" :key="item.shopId" :label="item.shopName" :value="item.shopId">
+              </el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="订单状态" prop="status">
+            <el-select v-model="searchForm.status" placeholder="请选择" size="small" :clearable="true">
+              <el-option :key="2" label="待发货" value="待发货"></el-option>
+              <el-option :key="3" label="已发货" value="已发货"></el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="视频状态" prop="status">
+            <el-select v-model="searchForm.publishStatus" placeholder="视频是否已发布" size="small" :clearable="true">
+              <el-option :key="2" label="视频已发布" value="已发布"></el-option>
+              <el-option :key="3" label="视频未发布" value="待发布"></el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="粉丝数:" label-width="85px">
+            <InputNumberRange v-model="fansNumRange" type="number"></InputNumberRange>
+          </el-form-item>
+          <el-form-item label="下单时间" prop="orderTime">
+            <el-date-picker
+              :clearable="true"
+              v-model="orderTimeRange"
+              type="datetimerange"
+              align="right"
+              value-format="yyyy-MM-dd HH:mm:ss"
+              start-placeholder="开始时间"
+              end-placeholder="结束时间"
+              :default-time="['00:00:00', '23:59:59']">
+            </el-date-picker>
+          </el-form-item>
+          <el-form-item label="发货时间" prop="deliveryTime">
+            <el-date-picker
+              :clearable="true"
+              v-model="deliveryTimeRange"
+              type="datetimerange"
+              align="right"
+              value-format="yyyy-MM-dd HH:mm:ss"
+              start-placeholder="开始时间"
+              end-placeholder="结束时间"
+              :default-time="['00:00:00', '23:59:59']">
+            </el-date-picker>
+          </el-form-item>
+          <el-form-item>
+            <div class="default-btn" @click="setDateRange(1)">今日</div>
+            <div class="default-btn" @click="setDateRange(2)">昨日</div>
+            <div class="default-btn" @click="setDateRange(3)">近3天</div>
+            <div class="default-btn" @click="setDateRange(4)">近5天</div>
+            <div class="default-btn primary-btn" @click="searchChange()">{{$t("crud.searchBtn")}}</div>
+            <div class="default-btn" @click="clear()">重置</div>
+          </el-form-item>
+        </div>
+      </el-form>
+    </div>
+    <!-- 列表相关区域 -->
+    <div class="main-container">
+      <div class="operation-bar">
+        <div class="default-btn primary-btn" @click="addOrUpdateHandle()">{{$t("crud.addTitle")}}</div>
+<!--        <div class="default-btn primary-btn" @click="openUploadDialog()">导入数据</div>-->
+      </div>
+      <div class="table-con spec-table">
+        <el-table
+          ref="specListTable"
+          :data="dataList"
+          header-cell-class-name="table-header"
+          row-class-name="table-row"
+          style="width: 100%">
+          <!-- 推广人名称 -->
+          <el-table-column label="推广人" prop="tgUserName" align="center">
+            <template slot-scope="scope">
+              <span>{{ scope.row.tgUserName}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="博主ID:名称" prop="upId" align="center" width="160px">
+            <template slot-scope="scope">
+              <div v-for="upItem in scope.row.videoList">
+                <div>{{upItem.upId}}</div>
+                <div>{{upItem.upName}}</div>
+              </div>
+            </template>
+          </el-table-column>
+          <!-- 博主粉丝 -->
+          <el-table-column label="博主粉丝" prop="fansNum" align="center">
+            <template slot-scope="scope">
+              <div v-for="item in scope.row.videoList">{{ item.publishPlatform + ":" + (item.fansNum? item.fansNum:"") + "\n"}}</div>
+            </template>
+          </el-table-column>
+          <!-- 订单编号 -->
+          <el-table-column label="推广订单" prop="orderNumber" align="center" width="200px">
+            <template slot-scope="scope">
+              <span>{{ scope.row.orderNumber}}</span>
+            </template>
+          </el-table-column>
+          <!-- 推广店铺 -->
+          <el-table-column label="推广店铺" prop="shopName" align="center">
+            <template slot-scope="scope">
+              <span>{{ scope.row.shopName}}</span>
+            </template>
+          </el-table-column>
+          <!-- 未发货,已发货 -->
+          <el-table-column label="订单状态" prop="status" align="center" width="160px">
+            <template slot-scope="scope">
+              <el-tag v-if="scope.row.status === '待发货'" type="warning">待发货</el-tag>
+              <div v-if="scope.row.status === '已发货'">
+                <div class="buyer-phone" v-for="deliveryOrder in scope.row.deliveryOrderList"
+                     style="text-decoration:underline;cursor: pointer; color: dodgerblue;font-size: 16px"
+                     @click="openDeliveryPage(deliveryOrder.dvyFlowId, deliveryOrder.dvyNo)">{{ deliveryOrder.dvyFlowId }}
+                </div>
+              </div>
+<!--              <el-tag v-if="scope.row.status === '已发货'" type="success">-->
+<!--                -->
+<!--              </el-tag>-->
+              <el-tag v-if="scope.row.status.indexOf('部分发货') != -1" type="warning">{{scope.row.status}}</el-tag>
+            </template>
+          </el-table-column>
+          <!-- 关联视频 -->
+          <el-table-column label="推广视频" prop="promotionVideo" align="center">
+            <template slot-scope="scope">
+              <el-button size="small" @click="openPromotionVideoList(scope.row.id)">查看视频</el-button>
+            </template>
+          </el-table-column>
+          <!-- 未发货,已发货 -->
+          <el-table-column label="寄拍/付费" prop="payType" align="center">
+            <template slot-scope="scope">
+              <el-tag v-if="scope.row.payType === '寄拍'" type="primary">寄拍</el-tag>
+              <el-tag v-if="scope.row.payType === '付费'" type="danger">付费:{{scope.row.payAmt}}元</el-tag>
+            </template>
+          </el-table-column>
+          <!-- 未发货,已发货 -->
+          <el-table-column label="结算状态" prop="settleStatus" align="center">
+            <template slot-scope="scope">
+              <el-tag v-if="scope.row.settleStatus === '待结算'" type="danger">待结算</el-tag>
+              <el-tag v-if="scope.row.settleStatus === '已结算'" type="success">已结算</el-tag>
+            </template>
+          </el-table-column>
+          <!-- 发货时间-->
+          <el-table-column label="下单时间" prop="orderTime" align="center">
+            <template slot-scope="scope">
+              <span>{{ scope.row.orderTime}}</span>
+            </template>
+          </el-table-column>
+          <!-- 发货时间-->
+          <el-table-column label="发货时间" prop="deliveryTime" align="center">
+            <template slot-scope="scope">
+              <span>{{ scope.row.deliveryTime}}</span>
+            </template>
+          </el-table-column>
+          <!-- 视频发布时间-->
+          <el-table-column label="视频发布时间" prop="publishTime" align="center">
+            <template slot-scope="scope">
+              <span>{{ scope.row.videoList.length > 0? scope.row.videoList[0].publishTime: ""}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column align="center" fixed="right" :label="$t('publics.operating')" width="auto">
+            <template slot-scope="scope">
+              <div class="text-btn-con">
+                <div class="default-btn text-btn" @click="addOrUpdateHandle(scope.row.id)"
+                     >{{$t("crud.updateBtn")}}</div>
+                <div class="default-btn text-btn" @click.stop="deleteHandle(scope.row.id)"
+                     >{{$t("text.delBtn")}}</div>
+                </div>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+        <el-pagination
+          v-if="dataList.length"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+          :current-page="page.currentPage"
+          :page-sizes="[10, 20, 50, 100]"
+          :page-size="page.pageSize"
+          layout="total, sizes, prev, pager, next, jumper"
+          :total="page.total">
+        </el-pagination>
+      </div>
+    <add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="refreshChange"></add-or-update>
+    <promotion-order-upload
+      v-if="uploadVisible"
+      ref="promotionOrderUpload"
+      @refreshDataList="getDataList(page)">
+    </promotion-order-upload>
+    <PromotionOrderVideo ref="promotionOrderVideo"></PromotionOrderVideo>
+  </div>
+</template>
+
+<script>
+import AddOrUpdate from './promotionOrder-add-or-update'
+import PromotionOrderUpload from './promotion-order-upload'
+import PromotionOrderVideo from './promotion-order-video'
+import InputNumberRange from '@/components/input-number-range'
+import moment from "moment"
+export default {
+  data () {
+    return {
+      dataList: [],
+      page: {
+        total: 0, // 总页数
+        currentPage: 1, // 当前页数
+        pageSize: 10 // 每页显示多少条
+      },
+      shopId: this.$store.state.user.shopId,
+      searchForm: {}, // 搜索
+      dataListLoading: false,
+      addOrUpdateVisible: false,
+      shopList: [],
+      orderTimeRange: [],
+      deliveryTimeRange: [],
+      uploadVisible: false,
+      fansNumRange:[]
+    }
+  },
+  components: {
+    AddOrUpdate,
+    PromotionOrderUpload,
+    InputNumberRange,
+    PromotionOrderVideo
+  },
+  created () {
+    this.getDataList(this.page);
+  },
+  mounted () {
+    this.getShopList()
+  },
+  methods: {
+    openPromotionVideoList(promotionOrderId){
+      this.$refs.promotionOrderVideo.init(promotionOrderId)
+    },
+    openUploadDialog(){
+      this.uploadVisible = true
+      this.$nextTick(() => {
+        this.$refs.promotionOrderUpload.init()
+      })
+    },
+    clear(){
+      this.searchForm = {}
+      this.dateRange = []
+      this.orderTimeRange = [],
+        this.deliveryTimeRange = [],
+        this.fansNumRange = []
+    },
+    getShopList() {
+      this.$http({
+        url: this.$http.adornUrl('/shop/shopDetail/getShopList'),
+        method: 'get',
+        params: this.$http.adornParams({shopId: this.shopId})
+      }).then(({ data }) => {
+        if (data) {
+          this.shopList = data
+        }
+      })
+    },
+    openDeliveryPage (deliveryNo, dvyNo) {
+      // window.open("https://t.17track.net/zh-cn#nums=" + deliveryNo, '_blank');
+      let copy = (e) => {
+        e.preventDefault()
+        e.clipboardData.setData('text/plain', deliveryNo)
+        document.removeEventListener('copy', copy)
+      }
+      document.addEventListener('copy', copy)
+      document.execCommand('Copy')
+      if (dvyNo === 'STO') {
+        window.open('https://www.sto.cn/pc/service-page/iframe_2_21_' + deliveryNo + ',')
+      } else if (dvyNo === 'YTO') {
+        window.open('https://www.yto.net.cn/tracesimple.html/?orders=' + deliveryNo)
+      } else if (dvyNo === 'ZTO') {
+        window.open('https://www.zto.com/express/expressCheck.html?txtBill=' + deliveryNo)
+      } else {
+        window.open('https://www.baidu.com/s?wd=%E7%89%A9%E6%B5%81%E6%9F%A5%E8%AF%A2&rsv_spt=1&rsv_iqid=0xe1fe334b0008559a&issp=1&f=8&rsv_bp=1&rsv_idx=2&ie=utf-8&tn=baiduhome_pg&rsv_enter=1&rsv_dl=tb&rsv_sug3=16&rsv_sug1=12&rsv_sug7=100&rsv_sug2=0&rsv_btype=i&inputT=2849&rsv_sug4=3141', '_blank')
+      }
+    },
+    getDataList (page) {
+      this.dataListLoading = true
+      this.$http({
+        url: this.$http.adornUrl('/promotion/promotionOrder/page'),
+        method: 'get',
+        params: this.$http.adornParams(
+          Object.assign({
+            current: page == null ? this.page.currentPage : page.currentPage,
+            size: page == null ? this.page.pageSize : page.pageSize,
+            startOrderTime: this.orderTimeRange == null ? null : this.orderTimeRange[0] ? this.orderTimeRange[0] : null,
+            endOrderTime: this.orderTimeRange == null ? null : this.orderTimeRange[1] ? this.orderTimeRange[1] : null,
+            startDeliveryTime: this.deliveryTimeRange == null ? null : this.deliveryTimeRange[0] ? this.deliveryTimeRange[0] : null,
+            endDeliveryTime: this.deliveryTimeRange == null ? null : this.deliveryTimeRange[1] ? this.deliveryTimeRange[1] : null,
+            startFansNum: this.fansNumRange == null ? null : this.fansNumRange[0] ? this.fansNumRange[0] : 0,
+            endFansNum: this.fansNumRange == null ? null : this.fansNumRange[1] ? this.fansNumRange[1] : 0,
+            shopId: this.$store.state.user.shopId,
+          },
+            this.searchForm
+          )
+        )
+      }).then(({data}) => {
+        this.dataList = data.records
+        this.page.total = data.total
+        this.dataListLoading = false
+      })
+    },
+    setDateRange(val) {
+      var startDay = null
+      var endDay = null
+      if (val === 1) {
+        startDay = 0
+        endDay = 0
+      } else if (val === 2) {
+        startDay = -1
+        endDay = -1
+      } else if (val === 3) {
+        startDay = -3
+        endDay = -1
+      } else if (val === 4) {
+        startDay = -5
+        endDay = -1
+      } else {
+        return
+      }
+      // 开始时间
+      let startTime = moment().add(startDay, 'days').startOf('days').format('LL')
+      // 结束时间
+      let endTime = moment().add(endDay, 'days').endOf('days').format('LL')
+      // this.orderTimeRange = [startTime, endTime]
+      this.deliveryTimeRange = [startTime, endTime]
+    },
+    // 新增 / 修改
+    addOrUpdateHandle (id) {
+      this.addOrUpdateVisible = true
+      this.$nextTick(() => {
+        this.$refs.addOrUpdate.init(id)
+      })
+    },
+    deleteHandle (id) {
+      this.$confirm(this.$i18n.t('admin.isDeleOper') + '?', this.$i18n.t('text.tips'), {
+        confirmButtonText: this.$i18n.t('crud.filter.submitBtn'),
+        cancelButtonText: this.$i18n.t('crud.filter.cancelBtn'),
+        type: 'warning'
+      }).then(() => {
+        this.$http({
+          url: this.$http.adornUrl('/promotion/promotionOrder/' + id),
+          method: 'delete',
+          data: this.$http.adornData({})
+        }).then(({ data }) => {
+          this.$message({
+            message: this.$i18n.t('publics.operation'),
+            type: 'success',
+            duration: 200,
+            onClose: () => {
+              this.refreshChange()
+            }
+          })
+        })
+      }).catch(() => { })
+    },
+    // 刷新回调
+    refreshChange () {
+      this.page.currentPage = 1
+      this.getDataList(this.page)
+    },
+    searchChange (params) {
+      this.page.currentPage = 1
+      this.getDataList(null)
+    },
+    handleSizeChange (val) {
+      this.page.pageSize = val
+      this.getDataList()
+    },
+    handleCurrentChange (val) {
+      this.page.currentPage = val
+      this.getDataList()
+    }
+  }
+}
+</script>
+<style lang="scss">
+.mod-print-promotionOrder {
+  .search-bar {
+    .input-row {
+      .select-time-btn {
+        margin-right: 20px;
+        display: inline-block;
+        color: #AAAAAA;
+        font-size: 14px;
+        cursor: pointer;
+
+        &:last-child {
+          margin-right: 0;
+        }
+      }
+
+      .select-time-btn.is-active {
+        color: #155BD4;
+      }
+
+    }
+  }
+}
+</style>

+ 161 - 0
src/views/modules/promotion/promotionUp-add-or-update.vue

@@ -0,0 +1,161 @@
+<template>
+  <el-dialog
+    :title="!dataForm.id ? this.$i18n.t('crud.addTitle') : this.$i18n.t('temp.modify')"
+    :close-on-click-modal="false"
+    :visible.sync="visible">
+    <el-form :model="dataForm" :rules="dataRule" ref="dataForm" label-width="80px">
+      <el-row>
+        <el-col :span="10">
+          <el-form-item label="推广人" prop="tgUserName" :rules="{required: true, message: '推广人必填', trigger: 'blur'}"  size="small">
+            <el-input v-model="dataForm.tgUserName"></el-input>
+          </el-form-item>
+        </el-col>
+        <el-col :span="10" :offset="1">
+          <el-form-item label="推广店铺" prop="shopId" :rules="{required: true, message: '推广店铺必填', trigger: 'blur'}"  size="small">
+            <el-select v-model="dataForm.shopId" placeholder="推广店铺" style="width: 330px" @change="shopChange"
+                       controls-position="right" :clearable="true">
+              <el-option v-for="(item,index) in shopList" :key="index" :label="item.shopName" :value="item.shopId">
+              </el-option>
+            </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="10">
+          <el-form-item label="博主ID" prop="upId"  size="small">
+            <el-input v-model="dataForm.upId"></el-input>
+          </el-form-item>
+        </el-col>
+        <el-col :span="10" :offset="1">
+          <el-form-item label="博主名称" prop="upName" :rules="{required: true, message: '博主昵称必填', trigger: 'blur'}" size="small">
+            <el-input v-model="dataForm.upName"></el-input>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="10">
+          <el-form-item label="视频平台" prop="publishPlatform" size="small">
+            <el-autocomplete
+              class="inline-input"
+              v-model="dataForm.publishPlatform"
+              :fetch-suggestions="querySearch"
+              placeholder="请输入内容"
+              style="width :330px;">
+              <template slot-scope="{ item }">
+                <div class="name">{{ item.label }}</div>
+              </template>
+            </el-autocomplete>
+          </el-form-item>
+        </el-col>
+        <el-col :span="10" :offset="1">
+          <el-form-item label="粉丝数" prop="fansNum" size="small">
+            <el-input v-model="dataForm.fansNum" type="number"></el-input>
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+    <span slot="footer" class="dialog-footer">
+      <el-button class="default-btn" @click="visible = false">{{$t("crud.filter.cancelBtn")}}</el-button>
+      <el-button class="default-btn primary-btn" type="primary" @click="dataFormSubmit()">{{$t("crud.filter.submitBtn")}}</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+export default {
+  data () {
+    return {
+      visible: false,
+      dataForm: {
+        id: null,
+        upId: null,
+        upName: null,
+        publishPlatform: null,
+        fansNum: null,
+        tgUserName: null,
+        shopId: this.$store.state.user.shopId,
+        shopName: null
+      },
+      dataRule: {
+      },
+      shopList:[],
+      videoPlatformList: [
+        {value: '抖音', label: '抖音'},
+        {value: '小红书', label: '小红书'},
+        {value: '视频号', label: '视频号'},
+        {value: '快手', label: '快手'},
+        {value: 'B站', label: 'B站'},
+      ],
+    }
+  },
+  mounted() {
+    this.getShopList()
+  },
+  methods: {
+    init (id) {
+      this.dataForm.id = id || 0
+      this.visible = true
+      this.$nextTick(() => {
+        this.$refs['dataForm'].resetFields()
+        if (this.dataForm.id) {
+          this.$http({
+            url: this.$http.adornUrl('/promotion/promotionUp/info/' + this.dataForm.id),
+            method: 'get',
+            params: this.$http.adornParams()
+          }).then(({data}) => {
+            this.dataForm = data
+          })
+        }
+      })
+    },
+    shopChange (index) {
+      this.dataForm.shopName = this.shopList[index].shopName
+    },
+    getShopList() {
+      this.$http({
+        url: this.$http.adornUrl('/shop/shopDetail/getShopList'),
+        method: 'get',
+        params: this.$http.adornParams({shopId: this.shopId})
+      }).then(({ data }) => {
+        if (data) {
+          this.shopList = data
+        }
+      })
+    },
+    querySearch (queryString, cb) {
+      var restaurants = this.videoPlatformList
+      var results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants
+      // 调用 callback 返回建议列表的数据
+      cb(results)
+    },
+    createFilter (queryString) {
+      return (restaurant) => {
+        return (restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0)
+      }
+    },
+    // 表单提交
+    dataFormSubmit () {
+      this.$refs['dataForm'].validate((valid) => {
+        if (valid) {
+          this.dataForm.shopName = this.shopList.find(item => item.shopId === this.dataForm.shopId).shopName
+          this.$http({
+            url: this.$http.adornUrl('/promotion/promotionUp'),
+            method: this.dataForm.id ? 'put' : 'post',
+            data: this.$http.adornData(this.dataForm)
+          }).then(({data}) => {
+            this.$message({
+              message: this.$i18n.t('publics.operation'),
+              type: 'success',
+              duration: 200,
+              onClose: () => {
+                this.visible = false
+                this.$emit('refreshDataList')
+              }
+            })
+          })
+        }
+      })
+    }
+  }
+}
+</script>

+ 272 - 0
src/views/modules/promotion/promotionUp.vue

@@ -0,0 +1,272 @@
+<template>
+  <div class="mod-print-promotionOrder">
+    <!-- 搜索相关区域 -->
+    <div class="search-bar">
+      <el-form :inline="true" :model="searchForm" @keyup.enter.native="getDataList(this.page)" size="small">
+        <div class="input-row">
+          <el-form-item label="推广人" prop="tgUserName">
+            <el-input v-model="searchForm.tgUserName" :clearable="true"></el-input>
+          </el-form-item>
+          <el-form-item label="博主ID" prop="upId">
+            <el-input v-model="searchForm.upId" :clearable="true"></el-input>
+          </el-form-item>
+          <el-form-item label="博主名称" prop="upName">
+            <el-input v-model="searchForm.upName" :clearable="true"></el-input>
+          </el-form-item>
+          <el-form-item label="视频平台" prop="publishPlatform">
+            <el-select v-model="searchForm.publishPlatform" filterable placeholder="请选择" :clearable="true">
+              <el-option
+                v-for="(item,index) in videoPlatformList"
+                :key="index"
+                :label="item.label"
+                :value="item.value">
+              </el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="推广店铺" prop="shopId">
+            <el-select v-model="searchForm.shopId" placeholder="推广店铺"
+                       controls-position="right" :clearable="true" style="width: 295px">
+              <el-option v-for="item in shopList" :key="item.shopId" :label="item.shopName" :value="item.shopId">
+              </el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item>
+            <div class="default-btn primary-btn" @click="searchChange()">{{$t("crud.searchBtn")}}</div>
+            <div class="default-btn" @click="clear()">重置</div>
+          </el-form-item>
+        </div>
+      </el-form>
+    </div>
+    <!-- 列表相关区域 -->
+    <div class="main-container">
+      <div class="operation-bar">
+        <div class="default-btn primary-btn" @click="addOrUpdateHandle()">{{$t("crud.addTitle")}}</div>
+      </div>
+      <div class="table-con spec-table">
+        <el-table
+          ref="specListTable"
+          :data="dataList"
+          header-cell-class-name="table-header"
+          row-class-name="table-row"
+          style="width: 100%">
+          <!-- 推广人名称 -->
+          <el-table-column label="推广人" prop="tgUserName" align="center">
+            <template slot-scope="scope">
+              <span>{{ scope.row.tgUserName}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="视频平台" prop="publishPlatform" align="center">
+            <template slot-scope="scope">
+              <span>{{ scope.row.publishPlatform}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="博主" prop="upId" align="center">
+            <template slot-scope="scope">
+              <span>{{ scope.row.upId}}</span>
+              <br/>
+              <span>{{ scope.row.upName}}</span>
+            </template>
+          </el-table-column>
+          <!-- 博主粉丝 -->
+          <el-table-column label="博主粉丝" prop="fansNum" align="center">
+            <template slot-scope="scope">
+              <span>{{ scope.row.fansNum}}</span>
+            </template>
+          </el-table-column>
+          <!-- 推广店铺 -->
+          <el-table-column label="推广店铺" prop="shopName" align="center">
+            <template slot-scope="scope">
+              <span>{{ scope.row.shopName}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column align="center" fixed="right" :label="$t('publics.operating')" width="auto">
+            <template slot-scope="scope">
+              <div class="text-btn-con">
+                <div class="default-btn text-btn" @click="addOrUpdateHandle(scope.row.id)"
+                     >{{$t("crud.updateBtn")}}</div>
+                <div class="default-btn text-btn" @click.stop="deleteHandle(scope.row.id)"
+                     >{{$t("text.delBtn")}}</div>
+                </div>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+        <el-pagination
+          v-if="dataList.length"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+          :current-page="page.currentPage"
+          :page-sizes="[10, 20, 50, 100]"
+          :page-size="page.pageSize"
+          layout="total, sizes, prev, pager, next, jumper"
+          :total="page.total">
+        </el-pagination>
+      </div>
+    <add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="refreshChange"></add-or-update>
+  </div>
+</template>
+
+<script>
+import AddOrUpdate from './promotionUp-add-or-update'
+export default {
+  data () {
+    return {
+      dataList: [],
+      page: {
+        total: 0, // 总页数
+        currentPage: 1, // 当前页数
+        pageSize: 10 // 每页显示多少条
+      },
+      shopId: this.$store.state.user.shopId,
+      searchForm: {}, // 搜索
+      dataListLoading: false,
+      addOrUpdateVisible: false,
+      shopList: [],
+      videoPlatformList: [
+        {value: '抖音', label: '抖音'},
+        {value: '小红书', label: '小红书'},
+        {value: '视频号', label: '视频号'},
+        {value: '快手', label: '快手'},
+        {value: 'B站', label: 'B站'},
+      ],
+    }
+  },
+  components: {
+    AddOrUpdate,
+  },
+  created () {
+    this.getDataList(this.page);
+  },
+  mounted () {
+    this.getShopList()
+  },
+  methods: {
+    openPromotionVideoList(promotionOrderId){
+      this.$refs.promotionOrderVideo.init(promotionOrderId)
+    },
+    openUploadDialog(){
+      this.uploadVisible = true
+      this.$nextTick(() => {
+        this.$refs.promotionOrderUpload.init()
+      })
+    },
+    clear(){
+      this.searchForm = {}
+    },
+    shopChange (index) {
+      this.dataForm.shopName = this.shopList[index].shopName
+    },
+    querySearch (queryString, cb) {
+      var restaurants = this.videoPlatformList
+      var results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants
+      // 调用 callback 返回建议列表的数据
+      cb(results)
+    },
+    createFilter (queryString) {
+      return (restaurant) => {
+        return (restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0)
+      }
+    },
+    getShopList() {
+      this.$http({
+        url: this.$http.adornUrl('/shop/shopDetail/getShopList'),
+        method: 'get',
+        params: this.$http.adornParams({shopId: this.shopId})
+      }).then(({ data }) => {
+        if (data) {
+          this.shopList = data
+        }
+      })
+    },
+    getDataList (page) {
+      this.dataListLoading = true
+      this.$http({
+        url: this.$http.adornUrl('/promotion/promotionUp/page'),
+        method: 'get',
+        params: this.$http.adornParams(
+          Object.assign({
+            current: page == null ? this.page.currentPage : page.currentPage,
+            size: page == null ? this.page.pageSize : page.pageSize,
+          },
+            this.searchForm
+          )
+        )
+      }).then(({data}) => {
+        this.dataList = data.records
+        this.page.total = data.total
+        this.dataListLoading = false
+      })
+    },
+    // 新增 / 修改
+    addOrUpdateHandle (id) {
+      this.addOrUpdateVisible = true
+      this.$nextTick(() => {
+        this.$refs.addOrUpdate.init(id)
+      })
+    },
+    deleteHandle (id) {
+      this.$confirm(this.$i18n.t('admin.isDeleOper') + '?', this.$i18n.t('text.tips'), {
+        confirmButtonText: this.$i18n.t('crud.filter.submitBtn'),
+        cancelButtonText: this.$i18n.t('crud.filter.cancelBtn'),
+        type: 'warning'
+      }).then(() => {
+        this.$http({
+          url: this.$http.adornUrl('/promotion/promotionUp/' + id),
+          method: 'delete',
+          data: this.$http.adornData({})
+        }).then(({ data }) => {
+          this.$message({
+            message: this.$i18n.t('publics.operation'),
+            type: 'success',
+            duration: 200,
+            onClose: () => {
+              this.refreshChange()
+            }
+          })
+        })
+      }).catch(() => { })
+    },
+    // 刷新回调
+    refreshChange () {
+      this.page.currentPage = 1
+      this.getDataList(this.page)
+    },
+    searchChange (params) {
+      this.page.currentPage = 1
+      this.getDataList(null)
+    },
+    handleSizeChange (val) {
+      this.page.pageSize = val
+      this.getDataList()
+    },
+    handleCurrentChange (val) {
+      this.page.currentPage = val
+      this.getDataList()
+    },
+  }
+}
+</script>
+<style lang="scss">
+.mod-print-promotionOrder {
+  .search-bar {
+    .input-row {
+      .select-time-btn {
+        margin-right: 20px;
+        display: inline-block;
+        color: #AAAAAA;
+        font-size: 14px;
+        cursor: pointer;
+
+        &:last-child {
+          margin-right: 0;
+        }
+      }
+
+      .select-time-btn.is-active {
+        color: #155BD4;
+      }
+
+    }
+  }
+}
+</style>

+ 357 - 0
src/views/modules/promotion/promotionVideo-add-or-update.vue

@@ -0,0 +1,357 @@
+<template>
+  <el-dialog
+    :title="!dataForm.id ? this.$i18n.t('crud.addTitle') : this.$i18n.t('temp.modify')"
+    :close-on-click-modal="false"
+    :modal-append-to-body="false"
+    :visible.sync="visible"
+    top="1vh"
+    @close="closeDialog">
+    <el-row>
+      <el-col :span="24">
+        <el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmit()" label-width="110px">
+<!--          <el-form-item label="" prop="id">-->
+<!--            <el-input v-model="dataForm.id"size="small"></el-input>-->
+<!--          </el-form-item>-->
+          <el-row>
+            <el-col :span="10">
+              <el-form-item label="推广人" prop="tgUserName">
+                <el-input v-model="dataForm.tgUserName"size="small"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="10" :offset="1">
+              <el-form-item label="推广店铺" prop="shopId">
+                <el-select v-model="dataForm.shopId" placeholder="推广店铺"
+                           controls-position="right" :clearable="true" style="width: 295px">
+                  <el-option v-for="item in shopList" :key="item.shopId" :label="item.shopName" :value="item.shopId">
+                  </el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row>
+            <el-col :span="10">
+              <el-form-item label="博主ID" prop="upId">
+                <el-input v-model="dataForm.upId"size="small"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="10"  :offset="1">
+              <el-form-item label="博主昵称" prop="upName">
+                <el-input v-model="dataForm.upName"size="small"></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row>
+            <el-col :span="21">
+              <el-form-item label="视频链接" prop="videoUrl">
+                <el-input v-model="dataForm.videoUrl"size="small" type="textarea" rows="3"></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row>
+            <el-col :span="10">
+              <el-form-item label="t+1点赞数" prop="likeNumT1">
+                <el-input v-model="dataForm.likeNumT1"size="small"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="10" :offset="1">
+              <el-form-item label="t+7点赞数" prop="likeNumT7">
+                <el-input v-model="dataForm.likeNumT7"size="small"></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row>
+            <el-col :span="10">
+              <el-form-item label="t+1播放数" prop="playNumT1">
+                <el-input v-model="dataForm.playNumT1"size="small"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="10" :offset="1">
+              <el-form-item label="t+7播放数" prop="playNumT7">
+                <el-input v-model="dataForm.playNumT7"size="small"></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row>
+              <el-col :span="10">
+                <el-form-item label="发布平台" prop="publishPlatform">
+                  <el-autocomplete style="width:300px"
+                    class="inline-input"
+                    v-model="dataForm.publishPlatform"
+                    :fetch-suggestions="querySearch"
+                    placeholder="请输入内容">
+                    <template slot-scope="{ item }">
+                      <div class="name">{{ item.label }}</div>
+                    </template>
+                  </el-autocomplete>
+                </el-form-item>
+              </el-col>
+            <el-col :span="10" :offset="1">
+              <el-form-item label="粉丝数" prop="fansNum">
+                <el-input v-model="dataForm.fansNum"size="small"></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row>
+              <el-col :span="7">
+                <el-form-item label="评论数" prop="commNum">
+                  <el-input v-model="dataForm.commNum"size="small"></el-input>
+                </el-form-item>
+              </el-col>
+            <el-col :span="7">
+              <el-form-item label="点赞数" prop="likeNum">
+                <el-input v-model="dataForm.likeNum"size="small"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="7">
+              <el-form-item label="播放数" prop="playNum">
+                <el-input v-model="dataForm.playNum"size="small"></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row>
+            <el-col :span="10">
+              <el-form-item label="寄拍付费" prop="payType">
+                <el-select v-model="dataForm.payType" placeholder="请选择" size="small" style="width: 295px;">
+                  <el-option :key="0" label="寄拍" value="寄拍"></el-option>
+                  <el-option :key="1" label="付费 " value="付费"></el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="10" :offset="1">
+              <el-form-item label="付费金额" prop="payAmt">
+                <el-input v-model="dataForm.payAmt"size="small" type="number"></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row>
+            <el-col :span="10">
+              <el-form-item label="发布状态" prop="status">
+                <el-select v-model="dataForm.status" placeholder="请选择" size="small" style="width: 295px">
+                  <el-option :key="1" label="待发布" value="待发布"></el-option>
+                  <el-option :key="2" label="已发布 " value="已发布"></el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="10" :offset="1">
+              <el-form-item label="结算状态" prop="settleStatus">
+                <el-select v-model="dataForm.settleStatus" placeholder="请选择" size="small" style="width: 295px;">
+                  <el-option :key="1" label="待结算" value="待结算"></el-option>
+                  <el-option :key="2" label="已结算 " value="已结算"></el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row>
+            <el-col :span="10">
+              <el-form-item label="发布时间" prop="publishTime">
+                <el-date-picker
+                  style="width: 295px"
+                  size="small"
+                  v-model="dataForm.publishTime"
+                  type="datetime"
+                  value-format="yyyy-MM-dd HH:mm:ss"
+                  placeholder="选择日期时间"
+                  default-time="12:00:00">
+                </el-date-picker>
+              </el-form-item>
+            </el-col>
+            <el-col :span="10" :offset="1">
+            </el-col>
+          </el-row>
+          <el-row>
+            <el-form-item label="相关图片" prop="pic">
+              <el-upload
+                :disabled="isView"
+                ref="upload"
+                :multiple="true"
+                :action="$http.adornUrl('/admin/file/simpleUpload')"
+                list-type="picture-card"
+                :headers="{Authorization: $cookie.get('Authorization_vs'),locale:lang}"
+                :on-success="onUploadSuccess"
+                :file-list="fileList"
+                :limit="1"
+                :on-remove="handlePicRemove"
+                :on-preview="handlePicPreview">
+                <i class="el-icon-plus"></i>
+              </el-upload>
+              <div  @paste="pasteImg($event)">
+                <textarea placeholder="点击这里,然后把图片粘贴" style="width: 100%;height: 100px;border: 1px solid #c9c9c9;border-radius: 5px;"></textarea>
+              </div>
+            </el-form-item>
+          </el-row>
+    </el-form>
+      </el-col>
+    </el-row>
+    <span slot="footer" class="dialog-footer">
+      <el-button class="default-btn" @click="visible = false">{{$t("crud.filter.cancelBtn")}}</el-button>
+      <el-button class="default-btn primary-btn" type="primary" @click="dataFormSubmit()">{{$t("crud.filter.submitBtn")}}</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+  import { uploadFile } from '@/utils/httpRequest.js'
+export default {
+  data () {
+    return {
+      visible: false,
+      isView: false,
+      lang: localStorage.getItem('lang') || 'zh_CN',
+      dataForm: {
+        id: null,
+        tgUserName: null,
+        upId: null,
+        upName: null,
+        videoUrl: null,
+        likeNumT1: null,
+        playNumT1: null,
+        commNum: null,
+        likeNumT7: null,
+        playNumT7: null,
+        shopId: this.$store.state.user.shopId,
+        shopName: null,
+        publishPlatform: null,
+        payType: null,
+        payAmt: null,
+        settleStatus: null,
+        createTime: null,
+        updateTime: null,
+        playNum: null,
+        likeNum: null,
+        status: null,
+        publishTime:null,
+        pic:null
+      },
+      dataRule: {
+      },
+      imgDialogVisible: false,
+      shopList: [],
+      fileList:[],
+      resourcesUrl: process.env.VUE_APP_RESOURCES_URL,
+      videoPlatformList: [
+        {value: '抖音', label: '抖音'},
+        {value: '小红书', label: '小红书'},
+        {value: '视频号', label: '视频号'},
+        {value: '快手', label: '快手'},
+        {value: 'B站', label: 'B站'},
+      ],
+    }
+  },
+  mounted () {
+    this.getShopList()
+  },
+  methods: {
+    init (id) {
+      this.dataForm.id = id || 0
+      this.visible = true
+      this.$nextTick(() => {
+        this.$refs['dataForm'].resetFields()
+        if (this.dataForm.id) {
+          this.$http({
+            url: this.$http.adornUrl('/promotion/promotionVideo/info/' + this.dataForm.id),
+            method: 'get',
+            params: this.$http.adornParams()
+          }).then(({data}) => {
+            this.dataForm = data
+            if(this.dataForm.pic) {
+              this.fileList = [];
+              let picArray = this.dataForm.pic.split(",");
+              for (let i = 0; i < picArray.length; i++) {
+                this.fileList.push({ url: this.resourcesUrl + picArray[i], response: {filePath: picArray[i] }})
+              }
+            }
+          })
+        }
+      })
+    },
+    closeDialog(){
+      this.fileList = []
+      this.$emit('refreshDataList')
+    },
+    pasteImg(e) {
+      const { items } = e.clipboardData; // 获取粘贴板文件对象
+      if (items.length) {
+        for (const item of items) {
+          if (item.type.indexOf('image') !== -1) {
+            const file = item.getAsFile(); // 获取图片文件
+            if (file) {
+              uploadFile(
+                this.$http.adornUrl('/admin/file/simpleUpload'),
+                file
+              ).then(({ data }) => {
+                let obj = {url: data.resourcesUrl + data.filePath, response: {filePath: data.filePath }}
+                this.fileList.push(obj)
+              })
+            }
+          }
+        }
+      }
+    },
+    onUploadSuccess(response, file, fileList){
+      this.fileList = fileList;
+    },
+    handlePicRemove(file, fileList){
+      this.fileList = fileList;
+    },
+    handlePicPreview(file){
+      this.dialogImageUrl = file.url
+      let url = file.response.resourcesUrl + file.response.filePath
+      this.videoFlag = this.checkMediaType(url)
+      this.imgDialogVisible = true
+    },
+    querySearch (queryString, cb) {
+      var restaurants = this.videoPlatformList
+      var results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants
+      // 调用 callback 返回建议列表的数据
+      cb(results)
+    },
+    createFilter (queryString) {
+      return (restaurant) => {
+        return (restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0)
+      }
+    },
+    getShopList() {
+      this.$http({
+        url: this.$http.adornUrl('/shop/shopDetail/getShopList'),
+        method: 'get',
+        params: this.$http.adornParams({shopId: this.shopId})
+      }).then(({ data }) => {
+        if (data) {
+          this.shopList = data
+        }
+      })
+    },
+    // 表单提交
+    dataFormSubmit () {
+      let filePath = [];
+      this.$refs['dataForm'].validate((valid) => {
+        if (valid) {
+          if(this.fileList.length > 0 && !this.dataForm.id){
+            this.fileList.forEach(item => {
+              filePath.push(item.response.filePath);
+            });
+            this.dataForm.pic = filePath.join(",");
+          }else{
+            this.fileList.forEach(item => {
+              filePath.push(item.response.filePath);
+            });
+            this.dataForm.pic = filePath.join(",");
+          }
+          this.$http({
+            url: this.$http.adornUrl('/promotion/promotionVideo'),
+            method: this.dataForm.id ? 'put' : 'post',
+            data: this.$http.adornData(this.dataForm)
+          }).then(({data}) => {
+            this.$message({
+              message: this.$i18n.t('publics.operation'),
+              type: 'success',
+            })
+            this.visible = false
+            this.$emit('refreshDataList')
+          })
+        }
+      })
+    }
+  }
+}
+</script>

+ 434 - 0
src/views/modules/promotion/promotionVideo.vue

@@ -0,0 +1,434 @@
+<template>
+  <div class="mod-print-promotionVideo">
+    <!-- 搜索相关区域 -->
+    <div class="search-bar">
+      <el-form :inline="true" :model="searchForm" @keyup.enter.native="getDataList(this.page)" size="small">
+        <el-form-item label="视频ID" prop="id">
+          <el-input v-model="searchForm.id" :clearable="true"></el-input>
+        </el-form-item>
+        <el-form-item label="推广人" prop="tgUserName">
+          <el-input v-model="searchForm.tgUserName" :clearable="true"></el-input>
+        </el-form-item>
+        <el-form-item label="博主ID" prop="upId">
+          <el-input v-model="searchForm.upId" :clearable="true"></el-input>
+        </el-form-item>
+        <el-form-item label="博主名称" prop="upName">
+          <el-input v-model="searchForm.upName" :clearable="true"></el-input>
+        </el-form-item>
+        <el-form-item label="发布平台" prop="publishPlatform">
+          <el-autocomplete
+            class="inline-input"
+            v-model="searchForm.publishPlatform"
+            :fetch-suggestions="querySearch"
+            placeholder="请输入内容">
+            <template slot-scope="{ item }">
+              <div class="name">{{ item.label }}</div>
+            </template>
+          </el-autocomplete>
+        </el-form-item>
+        <el-form-item label="寄拍/付费" prop="payType">
+          <el-select v-model="searchForm.payType" placeholder="请选择" size="small" :clearable="true">
+            <el-option :key="0" label="寄拍" value="寄拍"></el-option>
+            <el-option :key="1" label="付费 " value="付费"></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="发布状态" prop="status">
+          <el-select v-model="searchForm.status" placeholder="发布状态" size="small" :clearable="true">
+            <el-option :key="1" label="待发布" value="待发布"></el-option>
+            <el-option :key="2" label="已发布 " value="已发布"></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="粉丝数:" label-width="85px">
+          <InputNumberRange v-model="fansNumRange"></InputNumberRange>
+        </el-form-item>
+        <el-form-item label="点赞数量:" label-width="85px">
+          <InputNumberRange v-model="likeNumRange"></InputNumberRange>
+        </el-form-item>
+        <el-form-item label="评论数量:" label-width="85px">
+          <InputNumberRange v-model="commNumRange"></InputNumberRange>
+        </el-form-item>
+        <el-form-item label="推广店铺" prop="shopId">
+          <el-select v-model="searchForm.shopId" placeholder="推广店铺"
+                     controls-position="right" :clearable="true" style="width: 295px">
+            <el-option v-for="item in shopList" :key="item.shopId" :label="item.shopName" :value="item.shopId">
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="发布时间" prop="publishTime">
+          <el-date-picker
+            :clearable="true"
+            v-model="publishTimeDateRange"
+            type="datetimerange"
+            align="right"
+            value-format="yyyy-MM-dd HH:mm:ss"
+            start-placeholder="开始时间"
+            end-placeholder="结束时间"
+            :default-time="['00:00:00', '23:59:59']">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item>
+          <div class="default-btn" @click="setDateRange(1)">今日</div>
+          <div class="default-btn" @click="setDateRange(2)">昨日</div>
+          <div class="default-btn" @click="setDateRange(3)">近3天</div>
+          <div class="default-btn" @click="setDateRange(4)">近5天</div>
+          <div class="default-btn primary-btn" @click="searchChange()">{{$t("crud.searchBtn")}}</div>
+<!--          <div class="default-btn" @click="getSoldExcel()">{{ $t("order.export") }}</div>-->
+          <div class="default-btn" @click="clear()">重置</div>
+        </el-form-item>
+      </el-form>
+    </div>
+    <!-- 列表相关区域 -->
+    <div class="main-container">
+      <div class="operation-bar">
+<!--        <div class="default-btn primary-btn" @click="addOrUpdateHandle()"-->
+<!--             v-if="isAuth('print:promotionVideo:save')">{{$t("crud.addTitle")}}</div>-->
+<!--        <div class="default-btn primary-btn" @click="addOrUpdateHandle()">{{$t("crud.addTitle")}}</div>-->
+<!--        <div class="default-btn primary-btn" @click="openUploadDialog()">导入数据</div>-->
+      </div>
+      <div class="table-con spec-table">
+        <el-table
+          ref="specListTable"
+          :data="dataList"
+          header-cell-class-name="table-header"
+          row-class-name="table-row"
+          style="width: 100%">
+          <!-- 视频ID -->
+          <el-table-column label="视频ID" prop="id" align="center">
+            <template slot-scope="scope">
+              <span>{{ scope.row.id}}</span>
+            </template>
+          </el-table-column>
+          <!-- 推广人名称 -->
+          <el-table-column label="推广人" prop="tgUserName" align="center">
+            <template slot-scope="scope">
+              <span>{{ scope.row.tgUserName}}</span>
+            </template>
+          </el-table-column>
+          <!-- 店铺名称 -->
+          <el-table-column label="店铺" prop="shopName" align="center">
+            <template slot-scope="scope">
+              <span>{{ scope.row.shopName}}</span>
+            </template>
+          </el-table-column>
+          <!-- 博主ID -->
+          <el-table-column label="博主" prop="upId" align="center" width="150px">
+            <template slot-scope="scope">
+              <span>{{ scope.row.upId}}</span>
+              <br/>
+              <span>{{ scope.row.upName}}</span>
+            </template>
+          </el-table-column>
+          <!-- 粉丝数 -->
+          <el-table-column label="粉丝数" prop="fansNum" align="center">
+            <template slot-scope="scope">
+              <span>{{ scope.row.fansNum}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="点赞数" prop="likeNum" align="center">
+            <template slot-scope="scope">
+              <span>{{ scope.row.likeNum}}</span>
+            </template>
+          </el-table-column>
+          <!--&lt;!&ndash; t+1点赞数 &ndash;&gt;
+          <el-table-column :label="$t('promotionVideo.likeNumT1')" prop="likeNumT1" align="center">
+            <template slot-scope="scope">
+              <span>{{ scope.row.likeNumT1}}</span>
+            </template>
+          </el-table-column>
+          &lt;!&ndash; t+1播放数 &ndash;&gt;
+          <el-table-column :label="$t('promotionVideo.playNumT1')" prop="playNumT1" align="center">
+            <template slot-scope="scope">
+              <span>{{ scope.row.playNumT1}}</span>
+            </template>
+          </el-table-column>-->
+          <!-- 评论数 -->
+          <el-table-column label="评论数" prop="commNum" align="center">
+            <template slot-scope="scope">
+              <span>{{ scope.row.commNum}}</span>
+            </template>
+          </el-table-column>
+          <!--&lt;!&ndash; t+7点赞数 &ndash;&gt;
+          <el-table-column :label="$t('promotionVideo.likeNumT7')" prop="likeNumT7" align="center">
+            <template slot-scope="scope">
+              <span>{{ scope.row.likeNumT7}}</span>
+            </template>
+          </el-table-column>
+          &lt;!&ndash; t+7播放数 &ndash;&gt;
+          <el-table-column :label="$t('promotionVideo.playNumT7')" prop="playNumT7" align="center">
+            <template slot-scope="scope">
+              <span>{{ scope.row.playNumT7}}</span>
+            </template>
+          </el-table-column>-->
+          <!-- 总点赞数 -->
+
+          <!-- 总播放数 -->
+          <el-table-column label="播放数" prop="playNum" align="center">
+            <template slot-scope="scope">
+              <span>{{ scope.row.playNum}}</span>
+            </template>
+          </el-table-column>
+          <!-- 发布平台 -->
+          <el-table-column label="发布平台" prop="publishPlatform" align="center">
+            <template slot-scope="scope">
+              <span>{{ scope.row.publishPlatform}}</span>
+            </template>
+          </el-table-column>
+          <!-- 视频链接 -->
+          <el-table-column label="推广视频" prop="videoUrl" align="center" width="200px" :show-overflow-tooltip="true">
+            <template slot-scope="scope">
+              <!--<el-tooltip effect="dark" placement="top">
+                <div slot="content">{{scope.row.videoUrl}}</div>
+                <span style="overflow: hidden;width: 50px;white-space: nowrap;">{{scope.row.videoUrl}}</span>
+              </el-tooltip>-->
+              <span @click="jumpToLink(scope.row.videoUrl)" style="cursor: pointer;color: #2d8cf0">{{scope.row.videoUrl}}</span>
+            </template>
+          </el-table-column>
+          <!-- 是否付费,0寄拍,1付费 -->
+          <el-table-column label="寄拍/付费" prop="payType" align="center">
+            <template slot-scope="scope">
+              <el-tag v-if="scope.row.payType === '付费'" type="danger">付费:{{scope.row.payAmt}}</el-tag>
+              <el-tag v-if="scope.row.payType === '寄拍'" type="primary">寄拍:{{scope.row.payAmt}}</el-tag>
+            </template>
+          </el-table-column>
+          <!--<el-table-column label="付费金额" prop="payAmt" align="center">
+            <template slot-scope="scope">
+              <span>{{ scope.row.payAmt}}</span>
+            </template>
+          </el-table-column>-->
+          <!-- 结算状态 -->
+          <el-table-column label="结算状态" prop="settleStatus" align="center">
+            <template slot-scope="scope">
+              <el-tag v-if="scope.row.settleStatus === '待结算'" type="danger">待结算</el-tag>
+              <el-tag v-if="scope.row.settleStatus === '已结算'" type="success">已结算</el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column label="发布状态" prop="status" align="center">
+            <template slot-scope="scope">
+              <el-tag v-if="scope.row.status === '待发布'" type="warning">待发布</el-tag>
+              <el-tag v-if="scope.row.status === '已发布'" type="success">已发布</el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column label="发布时间" prop="publishTime" align="center">
+            <template slot-scope="scope">
+              <span>{{ scope.row.publishTime}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column align="center" fixed="right" :label="$t('publics.operating')" width="auto">
+            <template slot-scope="scope">
+              <div class="text-btn-con">
+                <div class="default-btn text-btn" @click="addOrUpdateHandle(scope.row.id)"
+                     >{{$t("crud.updateBtn")}}</div>
+                <div class="default-btn text-btn" @click.stop="deleteHandle(scope.row.id)"
+                     >{{$t("text.delBtn")}}</div>
+                </div>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+        <el-pagination
+          v-if="dataList.length"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+          :current-page="page.currentPage"
+          :page-sizes="[10, 20, 50, 100]"
+          :page-size="page.pageSize"
+          layout="total, sizes, prev, pager, next, jumper"
+          :total="page.total">
+        </el-pagination>
+      </div>
+    <add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="refreshChange"></add-or-update>
+    <promotion-video-upload
+      v-if="uploadVisible"
+      ref="promotionVideoUpload"
+      @refreshDataList="getDataList(page)">
+    </promotion-video-upload>
+  </div>
+</template>
+
+<script>
+import AddOrUpdate from './promotionVideo-add-or-update'
+import PromotionVideoUpload from './promotion-video-upload'
+import InputNumberRange from '@/components/input-number-range'
+import moment from "moment";
+export default {
+  data () {
+    return {
+      dataList: [],
+      page: {
+        total: 0, // 总页数
+        currentPage: 1, // 当前页数
+        pageSize: 10 // 每页显示多少条
+      },
+      shopId: this.$store.state.user.shopId,
+      searchForm: {}, // 搜索
+      dataListLoading: false,
+      addOrUpdateVisible: false,
+      shopList: [],
+      videoPlatformList: [
+        {value: '抖音', label: '抖音'},
+        {value: '小红书', label: '小红书'},
+        {value: '视频号', label: '视频号'},
+        {value: '快手', label: '快手'},
+        {value: 'B站', label: 'B站'},
+      ],
+      publishTimeDateRange:[],
+      uploadVisible: false,
+      fansNumRange: [],
+      likeNumRange: [],
+      commNumRange: [],
+    }
+  },
+  components: {
+    AddOrUpdate,
+    PromotionVideoUpload,
+    InputNumberRange
+  },
+  created () {
+    this.getDataList(this.page);
+  },
+  mounted () {
+    this.getShopList()
+  },
+  methods: {
+    openUploadDialog(){
+      this.uploadVisible = true
+      this.$nextTick(() => {
+        this.$refs.promotionVideoUpload.init()
+      })
+    },
+    jumpToLink(videoUrl){
+      let regex = /https?:\/\/[^\s]+/g // 匹配URL的正则表达式
+      let url =  videoUrl.match(regex) // 返回所有匹配到的链接
+      window.open(url)
+    },
+    clear(){
+      this.searchForm = {}
+      this.publishTimeDateRange = []
+      this.fansNumRange = []
+      this.likeNumRange = []
+      this.commNumRange = []
+    },
+    getShopList() {
+      this.$http({
+        url: this.$http.adornUrl('/shop/shopDetail/getShopList'),
+        method: 'get',
+        params: this.$http.adornParams({shopId: this.shopId})
+      }).then(({ data }) => {
+        if (data) {
+          this.shopList = data
+        }
+      })
+    },
+    getDataList (page) {
+      this.dataListLoading = true
+      this.$http({
+        url: this.$http.adornUrl('/promotion/promotionVideo/page'),
+        method: 'get',
+        params: this.$http.adornParams(
+          Object.assign({
+            current: page == null ? this.page.currentPage : page.currentPage,
+            size: page == null ? this.page.pageSize : page.pageSize,
+            startLikeNum: this.likeNumRange === null ? null : this.likeNumRange[0] ? this.likeNumRange[0]:0,
+            endLikeNum: this.likeNumRange === null ? null : this.likeNumRange[1] ? this.likeNumRange[1]:0,
+            startCommNum: this.commNumRange === null ? null : this.commNumRange[0] ? this.commNumRange[0]:0,
+            endCommNum: this.commNumRange === null ? null : this.commNumRange[1] ? this.commNumRange[1]:0,
+            startFansNum: this.fansNumRange === null ? null : this.fansNumRange[0] ? this.fansNumRange[0]:0,
+            endFansNum: this.fansNumRange === null ? null : this.fansNumRange[1] ? this.fansNumRange[1]:0,
+            startPublishTime: this.publishTimeDateRange === null ? null : this.publishTimeDateRange[0] ? this.publishTimeDateRange[0]:null,
+            endPublishTime: this.publishTimeDateRange === null ? null : this.publishTimeDateRange[1] ? this.publishTimeDateRange[1]:null,
+              shopId: this.$store.state.user.shopId,
+          },
+            this.searchForm
+          )
+        )
+      }).then(({data}) => {
+        this.dataList = data.records
+        this.page.total = data.total
+        this.dataListLoading = false
+      })
+    },
+    querySearch (queryString, cb) {
+      var restaurants = this.videoPlatformList
+      var results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants
+      // 调用 callback 返回建议列表的数据
+      cb(results)
+    },
+    createFilter (queryString) {
+      return (restaurant) => {
+        return (restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0)
+      }
+    },
+    setDateRange(val) {
+      var startDay = null
+      var endDay = null
+      if (val === 1) {
+        startDay = 0
+        endDay = 0
+      } else if (val === 2) {
+        startDay = -1
+        endDay = -1
+      } else if (val === 3) {
+        startDay = -3
+        endDay = -1
+      } else if (val === 4) {
+        startDay = -5
+        endDay = -1
+      } else {
+        return
+      }
+      // 开始时间
+      let startTime = moment().add(startDay, 'days').startOf('days').format('LL')
+      // 结束时间
+      let endTime = moment().add(endDay, 'days').endOf('days').format('LL')
+      this.publishTimeDateRange = [startTime, endTime]
+    },
+    // 新增 / 修改
+    addOrUpdateHandle (id) {
+      this.addOrUpdateVisible = true
+      this.$nextTick(() => {
+        this.$refs.addOrUpdate.init(id)
+      })
+    },
+    deleteHandle (id) {
+      this.$confirm(this.$i18n.t('admin.isDeleOper') + '?', this.$i18n.t('text.tips'), {
+        confirmButtonText: this.$i18n.t('crud.filter.submitBtn'),
+        cancelButtonText: this.$i18n.t('crud.filter.cancelBtn'),
+        type: 'warning'
+      }).then(() => {
+        this.$http({
+          url: this.$http.adornUrl('/promotion/promotionVideo/' + id),
+          method: 'delete',
+          data: this.$http.adornData({})
+        }).then(({ data }) => {
+          this.$message({
+            message: this.$i18n.t('publics.operation'),
+            type: 'success',
+          })
+          this.refreshChange()
+        })
+      }).catch(() => { })
+    },
+    // 刷新回调
+    refreshChange () {
+      this.page.currentPage = 1
+      this.getDataList(this.page)
+    },
+    searchChange (params) {
+      this.page.currentPage = 1
+      this.getDataList(null)
+    },
+    handleSizeChange (val) {
+      this.page.pageSize = val
+      this.getDataList()
+    },
+    handleCurrentChange (val) {
+      this.page.currentPage = val
+      this.getDataList()
+    }
+  }
+}
+</script>
+<style lang="scss">
+.mod-print-promotionVideo {
+}
+</style>