浏览代码

Merge branch 'feature_20241224_客资任务跟踪题目填写添加表格选项'

zhujindu 11 月之前
父节点
当前提交
48c4e81bc5

+ 151 - 0
src/components/complaintImg.vue

@@ -0,0 +1,151 @@
+<template>
+  <div class="cameraDiv1">
+    <p class="coverImg" @click="uploadImg">
+      <van-icon class="photo ico" name="photograph" size="16px" color="#969696"></van-icon>
+    </p>
+  </div>
+</template>
+
+<script>
+import { ImagePreview } from 'vant';
+import axios from 'axios';
+import { addPhotoK } from '@/api/clew';
+import { getPosition, getTicketFun } from '@/utils/TXApiFun';
+
+export default {
+  name: 'uploadImg',
+  props: {
+    itemData: {
+      type: Object,
+      default: {},
+    },
+    isRequired: {
+      // 是否开启拍照前校验
+      type: Boolean,
+      default: true,
+    },
+    customerClueId: {
+      type: String | Number,
+      default: '',
+    },
+    customerClueItemId: {
+      type: String | Number,
+      default: '',
+    },
+  },
+  data() {
+    return {};
+  },
+  created() {
+    // 授权
+    getTicketFun(['chooseImage', 'uploadImage']).then(() => {});
+  },
+  methods: {
+    uploadImg() {
+      // 拍照前校验
+      if (this.required) {
+      }
+      this.wx.ready(() => {
+        this.wx.chooseImage({
+          count: 1,
+          sizeType: ['original'], // 可以指定是原图还是压缩图,默认二者都有 compressed:压缩后的图片;original:原图
+          sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
+          defaultCameraMode: 'normal', //表示进入拍照界面的默认模式,目前有normal与batch两种选择,normal表示普通单拍模式,batch表示连拍模式,不传该参数则为normal模式。从3.0.26版本开始支持front和batch_front两种值,其中front表示默认为前置摄像头单拍模式,batch_front表示默认为前置摄像头连拍模式。(注:用户进入拍照界面仍然可自由切换两种模式)
+          isSaveToAlbum: 0,
+          success: (res) => {
+            let localIds = '';
+            if (res.localIds != undefined) {
+              localIds = res.localIds[0];
+            } else {
+              localIds = res.localId;
+            }
+            // andriod中localId可以作为img标签的src属性显示图片;
+            // iOS应当使用 getLocalImgData 获取图片base64数据,从而用于img标签的显示(在img标签内使用 wx.chooseImage 的 localid 显示可能会不成功)
+            wx.uploadImage({
+              localId: localIds, // 需要上传的图片的本地ID,由chooseImage接口获得
+              isShowProgressTips: 1, // 默认为1,显示进度提示
+              success: (res) => {
+                this.addPhotoK(res.serverId);
+              },
+            });
+          },
+        });
+      });
+    },
+    addPhotoK(meidaId) {
+      var form = {
+        mediaId: meidaId,
+        customerClueId: this.customerClueId,
+        customerClueItemId: this.customerClueItemId,
+      };
+      this.toastLoading(0, '加载中...', true);
+      addPhotoK(form).then((res) => {
+        this.toastLoading().clear();
+        if (res.code == 200) {
+          this.$toast('上传成功!');
+          this.$emit('newimgarr', {
+            fileUrl: res.data.url,
+            id: res.data.fileId,
+            itemData: this.itemData,
+          });
+        } else {
+          this.$toast('上传失败!');
+        }
+      });
+    },
+  },
+};
+</script>
+
+<style scoped>
+.cameraDiv1 {
+  height: 100%;
+  width: 100%;
+}
+
+.cameraDiv1 img {
+  /* position: absolute;
+  width: 100%;
+  display: block;
+  height: 20px;
+  top: 0; */
+}
+
+.imgPre {
+  height: 20px;
+  width: 100%;
+  background-color: white;
+  border-radius: 6px;
+  overflow: hidden;
+}
+
+.photos1 {
+  margin: 0px auto;
+  left: 20%;
+  margin-left: -14px;
+}
+
+.photobrowsing {
+  position: absolute;
+  padding: 4px;
+  right: 0;
+  top: 0;
+  z-index: 99;
+  background-color: rgba(255, 255, 255, 0.8);
+  border-bottom-left-radius: 3px;
+  border-top-left-radius: 3px;
+}
+
+.coverImg {
+  height: 100%;
+  width: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin: 0;
+}
+
+.coverImg .ico {
+  top: 0%;
+}
+</style>

