Ver código fonte

Merge branch 'feature_20241129_渠道客诉' into feature_20241118_家装客资

zhujindu 1 ano atrás
pai
commit
2a4e727558

+ 17 - 0
src/api/complaintDetail.js

@@ -0,0 +1,17 @@
+import request from '@/utils/request';
+
+// 不想写
+export function getComplaintCustomerClueInfoById(query) {
+  return request({
+    url: '/mobile/customerClueInfo/getComplaintCustomerClueInfoById',
+    method: 'get',
+    params: query,
+  });
+}
+export function insertCustomerClueAnswerKs(data) {
+  return request({
+    url: '/mobile/customerClueInfo/insertCustomerClueAnswerKs',
+    method: 'post',
+    data,
+  });
+}

+ 23 - 10
src/router/index.js

@@ -46,16 +46,6 @@ const router = new VueRouter({
           name: 'login',
           component: () => import('@/views/home/login.vue'),
         },
-        {
-          path: '/clew',
-          name: 'clew',
-          component: () => import('@/views/clew/index.vue'),
-        },
-        {
-          path: '/clewent',
-          name: 'clew',
-          component: () => import('@/views/clew/clewent.vue'),
-        },
         // {
         //     path: "/logincs",
         //     name: "logincs",
@@ -433,6 +423,29 @@ const router = new VueRouter({
         },
       ],
     },
+    {
+      path: '/clew',
+      component: layout,
+      redirect: '/clew',
+      children: [
+        {
+          path: '/clew',
+          name: 'clew',
+          component: () => import('@/views/clew/index.vue'),
+        },
+        {
+          path: '/clewent',
+          name: 'clewent',
+          component: () => import('@/views/clew/clewent.vue'),
+        },
+        {
+          path: '/complaintDetail',
+          name: 'complaintDetail',
+          meta: { title: '渠道投诉' },
+          component: () => import('@/views/clew/complaintDetail/index.vue'),
+        },
+      ],
+    },
   ],
 });
 export default router;

+ 81 - 0
src/views/clew/complaintDetail/complaintLog.vue

@@ -0,0 +1,81 @@
+<template>
+  <div class="cardclewContent infoDetail">
+    <div class="complaintLog" v-for="(iten, index) in customerClueInfoComplaintList" :key="index">
+      <div class="info">
+        <div class="label">来电分类:</div>
+        <div class="value">
+          <!-- 一级分类 -->
+          <span v-if="iten.customerClassifyName">{{ iten.customerClassifyName }}-</span>
+          <!-- 二级分类 -->
+          <span v-if="iten.customerSubClassifyName">{{ iten.customerSubClassifyName }}-</span>
+          <!-- 三级分类 -->
+          <span v-if="iten.customerThreeClassifyName">{{ iten.customerThreeClassifyName }}</span>
+        </div>
+      </div>
+      <div class="info">
+        <div class="label">用户诉求:</div>
+        <div class="value">{{ iten.userDemand }}</div>
+      </div>
+      <div class="info">
+        <div class="label">反馈内容:</div>
+        <div class="value">{{ iten.feedbackContent }}</div>
+      </div>
+      <div class="info">
+        <div class="label">来点时间:</div>
+        <div class="value">{{ iten.createTime }}</div>
+      </div>
+      <div class="info">
+        <div class="label">来点次数:</div>
+        <div class="value">{{ iten.serialNumber }}</div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getDictOption } from '@/api/index';
+export default {
+  name: 'infoDetail',
+  props: {
+    customerClueInfoComplaintList: {
+      type: Array,
+      default: () => [],
+    },
+  },
+  data() {
+    return {};
+  },
+  activated() {},
+  methods: {},
+};
+</script>
+<style scoped lang="scss">
+.cardclewContent {
+  background: #fff;
+  box-sizing: border-box;
+  padding: 10px 16px;
+  margin: 6px 10px 10px;
+}
+.cardclewContent .info {
+  font-size: 14px;
+  color: #444;
+  line-height: 28px;
+  display: flex;
+  .value {
+    flex: 1;
+  }
+}
+.cardclewContent .title p {
+  padding: 0;
+  margin: 0;
+}
+.cardclewContent .title .textLeft {
+  display: inline-block;
+  padding-bottom: 10px;
+}
+.complaintLog {
+  border-bottom: 1px solid #ccc;
+  margin-bottom: 8px;
+  padding-bottom: 8px;
+}
+</style>

