浏览代码

feature:跟进记录增加协访渠道和人员信息,合同页面添加运维信息导出功能

sunxinyuan 1 年之前
父节点
当前提交
4963c11b11

+ 4 - 0
src/api/contract/index.js

@@ -54,4 +54,8 @@ export default {
   getContractShareList(query) {
     return micro_request.postRequest(basePath, 'CtrContract', 'GetContractShareList', query)
   },
+  // 合同项目运维信息导出
+  exportMaintenance(query) {
+    return micro_request.postRequest(basePath, 'CtrContract', 'CtrContractMaintenanceExport', query)
+  },
 }

+ 5 - 0
src/views/base/agent/detail.vue

@@ -131,6 +131,9 @@
           <el-tab-pane label="历史代理记录" name="historyProxy">
             <history-proxy v-if="activeName == 'historyProxy'" />
           </el-tab-pane>
+          <el-tab-pane label="协访记录" name="visit">
+            <visit v-if="activeName == 'visit'" ref="followEl" target-type="50" />
+          </el-tab-pane>
         </el-tabs>
       </div>
       <div class="info-side">
@@ -158,11 +161,13 @@
   import DetailsRecords from './components/DetailsRecords'
   import BusinessTarget from './components/BusinessTarget'
   import Follow from '../components/Follow'