+ 85 - 0
src/components/deletComplaintImg.vue

@@ -0,0 +1,85 @@
+<template>
+  <div v-if="itemData.fileInfoList">
+    <van-col span="6" v-for="(urls, index) in itemData.fileInfoList" :key="index">
+      <div class="imgview2">
+        <van-icon name="close" size="16" v-on:click="deleteImg(index, urls.id)" />
+        <img :src="urls.fileUrl" width="100px" height="100px" @click="previewsImg(index)" />
+      </div>
+    </van-col>
+  </div>
+</template>
+
+<script>
+import { ImagePreview } from 'vant';
+import { removeSummaryPhoto, removePhoto } from '@/api/index';
+
+export default {
+  name: 'deleteUploadImg',
+  props: {
+    itemData: {
+      type: Object,
+      default: {},
+    },
+  },
+  data() {
+    return {
+      url: process.env.VUE_APP_Target1 + process.env.VUE_APP_BASE_API,
+    };
+  },
+  methods: {
+    deleteImg(index, id) {
+      var fileName = {
+        fileId: id,
+      };
+      removeSummaryPhoto(fileName).then((res) => {
+        if (res.code == 200) {
+          this.$toast('删除成功!');
+          this.$emit('deleteImg', { itemData: this.itemData, index: index });
+          // this.imgs.splice(index, 1);
+        } else {
+          this.$toast('删除失败!');
+        }
+      });
+    },
+    previewsImg(index) {
+      var arrimg = [];
+      for (var imgi = 0; imgi < this.itemData.fileInfoList.length; imgi++) {
+        arrimg.push(this.itemData.fileInfoList[imgi].fileUrl);
+      }
+      ImagePreview({
+        images: arrimg,
+        startPosition: index,
+        onClose() {
+          // do something
+        },
+      });
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.imgview2 {
+  height: 80px;
+  width: 80px;
+  padding: 3px;
+  /* border: 1px solid #ccc; */
+  height: 72px;
+  position: relative;
+  border-radius: 5px;
+  display: inline-block;
+  i {
+    position: absolute;
+    right: -2px;
+    top: -3px;
+    color: white;
+    background: red;
+    overflow: hidden;
+    border-radius: 50%;
+  }
+  img {
+    width: 100%;
+    height: 100%;
+  }
+}
+</style>

+ 25 - 20
src/components/deleteUploadImg2.vue

@@ -2,9 +2,14 @@
   <div>
     <van-col span="6" v-for="(urls, index) in imgs" :key="index">
       <div class="imgview2">
-        <van-icon name="close" size="16" v-on:click="deleteImg(index,urls.id)"/>
-        <img v-if="urls.type=='2'" :src="urls.fileUrl" width="100px" height="100px" @click="previewsImg(index)"/>
-        <img v-else :src="urls.fileUrl" width="100px" height="100px" @click="previewsImg(index)"/>
+        <van-icon name="close" size="16" v-on:click="deleteImg(index, urls.id)" />
+        <img
+          v-if="urls.type == '2'"
+          :src="urls.fileUrl"
+          width="100px"
+          height="100px"
+          @click="previewsImg(index)" />
+        <img v-else :src="urls.fileUrl" width="100px" height="100px" @click="previewsImg(index)" />
       </div>
     </van-col>
   </div>
@@ -18,8 +23,8 @@
 </template>
 
 <script>
-import {ImagePreview} from "vant";
-import {removeSummaryPhoto, removePhoto} from "@/api/index";
+import { ImagePreview } from 'vant';
+import { removeSummaryPhoto, removePhoto } from '@/api/index';
 
 export default {
   name: 'deleteUploadImg',
@@ -27,44 +32,44 @@ export default {
     imgs: {
       type: Array,
       default() {
-        return []
-      }
+        return [];
+      },
     },
   },
   data() {
     return {
-      url: process.env.VUE_APP_Target1 + process.env.VUE_APP_BASE_API
-    }
+      url: process.env.VUE_APP_Target1 + process.env.VUE_APP_BASE_API,
+    };
   },
   methods: {
     deleteImg(index, collectionItemId) {
-      var fileName={
-        fileId:collectionItemId
-      }
-      removeSummaryPhoto(fileName).then(res => {
+      var fileName = {
+        fileId: collectionItemId,
+      };
+      removeSummaryPhoto(fileName).then((res) => {
         if (res.code == 200) {
-          this.$toast("删除成功!")
+          this.$toast('删除成功!');
           this.imgs.splice(index, 1);
         } else {
-          this.$toast("删除失败!")
+          this.$toast('删除失败!');
         }
-      })
+      });
     },
     previewsImg(index) {
-      var arrimg = []
+      var arrimg = [];
       for (var imgi = 0; imgi < this.imgs.length; imgi++) {
-        arrimg.push(this.imgs[imgi].fileUrl)
+        arrimg.push(this.imgs[imgi].fileUrl);
       }
       ImagePreview({
         images: arrimg,
         startPosition: index,
         onClose() {
           // do something
-        }
+        },
       });
     },
   },
-}
+};
 </script>
 
 <style lang="scss" scoped>