+ 246 - 0
src/views/clew/complaintDetail/followUpHistory.vue

@@ -0,0 +1,246 @@
+<template>
+  <div
+    class="container linep containertext followUpHistory"
+    style="
+      background-color: #fff;
+      width: 94%;
+      margin: 0px auto;
+      border-radius: 6px;
+      font-size: 14px;
+    ">
+    <van-form ref="tabstoreVal">
+      <div v-for="(item, index) in customItemList" :key="index">
+        <div
+          class="formLabel z-cell z-cells z-celly"
+          v-if="item.answerType == 'sz' || item.answerType == 'rq'">
+          <van-cell>
+            <template #title
+              >{{ index + 1 }}.{{ item.customerClueName }}
+              <span
+                style="color: #444; font-size: 12px; margin: 0; padding: 10px 0; text-align: right"
+                >{{ item.remark }}</span
+              ></template
+            >
+          </van-cell>
+          <p class="mg0" style="word-break: break-all">{{ item.answerValue }}</p>
+        </div>
+        <div class="formLabel z-cell z-cells z-celly" v-if="item.answerType == 'zp'">
+          <van-cell>
+            <template #title>{{ index + 1 }}.{{ item.customerClueName }}</template>
+          </van-cell>
+          <delete-upload-imgv :imgs="item.fileInfoList"></delete-upload-imgv>
+        </div>
+        <div
+          class="formLabel z-cell z-cells z-celly"
+          v-if="item.answerType == 'wb' && viewTextShow">
+          <van-cell>
+            <template #title>{{ index + 1 }}.{{ item.customerClueName }}</template>
+          </van-cell>
+          <div class="selesetText">
+            <p class="mg0" style="word-break: break-all">{{ item.answerValue }}</p>
+          </div>
+          <!-- <p style="color: #444; font-size: 12px; margin: 0; padding: 10px 0; text-align: right">
+            {{ item.remark }}
+          </p> -->
+          <delete-upload-imgv :imgs="item.fileInfoList"></delete-upload-imgv>
+        </div>
+
+        <div class="formLabel z-cell z-cells z-celly" v-if="item.answerType == 'duox'">
+          <van-cell>
+            <template #title>{{ index + 1 }}.{{ item.customerClueName }}</template>
+          </van-cell>
+          <div class="selesetText">
+            <div class="mg0" v-for="(item1, index1) in item.customerClueOptionList" :key="index1">
+              <p style="color: #0057ba" v-if="item1.checked">
+                <i
+                  style="
+                    border: 1px solid #0057ba;
+                    margin-right: 10px;
+                    border-radius: 2px;
+                    padding: 2px;
+                  "
+                  class="van-icon van-icon-success"></i>
+                <span>{{ item1.customerClueOption }}</span>
+              </p>
+              <p v-if="!item1.checked">
+                <i
+                  style="
+                    border: 1px solid #ccc;
+                    margin-right: 10px;
+                    border-radius: 2px;
+                    color: #fff;
+                    padding: 2px;
+                  "
+                  class="van-icon van-icon-success"></i>
+                <span>{{ item1.customerClueOption }}</span>
+              </p>
+            </div>
+          </div>
+        </div>
+        <div class="formLabel z-cell z-cells z-celly" v-if="item.answerType == 'dx'">
+          <van-cell>
+            <template #title> {{ index + 1 }}.{{ item.customerClueName }} </template>
+          </van-cell>
+          <div class="selesetText">
+            <div class="mg0" v-for="(item2, index2) in item.customerClueOptionList" :key="index2">
+              <p style="color: #0057ba" v-if="item2.checked">
+                <i
+                  style="
+                    border: 1px solid #0057ba;
+                    border-radius: 40px;
+                    margin-right: 10px;
+                    padding: 2px;
+                  "
+                  class="van-icon van-icon-success"></i>
+                <span>{{ item2.customerClueOption }}</span>
+              </p>
+              <p v-if="!item2.checked">
+                <i
+                  style="
+                    border: 1px solid #ccc;
+                    border-radius: 40px;
+                    margin-right: 10px;
+                    color: #fff;
+                    padding: 2px;
+                  "
+                  class="van-icon van-icon-success"></i>
+                <span>{{ item2.customerClueOption }}</span>
+              </p>
+            </div>
+          </div>
+          <delete-upload-imgv :imgs="item.fileInfoList"></delete-upload-imgv>
+        </div>
+      </div>
+    </van-form>
+  </div>
+</template>
+<script>
+import deleteUploadImg from '@/components/deleteUploadImg2';
+import deleteUploadImgv from '@/components/deleteUploadImg';
+import { getCustomerClueAnswerById } from '@/api/clew';
+export default {
+  components: { deleteUploadImg, deleteUploadImgv },
+  props: {
+    historyId: {
+      type: [String, Number],
+      default: '',
+    },
+    showView: {
+      type: Boolean,
+      default: '',
+    },
+  },
+  data() {
+    return {
+      customItemList: [],
+      viewTextShow: false,
+    };
+  },
+  watch: {
+    showView: {
+      handler(val) {
+        if (val) this.getFollowUpHistory();
+      },
+      immediate: true,
+    },
+  },
+  methods: {
+    getFollowUpHistory(val) {
+      this.toastLoading(0, '加载中...', true);
+      getCustomerClueAnswerById({ userCustomerClueId: this.historyId }).then((res) => {
+        this.toastLoading().clear();
+        this.customItemList = res.data.customerClue.customerClueItemList;
+        for (var pl = 0; pl < this.customItemList[1].customerClueOptionList.length; pl++) {
+          if (
+            this.customItemList[1].customerClueOptionList[pl].customerClueOption.indexOf(
+              '跟进中'
+            ) != -1
+          ) {
+            if (this.customItemList[1].customerClueOptionList[pl].value == 'Y') {
+              this.viewTextShow = true;
+              if (
+                this.customItemList[1].customerClueOptionList[pl].customerClueOption.indexOf(
+                  '跟进'
+                ) != -1
+              ) {
+                this.customItemList[2].customerClueName =
+                  '具体合作意向反馈(拜访时间、合同方向、预估合作时间)';
+              }
+            }
+          } else {
+            if (this.customItemList[1].customerClueOptionList[pl].value == 'Y') {
+              this.viewTextShow = true;
+              if (
+                this.customItemList[1].customerClueOptionList[pl].customerClueOption.indexOf(
+                  '意向'
+                ) != -1
+              ) {
+                this.customItemList[2].customerClueName = '没有意向原因';
+                this.customItemList[2].remark = '请输入';
+              }
+              if (
+                this.customItemList[1].customerClueOptionList[pl].customerClueOption.indexOf(
+                  '开户'
+                ) != -1
+              ) {
+                this.customItemList[2].customerClueName = '开户经销商代码(例:0110067321)';
+                this.customItemList[2].remark = '请输入';
+              }
+              if (
+                this.customItemList[1].customerClueOptionList[pl].customerClueOption.indexOf(
+                  '开店'
+                ) != -1
+              ) {
+                this.customItemList[2].customerClueName = '开户门店代码(例:0190129032)';
+                this.customItemList[2].remark = '请输入';
+              }
+              if (
+                this.customItemList[1].customerClueOptionList[pl].customerClueOption.indexOf(
+                  '出货'
+                ) != -1
+              ) {
+                this.customItemList[2].customerClueName = '填写具体的产品和数量';
+              }
+            }
+          }
+        }
+      });
+    },
+  },
+};
+</script>
+<style lang="scss">
+.followUpHistory {
+  .formLabel {
+    margin: 0 16px;
+    border-bottom: 1px solid #f1f1f1;
+  }
+  .formLabel .van-cell {
+    padding: 10px 0;
+    font-size: 14px;
+  }
+  .formLabel .van-cell::after {
+    border: 0;
+  }
+  .formLabeltext .van-field {
+    border: 1px solid #f1f1f1;
+    padding: 6px;
+    width: 100%;
+    border-radius: 4px;
+    overflow: hidden;
+  }
+  .formLabel .van-field__control {
+    padding: 0 10px;
+  }
+  .z-checkbox .van-radio {
+    padding: 6px 0;
+  }
+  .z-cell .van-cell__title {
+    font-size: 14px;
+  }
+  .formLabel .van-radio__label,
+  .formLabel .van-checkbox__label {
+    font-size: 14px;
+  }
+}
+</style>

