Przeglądaj źródła

feature(项目管理): 项目管理修改

ZZH-wl 2 lat temu
rodzic
commit
0a2e6f0f61

+ 6 - 6
src/api/customer/index.js

@@ -16,7 +16,7 @@ export default {
   },
   // 客户详情内容摘要
   getAbstract(query) {
-    return micro_request.postRequest(basePath, 'Customer', 'CustAbstract', query)
+    return micro_request.postRequest(basePath, 'Customer', 'GetCustAbstract', query)
   },
   // 客户编辑
   updateCostomer(query) {
@@ -24,7 +24,7 @@ export default {
   },
   // 客户合并
   mergeCustomer(query) {
-    return micro_request.postRequest(basePath, 'Customer', 'Mergecustomer', query)
+    return micro_request.postRequest(basePath, 'Customer', 'MergeCustomer', query)
   },
   // 客户联系人详情
   getContact(query) {
@@ -64,15 +64,15 @@ export default {
   },
   // 客户领取
   receiveCustomer(query) {
-    return micro_request.postRequest(basePath, 'Customer', 'DistriCustomer', query)
+    return micro_request.postRequest(basePath, 'Customer', 'AssignCustomer', query)
   },
   // 客户转移
   updateBytransfer(query) {
-    return micro_request.postRequest(basePath, 'Customer', 'UpdateBytransfer', query)
+    return micro_request.postRequest(basePath, 'Customer', 'TransCustomer', query)
   },
   // 省份
   getProvinceInfo(query) {
-    return micro_request.postRequest(basePath, 'District', 'GetProvinceInfo', query)
+    return micro_request.postRequest(basePath, 'District', 'GetProvinceList', query)
   },
   // 省份详情
   getProvinceDetail(query) {
@@ -88,6 +88,6 @@ export default {
   },
   //导出
   deriveList(query) {
-    return micro_request.postRequest(basePath, 'Customer', 'DeriveList', query)
+    return micro_request.postRequest(basePath, 'Customer', 'Export', query)
   },
 }

+ 8 - 5
src/components/select/SelectBusiness.vue

@@ -1,5 +1,5 @@
 <template>
-  <el-dialog append-to-body :title="title" :visible.sync="innerVisible">
+  <el-dialog append-to-body :title="title" :visible.sync="innerVisible" @close="close">
     <el-row>
       <el-col :span="24">
         <div style="float: right">
@@ -102,7 +102,7 @@
         checkList: [],
         columns: [
           {
-            label: '商机标题',
+            label: '项目标题',
             width: 'auto',
             prop: 'nboName',
             sortable: true,
@@ -119,17 +119,17 @@
             prop: 'approStatus',
           },
           {
-            label: '商机状态',
+            label: '项目状态',
             width: 'auto',
             prop: 'nboPhase',
           },
           {
-            label: '商机类别',
+            label: '项目类别',
             width: 'auto',
             prop: 'nboType',
           },
           {
-            label: '商机金额',
+            label: '项目金额',
             width: 'auto',
             prop: 'nboBudget',
           },
@@ -163,6 +163,9 @@
       open() {
         this.innerVisible = true
       },
+      close() {
+        this.selectRows = []
+      },
       save() {
         this.innerVisible = false
         this.$emit('save', this.selectRows)

+ 195 - 0
src/components/select/SelectBusinessContact.vue

@@ -0,0 +1,195 @@
+<template>
+  <el-dialog append-to-body :title="title" :visible.sync="innerVisible" @close="close">
+    <el-row>
+      <el-col :span="24">
+        <el-input
+          v-model="queryForm.keyword"
+          clearable
+          placeholder="客户名称/手机/电话"
+          style="width: 30%; margin-right: 10px"
+          suffix-icon="el-icon-search" />
+        <table-tool :check-list.sync="checkList" :columns="columns" style="float: right" />
+      </el-col>
+    </el-row>
+    <el-table ref="contactTable" v-loading="listLoading" :data="list" @selection-change="setSelectRows">
+      <el-table-column align="center" type="selection" />
+      <el-table-column
+        v-for="(item, index) in finallyColumns"
+        :key="index"
+        align="center"
+        :label="item.label"
+        :prop="item.prop"
+        show-overflow-tooltip
+        :sortable="item.sortable"
+        :width="item.width">
+        <template #default="{ row }">
+          <span v-if="item.prop === 'custStatus'">
+            {{ row.custStatus == 10 ? '正常' : '异常' }}
+          </span>
+          <span v-else>{{ row[item.prop] }}</span>
+        </template>
+      </el-table-column>
+    </el-table>
+    <el-pagination
+      background
+      :current-page="queryForm.pageNo"
+      :layout="layout"
+      :page-size="queryForm.pageSize"
+      :total="total"
+      @current-change="handleCurrentChange"
+      @size-change="handleSizeChange" />
+    <span slot="footer">
+      <el-button size="mini" type="primary" @click="save">保存</el-button>
+      <el-button size="mini" @click="innerVisible = false">取消</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+  import businessContactApi from '@/api/proj/businessContact'
+  import TableTool from '@/components/table/TableTool'
+
+  export default {
+    name: 'SelectContact',
+    components: {
+      TableTool,
+    },
+    props: {
+      title: {
+        type: String,
+        default: '选择客户联系人',
+      },
+      addButton: Boolean,
+      multiple: Boolean,
+      // 示例{ custId: id, custName: custName}
+      defaultCustomer: {
+        type: Object,
+        default() {
+          return {}
+        },
+      },
+      queryParams: {
+        type: Object,
+        default() {
+          return {}
+        },
+      },
+    },
+    data() {
+      return {
+        innerVisible: false,
+        queryForm: {
+          keyword: '',
+          pageNum: 1,
+          pageSize: 10,
+        },
+        checkList: [],
+        columns: [
+          {
+            label: '联系人姓名',
+            width: 'auto',
+            prop: 'cuctName',
+            // sortable: true,
+            disableCheck: true,
+          },
+          {
+            label: '客户名称',
+            width: 'auto',
+            prop: 'custName',
+          },
+          {
+            label: '手机号码',
+            width: 'auto',
+            prop: 'telephone',
+          },
+          {
+            label: '微信',
+            width: 'auto',
+            prop: 'wechat',
+          },
+          {
+            label: '邮箱',
+            width: 'auto',
+            prop: 'email',
+          },
+          {
+            label: '职务',
+            width: 'auto',
+            prop: 'postion',
+          },
+          {
+            label: '关键决策人',
+            width: 'auto',
+            prop: 'policy',
+          },
+          {
+            label: '性别',
+            width: 'auto',
+            prop: 'cuctGender',
+            // sortable: true,
+          },
+        ],
+        list: [],
+        listLoading: true,
+        layout: 'total, sizes, prev, pager, next, jumper',
+        total: 0,
+        selectRows: [],
+      }
+    },
+    computed: {
+      finallyColumns() {
+        return this.columns.filter((item) => this.checkList.includes(item.label))
+      },
+    },
+    mounted() {},
+    methods: {
+      open() {
+        this.innerVisible = true
+        this.fetchData()
+      },
+      close() {
+        this.selectRows = []
+      },
+      save() {
+        this.innerVisible = false
+        this.$emit('save', this.selectRows)
+      },
+      async fetchData() {
+        this.listLoading = true
+        let query = Object.assign(this.queryForm, this.queryParams)
+        const { data } = await businessContactApi.getList(query)
+        if (data) {
+          this.list = data.list
+          this.total = data.total
+        }
+        this.listLoading = false
+      },
+      setSelectRows(val) {
+        if (!this.multiple && val.length === this.list.length && val.length > 1) {
+          // 返回单条数据情况下-控制全选情况下单选第一条数据
+          this.$refs.contactTable.clearSelection()
+          if (this.selectRows.length === 1) {
+            return
+          }
+          this.$refs.contactTable.toggleRowSelection(val.shift(), true)
+        } else if (!this.multiple && val.length > 1) {
+          // 返回单条数据情况下-控制选择当前点击数据
+          this.$refs.contactTable.clearSelection()
+          this.$refs.contactTable.toggleRowSelection(val.pop(), true)
+        } else {
+          this.selectRows = val
+        }
+      },
+      handleSizeChange(val) {
+        this.queryForm.pageSize = val
+        this.fetchData()
+      },
+      handleCurrentChange(val) {
+        this.queryForm.pageNo = val
+        this.fetchData()
+      },
+    },
+  }
+</script>
+
+<style scoped></style>

+ 4 - 1
src/components/select/SelectCustomer.vue

@@ -1,5 +1,5 @@
 <template>
-  <el-dialog append-to-body :title="title" :visible.sync="innerVisible">
+  <el-dialog append-to-body :title="title" :visible.sync="innerVisible" @close="close">
     <el-row>
       <el-col :span="24">
         <div style="float: right">
@@ -167,6 +167,9 @@
       open() {
         this.innerVisible = true
       },
+      close() {
+        this.selectRows = []
+      },
       save() {
         this.innerVisible = false
         this.$emit('save', this.selectRows)

+ 4 - 1
src/components/select/SelectContact.vue → src/components/select/SelectCustomerContact.vue

@@ -1,5 +1,5 @@
 <template>
-  <el-dialog append-to-body :title="title" :visible.sync="innerVisible">
+  <el-dialog append-to-body :title="title" :visible.sync="innerVisible" @close="close">
     <el-row>
       <el-col :span="24">
         <div style="float: right">
@@ -170,6 +170,9 @@
         this.innerVisible = true
         this.fetchData()
       },
+      close() {
+        this.selectRows = []
+      },
       save() {
         this.innerVisible = false
         console.log(this.selectRows)

+ 4 - 1
src/components/select/SelectDistributor.vue

@@ -1,5 +1,5 @@
 <template>
-  <el-dialog append-to-body :title="title" :visible.sync="innerVisible">
+  <el-dialog append-to-body :title="title" :visible.sync="innerVisible" @close="close">
     <el-row>
       <el-col :span="24">
         <div style="float: right">
@@ -163,6 +163,9 @@
       open() {
         this.innerVisible = true
       },
+      close() {
+        this.selectRows = []
+      },
       save() {
         this.innerVisible = false
         this.$emit('save', this.selectRows)

+ 4 - 1
src/components/select/SelectProduct.vue

@@ -1,5 +1,5 @@
 <template>
-  <el-dialog append-to-body :title="title" :visible.sync="innerVisible">
+  <el-dialog append-to-body :title="title" :visible.sync="innerVisible" @close="close">
     <el-row>
       <el-col :span="24">
         <div style="float: right">
@@ -164,6 +164,9 @@
       open() {
         this.innerVisible = true
       },
+      close() {
+        this.selectRows = []
+      },
       save() {
         this.innerVisible = false
         this.$emit('save', this.selectRows)

+ 1 - 4
src/components/table/TableTool.vue

@@ -42,10 +42,7 @@
         </vab-draggable>
       </el-checkbox-group>
       <template #reference>
-        <el-button
-          icon="el-icon-setting"
-          style="margin: 0 10px 10px 0 !important; font-size: 18px; color: black"
-          type="text" />
+        <el-button icon="el-icon-setting" style="margin: 0 10px 10px 0 !important" />
       </template>
     </el-popover>
   </div>

+ 1 - 1
src/views/customer/components/Merge.vue

@@ -11,7 +11,7 @@
     <el-alert :closable="false" show-icon type="warning">
       <div slot="title">
         <h3>特别提示</h3>
-        <p>1、合并后系统只保留目标客户,同时将另一个客户的联系人、商机、订单、附件、销售动态等迁移到目标客户。</p>
+        <p>1、合并后系统只保留目标客户,同时将另一个客户的联系人、项目、订单、附件、销售动态等迁移到目标客户。</p>
         <p>2、红色字段表示两个客户该字段值不同。</p>
       </div>
     </el-alert>

+ 4 - 4
src/views/customer/detail.vue

@@ -133,10 +133,10 @@
               <el-descriptions-item label="未跟进时长">
                 {{ abstract.notFollowDay }}
               </el-descriptions-item>
-              <el-descriptions-item label="商机数量">
+              <el-descriptions-item label="项目数量">
                 {{ abstract.business }}
               </el-descriptions-item>
-              <el-descriptions-item label="商机总额">
+              <el-descriptions-item label="项目总额">
                 {{ formatPrice(abstract.businessTotal) }}
               </el-descriptions-item>
               <el-descriptions-item label="成交次数">
@@ -303,8 +303,8 @@
         abstract: {
           followContent: '', //跟进次数
           notFollowDay: '', //未跟进天数
-          business: '', //商机数量
-          businessTotal: '', //商机总额
+          business: '', //项目数量
+          businessTotal: '', //项目总额
           dealCotal: '', //成交次数
           dealTotal: '', //成交总额
           paymentTotal: '', //回款总额

+ 4 - 4
src/views/index/index.vue

@@ -342,8 +342,8 @@
                 { value: 500, name: '初步洽谈' },
                 { value: 300, name: '深入沟通' },
                 { value: 250, name: '产品报价' },
-                { value: 150, name: '成交商机' },
-                { value: 120, name: '流失商机' },
+                { value: 150, name: '成交项目' },
+                { value: 120, name: '流失项目' },
               ],
             },
             {
@@ -358,8 +358,8 @@
                 { value: 500, name: '初步洽谈' },
                 { value: 300, name: '深入沟通' },
                 { value: 250, name: '产品报价' },
-                { value: 150, name: '成交商机' },
-                { value: 120, name: '流失商机' },
+                { value: 150, name: '成交项目' },
+                { value: 120, name: '流失项目' },
               ],
             },
           ],

+ 29 - 11
src/views/proj/business/components/BusinessEdit.vue

@@ -6,7 +6,7 @@
       <el-step title="跟进日程" />
     </el-steps>
 
-    <el-form ref="form" label-width="120px" :model="form" :rules="rules">
+    <el-form ref="form" :model="form" :rules="rules">
       <el-row v-if="activeSteps === 1" :gutter="20">
         <el-col :span="12">
           <el-form-item label="项目名称" prop="nboName">
@@ -15,7 +15,7 @@
         </el-col>
         <el-col :span="12">
           <el-form-item label="关联客户" prop="custName">
-            <el-input v-model="form.custName" readonly @focus="handleSelectCustomer" />
+            <el-input v-model="form.custName" :disabled="custInfo.custName" readonly @focus="handleSelectCustomer" />
           </el-form-item>
         </el-col>
         <el-col :span="12">
@@ -136,7 +136,7 @@
 <script>
   import businessApi from '@/api/proj/business'
   import ProductTable from './ProductTable'
-  import SelectContact from '@/components/select/SelectContact'
+  import SelectContact from '@/components/select/SelectCustomerContact'
   import SelectCustomer from '@/components/select/SelectCustomer'
   import SelectUser from '@/components/select/SelectUser'
   import SelectDistributor from '@/components/select/SelectDistributor'
@@ -145,6 +145,15 @@
   export default {
     name: 'BusinessEdit',
     components: { ProductTable, SelectContact, SelectProduct, SelectDistributor, SelectCustomer, SelectUser },
+    props: {
+      // 客户信息{ custId: id, custName: custName}
+      custInfo: {
+        type: Object,
+        default() {
+          return {}
+        },
+      },
+    },
     data() {
       const validateDistributor = (rule, value, callback) => {
         if ('' === value && this.form.salesModel !== '10')
@@ -199,6 +208,13 @@
         productData: [],
       }
     },
+    watch: {
+      custInfo: function (val) {
+        this.form.custId = val.custId
+        this.form.custName = val.custName
+        this.customerInfo = val
+      },
+    },
     created() {},
     mounted() {
       this.getDicts('proj_nbo_source').then((response) => {
@@ -216,12 +232,9 @@
               this.activeSteps++
             }
           })
-          return
-        }
-        if (this.activeSteps === 2) {
+        } else if (this.activeSteps === 2) {
           this.form.products = this.productData
           this.activeSteps++
-          return
         }
       },
       handleSelectCustomer() {
@@ -281,13 +294,13 @@
         this.form.followUserName = val.map((item) => item.userName).join()
       },
       selectProduct(data) {
-        console.log(data)
         let projData = data.map((item) => ({
           prodId: item.id,
           prodCode: item.prodCode,
           prodName: item.prodName,
           prodClass: item.prodClass,
-          prodPrice: item.guidPrice,
+          guidPrice: item.guidPrice,
+          prodPrice: item.marketPrice,
           prodNum: 1,
         }))
         this.productData.push(...projData)
@@ -334,8 +347,13 @@
       save() {
         this.$refs['form'].validate(async (valid) => {
           if (valid) {
-            const { msg } = await businessApi.doAdd(this.form)
-            this.$baseMessage(msg, 'success')
+            let res
+            if (this.form.id) {
+              res = await businessApi.doEdit(this.form)
+            } else {
+              res = await businessApi.doAdd(this.form)
+            }
+            this.$baseMessage(res.msg, 'success')
             this.$emit('fetch-data')
             this.close()
           } else {

+ 7 - 4
src/views/proj/business/components/DetailsContact.vue

@@ -55,7 +55,7 @@
 <script>
   import businessApi from '@/api/proj/business'
   import businessContactApi from '@/api/proj/businessContact'
-  import SelectContact from '@/components/select/SelectContact'
+  import SelectContact from '@/components/select/SelectCustomerContact'
   import CustomerContact from '@/views/customer/components/Contact'
 
   export default {
@@ -84,6 +84,8 @@
       return {
         queryForm: {
           cuctName: undefined,
+          pageNo: 1,
+          pageSize: 9999,
         },
         listLoading: false,
         selectRows: [],
@@ -150,10 +152,11 @@
       async fetchData() {
         this.listLoading = true
         this.queryForm.busId = this.busId
-        const { data } = await businessContactApi.getList(this.queryForm)
-        this.contactList = data
+        const {
+          data: { list },
+        } = await businessContactApi.getList(this.queryForm)
+        this.contactList = list
         this.listLoading = false
-        console.log(this.contactList)
       },
     },
   }

+ 2 - 2
src/views/proj/business/components/ProductTable.vue

@@ -19,9 +19,9 @@
         <template #default="{ row }">
           <span v-if="item.prop == 'prodPrice'">
             <amount-input
-              v-model.trim="row.price"
+              v-model.trim="row.prodPrice"
               placeholder="请输入金额"
-              :value="row.price"
+              :value="row.prodPrice"
               @change="handleChange(row)" />
           </span>
           <span v-else-if="item.prop == 'prodNum'">

+ 2 - 2
src/views/proj/business/detail.vue

@@ -43,13 +43,13 @@
           </el-tab-pane>
           <el-tab-pane label="详细信息" name="details">
             <el-descriptions border :column="2" size="medium">
-              <el-descriptions-item label="商机名称">
+              <el-descriptions-item label="项目名称">
                 {{ details.nboName }}
               </el-descriptions-item>
               <el-descriptions-item label="客户名称">
                 {{ details.custName }}
               </el-descriptions-item>
-              <el-descriptions-item label="商机金额">
+              <el-descriptions-item label="项目金额">
                 {{ details.estTransPrice }}
               </el-descriptions-item>
               <el-descriptions-item label="预计成交日期">

+ 30 - 27
src/views/proj/business/index.vue

@@ -1,19 +1,19 @@
 <template>
   <div class="business-container">
-    <el-menu :default-active="activeIndex" mode="horizontal" @select="handleMenuSelect">
-      <el-menu-item index="ALL">全部项目</el-menu-item>
-      <el-menu-item index="C">C类项目</el-menu-item>
-      <el-menu-item index="B">B类项目</el-menu-item>
-      <el-menu-item index="A">A类项目</el-menu-item>
-      <el-menu-item index="DEAL">成交项目</el-menu-item>
-      <el-menu-item index="VOID">无效项目</el-menu-item>
-    </el-menu>
+    <el-tabs v-model="activeName" @tab-click="handleTabClick">
+      <el-tab-pane label="全部项目" name="ALL" />
+      <el-tab-pane label="C类项目" name="C" />
+      <el-tab-pane label="B类项目" name="B" />
+      <el-tab-pane label="A类项目" name="A" />
+      <el-tab-pane label="成交项目" name="DEAL" />
+      <el-tab-pane label="无效项目" name="VOID" />
+    </el-tabs>
 
     <vab-query-form style="margin-top: 10px">
       <vab-query-form-top-panel>
         <el-form ref="queryForm" :inline="true" :model="queryForm" @submit.native.prevent>
           <el-form-item prop="nboName">
-            <el-input v-model="queryForm.nboName" clearable placeholder="商机标题" @keyup.enter.native="queryData" />
+            <el-input v-model="queryForm.nboName" clearable placeholder="项目名称" @keyup.enter.native="queryData" />
           </el-form-item>
 
           <el-form-item prop="custName">
@@ -26,7 +26,7 @@
           </el-form-item>
 
           <el-form-item prop="nboType">
-            <el-select v-model="queryForm.nboType" clearable placeholder="商机类别">
+            <el-select v-model="queryForm.nboType" clearable placeholder="项目类别">
               <el-option v-for="dict in nboTypeOptions" :key="dict.key" :label="dict.value" :value="dict.key" />
             </el-select>
           </el-form-item>
@@ -66,6 +66,7 @@
         :key="index"
         align="center"
         :label="item.label"
+        :min-width="item.minWidth"
         :prop="item.prop"
         show-overflow-tooltip
         :sortable="item.sortable"
@@ -79,7 +80,7 @@
         </template>
       </el-table-column>
 
-      <el-table-column align="center" label="操作" width="120">
+      <el-table-column align="center" fixed="right" label="操作" width="68">
         <template #default="{ row }">
           <!--          <el-button type="text" @click="handleFollow(row)">跟进</el-button>-->
           <el-button type="text" @click="handleEdit(row)">编辑</el-button>
@@ -116,50 +117,52 @@
     components: { Edit, Transfer, TableTool, FollowAdd },
     data() {
       return {
-        activeIndex: 'ALL',
+        activeName: 'ALL',
         height: this.$baseTableHeight(2) - 20,
         checkList: [],
         columns: [
           {
-            label: '商机标题',
-            width: '120px',
+            label: '项目名称',
+            width: 'auto',
+            minWidth: '280',
             prop: 'nboName',
             sortable: true,
             disableCheck: true,
           },
           {
             label: '关联客户',
-            width: '200px',
+            width: 'auto',
+            minWidth: '280',
             prop: 'custName',
           },
           {
             label: '审批状态',
-            width: '320px',
+            width: '120px',
             prop: 'approStatus',
           },
           {
-            label: '商机状态',
-            width: '320px',
+            label: '项目状态',
+            width: '120px',
             prop: 'nboPhase',
           },
           {
-            label: '商机类别',
-            width: '320px',
+            label: '项目类别',
+            width: '120px',
             prop: 'nboType',
           },
           {
-            label: '商机金额',
-            width: '320px',
+            label: '项目金额',
+            width: '120px',
             prop: 'estTransPrice',
           },
           {
             label: '最后跟进时间',
-            width: '320px',
+            width: '140px',
             prop: 'finalFollowTime',
           },
           {
             label: '下次跟进时间',
-            width: '320px',
+            width: '140px',
             prop: 'nextFollowTime',
           },
         ],
@@ -197,10 +200,10 @@
     },
     methods: {
       approStatusFormat() {},
-      handleMenuSelect(key) {
-        this.queryForm.nboType = key
+      handleTabClick() {
+        this.queryForm.nboType = this.activeName
         // 全不项目,成交项目,无效项目 项目类型不传
-        if (key === 'ALL' || key === 'DEAL' || key === 'VOID') {
+        if (this.activeName === 'ALL' || this.activeName === 'DEAL' || this.activeName === 'VOID') {
           this.queryForm.nboType = ''
         }
         this.fetchData()