+ 19 - 4
src/components/uploadImgVStorec.vue

@@ -48,6 +48,15 @@ export default {
       type: String,
       default: '',
     },
+    itemData: {
+      type: Object,
+      default: {},
+    },
+    isRequired: {
+      // 是否开启拍照前校验
+      type: Boolean,
+      default: true,
+    },
   },
   data() {
     return {
@@ -60,9 +69,11 @@ export default {
       ImagePreview([val]);
     },
     uploadImg() {
-      if (localStorage.getItem('chainName') == null) {
-        this.$toast('请输入名称!');
-        return;
+      if (this.required) {
+        if (localStorage.getItem('chainName') == null) {
+          this.$toast('请输入名称!');
+          return;
+        }
       }
       let url = window.location.href;
       let that = this;
@@ -137,7 +148,11 @@ export default {
           });
           loind1.clear();
           that.$toast('上传成功!');
-          that.$emit('newimgarr', { fileUrl: imgArr.join(','), type: that.type });
+          that.$emit('newimgarr', {
+            fileUrl: imgArr.join(','),
+            type: that.type,
+            itemData: itemData,
+          });
         } else {
           that.$toast('上传失败!');
         }

+ 138 - 0
src/mixin/clew.js

@@ -0,0 +1,138 @@
+export const clewMixins = {
+  data() {
+    return {};
+  },
+  computed: {},
+  created() {},
+  mounted() {},
+  methods: {
+    purchaseSubmit(callback) {
+      this.requiredFlag = true;
+      // 每一个层级都是一道题的题目,子级就是题,被选中和填写的题要带上题目一块上传(题的同级也要上传)
+      // 第一级题目下的题默认都要上传
+      let params = {
+        customerClueItemList: [],
+      };
+      // 复制第一级题目
+      params.customerClueItemList.push(...this.deepClone(this.taskGather, 0));
+      this.filterOption(this.taskGather, params);
+      console.log(JSON.stringify(params));
+      // 必填验证
+      if (this.requiredFlag) {
+        callback && callback(params);
+      } else {
+        this.$toast(this.requiredMessage);
+      }
+    },
+    filterOption(optionList, params) {
+      for (let val = 0; val < optionList.length; val++) {
+        if (
+          optionList[val].isMust == '0' &&
+          optionList[val].searchValue == null &&
+          optionList[val].answerType == 'dx'
+        ) {
+          // 题目必填校验
+          this.requiredFlag = false;
+          this.requiredMessage = '请选择' + optionList[val].customerClueName;
+          return;
+        } else if (optionList[val].isMust == '0') {
+          // 子级题校验
+          let customerClueOptionList = optionList[val].customerClueOptionList;
+          if (customerClueOptionList.length) {
+            for (let i = 0; i < customerClueOptionList.length; i++) {
+              // 选中的题目Y:选中,N:未选中
+              if (customerClueOptionList[i].value == 'Y') {
+                if (customerClueOptionList[i].customerClueItemList) {
+                  // 必填校验
+                  this.isRequiredFlag(customerClueOptionList[i].customerClueItemList);
+                  // 赋值选中题
+                  let customerClueItemList = params.customerClueItemList;
+                  customerClueItemList.push(
+                    ...this.deepClone(customerClueOptionList[i].customerClueItemList, 0)
+                  );
+                  if (customerClueOptionList[i].customerClueItemList.length) {
+                    this.filterOption(customerClueOptionList[i].customerClueItemList, params);
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    // 深拷贝指定拷贝层级
+    deepClone(obj, num) {
+      // 检查是否为对象或数组
+      if (obj === null || typeof obj !== 'object') {
+        return obj; // 基本类型直接返回
+      }
+      // 创建一个数组或对象
+      const copy = Array.isArray(obj) ? [] : {};
+      // 遍历对象的每个属性
+      for (const key in obj) {
+        // 每个题只复制两层子级
+        if (obj.hasOwnProperty(key) && num < 2) {
+          // 递归调用深拷贝
+          if (key == 'customerClueOptionList' || key == 'customerClueItemList') {
+            num = num + 1;
+          }
+          copy[key] = this.deepClone(obj[key], num);
+        }
+      }
+      return copy;
+    },
+    isRequiredFlag(optionList) {
+      // console.log(optionList);
+      for (let i = 0; i < optionList.length; i++) {
+        // 是否必填
+        if (optionList[i].isMust == 0) {
+          // 输入框
+          if (optionList[i].answerType == 'wb' || optionList[i].answerType == 'sz') {
+            if (!optionList[i].answerValue) {
+              // 必填类型
+              this.requiredFlag = false;
+              this.requiredMessage = optionList[i].remark;
+              return;
+            } else {
+              // 条件校验
+              if (optionList[i].minTextLength) {
+                // 输入内容长度校验
+                if (optionList[i].answerValue.length < optionList[i].minTextLength) {
+                  this.requiredFlag = false;
+                  this.requiredMessage = optionList[i].remark;
+                  return;
+                }
+              }
+            }
+          } else if (optionList[i].answerType == 'zp') {
+            // 照片
+            if (!optionList[i].fileInfoList || !optionList[i].fileInfoList.length) {
+              this.requiredFlag = false;
+              this.requiredMessage = optionList[i].remark;
+              return;
+            }
+          } else if (optionList[i].answerType == 'bg') {
+            // 表格
+            let tableData = optionList[i].tableData;
+            if (!this.filterBGData(tableData).length) {
+              this.requiredFlag = false;
+              this.requiredMessage = '请填写' + optionList[i].customerClueName;
+              return;
+            } else {
+              optionList[i].answerValue = JSON.stringify(tableData);
+            }
+          }
+        }
+      }
+    },
+    filterBGData(tableData) {
+      let data = [];
+      const isValid = tableData.data.some((row) => {
+        if (Object.values(row).every((value) => value.trim() !== '')) {
+          data.push(row);
+        }
+      });
+      return data;
+    },
+  },
+};

+ 1 - 0
src/store/getters.js

@@ -1,4 +1,5 @@
 const getters = {
   userInfo: (state) => state.user.userInfo,
+  refreshClewPage: (state) => state.isRefreshPage.refreshClewPage,
 };
 export default getters;

+ 2 - 0
src/store/index.js

@@ -1,6 +1,7 @@
 import Vue from 'vue';
 import Vuex from 'vuex';
 import user from './modules/user';
+import isRefreshPage from './modules/isRefreshPage';
 import getters from './getters';
 
 Vue.use(Vuex);
@@ -8,6 +9,7 @@ Vue.use(Vuex);
 const store = new Vuex.Store({
   modules: {
     user,
+    isRefreshPage,
   },
   getters,
 });

+ 19 - 0
src/store/modules/isRefreshPage.js

@@ -0,0 +1,19 @@
+const isRefreshPage = {
+  state: {
+    refreshClewPage: false,
+  },
+
+  mutations: {
+    SET_REFRESH_CLEW_PAGE: (state, value) => {
+      state.refreshClewPage = value;
+    },
+  },
+
+  actions: {
+    setRefreshClewPage({ commit }, value) {
+      commit('SET_REFRESH_CLEW_PAGE', value);
+    },
+  },
+};
+
+export default isRefreshPage;

+ 3 - 0
src/utils/request.js

@@ -5,6 +5,7 @@
 import axios from 'axios';
 import { Toast, Dialog } from 'vant';
 import errorCode from '@/utils/errorCode';
+import { toastLoading } from '@/utils/commonVant';
 
 axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8';
 const service = axios.create({
@@ -15,6 +16,7 @@ const service = axios.create({
 // request拦截器
 service.interceptors.request.use(
   (config) => {
+    toastLoading(0, '加载中...', true);
     config.headers['userId'] = localStorage.getItem('loginName');
     return config;
   },
@@ -26,6 +28,7 @@ service.interceptors.request.use(
 // 响应拦截器
 service.interceptors.response.use(
   (res) => {
+    toastLoading().clear();
     const code = res.data.code || 200;
     const msg = errorCode[code] || res.data.msg || errorCode['default'];
     if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {

文件差异内容过多而无法显示
+ 586 - 528
src/views/clew/clewent.vue


+ 83 - 0
src/views/clew/clewentDetails.vue

@@ -0,0 +1,83 @@
+<template>
+  <div class="cardclewContent clewentDetails">
+    <div class="info">
+      客资线索:<span v-if="infoData.cid == 3">申请代理</span
+      ><span v-if="infoData.cid == 4">开设门店</span><span v-if="infoData.cid == 5">批量采购</span>
+    </div>
+    <div class="info">区域:{{ infoData.companyName }}</div>
+    <div class="info">省:{{ infoData.provinceName }}</div>
+    <div class="info">市:{{ infoData.cityName }}</div>
+    <div class="info">区/县:{{ infoData.countryName }}</div>
+    <div class="info">姓名:{{ infoData.name }}</div>
+    <div class="info">
+      来电电话:<a
+        style="color: #0057ba; font-weight: bold; text-decoration: underline"
+        :href="'tel:' + infoData.phone"
+        >{{ infoData.phone }}<van-icon name="phone"
+      /></a>
+    </div>
+    <div class="info">
+      有无涂料从业经验:<span v-if="infoData.paintExperience == 1">有</span
+      ><span v-if="infoData.paintExperience == 2">无</span>
+    </div>
+    <div class="info">目前经营的行业:{{ infoData.industry }}</div>
+    <div class="info">目前经营的品牌:{{ infoData.brand }}</div>
+    <div class="info">
+      目前有无实体店:<span v-if="infoData.physicalStore == 1">有</span
+      ><span v-if="infoData.physicalStore == 2">无</span>
+    </div>
+    <div class="info" v-if="infoData.createTime">首次接入时间:{{ infoData.createTime }}</div>
+    <div class="info" v-if="infoData.latestClueTime">
+      最后一次跟进时间:{{ infoData.latestClueTime }}
+    </div>
+    <div class="info">
+      跟进状态:<span v-if="infoData.isClose == 1">跟进完成</span
+      ><span v-if="infoData.isClose == 0">跟进中</span
+      ><span v-if="infoData.isClose == -1">未跟进</span>
+    </div>
+    <div class="info" v-if="infoData.followUpResult" style="word-break: break-all">
+      跟进结果:{{ infoData.followUpResult }}
+    </div>
+    <slot></slot>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'clewentDetails',
+  props: {
+    infoData: {
+      type: Object,
+      default: {},
+    },
+  },
+  data() {
+    return {};
+  },
+  methods: {},
+};
+</script>
+<style scoped lang="scss">
+.cardclewContentCell {
+  margin: 0 10px;
+}
+.cardclewContent {
+  background: #fff;
+  box-sizing: border-box;
+  padding: 10px 16px;
+  margin: 6px 10px 10px;
+}
+.cardclewContent .info {
+  font-size: 14px;
+  color: #444;
+  line-height: 28px;
+}
+.cardclewContent .title p {
+  padding: 0;
+  margin: 0;
+}
+.cardclewContent .title .textLeft {
+  display: inline-block;
+  padding-bottom: 10px;
+}
+</style>

+ 31 - 20
src/views/clew/complaintDetail/index.vue

@@ -255,9 +255,9 @@ export default {
       let item = this.customerClassifyOption.find(
         (val) => val.dictValue == this.infoData.customerClassify
       );
-      this.customerClassifyValue = item.remark || '';
-      this.customerClassify = item.dictValue;
-      this.getCustomerSubClassify(this.customerClassify);
+      this.customerClassifyValue = item ? item.remark : '';
+      this.customerClassify = item ? item.dictValue : '';
+      if (this.customerClassify != '') this.getCustomerSubClassify(this.customerClassify);
     },
     async getCustomerSubClassify(parentId) {
       let option = await customerSubClassify({ parentId: parentId });
@@ -348,12 +348,15 @@ export default {
           this.requiredMessage = '请选择' + optionList[val].customerClueName;
           return;
         } else if (optionList[val].isMust == '0' && optionList[val].searchValue) {
+          // 子级题校验
           let customerClueOptionList = optionList[val].customerClueOptionList;
           for (let i = 0; i < customerClueOptionList.length; i++) {
+            // 选中的题目Y:选中,N:未选中
             if (customerClueOptionList[i].value == 'Y') {
               if (customerClueOptionList[i].customerClueItemList) {
                 // 必填校验
                 this.isRequiredFlag(customerClueOptionList[i].customerClueItemList);
+                // 赋值选中题
                 let customerClueItemList =
                   params.customerClueItemList[val].customerClueOptionList[i].customerClueItemList;
                 customerClueItemList.push(
@@ -391,25 +394,33 @@ export default {
     isRequiredFlag(optionList) {
       // console.log(optionList);
       for (let i = 0; i < optionList.length; i++) {
-        if (
-          (optionList[i].answerType == 'wb' || optionList[i].answerType == 'wb') &&
-          optionList[i].isMust == 0
-        ) {
-          if (!optionList[i].answerValue) {
-            // 必填类型
-            this.requiredFlag = false;
-            this.requiredMessage = optionList[i].remark;
-            return;
-          } else {
-            // 条件校验
-            if (optionList[i].minTextLength) {
-              // 输入内容长度校验
-              if (optionList[i].answerValue.length < optionList[i].minTextLength) {
-                this.requiredFlag = false;
-                this.requiredMessage = optionList[i].remark;
-                return;
+        // 是否必填
+        if (optionList[i].isMust == 0) {
+          // 输入框
+          if (optionList[i].answerType == 'wb' || optionList[i].answerType == 'sz') {
+            if (!optionList[i].answerValue) {
+              // 必填类型
+              this.requiredFlag = false;
+              this.requiredMessage = optionList[i].remark;
+              return;
+            } else {
+              // 条件校验
+              if (optionList[i].minTextLength) {
+                // 输入内容长度校验
+                if (optionList[i].answerValue.length < optionList[i].minTextLength) {
+                  this.requiredFlag = false;
+                  this.requiredMessage = optionList[i].remark;
+                  return;
+                }
               }
             }
+          } else if (optionList[i].answerType == 'zp') {
+            // 照片
+            if (!optionList[i].fileInfoList || !optionList[i].fileInfoList.length) {
+              this.requiredFlag = false;
+              this.requiredMessage = optionList[i].remark;
+              return;
+            }
           }
         }
       }

+ 1 - 0
src/views/clew/complaintDetail/infoDetail.vue

@@ -45,6 +45,7 @@ export default {
   },
   methods: {
     filterClassify(customerClassify) {
+      if (!customerClassify) return '';
       let item = this.customerClassify.find((val) => val.dictValue == customerClassify);
       return item.dictLabel || '';
     },

+ 123 - 3
src/views/clew/complaintDetail/radioGroup.vue

@@ -1,11 +1,15 @@
 <template>
   <div class="radioGroup">
     <template v-for="(val, ind) in clueOptionList">
-      <div class="title" v-if="val.customerClueName">
+      <!-- <div class="title" v-if="val.customerClueName">
         <span class="van-f-red" v-if="val.isMust == 0">*</span>
         {{ val.customerClueName }}
-      </div>
+      </div> -->
       <template v-if="val.answerType == 'dx'">
+        <div class="title" v-if="val.customerClueName">
+          <span class="van-f-red" v-if="val.isMust == 0">*</span>
+          {{ val.customerClueName }}
+        </div>
         <van-radio-group v-model="val.searchValue" @change="radioGroupChange">
           <template v-for="(item, index) in val.customerClueOptionList">
             <van-radio :name="item.customerClueOptionId" :key="index" @click="radioClick">
@@ -19,8 +23,12 @@
           </template>
         </van-radio-group>
       </template>
-      <!-- 回答类型:wb-文本,sz-数字,rq-日期,zp-照片,dx -->
+      <!-- 回答类型:wb-文本,sz-数字,rq-日期,zp-照片,dx-单选,bg-表格 -->
       <template v-if="val.answerType == 'wb'">
+        <div class="title" v-if="val.customerClueName">
+          <span class="van-f-red" v-if="val.isMust == 0">*</span>
+          {{ val.customerClueName }}
+        </div>
         <template v-if="parentOptionList.searchValue == val.itemOptionParentId">
           <van-field
             v-model="val.answerValue"
@@ -38,7 +46,12 @@
           </span>
         </template>
       </template>
+      <!-- 数字输入框 -->
       <template v-if="val.answerType == 'sz'">
+        <div class="title" v-if="val.customerClueName">
+          <span class="van-f-red" v-if="val.isMust == 0">*</span>
+          {{ val.customerClueName }}
+        </div>
         <van-field
           class="fieldInput"
           v-model="val.answerValue"
@@ -47,11 +60,71 @@
           :error-message="val.remark"
           type="number"></van-field>
       </template>
+      <!-- 照片 -->
+      <template v-if="val.answerType == 'zp'">
+        <van-cell>
+          <template #title>
+            <span v-if="val.isMust == 0" class="van-f-red">*</span>
+            {{ val.customerClueName }}
+            <!-- 操作说明图片和电话 -->
+            <taskTips
+              v-if="val.contactPhone || val.examplePhoto"
+              :contactPhone="val.contactPhone"
+              :examplePhoto="val.examplePhoto">
+            </taskTips>
+          </template>
+          <template #right-icon>
+            <span v-if="val.isMust == '0'" style="color: red">图片必填</span>
+            <div class="uploadImg">
+              <complaintImg
+                uploadid="uploadid2"
+                :itemData="val"
+                @newimgarr="newimgarr1"
+                :customerClueId="val.customerClueId"
+                :customerClueItemId="val.customerClueItemId"
+                :required="false">
+              </complaintImg>
+            </div>
+            <!-- <van-icon color="#666" name="photograph" size="24" @click="imgClick(val)" /> -->
+          </template>
+        </van-cell>
+        <deletComplaintImg :itemData="val" @deleteImg="deleteImg"></deletComplaintImg>
+      </template>
+      <!-- 表格 -->
+      <template v-if="val.answerType == 'bg'">
+        <div class="title" v-if="val.customerClueName">
+          <span class="van-f-red" v-if="val.isMust == 0">*</span>
+          {{ val.customerClueName }}
+        </div>
+        <el-table :data="val.tableData.data" style="width: 100%; position: relative; left: -10px">
+          <el-table-column
+            v-for="(item, index) in val.tableData.title"
+            :prop="item.prop"
+            :label="item.label"
+            align="center">
+            <template slot-scope="scope">
+              <template v-if="item.answerType == 'text'">
+                {{ scope.row[item.prop] }}
+              </template>
+              <template v-if="item.answerType == 'wb'">
+                <van-field v-model="scope.row[item.prop]" />
+              </template>
+              <template v-if="item.answerType == 'sz'">
+                <van-field v-model="scope.row[item.prop]" type="number" />
+              </template>
+            </template>
+          </el-table-column>
+        </el-table>
+      </template>
     </template>
   </div>
 </template>
 <script>
+import taskTips from '@/views/deviceWithin/taskTips';
+import deletComplaintImg from '@/components/deletComplaintImg';
+import complaintImg from '@/components/complaintImg';
 export default {
+  components: { deletComplaintImg, taskTips, complaintImg },
   name: 'radioGroup',
   props: {
     clueOptionList: {
@@ -70,6 +143,19 @@ export default {
   data() {
     return {};
   },
+  watch: {
+    clueOptionList: {
+      handler(val) {
+        val.forEach((item) => {
+          // bg表格数据存在remark
+          if (item.answerType == 'bg') {
+            this.$set(item, 'tableData', JSON.parse(item.remark));
+          }
+        });
+      },
+      immediate: true,
+    },
+  },
   created() {
     // console.log(this.clueOptionList);
   },
@@ -116,6 +202,32 @@ export default {
     radioClick(event) {
       // console.log(event);
     },
+    imgClick(val) {
+      this.show = true;
+    },
+    // 设置照片数据
+    newimgarr1(val) {
+      console.log(val);
+      let fileInfoList = [{ fileUrl: val.fileUrl, id: val.id }].concat(
+        val.itemData.fileInfoList ? val.itemData.fileInfoList : []
+      );
+      this.$set(val.itemData, 'fileInfoList', fileInfoList);
+      this.setFileIdList(val);
+    },
+    // 设置照片id
+    setFileIdList(val) {
+      let fileIdList = [];
+      let fileInfoList = val.itemData.fileInfoList || [];
+      fileInfoList.forEach((val) => {
+        fileIdList.push(val.id);
+      });
+      this.$set(val.itemData, 'fileIdList', fileIdList);
+    },
+    // 删除照片
+    deleteImg(val) {
+      val.itemData.fileInfoList.splice(val.index, 1);
+      this.setFileIdList(val);
+    },
   },
 };
 </script>
@@ -167,5 +279,13 @@ export default {
     font-size: 12px;
     padding: 3px 0;
   }
+  .uploadImg {
+    width: 50px;
+  }
+  .el-table {
+    .el-table__cell {
+      padding: 3px 0;
+    }
+  }
 }
 </style>

+ 19 - 8
src/views/clew/index.vue

@@ -63,8 +63,15 @@
 <script>
 import { infolist } from '@/api/clew';
 import { getDictOption } from '@/api';
+import { mapState } from 'vuex';
+import store from '@/store';
 export default {
   name: 'clew',
+  computed: {
+    ...mapState({
+      refreshClewPage: (state) => state.isRefreshPage.refreshClewPage,
+    }),
+  },
   data() {
     return {
       isHandle: '-1',
@@ -76,11 +83,21 @@ export default {
       customerClueOption: [],
     };
   },
-  activated() {
+  created() {
     this.getCustomerClue();
     this.approveList();
   },
+  activated() {},
   watch: {
+    refreshClewPage: {
+      handler(val) {
+        if (val) {
+          this.approveList();
+          store.dispatch('setRefreshClewPage', false);
+        }
+      },
+      immediate: true,
+    },
     $route(to, from) {
       if (to.path == '/clew' && from.path == '/My/index') {
         this.isHandle = '-1';
@@ -157,7 +174,7 @@ export default {
         });
       } else {
         // 非家装客资跟进
-        this.list = [];
+        // this.list = [];
         this.$router.push({
           path: '/clewent',
           query: { id: row.customerClueInfoId },
@@ -171,13 +188,7 @@ export default {
       this.approveList();
     },
     approveList() {
-      let loading1 = this.$toast.loading({
-        duration: 0,
-        message: '数据加载中...',
-        forbidClick: true,
-      });
       infolist({ type: this.isHandle, cid: this.cid == -1 ? null : this.cid }).then((res) => {
-        loading1.clear();
         this.disabled = false;
         this.loading = false;
         this.list = res.data;