+ 377 - 0
src/views/clew/complaintDetail/index.vue

@@ -0,0 +1,377 @@
+<template>
+  <div class="bgcolor complaintDetail">
+    <div class="navBarTOP">
+      <van-nav-bar class="navBar" left-arrow :title="title" @click-left="onClickLeft" />
+    </div>
+    <div class="lineGrey"></div>
+    <div class="lineGrey"></div>
+    <div class="lineGrey"></div>
+    <div class="lineGrey"></div>
+    <div class="lineGrey"></div>
+    <!-- 客诉详情 -->
+    <infoDetail v-if="infoData" :infoData="infoData" :customerClassify="customerClassifyOption">
+    </infoDetail>
+    <!-- 客诉记录 -->
+    <complaintLog
+      v-if="infoData && infoData.customerClueInfoComplaintList.length"
+      :customerClueInfoComplaintList="infoData.customerClueInfoComplaintList"></complaintLog>
+    <!-- 跟进记录 userCustomerClueList -->
+    <!-- 历史跟进记录 -->
+    <p style="margin: 0 16px 8px; color: #888" v-if="infoData && infoData.userCustomerClueList">
+      该客诉历史跟进记录
+    </p>
+    <van-cell-group inset class="cardclewContentCell" v-if="infoData">
+      <div style="border-radius: 6px; overflow: hidden">
+        <van-cell
+          is-link
+          v-for="(item, index) in infoData.userCustomerClueList"
+          :key="index"
+          @click="viewFn(item.userCustomerClueId)">
+          <template #title>
+            <span class="custom-title">{{ item.nickName }}</span>
+          </template>
+          <div class="cardContent">
+            <p class="textLeft" style="padding-bottom: 0px; margin: 0">{{ item.createTime }}</p>
+          </div>
+        </van-cell>
+      </div>
+    </van-cell-group>
+    <!-- 跟进任务填写 -->
+    <div class="assign" v-if="infoData && infoData.isClose != 1">
+      <!-- <div class="assign"> -->
+      <!-- 来电分类 -->
+      <div class="complaintType">
+        <div class="typeItem">
+          <van-field
+            readonly
+            clickable
+            name="picker"
+            :value="customerClassifyValue"
+            label="来电分类一"
+            placeholder="点击选择来电分类一"
+            @click="showPicker1 = true" />
+        </div>
+        <div class="typeItem">
+          <van-field
+            readonly
+            clickable
+            name="picker"
+            :value="customerSubClassifyValue"
+            label="来电分类二"
+            placeholder="点击选择来电分类二"
+            @click="showPicker2 = true" />
+        </div>
+      </div>
+      <!-- <div class="followUp required">跟进结果</div> -->
+      <div class="taskGather" v-if="taskGather">
+        <radioGroup :clueOptionList="taskGather"></radioGroup>
+      </div>
+      <div class="tc" style="padding: 0 16px">
+        <van-button class="submitBtn" block type="info" color="#0057ba" @click="onSubmit">
+          提交
+        </van-button>
+      </div>
+    </div>
+    <!-- 客诉跟进历史 -->
+    <van-dialog
+      v-model="showView"
+      title="客诉历史"
+      show-cancel-button
+      cancel-button-text="关闭"
+      :show-confirm-button="false"
+      class="dialogz">
+      <followUpHistory :historyId="historyId" :showView="showView"></followUpHistory>
+    </van-dialog>
+    <van-popup v-model="showPicker1" position="bottom">
+      <van-picker
+        show-toolbar
+        value-key="dictLabel"
+        :columns="customerClassifyOption"
+        @confirm="onConfirm1"
+        @cancel="showPicker1 = false" />
+    </van-popup>
+    <van-popup v-model="showPicker2" position="bottom">
+      <van-picker
+        show-toolbar
+        value-key="dictLabel"
+        :columns="customerSubClassifyOption"
+        @confirm="onConfirm2"
+        @cancel="showPicker2 = false" />
+    </van-popup>
+  </div>
+</template>
+
+<script>
+import {
+  getComplaintCustomerClueInfoById,
+  insertCustomerClueAnswerKs,
+} from '@/api/complaintDetail';
+import infoDetail from './infoDetail.vue';
+import complaintLog from './complaintLog.vue';
+import { mapState } from 'vuex';
+import radioGroup from './radioGroup';
+import followUpHistory from './followUpHistory';
+import { getDictOption } from '@/api/index';
+
+export default {
+  name: 'complaintDetail',
+  components: {
+    infoDetail,
+    complaintLog,
+    radioGroup,
+    followUpHistory,
+  },
+  computed: {
+    ...mapState({
+      userInfo: (state) => state.user.userInfo,
+    }),
+  },
+  data() {
+    return {
+      id: '',
+      infoData: null,
+      title: '',
+      postName: '',
+      taskGather: null, //跟进任务集合
+      requiredFlag: true, //问题必填检验
+      requiredMessage: '', //必填提示信息
+      showView: false,
+      historyId: '',
+      customerClassifyValue: '',
+      customerClassify: '',
+      customerSubClassifyValue: '',
+      customerSubClassify: '',
+      showPicker1: false,
+      showPicker2: false,
+      customerClassifyOption: [],
+      customerSubClassifyOption: [],
+    };
+  },
+  watch: {},
+  activated() {
+    this.id = this.$route.query.id;
+    this.postName = localStorage.getItem('postName');
+    this.getComplaintCustomerClueInfoByIdFun();
+  },
+  methods: {
+    async getCustomerClassify() {
+      let option = await getDictOption({}, 'customer_classify');
+      this.customerClassifyOption = option.data || [];
+      // 来电分类一
+      let item = this.customerClassifyOption.find(
+        (val) => val.dictValue == this.infoData.customerClassify
+      );
+      this.customerClassifyValue = item.dictLabel || '';
+      this.customerClassify = item.dictValue;
+    },
+    async getCustomerSubClassify() {
+      let option = await getDictOption({}, 'customer_sub_classify');
+      this.customerSubClassifyOption = option.data || [];
+      // 来电分类二
+      let item = this.customerSubClassifyOption.find(
+        (val) => val.dictValue == this.infoData.customerSubClassify
+      );
+      this.customerSubClassifyValue = item.dictLabel || '';
+      this.customerSubClassify = item.dictValue;
+    },
+    getComplaintCustomerClueInfoByIdFun() {
+      this.toastLoading(0, '加载中...', true);
+      this.id = this.$route.query.id;
+      getComplaintCustomerClueInfoById({ customerClueInfoId: this.id }).then((response) => {
+        this.toastLoading().clear();
+        if (response.code == 200) {
+          this.infoData = response.data;
+          this.title = response.data.name;
+          if (this.infoData.isClose != 1) {
+            // response.data.customerClue.customerClueItemList[0].customerClueInfoId = this.id;
+            this.taskGather = response.data.customerClue.customerClueItemList;
+          }
+          this.getCustomerClassify();
+          this.getCustomerSubClassify();
+        } else {
+          this.$toast(res.msg);
+        }
+      });
+    },
+    onSubmit() {
+      // 没有选择跟进记录
+      // if (!this.taskGather[0].searchValue) {
+      //   this.$toast('请选择跟进结果');
+      //   return;
+      // }
+      this.requiredFlag = true;
+      let customerClueItemList = [];
+      // 每一个层级都是一道题的题目,子级就是题,被选中和填写的题要带上题目一块上传(题的同级也要上传)
+      // 第一级题目下的题默认都要上传
+      let params = {
+        customerClueItemList: [],
+        customerClassify: this.customerClassify,
+        customerSubClassify: this.customerSubClassify,
+      };
+      params.customerClueItemList.push(...this.deepClone(this.taskGather, 0));
+      // let optionList = this.taskGather[0].customerClueOptionList;
+      this.filterOption(this.taskGather, params);
+      console.log(JSON.stringify(params));
+      // 必填验证
+      if (this.requiredFlag) {
+        this.toastLoading(0, '加载中...', true);
+        insertCustomerClueAnswerKs(params).then((res) => {
+          this.toastLoading().clear();
+          if (res.code == 200) {
+            this.$toast(res.msg);
+            window.location.replace(window.location.origin + '/mobile/clew');
+          } else {
+            this.$toast(res.msg);
+          }
+        });
+      } 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' && optionList[val].searchValue) {
+          let customerClueOptionList = optionList[val].customerClueOptionList;
+          for (let i = 0; i < customerClueOptionList.length; i++) {
+            if (customerClueOptionList[i].value == 'Y') {
+              if (customerClueOptionList[i].customerClueItemList) {
+                // 必填校验
+                this.isRequiredFlag(customerClueOptionList[i].customerClueItemList);
+                let customerClueItemList =
+                  params.customerClueItemList[val].customerClueOptionList[i].customerClueItemList;
+                customerClueItemList.push(
+                  ...this.deepClone(customerClueOptionList[i].customerClueItemList, 0)
+                );
+                if (customerClueOptionList[i].customerClueItemList[0]) {
+                  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].answerType == 'wb' && optionList[i].isMust == 0) {
+          if (!optionList[i].answerValue) {
+            this.requiredFlag = false;
+            this.requiredMessage = optionList[i].remark;
+            return;
+          }
+        }
+      }
+    },
+    // 校验错误返回信息
+    onFailed(errorInfo) {
+      console.log('failed', errorInfo);
+    },
+    // 查看历史跟进记录
+    viewFn(val) {
+      //   this.viewTextShow = false;
+      this.historyId = val;
+      this.showView = true;
+    },
+    onConfirm1(value) {
+      this.customerClassifyValue = value.dictLabel;
+      this.customerClassify = value.dictValue;
+      this.showPicker1 = false;
+    },
+    onConfirm2(value) {
+      this.customerSubClassifyValue = value.dictLabel;
+      this.customerSubClassify = value.dictValue;
+      this.showPicker2 = false;
+    },
+    onClickLeft() {
+      this.$router.go(-1);
+    },
+  },
+};
+</script>
+<style scoped lang="scss">
+.complaintDetail {
+  .assign {
+    margin: 10px;
+    background-color: #fff;
+    padding-bottom: 20px;
+    .followUp {
+      padding: 16px;
+      font-size: 14px;
+      font-weight: 600;
+    }
+  }
+  .taskGather {
+    padding-left: 20px;
+    .title {
+      font-size: 15px;
+      font-weight: 600;
+      padding: 5px 0;
+    }
+  }
+}
+</style>
+<style lang="scss">
+.complaintDetail {
+  .van-field__label {
+    width: 100px;
+    &::before {
+      content: '*';
+      color: red;
+    }
+  }
+  .centerBtn {
+    float: right;
+    background: #0057ba;
+    border-color: #0057ba;
+    color: #fff;
+    margin-top: -33px;
+    border-radius: 5px;
+  }
+  .dialogz {
+    width: 100%;
+    display: flex;
+    flex-direction: column;
+    overflow: hidden;
+    height: 72vh;
+    .van-dialog__content {
+      flex: 1;
+      overflow-y: auto;
+    }
+  }
+  .van-cell {
+    font-size: 15px;
+    color: #000;
+  }
+}
+</style>

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

@@ -0,0 +1,77 @@
+<template>
+  <div class="cardclewContent infoDetail">
+    <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">区域:{{ infoData.companyName }}</div>
+    <div class="info">省:{{ infoData.provinceName }}</div>
+    <div class="info">市:{{ infoData.cityName }}</div>
+    <div class="info">区/县:{{ infoData.countryName }}</div>
+    <div class="info">
+      分类:
+      <span v-if="customerClassify.length">{{ filterClassify(infoData.customerClassify) }}</span>
+    </div>
+    <div class="info">详细地址:{{ infoData.detailAddress }}</div>
+    <div class="info">商店授权号:{{ infoData.storeCode }}</div>
+    <div class="info">商店地址:{{ infoData.storeAddr }}</div>
+    <slot></slot>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'infoDetail',
+  props: {
+    infoData: {
+      type: Object,
+      default: {},
+    },
+    source: {
+      // assignPage 拥有家装分配权限
+      type: String,
+    },
+    customerClassify: {
+      type: Array,
+      default: () => [],
+    },
+  },
+  data() {
+    return {};
+  },
+  methods: {
+    filterClassify(customerClassify) {
+      let item = this.customerClassify.find((val) => val.dictValue == customerClassify);
+      return item.dictLabel || '';
+    },
+  },
+};
+</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>

