Procházet zdrojové kódy

客户档案跟进开发

cz před 1 rokem
rodič
revize
d5133ebadd

+ 5 - 0
src/components/byTable/index.vue

@@ -101,6 +101,7 @@
         v-on="tableEvents"
         row-key="id"
         :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
+        :height="tableHeight"
       >
         <el-table-column
           v-for="(item, index) in config"
@@ -212,6 +213,10 @@ export default defineComponent({
         return [];
       },
     },
+    tableHeight: {
+      type: Number,
+      required: false,
+    },
     searchConfig: {
       type: Object,
       default() {

+ 71 - 28
src/views/EHSD/productLibrary/companyProduct/index.vue

@@ -30,7 +30,7 @@
             disabled: false,
           },
           {
-            text: '新增',
+            text: '添加',
             action: () => openModal('add'),
             disabled: false,
           },
@@ -675,33 +675,41 @@ const getList = async (req) => {
   loading.value = true;
   proxy
     .post("/productInfo/getConditionProductList", sourceList.value.pagination)
-    .then((message) => {
-      sourceList.value.data = message.rows.map((x) => ({
-        ...x,
-        fileList: [],
-        ...JSON.parse(x.ehsdJson),
-      }));
-      sourceList.value.pagination.total = message.total;
-      setTimeout(() => {
-        loading.value = false;
-      }, 200);
-      const productIdList = message.rows.map((x) => x.id);
-      // 请求文件数据并回显
-      if (productIdList.length > 0) {
-        proxy
-          .post("/fileInfo/getList", { businessIdList: productIdList })
-          .then((fileObj) => {
-            for (let i = 0; i < sourceList.value.data.length; i++) {
-              const e = sourceList.value.data[i];
-              for (const key in fileObj) {
-                if (e.id === key) {
-                  e.fileList = fileObj[key];
+    .then(
+      (message) => {
+        sourceList.value.data = message.rows.map((x) => ({
+          ...x,
+          fileList: [],
+          ...JSON.parse(x.ehsdJson),
+        }));
+        sourceList.value.pagination.total = message.total;
+        setTimeout(() => {
+          loading.value = false;
+        }, 200);
+        const productIdList = message.rows.map((x) => x.id);
+        // 请求文件数据并回显
+        if (productIdList.length > 0) {
+          proxy
+            .post("/fileInfo/getList", {
+              businessIdList: productIdList,
+              fileType: 1,
+            })
+            .then((fileObj) => {
+              for (let i = 0; i < sourceList.value.data.length; i++) {
+                const e = sourceList.value.data[i];
+                for (const key in fileObj) {
+                  if (e.id === key) {
+                    e.fileList = fileObj[key];
+                  }
                 }
               }
-            }
-          });
+            });
+        }
+      },
+      (err) => {
+        loading.value = false;
       }
-    });
+    );
 };
 
 const treeChange = (e) => {
@@ -813,12 +821,47 @@ const getTreeList = () => {
 const getDtl = (row) => {
   modalType.value = "edit";
   proxy.post("/productInfo/detailByEhsd", { id: row.id }).then((res) => {
-    fileList.value = row.fileList.map((x) => ({ ...x, url: x.fileUrl }));
-    fileListCopy.value = [...fileList.value];
     res.definition = "1"; //产品
-    res.standardJson = res.standardJson ? JSON.parse(res.standardJson) : {};
+    res = {
+      ...res,
+      ...JSON.parse(res.ehsdJson),
+      imgList: [],
+      imgListCopy: [],
+      minorImgList: [],
+      minorImgListCopy: [],
+      fileList: [],
+      fileListCopy: [],
+    };
+    if (res.innerPackMethod) {
+      res.innerPackMethod = res.innerPackMethod.split(",");
+    } else {
+      res.innerPackMethod = [];
+    }
+    if (res.outerPackMethod) {
+      res.outerPackMethod = res.outerPackMethod.split(",");
+    } else {
+      res.outerPackMethod = [];
+    }
     formData.data = res;
     dialogVisible.value = true;
+    proxy
+      .post("/fileInfo/getList", { businessIdList: [row.id], fileType: 1 })
+      .then((fileObj) => {
+        formData.data.imgList = fileObj[row.id] || [];
+        formData.data.imgListCopy = fileObj[row.id] || [];
+      });
+    proxy
+      .post("/fileInfo/getList", { businessIdList: [row.id], fileType: 2 })
+      .then((fileObj) => {
+        formData.data.minorImgList = fileObj[row.id] || [];
+        formData.data.minorImgListCopy = fileObj[row.id] || [];
+      });
+    proxy
+      .post("/fileInfo/getList", { businessIdList: [row.id], fileType: 3 })
+      .then((fileObj) => {
+        formData.data.fileList = fileObj[row.id] || [];
+        formData.data.fileListCopy = fileObj[row.id] || [];
+      });
   });
 };
 const handleBeforeUpload = async (file, att) => {

+ 28 - 27
src/views/WDLY/basic/product/index.vue

@@ -13,6 +13,7 @@
     </div>
     <div class="content">
       <byTable
+        :tableHeight="tableHeight"
         :source="sourceList.data"
         :pagination="sourceList.pagination"
         :config="config"
@@ -323,13 +324,11 @@ import SelectProduct from "@/components/WDLY/product/SelectProduct";
 import useUserStore from "@/store/modules/user";
 // 引入插件解决json.parse()会导致id值错误
 import { parse, stringify } from "lossless-json";
-
 import { computed, defineComponent, ref } from "vue";
+const tableHeight = window.innerHeight - 360;
 let openProduct = ref(false);
-
 const loading = ref(false);
 const loadingOne = ref(false);
-
 const submitLoading = ref(false);
 const sourceList = ref({
   data: [],
@@ -360,11 +359,13 @@ let rules = ref({
   ],
 });
 const { proxy } = getCurrentInstance();
-const selectConfig = reactive([
+const productUnit = ref([]);
+const productType = ref([]);
+const selectConfig = computed(() => [
   {
     label: "产品类型",
     prop: "type",
-    data: [],
+    data: productType.value,
   },
   {
     label: "生命周期",
@@ -391,9 +392,10 @@ const config = computed(() => {
       attrs: {
         label: "产品类型",
         prop: "type",
+        width: 80,
       },
       render(type) {
-        return proxy.dictDataEcho(type, productType.value);
+        return proxy.dictValueLabel(type, productType.value);
       },
     },
     {
@@ -413,6 +415,7 @@ const config = computed(() => {
         label: "图片",
         prop: "unit",
         slot: "pic",
+        width: 60,
       },
     },
     {
@@ -421,7 +424,7 @@ const config = computed(() => {
         prop: "unit",
       },
       render(unit) {
-        return proxy.dictDataEcho(unit, productUnit.value);
+        return proxy.dictValueLabel(unit, productUnit.value);
       },
     },
     {
@@ -440,6 +443,7 @@ const config = computed(() => {
       attrs: {
         label: "生命周期",
         prop: "lifeCycle",
+        width: 80,
       },
       render(lifeCycle) {
         return lifeCycle == "1" ? "新品" : lifeCycle == "2" ? "成长" : "成熟";
@@ -449,31 +453,35 @@ const config = computed(() => {
       attrs: {
         label: "京东供价",
         prop: "jdPurchasePrice",
+        width: 80,
       },
     },
     {
       attrs: {
         label: "标准售价",
         prop: "sellingPrice",
+        width: 80,
       },
     },
     {
       attrs: {
         label: "标准采购价",
         prop: "purchasePrice",
+        width: 100,
       },
     },
-    {
-      attrs: {
-        label: "产品备注",
-        prop: "remark",
-      },
-    },
+    // {
+    //   attrs: {
+    //     label: "产品备注",
+    //     prop: "remark",
+    //   },
+    // },
     {
       attrs: {
         label: "操作",
-        width: "200",
-        align: "right",
+        width: "160",
+        align: "center",
+        fixed: "right",
       },
       // 渲染 el-button,一般用在最后一列。
       renderHTML(row) {
@@ -567,7 +575,7 @@ const formConfig = computed(() => {
       prop: "type",
       label: "产品类型",
       required: true,
-      data: [],
+      data: productType.value,
     },
     {
       type: "input",
@@ -589,10 +597,7 @@ const formConfig = computed(() => {
       prop: "unit",
       label: "单位",
       required: true,
-      data: productUnit.value.map((x) => ({
-        label: x.dictValue,
-        value: x.dictKey,
-      })),
+      data: productUnit.value,
     },
     {
       type: "slot",
@@ -1012,18 +1017,13 @@ const submitMove = () => {
     });
 };
 
-const productUnit = ref([]);
-const productType = ref([]);
-
 const getDict = () => {
   proxy.getDictOne(["unit", "product_type"]).then((res) => {
-    productUnit.value = res["unit"];
-    productType.value = res["product_type"];
-    formConfig.value[1].data = productType.value.map((x) => ({
+    productUnit.value = res["unit"].map((x) => ({
       label: x.dictValue,
       value: x.dictKey,
     }));
-    selectConfig[0].data = productType.value.map((x) => ({
+    productType.value = res["product_type"].map((x) => ({
       label: x.dictValue,
       value: x.dictKey,
     }));
@@ -1042,6 +1042,7 @@ getDict();
   }
   .content {
     width: calc(100% - 320px);
+    height: calc(100vh - 140px);
   }
 }
 .pic {

+ 0 - 9
src/views/WDLY/basic/supplier/index.vue

@@ -123,9 +123,6 @@
               class="upload-demo"
               action="https://winfaster.obs.cn-south-1.myhuaweicloud.com"
               :data="uploadData"
-              :on-preview="handlePreview"
-              :on-remove="handleRemove"
-              :on-success="handleSuccess"
               :before-upload="handleBeforeUpload"
             >
               <el-button type="primary">选择</el-button>
@@ -615,12 +612,6 @@ const handleClickFile = (row) => {
 };
 
 const handleClose = (index) => {
-  // if (fileListCopy.value.length === 1) {
-  //   return ElMessage({
-  //     message: "最后一个附件啦!",
-  //     type: "info",
-  //   });
-  // }
   fileList.value.splice(index, 1);
   fileListCopy.value.splice(index, 1);
 };

+ 105 - 7
src/views/WDLY/purchaseManage/alreadyPurchase/index.vue

@@ -23,6 +23,14 @@
             {{ item.fileName }}
           </div>
         </template>
+        <template #contractCode="{ item }">
+          <div
+            style="cursor: pointer; color: #409eff"
+            @click="handleClickContractCode(item)"
+          >
+            {{ item.contractCode }}
+          </div>
+        </template>
       </byTable>
     </div>
     <el-dialog
@@ -123,6 +131,52 @@
         </el-button>
       </template>
     </el-dialog>
+
+    <el-dialog
+      title="采购详情"
+      v-model="dialogVisibleOne"
+      width="70%"
+      destroy-on-close
+    >
+      <byForm
+        :formConfig="formConfigOne"
+        :formOption="formOption"
+        v-model="formData.dataOne"
+        :rules="rules"
+        ref="byform"
+      >
+        <template #detailSlot>
+          <div style="width: 100%">
+            <el-table :data="formData.dataOne.deliverGoodsDetailsList">
+              <el-table-column
+                prop="productDefinition"
+                label="物品类型"
+                :formatter="
+                  (row) =>
+                    row.productDefinition == 1
+                      ? '产品'
+                      : row.productDefinition == 2
+                      ? '物料'
+                      : ''
+                "
+              />
+
+              <el-table-column prop="productCode" label="物品编码" />
+              <el-table-column prop="productName" label="物品名称" />
+              <el-table-column prop="productSpec" label="规格型号" />
+              <el-table-column prop="productUnit" label="单位" />
+              <el-table-column prop="count" label="采购数量" />
+            </el-table>
+          </div>
+        </template>
+      </byForm>
+
+      <template #footer>
+        <el-button @click="dialogVisibleOne = false" size="large"
+          >取 消</el-button
+        >
+      </template>
+    </el-dialog>
   </div>
 </template>
   
@@ -130,7 +184,7 @@
 import { ElMessage, ElMessageBox } from "element-plus";
 import byTable from "@/components/byTable/index";
 import byForm from "@/components/byForm/index";
-import { watch } from "vue";
+import { computed, watch } from "vue";
 
 const loading = ref(false);
 const submitLoading = ref(false);
@@ -143,6 +197,7 @@ const sourceList = ref({
   },
 });
 let dialogVisible = ref(false);
+let dialogVisibleOne = ref(false);
 let modalType = ref("add");
 let rules = ref({
   deliverGoodsId: [
@@ -225,16 +280,17 @@ const selectConfig = reactive([
 ]);
 const config = computed(() => {
   return [
+    // {
+    //   attrs: {
+    //     label: "采购单号",
+    //     prop: "code",
+    //   },
+    // },
     {
       attrs: {
         label: "采购单号",
-        prop: "code",
-      },
-    },
-    {
-      attrs: {
-        label: "合同编号",
         prop: "contractCode",
+        slot: "contractCode",
       },
     },
     {
@@ -360,6 +416,7 @@ const config = computed(() => {
 
 let formData = reactive({
   data: {},
+  dataOne: {},
 });
 const formOption = reactive({
   inline: true,
@@ -368,6 +425,31 @@ const formOption = reactive({
 });
 const byform = ref(null);
 let formConfig = reactive([]);
+let formConfigOne = computed(() => [
+  {
+    type: "input",
+    prop: "supplyName",
+    label: "供应商",
+    disabled: true,
+    itemWidth: 50,
+  },
+  {
+    type: "input",
+    prop: "purchaseCode",
+    label: "采购单号",
+    disabled: true,
+    itemWidth: 50,
+  },
+  {
+    type: "title",
+    title: "采购明细",
+  },
+  {
+    type: "slot",
+    slotName: "detailSlot",
+    label: "",
+  },
+]);
 const configData = [
   [
     {
@@ -672,6 +754,22 @@ watch(
   }
 );
 
+const handleClickContractCode = (row) => {
+  proxy.post("/deliverGoodsDetails/detail", { id: row.id }).then((res) => {
+    formData.dataOne = {
+      supplyName: row.supplyName,
+      purchaseCode: row.contractCode,
+      deliverGoodsDetailsList: res.map((x) => ({
+        ...x,
+        purchaseDetailId: x.id,
+        alreadyDeliverGoodsQuantity: x.deliverGoodsQuantity,
+        deliverGoodsQuantity: Number(x.count) - Number(x.deliverGoodsQuantity),
+      })),
+    };
+    dialogVisibleOne.value = true;
+  });
+};
+
 getList();
 getLogisticsData();
 </script>

+ 370 - 25
src/views/customer/file/index.vue

@@ -14,42 +14,116 @@
             action: () => openModal('add'),
           },
         ]"
-        @get-list="getList">
+        @get-list="getList"
+      >
         <template #address="{ item }">
           <span>{{ item.countryName }}</span>
           <span v-if="item.provinceName"> ,{{ item.provinceName }}</span>
           <span v-if="item.cityName"> ,{{ item.cityName }}</span>
         </template>
         <template #name="{ item }">
-          <div style="cursor: pointer; color: #409eff" @click="handleClickName(item)">
+          <div
+            style="cursor: pointer; color: #409eff"
+            @click="handleClickName(item)"
+          >
             {{ item.name }}
           </div>
         </template>
+        <template #tags="{ item }">
+          <div>
+            <el-tag
+              style="margin-right: 10px"
+              type="success"
+              v-for="(tag, index) in item.tag"
+              :key="index"
+              >{{ dictValueLabel(tag, customerTag) }}</el-tag
+            >
+          </div>
+        </template>
+        <template #follow="{ item }">
+          <div style="width: 100%; display: flex">
+            <div
+              v-for="(follow, index) in item.customerFollowRecordsList"
+              :key="index"
+              style="width: 190px; padding: 0 5px; border-right: 1px solid #ccc"
+            >
+              <div style="display: flex; align-items: center">
+                <span>{{ follow.date }}</span>
+                <el-icon
+                  style="margin: 0 10px; cursor: pointer"
+                  @click="updateFollow(follow)"
+                  ><Edit
+                /></el-icon>
+                <el-icon style="cursor: pointer" @click="deleteFollow(follow)"
+                  ><Delete
+                /></el-icon>
+              </div>
+              <div style="margin-top: 5px">
+                {{ follow.content }}
+              </div>
+            </div>
+          </div>
+        </template>
       </byTable>
     </div>
 
-    <el-dialog :title="modalType == 'add' ? '新增' : '编辑'" v-if="dialogVisible" v-model="dialogVisible" width="800" v-loading="loadingOperation">
-      <byForm :formConfig="formConfig" :formOption="formOption" v-model="formData.data" :rules="rules" ref="submit">
+    <el-dialog
+      :title="modalType == 'add' ? '新增' : '编辑'"
+      v-if="dialogVisible"
+      v-model="dialogVisible"
+      width="800"
+      v-loading="loadingOperation"
+    >
+      <byForm
+        :formConfig="formConfig"
+        :formOption="formOption"
+        v-model="formData.data"
+        :rules="rules"
+        ref="submit"
+      >
         <template #address>
           <el-row style="width: 100%">
             <el-col :span="8">
               <el-form-item prop="countryId">
-                <el-select v-model="formData.data.countryId" placeholder="国家" @change="(val) => getCityData(val, '20', true)">
-                  <el-option v-for="item in countryData" :label="item.chineseName" :value="item.id"> </el-option>
+                <el-select
+                  v-model="formData.data.countryId"
+                  placeholder="国家"
+                  @change="(val) => getCityData(val, '20', true)"
+                >
+                  <el-option
+                    v-for="item in countryData"
+                    :label="item.chineseName"
+                    :value="item.id"
+                  >
+                  </el-option>
                 </el-select>
               </el-form-item>
             </el-col>
             <el-col :span="8">
               <el-form-item prop="provinceId">
-                <el-select v-model="formData.data.provinceId" placeholder="省/洲" @change="(val) => getCityData(val, '30', true)">
-                  <el-option v-for="item in provinceData" :label="item.name" :value="item.id"> </el-option>
+                <el-select
+                  v-model="formData.data.provinceId"
+                  placeholder="省/洲"
+                  @change="(val) => getCityData(val, '30', true)"
+                >
+                  <el-option
+                    v-for="item in provinceData"
+                    :label="item.name"
+                    :value="item.id"
+                  >
+                  </el-option>
                 </el-select>
               </el-form-item>
             </el-col>
             <el-col :span="8">
               <el-form-item prop="cityId">
                 <el-select v-model="formData.data.cityId" placeholder="城市">
-                  <el-option v-for="item in cityData" :label="item.name" :value="item.id"> </el-option>
+                  <el-option
+                    v-for="item in cityData"
+                    :label="item.name"
+                    :value="item.id"
+                  >
+                  </el-option>
                 </el-select>
               </el-form-item>
             </el-col>
@@ -57,7 +131,8 @@
           <el-row style="margin-top: 20px; width: 100%">
             <el-col :span="24">
               <el-form-item prop="address">
-                <el-input v-model="formData.data.address" type="textarea"> </el-input>
+                <el-input v-model="formData.data.address" type="textarea">
+                </el-input>
               </el-form-item>
             </el-col>
           </el-row>
@@ -65,29 +140,110 @@
         <template #person>
           <div>
             <el-button type="primary" @click="clickAddPerson"> 添加 </el-button>
-            <byTable :source="formData.data.customerUserList" :config="configPerson" hideSearch hidePagination> </byTable>
+            <byTable
+              :source="formData.data.customerUserList"
+              :config="configPerson"
+              hideSearch
+              hidePagination
+            >
+            </byTable>
           </div>
         </template>
       </byForm>
       <template #footer>
         <el-button @click="dialogVisible = false" size="large">取 消</el-button>
-        <el-button type="primary" @click="submitForm('submit')" size="large" :loading="submitLoading"> 确 定 </el-button>
+        <el-button
+          type="primary"
+          @click="submitForm('submit')"
+          size="large"
+          :loading="submitLoading"
+        >
+          确 定
+        </el-button>
       </template>
     </el-dialog>
 
     <el-dialog title="添加联系人" v-model="openPerson" width="400">
-      <byForm :formConfig="formConfigPerson" :formOption="formOption" v-model="formPerson.data" :rules="rulesPerson" ref="person"> </byForm>
+      <byForm
+        :formConfig="formConfigPerson"
+        :formOption="formOption"
+        v-model="formPerson.data"
+        :rules="rulesPerson"
+        ref="person"
+      >
+      </byForm>
       <template #footer>
         <el-button @click="openPerson = false" size="large">取 消</el-button>
-        <el-button type="primary" @click="submitPerson('person')" size="large"> 确 定 </el-button>
+        <el-button type="primary" @click="submitPerson('person')" size="large">
+          确 定
+        </el-button>
       </template>
     </el-dialog>
 
     <el-dialog title="分配" v-model="openAllocation" width="300">
-      <byForm :formConfig="formConfigAllocation" :formOption="formOption" v-model="formAllocation.data" ref="allocation"> </byForm>
+      <byForm
+        :formConfig="formConfigAllocation"
+        :formOption="formOption"
+        v-model="formAllocation.data"
+        ref="allocation"
+      >
+      </byForm>
+      <template #footer>
+        <el-button @click="openAllocation = false" size="large"
+          >取 消</el-button
+        >
+        <el-button
+          type="primary"
+          @click="submitAllocation('allocation')"
+          size="large"
+        >
+          确 定
+        </el-button>
+      </template>
+    </el-dialog>
+
+    <el-dialog title="跟进" v-model="openFollow" width="500" destroy-on-close>
+      <byForm
+        :formConfig="formConfigAFollow"
+        :formOption="formOption"
+        v-model="formFollow.data"
+        :rules="rulesFollow"
+        ref="follow"
+      >
+        <template #fileSlot>
+          <div>
+            <el-upload
+              v-model:fileList="fileList"
+              :show-file-list="false"
+              class="upload-demo"
+              action="https://winfaster.obs.cn-south-1.myhuaweicloud.com"
+              :data="uploadData"
+              :before-upload="handleBeforeUpload"
+            >
+              <el-button type="primary">文件上传</el-button>
+            </el-upload>
+            <div>
+              <div style="margin-top: 15px">
+                <el-tag
+                  style="margin-right: 10px"
+                  class="ml-2"
+                  type="info"
+                  v-for="(item, index) in fileListCopy"
+                  :key="index"
+                  closable
+                  @close="handleClose(index)"
+                  >{{ item.fileName }}</el-tag
+                >
+              </div>
+            </div>
+          </div>
+        </template>
+      </byForm>
       <template #footer>
-        <el-button @click="openAllocation = false" size="large">取 消</el-button>
-        <el-button type="primary" @click="submitAllocation('allocation')" size="large"> 确 定 </el-button>
+        <el-button @click="openFollow = false" size="large">取 消</el-button>
+        <el-button type="primary" @click="submitFollow('follow')" size="large">
+          确 定
+        </el-button>
       </template>
     </el-dialog>
   </div>
@@ -106,9 +262,13 @@ const loadingOperation = ref(false);
 const submitLoading = ref(false);
 const openPerson = ref(false);
 const openAllocation = ref(false);
+const customerTag = ref([]);
 const customerSource = ref([]);
 const customerStatus = ref([]);
 const userList = ref([]);
+const fileList = ref([]);
+const fileListCopy = ref([]);
+const uploadData = ref({});
 const sourceList = ref({
   data: [],
   pagination: {
@@ -155,6 +315,7 @@ const config = computed(() => {
         label: "客户名称",
         prop: "name",
         slot: "name",
+        fixed: "left",
       },
     },
     {
@@ -203,6 +364,13 @@ const config = computed(() => {
     },
     {
       attrs: {
+        label: "客户标签",
+        slot: "tags",
+        width: 200,
+      },
+    },
+    {
+      attrs: {
         label: "业务员",
         prop: "userId",
         width: 140,
@@ -218,9 +386,17 @@ const config = computed(() => {
     },
     {
       attrs: {
+        label: "跟进",
+        slot: "follow",
+        width: 700,
+      },
+    },
+    {
+      attrs: {
         label: "操作",
-        width: "160",
+        width: "200",
         align: "center",
+        fixed: "right",
       },
       renderHTML(row) {
         return [
@@ -240,6 +416,23 @@ const config = computed(() => {
           },
           {
             attrs: {
+              label: "跟进",
+              type: "primary",
+              text: true,
+            },
+            el: "button",
+            click() {
+              formFollow.data = {
+                customerId: row.id,
+              };
+              fileList.value = [];
+              fileListCopy.value = [];
+              modalType.value = "add";
+              openFollow.value = true;
+            },
+          },
+          {
+            attrs: {
               label: "修改",
               type: "primary",
               text: true,
@@ -257,11 +450,15 @@ const config = computed(() => {
             },
             el: "button",
             click() {
-              ElMessageBox.confirm("此操作将永久删除该数据, 是否继续?", "提示", {
-                confirmButtonText: "确定",
-                cancelButtonText: "取消",
-                type: "warning",
-              }).then(() => {
+              ElMessageBox.confirm(
+                "此操作将永久删除该数据, 是否继续?",
+                "提示",
+                {
+                  confirmButtonText: "确定",
+                  cancelButtonText: "取消",
+                  type: "warning",
+                }
+              ).then(() => {
                 proxy
                   .post("/customer/delete", {
                     id: row.id,
@@ -283,6 +480,7 @@ const config = computed(() => {
 });
 let modalType = ref("add");
 let dialogVisible = ref(false);
+let openFollow = ref(false);
 let formData = reactive({
   data: {
     countryId: "China",
@@ -294,6 +492,9 @@ let formPerson = reactive({
 let formAllocation = reactive({
   data: {},
 });
+let formFollow = reactive({
+  data: {},
+});
 const formOption = reactive({
   inline: true,
   labelWidth: 100,
@@ -346,6 +547,18 @@ const formConfig = computed(() => {
       data: userList.value,
     },
     {
+      type: "select",
+      label: "客户标签",
+      prop: "tag",
+      itemWidth: 100,
+      multiple: true,
+      data: customerTag.value,
+      style: {
+        width: "100%",
+      },
+    },
+
+    {
       type: "slot",
       slotName: "person",
       label: "客户联系人",
@@ -411,6 +624,30 @@ const configPerson = computed(() => {
     },
   ];
 });
+const formConfigAFollow = computed(() => {
+  return [
+    {
+      type: "date",
+      itemType: "datetime",
+      label: "跟进时间",
+      prop: "date",
+      itemWidth: 100,
+    },
+    {
+      type: "input",
+      itemType: "textarea",
+      label: "跟进内容",
+      prop: "content",
+      itemWidth: 100,
+    },
+    {
+      type: "slot",
+      label: "上传附件",
+      prop: "fileList",
+      slotName: "fileSlot",
+    },
+  ];
+});
 const formConfigPerson = computed(() => {
   return [
     {
@@ -435,13 +672,25 @@ let rulesPerson = ref({
   name: [{ required: true, message: "请输入联系人名称", trigger: "blur" }],
   phone: [{ required: true, message: "请输入联系人电话", trigger: "blur" }],
 });
+let rulesFollow = ref({
+  date: [{ required: true, message: "请选择跟进时间", trigger: "change" }],
+  content: [{ required: true, message: "请输入跟进内容", trigger: "blur" }],
+});
+
 const submit = ref(null);
 const person = ref(null);
 const allocation = ref(null);
+const follow = ref(null);
+
 const getList = async (req) => {
   sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
   loading.value = true;
   proxy.post("/customer/page", sourceList.value.pagination).then((res) => {
+    res.rows.forEach((x) => {
+      if (x.tag) {
+        x.tag = x.tag.split(",");
+      }
+    });
     sourceList.value.data = res.rows;
     sourceList.value.pagination.total = res.total;
     setTimeout(() => {
@@ -453,6 +702,7 @@ const openModal = () => {
   modalType.value = "add";
   formData.data = {
     countryId: "China",
+    tag: [],
   };
   getCityData(formData.data.countryId, "20");
   loadingOperation.value = false;
@@ -469,6 +719,11 @@ const update = (row) => {
         customerId: item.customerId,
       };
     });
+    if (res.tag) {
+      res.tag = res.tag.split(",");
+    } else {
+      res.tag = [];
+    }
     formData.data = res;
     getCityData(formData.data.countryId, "20");
     getCityData(formData.data.provinceId, "30");
@@ -514,9 +769,38 @@ const submitAllocation = () => {
     });
   });
 };
+
+const submitFollow = () => {
+  follow.value.handleSubmit(() => {
+    formFollow.data.fileList =
+      fileListCopy.value.map((x) => ({
+        id: x.id,
+        fileName: x.fileName,
+      })) || [];
+    proxy
+      .post("/customerFollowRecords/" + modalType.value, formFollow.data)
+      .then(
+        () => {
+          ElMessage({
+            message: modalType.value == "add" ? "添加成功" : "编辑成功",
+            type: "success",
+          });
+          openFollow.value = false;
+          getList();
+        },
+        (err) => {
+          console.log(err);
+        }
+      );
+  });
+};
+
 const submitPerson = () => {
   person.value.handleSubmit(() => {
-    if (formData.data.customerUserList && formData.data.customerUserList.length > 0) {
+    if (
+      formData.data.customerUserList &&
+      formData.data.customerUserList.length > 0
+    ) {
       formData.data.customerUserList.push({
         name: formPerson.data.name,
         phone: formPerson.data.phone,
@@ -534,7 +818,11 @@ const submitPerson = () => {
 };
 const submitForm = () => {
   submit.value.handleSubmit(() => {
-    if (formData.data.customerUserList && formData.data.customerUserList.length > 0) {
+    if (
+      formData.data.customerUserList &&
+      formData.data.customerUserList.length > 0
+    ) {
+      formData.data.tag = formData.data.tag.join(",");
       submitLoading.value = true;
       proxy.post("/customer/" + modalType.value, formData.data).then(
         () => {
@@ -556,6 +844,7 @@ const submitForm = () => {
     }
   });
 };
+
 const getDict = () => {
   proxy
     .post("/dictTenantData/page", {
@@ -601,6 +890,12 @@ const getDict = () => {
         };
       });
     });
+  proxy.getDictOne(["customer_tag"]).then((res) => {
+    customerTag.value = res["customer_tag"].map((x) => ({
+      label: x.dictValue,
+      value: x.dictKey,
+    }));
+  });
 };
 getDict();
 getList();
@@ -613,6 +908,56 @@ const handleClickName = (row) => {
     },
   });
 };
+
+const handleBeforeUpload = async (file) => {
+  const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
+  uploadData.value = res.uploadBody;
+  fileListCopy.value.push({
+    id: res.id,
+    fileName: res.fileName,
+    path: res.fileUrl,
+    url: res.fileUrl,
+    uid: file.uid,
+  });
+};
+
+const handleClose = (index) => {
+  fileList.value.splice(index, 1);
+  fileListCopy.value.splice(index, 1);
+};
+
+const updateFollow = (data) => {
+  modalType.value = "edit";
+  formFollow.data = {
+    ...data,
+  };
+  proxy
+    .post("/fileInfo/getList", { businessIdList: [data.id] })
+    .then((fileObj) => {
+      fileList.value = fileObj[data.id] || [];
+      fileListCopy.value = fileObj[data.id] || [];
+    });
+  openFollow.value = true;
+};
+const deleteFollow = (data) => {
+  ElMessageBox.confirm("是否确认删除该跟进?", "提示", {
+    confirmButtonText: "确定",
+    cancelButtonText: "取消",
+    type: "warning",
+  }).then(() => {
+    proxy
+      .post("/customerFollowRecords/delete", {
+        id: data.id,
+      })
+      .then(() => {
+        ElMessage({
+          message: "删除成功",
+          type: "success",
+        });
+        getList();
+      });
+  });
+};
 </script>
 
 <style lang="scss" scoped>