+  import Visit from '../components/Visit'
   import FollowAdd from '@/views/proj/business/components/FollowAdd'
 
   export default {
     name: 'DistributorDetail',
     components: {
+      Visit,
       DetailsRecords,
       Contacts,
       ProjectRecords,

+ 248 - 0
src/views/base/components/Visit.vue

@@ -0,0 +1,248 @@
+<template>
+  <div style="height: 100%">
+    <ul v-if="followList.length" class="follow">
+      <li v-for="(date, index) in followList" :key="index">
+        <div class="date">
+          <h2>{{ date.followDay.split('-')[2] }}</h2>
+          <h3>
+            {{ date.followDay.split('-').splice(0, 2).join('.') }}
+          </h3>
+        </div>
+        <ul class="content">
+          <li v-for="(item, idx) in date.followupList" :key="idx">
+            <!-- <el-avatar class="user-avatar"
+              :src="avatar" />-->
+            <div class="text-container">
+              <vab-icon class="user-avatar" icon="account-circle-fill" />
+              <div class="text">
+                <p class="action">
+                  <span>{{ item.createdName }} 跟进({{ selectDictLabel(followTypeOptions, item.followType) }})</span>
+                  <span>
+                    <vab-icon icon="time-line" />
+                    {{ item.followDate }}
+                  </span>
+                </p>
+                <p>{{ item.followContent }}</p>
+                <p v-if="item.distName" style="white-space: pre-wrap">渠道: {{ item.distName }}</p>
+                <p v-if="item.visitorName" style="white-space: pre-wrap">协访人员:{{ item.visitorName }}</p>
+                <div class="footer">
+                  <!-- <p>
+                    来自客户:
+                    <span>{{ item.custName }}</span>
+                  </p> -->
+                  <div>
+                    <el-button icon="el-icon-edit" size="mini" @click="postComments(item)">发表评论</el-button>
+                    <el-button size="mini" @click="showDetail(item)">
+                      <vab-icon icon="arrow-right-circle-fill" />
+                      详情
+                    </el-button>
+                    <!--                    <el-button size="mini" @click="showComment(item)">评论({{ item.commentNumber }})</el-button>-->
+                  </div>
+                </div>
+              </div>
+            </div>
+            <transition name="height">
+              <ul class="comments">
+                <li v-for="comment in item.comments" :key="comment.id">
+                  <vab-icon class="user-avatar" icon="account-circle-fill" />
+                  <div class="text">
+                    <p>{{ comment.createdName }}</p>
+                    <p>{{ comment.content }}</p>
+                    <p>{{ comment.createdTime }}</p>
+                  </div>
+                </li>
+              </ul>
+            </transition>
+          </li>
+        </ul>
+      </li>
+    </ul>
+    <div v-else class="no-follow">暂无协访记录</div>
+    <!-- 跟进详情 -->
+    <FollowDetail ref="followDetail" />
+  </div>
+</template>
+
+<script>
+  import to from 'await-to-js'
+  import FollowDetail from './FollowDetail.vue'
+  import followApi from '@/api/customer/follow'
+  export default {
+    components: { FollowDetail },
+    props: {
+      targetType: {
+        type: String,
+        required: true,
+      },
+    },
+    data() {
+      return {
+        followList: [], //跟进记录
+        followTypeOptions: [],
+      }
+    },
+    mounted() {
+      this.getOptions()
+      this.getFollowList()
+    },
+    methods: {
+      getOptions() {
+        Promise.all([this.getDicts('plat_follow_type')]).then(([followType]) => {
+          this.followTypeOptions = followType.data.values || []
+        })
+      },
+      async getFollowList() {
+        let params = {
+          distId: this.$route.query.id.toString(),
+          // targetType: this.targetType,
+          DaysBeforeToday: 9999,
+        }
+        const [err, res] = await to(followApi.getListByDay(params))
+        if (err) return
+        this.followList = res.data.list || []
+      },
+      // 跟进记录详情
+      showDetail(row) {
+        this.$refs.followDetail.init({ ...row })
+      },
+      // 发表评论
+      postComments(row) {
+        this.$PostComment({ form: row, visible: true })
+          .then(() => {
+            this.getFollowList()
+          })
+          .catch(() => {})
+      },
+      // 展开评论
+      showComment(row) {
+        if (!row.comments.length) return this.$message.warning('暂无评论')
+        row.showComment = !row.showComment
+        this.$forceUpdate()
+      },
+    },
+  }
+</script>
+
+<style lang="scss" scoped>
+  .follow {
+    height: 100%;
+    padding: 10px 20px;
+    overflow: auto;
+
+    > li {
+      display: flex;
+
+      + li {
+        margin-top: 10px;
+      }
+    }
+
+    .date {
+      width: 100px;
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+
+      h2,
+      h3 {
+        margin: 0;
+      }
+
+      h2 {
+        font-size: 26px;
+        line-height: 32px;
+      }
+    }
+
+    .content {
+      flex: 1;
+      list-style: none;
+
+      > li {
+        border: 1px solid rgb(215, 232, 244);
+        background: rgb(247, 251, 254);
+        border-radius: 4px;
+        padding: 8px;
+        overflow: hidden;
+
+        .text-container {
+          display: flex;
+        }
+
+        .comments {
+          padding-left: 60px;
+          margin-top: 10px;
+          max-height: 200px;
+          overflow: auto;
+
+          li {
+            display: flex;
+            border-top: 1px solid #e3e5e7;
+
+            .text {
+              flex: 1;
+              padding: 0 10px;
+
+              p {
+                font-weight: 500;
+                margin: 0;
+                line-height: 32px;
+              }
+
+              p:first-child {
+                line-height: 30px;
+                font-weight: bold;
+              }
+
+              p:last-child {
+                font-size: 12px;
+                color: #9499a0;
+                text-align: right;
+              }
+            }
+          }
+        }
+
+        + li {
+          margin-top: 10px;
+        }
+      }
+
+      .user-avatar {
+        font-size: 40px;
+      }
+
+      .text {
+        flex: 1;
+        padding-left: 20px;
+        padding-right: 10px;
+
+        p {
+          font-weight: 500;
+          margin: 0;
+          line-height: 32px;
+
+          span {
+            color: #1d66dc;
+          }
+        }
+
+        .action {
+          display: flex;
+          justify-content: space-between;
+
+          span:first-child {
+            font-weight: bold;
+            color: #333;
+          }
+        }
+
+        .footer {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+        }
+      }
+    }
+  }
+</style>

+ 5 - 1
src/views/base/distributor/detail.vue

@@ -102,6 +102,9 @@
           <el-tab-pane label="历史代理记录" name="historyProxy">
             <history-proxy v-if="activeName == 'historyProxy'" />
           </el-tab-pane>
+          <el-tab-pane label="协访记录" name="visit">
+            <visit v-if="activeName == 'visit'" ref="followEl" target-type="50" />
+          </el-tab-pane>
         </el-tabs>
       </div>
       <div class="info-side">
@@ -128,11 +131,12 @@
   import HistoryProxy from '../components/HistoryProxy'
   import DetailsRecords from './components/DetailsRecords'
   import Follow from '../components/Follow'
+  import Visit from '../components/Visit'
   import FollowAdd from '@/views/proj/business/components/FollowAdd'
 
   export default {
     name: 'DistributorDetail',
-    components: { DetailsRecords, Contacts, ProjectRecords, ContractRecords, HistoryProxy, Follow, FollowAdd },
+    components: { DetailsRecords, Contacts, ProjectRecords, ContractRecords, HistoryProxy, Follow, FollowAdd, Visit },
     data() {
       return {
         id: 0,

+ 93 - 0
src/views/contract/index.vue

@@ -71,6 +71,7 @@
               type="daterange"
               value-format="yyyy-MM-dd" />
           </el-form-item>
+
           <el-form-item prop="contractSignTime">
             <el-date-picker
               v-model="queryForm.contractSignTime"
@@ -80,8 +81,48 @@
               type="daterange"
               value-format="yyyy-MM-dd" />
           </el-form-item>
+
+          <el-form-item prop="softwareMaintenanceBeginTime">
+            <el-date-picker
+              v-model="queryForm.softwareMaintenanceBeginTime"
+              end-placeholder="软件运维时间开始"
+              range-separator="至"
+              start-placeholder="软件运维时间开始"
+              type="daterange"
+              value-format="yyyy-MM-dd" />
+          </el-form-item>
+          <el-form-item prop="softwareMaintenanceEndTime">
+            <el-date-picker
+              v-model="queryForm.softwareMaintenanceEndTime"
+              end-placeholder="软件运维时间结束"
+              range-separator="至"
+              start-placeholder="软件运维时间结束"
+              type="daterange"
+              value-format="yyyy-MM-dd" />
+          </el-form-item>
+          <el-form-item prop="hardwareMaintenanceBeginTime">
+            <el-date-picker
+              v-model="queryForm.hardwareMaintenanceBeginTime"
+              end-placeholder="硬件运维时间开始"
+              range-separator="至"
+              start-placeholder="硬件运维时间开始"
+              type="daterange"
+              value-format="yyyy-MM-dd" />
+          </el-form-item>
+          <el-form-item prop="hardwareMaintenanceEndTime">
+            <el-date-picker
+              v-model="queryForm.hardwareMaintenanceEndTime"
+              end-placeholder="硬件运维时间结束"
+              range-separator="至"
+              start-placeholder="硬件运维时间结束"
+              type="daterange"
+              value-format="yyyy-MM-dd" />
+          </el-form-item>
           <el-form-item>
             <el-button icon="el-icon-search" type="primary" @click="queryData">查询</el-button>
+            <el-button v-permissions="['contract:manage:exportMaintenance']" type="primary" @click="exportMaintenance">
+              导出
+            </el-button>
           </el-form-item>
         </el-form>
       </vab-query-form-top-panel>
@@ -272,6 +313,10 @@
           custCity: null,
           filterDate: [],
           contractSignTime: [],
+          softwareMaintenanceBeginTime: [],
+          softwareMaintenanceEndTime: [],
+          hardwareMaintenanceBeginTime: [],
+          hardwareMaintenanceEndTime: [],
         },
         provinceOptions: [],
         selectRows: [], //选择的表格数据
@@ -445,6 +490,22 @@
           params.contractSignTimeStart = this.queryForm.contractSignTime[0]
           params.contractSignTimeEnd = this.queryForm.contractSignTime[1]
         }
+        if (this.queryForm.softwareMaintenanceBeginTime && this.queryForm.softwareMaintenanceBeginTime.length === 2) {
+          params.softwareMaintenanceBeginTimeStart = this.queryForm.softwareMaintenanceBeginTime[0]
+          params.softwareMaintenanceBeginTimeEnd = this.queryForm.softwareMaintenanceBeginTime[1]
+        }
+        if (this.queryForm.softwareMaintenanceEndTime && this.queryForm.softwareMaintenanceEndTime.length === 2) {
+          params.softwareMaintenanceEndTimeStart = this.queryForm.softwareMaintenanceEndTime[0]
+          params.softwareMaintenanceEndTimeEnd = this.queryForm.softwareMaintenanceEndTime[1]
+        }
+        if (this.queryForm.hardwareMaintenanceBeginTime && this.queryForm.hardwareMaintenanceBeginTime.length === 2) {
+          params.hardwareMaintenanceBeginTimeStart = this.queryForm.hardwareMaintenanceBeginTime[0]
+          params.hardwareMaintenanceBeginTimeEnd = this.queryForm.hardwareMaintenanceBeginTime[1]
+        }
+        if (this.queryForm.hardwareMaintenanceEndTime && this.queryForm.hardwareMaintenanceEndTime.length === 2) {
+          params.hardwareMaintenanceEndTimeStart = this.queryForm.hardwareMaintenanceEndTime[0]
+          params.hardwareMaintenanceEndTimeEnd = this.queryForm.hardwareMaintenanceEndTime[1]
+        }
         const [err, res] = await to(contractApi.getList(params))
         if (err) return (this.listLoading = false)
         this.list = res.data.list || []
@@ -452,6 +513,38 @@
         this.listLoading = false
         this.$nextTick(() => this.$refs.table.doLayout())
       },
+      async exportMaintenance() {
+        const params = { ...this.queryForm }
+        params.custProvinceId = params.custProvince ? params.custProvince.id : 0
+        params.custCityId = params.custCity ? params.custCity.id : 0
+        if (this.queryForm.filterDate && this.queryForm.filterDate.length === 2) {
+          params.contractEndTimeStart = this.queryForm.filterDate[0]
+          params.contractEndTimeEnd = this.queryForm.filterDate[1]
+        }
+        if (this.queryForm.contractSignTime && this.queryForm.contractSignTime.length === 2) {
+          params.contractSignTimeStart = this.queryForm.contractSignTime[0]
+          params.contractSignTimeEnd = this.queryForm.contractSignTime[1]
+        }
+        if (this.queryForm.softwareMaintenanceBeginTime && this.queryForm.softwareMaintenanceBeginTime.length === 2) {
+          params.softwareMaintenanceBeginTimeStart = this.queryForm.softwareMaintenanceBeginTime[0]
+          params.softwareMaintenanceBeginTimeEnd = this.queryForm.softwareMaintenanceBeginTime[1]
+        }
+        if (this.queryForm.softwareMaintenanceEndTime && this.queryForm.softwareMaintenanceEndTime.length === 2) {
+          params.softwareMaintenanceEndTimeStart = this.queryForm.softwareMaintenanceEndTime[0]
+          params.softwareMaintenanceEndTimeEnd = this.queryForm.softwareMaintenanceEndTime[1]
+        }
+        if (this.queryForm.hardwareMaintenanceBeginTime && this.queryForm.hardwareMaintenanceBeginTime.length === 2) {
+          params.hardwareMaintenanceBeginTimeStart = this.queryForm.hardwareMaintenanceBeginTime[0]
+          params.hardwareMaintenanceBeginTimeEnd = this.queryForm.hardwareMaintenanceBeginTime[1]
+        }
+        if (this.queryForm.hardwareMaintenanceEndTime && this.queryForm.hardwareMaintenanceEndTime.length === 2) {
+          params.hardwareMaintenanceEndTimeStart = this.queryForm.hardwareMaintenanceEndTime[0]
+          params.hardwareMaintenanceEndTimeEnd = this.queryForm.hardwareMaintenanceEndTime[1]
+        }
+        const [err, res] = await to(contractApi.exportMaintenance(params))
+        if (err) return (this.listLoading = false)
+        window.open(res.data)
+      },
       handleApply(row) {
         this.$refs.applyContract.form.id = row.id
         this.$refs.applyContract.openDialog(row)

+ 2 - 0
src/views/customer/detail.vue

@@ -140,6 +140,8 @@
                           </span>
                         </p>
                         <p style="white-space: pre-wrap">{{ item.followContent }}</p>
+                        <p v-if="item.distName" style="white-space: pre-wrap">渠道: {{ item.distName }}</p>
+                        <p v-if="item.visitorName" style="white-space: pre-wrap">协访人员:{{ item.visitorName }}</p>
                         <div class="footer">
                           <p>
                             来自客户:

+ 34 - 0
src/views/proj/business/components/FollowAdd.vue

@@ -76,6 +76,23 @@
             </el-upload>
           </el-form-item>
         </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="渠道" prop="distName">
+            <el-input
+              v-model="form.distName"
+              placeholder="请选择渠道"
+              readonly
+              suffix-icon="el-icon-search"
+              @focus="openDistributor" />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="协访人员" prop="visitorName">
+            <el-input v-model="form.visitorName" placeholder="请输入协访人员" />
+          </el-form-item>
+        </el-col>
         <!--        <el-col :span="12">-->
         <!--          <el-form-item label="提醒对象" prop="reminders">-->
         <!--            <el-input v-model="form.reminders" />-->
@@ -107,6 +124,7 @@
       :query-params="queryContact"
       @save="selectContact" />
 
+    <SelectDist ref="selectDist" :multiple="false" @save="getDistributor" />
     <select-distributor
       ref="selectDistributor"
       :query-params="queryContact"
@@ -122,6 +140,7 @@
   import to from 'await-to-js'
   import followApi from '@/api/customer/follow'
   import SelectDistributor from '@/components/select/SelectDistributorContact'
+  import SelectDist from '@/components/select/SelectDistributor'
   import SelectUser from '@/components/select/SelectUser'
   import asyncUploadFile from '@/utils/uploadajax'
   import SelectCustomerContact from '@/components/select/SelectCustomerContact'
@@ -134,6 +153,7 @@
       SelectBusinessContact,
       SelectDistributor,
       SelectUser,
+      SelectDist,
     },
     data() {
       return {
@@ -159,6 +179,9 @@
           nextTime: '',
           remark: '',
           supportName: '',
+          distId: '',
+          distName: '',
+          visitorName: '',
           files: [],
         },
         rules: {
@@ -303,6 +326,17 @@
           }
         })
       },
+      // 打开选择经销商
+      openDistributor() {
+        this.$refs.selectDist.open()
+      },
+      // 关闭经销商获取经销商信息
+      getDistributor(data) {
+        let distributor = data[0] || null
+        if (!distributor) return
+        this.form.distName = distributor.distName
+        this.form.distId = distributor.id
+      },
 
       // 上传图片
       beforeAvatarUpload(file) {