+ 139 - 0
src/views/clew/complaintDetail/radioGroup.vue

@@ -0,0 +1,139 @@
+<template>
+  <div class="radioGroup">
+    <template v-for="(val, ind) in clueOptionList">
+      <div class="title" v-if="val.customerClueName">
+        <span class="van-f-red" v-if="val.isMust == 0">*</span>
+        {{ val.customerClueName }}
+      </div>
+      <template v-if="val.answerType == 'dx'">
+        <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">
+              {{ item.customerClueOption }}
+            </van-radio>
+            <radioGroup
+              :clueOptionList="item.customerClueItemList"
+              :parentOptionList="val"
+              :parentId="item.customerClueOptionId"
+              v-if="val.searchValue == item.customerClueOptionId"></radioGroup>
+          </template>
+        </van-radio-group>
+      </template>
+      <template v-if="val.answerType == 'wb'">
+        <template v-if="parentOptionList.searchValue == val.itemOptionParentId">
+          <van-field v-model="val.answerValue" :placeholder="val.remark" />
+        </template>
+      </template>
+    </template>
+  </div>
+</template>
+<script>
+export default {
+  name: 'radioGroup',
+  props: {
+    clueOptionList: {
+      type: Array,
+      default: () => [],
+    },
+    parentOptionList: {
+      type: Object,
+      default: () => {},
+    },
+    parentId: {
+      type: [Number, null],
+      default: null,
+    },
+  },
+  data() {
+    return {};
+  },
+  created() {
+    // console.log(this.clueOptionList);
+  },
+  methods: {
+    radioGroupChange(name) {
+      if (!name) return;
+      // console.log(name);
+      // console.log(this.clueOptionList);
+      // 如果选中的数据有父级,将父级数据修改为选中状态
+      if (this.parentOptionList && this.parentId) {
+        this.$set(this.parentOptionList, 'searchValue', this.parentId);
+      }
+      // 获取选中数据
+      let clueOptionList = this.clueOptionList.find((val) => val.searchValue == name);
+      let activaRadio = clueOptionList.customerClueOptionList.find(
+        (val) => val.customerClueOptionId == name
+      );
+      // 修改选中状态
+      this.$set(activaRadio, 'value', 'Y');
+
+      // 过滤未选中的数据
+      let exceptItself = clueOptionList.customerClueOptionList.filter(
+        (val) => val.customerClueOptionId !== name
+      );
+      // 删除未选中数据状态兄弟级和子级
+      // console.log(exceptItself);
+      this.toggleOtheChildren(exceptItself);
+    },
+    toggleOtheChildren(exceptItself) {
+      if (!exceptItself) return;
+      exceptItself.forEach((val) => {
+        this.$set(val, 'value', 'N');
+        if (val.customerClueItemList && val.customerClueItemList[0]) {
+          this.$set(val.customerClueItemList[0], 'searchValue', null);
+          if (
+            val.customerClueItemList[0] &&
+            val.customerClueItemList[0].customerClueOptionList.length
+          ) {
+            this.toggleOtheChildren(val.customerClueItemList[0].customerClueOptionList);
+          }
+        }
+      });
+    },
+    radioClick(event) {
+      // console.log(event);
+    },
+  },
+};
+</script>
+<style lang="scss">
+.radioGroup {
+  font-size: 15px;
+  .van-radio {
+    padding: 5px 0;
+  }
+  .van-radio-group {
+    padding-left: 20px;
+  }
+  .van-cell {
+    padding: 10px 0;
+    /* font-size: 14px; */
+  }
+  .van-cell::after {
+    border: 0;
+  }
+  .van-field {
+    border: 1px solid #cdc8c8;
+    padding: 0;
+    width: 100%;
+    border-radius: 4px;
+    overflow: hidden;
+    background-color: unset;
+    height: 30px;
+    line-height: 30px;
+    margin: 5px 0;
+  }
+  .van-field__control {
+    padding: 0 10px;
+  }
+  .van-field__control {
+    padding: 0 10px;
+  }
+  .van-radio__label {
+    /* font-size: 14px; */
+  }
+  .van-f-red {
+    font-size: 14px;
+  }
+}
+</style>

+ 62 - 5
src/views/clew/index.vue

@@ -1,7 +1,16 @@
 <template>
-  <div class="bgcolor">
+  <div class="bgcolor clew">
     <div class="navBarTOP">
-      <van-nav-bar class="navBar" title="客资任务" left-arrow @click-left="onClickLeft" />
+      <van-nav-bar class="navBar" title="客资任务" left-arrow @click-left="onClickLeft">
+        <template #right>
+          <van-dropdown-menu>
+            <van-dropdown-item
+              v-model="cid"
+              :options="customerClueOption"
+              @change="dropdownChange" />
+          </van-dropdown-menu>
+        </template>
+      </van-nav-bar>
       <van-tabs v-model="isHandle" color="#0057ba" @change="tabChange">
         <van-tab title="未跟进" name="-1" :disabled="disabled"></van-tab>
         <van-tab title="跟进中" name="0" :disabled="disabled"></van-tab>
@@ -32,6 +41,7 @@
                 <span v-if="item.cid == 4">开设门店</span>
                 <span v-if="item.cid == 5">批量采购</span>
                 <span v-if="item.cid == 7">家装客资</span>
+                <span v-if="item.cid == 9">渠道客诉</span>
               </div>
               <div class="info">联系电话:{{ item.phone }}</div>
               <div class="info" v-if="item.createTime">首次接入时间:{{ item.createTime }}</div>
@@ -49,6 +59,7 @@
 
 <script>
 import { infolist } from '@/api/clew';
+import { getDictOption } from '@/api';
 export default {
   name: 'clew',
   data() {
@@ -58,9 +69,12 @@ export default {
       loading: false,
       list: [],
       finished: true,
+      cid: -1,
+      customerClueOption: [],
     };
   },
   activated() {
+    this.getCustomerClue();
     this.approveList();
   },
   watch: {
@@ -81,6 +95,18 @@ export default {
     next();
   },
   methods: {
+    async getCustomerClue() {
+      let option = await getDictOption({}, 'customer_clue');
+      let arr = [{ text: '全部', value: -1 }];
+      option.data.forEach((val) => {
+        arr.push({
+          text: val.dictLabel,
+          value: val.dictValue,
+        });
+      });
+      this.customerClueOption = arr;
+      console.log(this.customerClueOption);
+    },
     submit() {
       var taskIds = [];
       var instanceIds = [];
@@ -113,7 +139,13 @@ export default {
         });
     },
     approveFn(row) {
-      if (row.cid == 7) {
+      if (row.cid == 9) {
+        // 渠道客诉
+        this.$router.push({
+          path: '/complaintDetail',
+          query: { id: row.customerClueInfoId },
+        });
+      } else if (row.cid == 7) {
         // 家装客资跟进
         this.$router.push({
           path: '/JZfollowUp',
@@ -140,20 +172,25 @@ export default {
         message: '数据加载中...',
         forbidClick: true,
       });
-      infolist({ type: this.isHandle }).then((res) => {
+      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;
       });
     },
+    dropdownChange(value) {
+      this.list = [];
+      this.pageNum = 1;
+      this.approveList();
+    },
     onClickLeft() {
       this.$router.push('/My/index');
     },
   },
 };
 </script>
-<style>
+<style lang="scss">
 .newCarList {
   margin: 14px;
   border-radius: 8px;
@@ -199,4 +236,24 @@ export default {
 .van-tab--active {
   color: #0057ba;
 }
+.clew {
+  .van-nav-bar {
+    z-index: 2;
+  }
+  .van-nav-bar__right {
+    height: 40px;
+    margin-top: 3px;
+    .van-dropdown-menu {
+      height: 100%;
+      border: 1px solid #f4f0f0;
+    }
+  }
+  .van-dropdown-menu__bar {
+    padding: 0 4px;
+    height: 100%;
+  }
+  .van-dropdown-menu__title::after {
+    right: 0 !important;
+  }
+}
 </style>