Browse Source

Merge branch 'master' of http://36.137.93.232:3000/hf/byte-sailing-new

lxf 1 year ago
parent
commit
d39ff8ff6b

+ 29 - 5
src/components/WDLY/process/SendSubscribeWDLY.vue

@@ -87,7 +87,9 @@ import byForm from "@/components/byForm/index";
 import { ElMessage, ElMessageBox } from "element-plus";
 import SelectGoods from "@/components/WDLY/product/SelectGoods";
 import useUserStore from "@/store/modules/user";
+import { computed } from "vue";
 const { proxy } = getCurrentInstance();
+const route = useRoute();
 
 let formData = reactive({
   data: {
@@ -104,11 +106,12 @@ let rules = ref({
   count: [{ required: true, message: "请输入申购数量", trigger: "blur" }],
   // remark: [{ required: true, message: "请输入申购备注", trigger: "blur" }],
 });
-const formOption = reactive({
+const formOption = computed(() => ({
+  disabled: false,
   inline: true,
   labelWidth: 100,
   itemWidth: 100,
-});
+}));
 const formConfig = computed(() => {
   return [
     {
@@ -252,9 +255,30 @@ getDict();
 // 获取用户信息并赋默认值
 const userInfo = useUserStore().user;
 onMounted(() => {
-  formData.data.subcribeTime = proxy.parseTime(new Date());
-  formData.data.deptName = userInfo.dept.deptName;
-  formData.data.subcribeName = userInfo.nickName;
+  if (route.query.id && route.query.processType == 20) {
+    formOption.value.disabled = true;
+    setTimeout(() => {
+      formData.data = {
+        ...props.queryData,
+      };
+      if (formData.data && route.query.subscribeId) {
+        // const ids = formData.data.subscribeDetailList.map((x) => x.bussinessId);
+        proxy
+          .post("/subscribe/detail", {
+            id: route.query.subscribeId,
+          })
+          .then((res) => {
+            formData.data.subscribeDetailList = res.subscribeDetailList.map(
+              (x) => ({ ...x, goodType: x.productDefinition })
+            );
+          });
+      }
+    }, 2000);
+  } else {
+    formData.data.subcribeTime = proxy.parseTime(new Date());
+    formData.data.deptName = userInfo.dept.deptName;
+    formData.data.subcribeName = userInfo.nickName;
+  }
 });
 // 向父组件暴露
 defineExpose({

+ 17 - 11
src/views/JXSK/production/workOrder/index.vue

@@ -293,7 +293,7 @@ const workOrderSource = ref([]);
 const selectConfig = computed(() => [
   {
     label: "工单来源",
-    prop: "type",
+    prop: "source",
     data: workOrderSource.value,
   },
 ]);
@@ -333,13 +333,18 @@ const config = computed(() => {
     {
       attrs: {
         label: "已计划数量",
-        prop: "remark",
+        prop: "arrangedQuantity",
       },
     },
     {
       attrs: {
         label: "完成率",
-        prop: "aa",
+        prop: "completionRate",
+      },
+      render(completionRate) {
+        if (completionRate !== undefined && completionRate !== "") {
+          return completionRate + "%";
+        }
       },
     },
     {
@@ -414,14 +419,15 @@ const formConfigOne = reactive([
 const getList = async (req) => {
   sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
   loading.value = true;
-  proxy.post("/workOrder/page", sourceList.value.pagination).then((message) => {
-    console.log(message);
-    sourceList.value.data = message.rows;
-    sourceList.value.pagination.total = message.total;
-    setTimeout(() => {
-      loading.value = false;
-    }, 200);
-  });
+  proxy
+    .post("/workOrder/pageByJxst", sourceList.value.pagination)
+    .then((message) => {
+      sourceList.value.data = message.rows;
+      sourceList.value.pagination.total = message.total;
+      setTimeout(() => {
+        loading.value = false;
+      }, 200);
+    });
 };
 const openModal = () => {
   dialogVisible.value = true;

+ 106 - 51
src/views/JXSK/warehouseConfig/warehouse/index.vue

@@ -58,66 +58,69 @@
       v-model="dialogVisibleOne"
       width="800"
       v-loading="loadingOne"
+      destroy-on-close
     >
       <byForm
         :formConfig="formConfigOne"
         :formOption="formOption"
         v-model="formData.dataOne"
         :rules="rulesOne"
-        ref="byform"
+        ref="byformOne"
       >
         <template #slot>
           <div style="width: 100%">
             <el-button type="primary" @click="clickAdd">添 加</el-button>
             <el-table
-              :data="formData.dataOne.list"
+              :data="formData.dataOne.warehouseLocationInfoList"
               style="width: 100%; margin-top: 16px"
             >
-              <el-table-column label="库位编码">
+              <el-table-column label="库位编码" width="150">
                 <template #default="{ row, $index }">
                   <div style="width: 100%">
                     <el-form-item
-                      :prop="'list.' + $index + '.contactNo'"
-                      :rules="rulesOne.contactNo"
+                      :prop="'warehouseLocationInfoList.' + $index + '.code'"
+                      :rules="rulesOne.code"
                       :inline-message="true"
                     >
-                      <el-input v-model="row.contactNo" placeholder="请输入" />
+                      <el-input v-model="row.code" placeholder="请输入" />
                     </el-form-item>
                   </div>
                 </template>
               </el-table-column>
-              <el-table-column label="库位名称">
+              <el-table-column label="库位名称" width="150">
                 <template #default="{ row, $index }">
                   <div style="width: 100%">
                     <el-form-item
-                      :prop="'list.' + $index + '.contactNo'"
-                      :rules="rulesOne.contactNo"
+                      :prop="'warehouseLocationInfoList.' + $index + '.name'"
+                      :rules="rulesOne.name"
                       :inline-message="true"
                     >
-                      <el-input v-model="row.contactNo" placeholder="请输入" />
+                      <el-input v-model="row.name" placeholder="请输入" />
                     </el-form-item>
                   </div>
                 </template>
               </el-table-column>
-              <el-table-column label="类型" width="180">
+              <el-table-column label="绑定物品">
                 <template #default="{ row, $index }">
                   <div style="width: 100%">
                     <el-form-item
-                      :prop="'list.' + $index + '.type'"
-                      :rules="rulesOne.type"
+                      :prop="
+                        'warehouseLocationInfoList.' + $index + '.productIds'
+                      "
+                      :rules="rulesOne.productIds"
                       :inline-message="true"
                     >
                       <el-select
-                        v-model="row.type"
-                        placeholder="请选择类型"
+                        v-model="row.productIds"
+                        placeholder="请选择绑定物品"
                         style="width: 100%"
                         multiple
                       >
                         <el-option
-                          v-for="item in []"
-                          :key="item.value"
-                          :label="item.label"
-                          :value="item.value"
+                          v-for="item in productList"
+                          :key="item.id"
+                          :label="item.name"
+                          :value="item.id"
                         />
                       </el-select>
                     </el-form-item>
@@ -128,7 +131,7 @@
               <el-table-column
                 align="center"
                 label="操作"
-                width="120"
+                width="80"
                 fixed="right"
               >
                 <template #default="{ $index }">
@@ -147,7 +150,7 @@
         >
         <el-button
           type="primary"
-          @click="submitForm('byform')"
+          @click="submitFormOne('byform')"
           size="large"
           :loading="loadingOne"
         >
@@ -167,6 +170,7 @@ import { computed, defineComponent, ref } from "vue";
 import useUserStore from "@/store/modules/user";
 
 const loading = ref(false);
+const loadingOne = ref(false);
 const submitLoading = ref(false);
 const sourceList = ref({
   data: [],
@@ -178,7 +182,6 @@ const sourceList = ref({
 });
 let dialogVisible = ref(false);
 let dialogVisibleOne = ref(false);
-
 let roomDialogVisible = ref(false);
 let modalType = ref("add");
 let rules = ref({
@@ -188,17 +191,18 @@ let rules = ref({
   name: [{ required: true, message: "请输入仓库名称", trigger: "blur" }],
 });
 let rulesOne = ref({
-  type: [
-    { required: true, message: "请选择仓库类型", trigger: ["blur", "change"] },
-  ],
-  name: [{ required: true, message: "请输入仓库名称", trigger: "blur" }],
+  code: [{ required: true, message: "请输入库位编码", trigger: "blur" }],
+  name: [{ required: true, message: "请输入库位名称", trigger: "blur" }],
+  productIds: [{ required: true, message: "请绑定物品", trigger: "change" }],
 });
 const { proxy } = getCurrentInstance();
-const selectConfig = reactive([
+const warehouseType = ref([]);
+const productList = ref([]);
+const selectConfig = computed(() => [
   {
     label: "仓库类型",
     prop: "type",
-    data: [],
+    data: warehouseType.value,
   },
 ]);
 
@@ -216,7 +220,7 @@ const config = computed(() => {
         prop: "type",
       },
       render(type) {
-        return proxy.dictDataEcho(type, warehouseType.value);
+        return proxy.dictValueLabel(type, warehouseType.value);
       },
     },
     {
@@ -313,14 +317,16 @@ const formOption = reactive({
   rules: [],
 });
 const byform = ref(null);
+const byformOne = ref(null);
+
 const treeData = ref([]);
-const formConfig = reactive([
+const formConfig = computed(() => [
   {
     type: "select",
     prop: "type",
     label: "仓库类型",
     required: true,
-    data: [],
+    data: warehouseType.value,
   },
   {
     type: "input",
@@ -399,7 +405,6 @@ const openModal = () => {
 };
 
 const submitForm = () => {
-  console.log(byform.value);
   byform.value.handleSubmit((valid) => {
     submitLoading.value = true;
     proxy.post("/warehouse/" + modalType.value, formData.data).then(
@@ -417,6 +422,41 @@ const submitForm = () => {
   });
 };
 
+const submitFormOne = () => {
+  byformOne.value.handleSubmit((valid) => {
+    if (formData.dataOne.warehouseLocationInfoList.length > 0) {
+      const oldList = formData.dataOne.warehouseLocationInfoList;
+      const list = formData.dataOne.warehouseLocationInfoList;
+      for (let i = 0; i < list.length; i++) {
+        const e = list[i];
+        e.productIds = e.productIds.join(",");
+      }
+      formData.dataOne.warehouseLocationInfoList = list;
+      loadingOne.value = true;
+      proxy.post("/warehouseLocationInfo/edit", formData.dataOne).then(
+        (res) => {
+          ElMessage({
+            message: "操作成功",
+            type: "success",
+          });
+          dialogVisible.value = false;
+          loadingOne.value = false;
+          getList();
+        },
+        (err) => {
+          loadingOne.value = false;
+          formData.dataOne.warehouseLocationInfoList = oldList;
+        }
+      );
+    } else {
+      return ElMessage({
+        message: "请添加库位信息",
+        type: "info",
+      });
+    }
+  });
+};
+
 const getDtl = (row) => {
   modalType.value = "edit";
   proxy.post("/warehouse/detail", { id: row.id }).then((res) => {
@@ -428,45 +468,60 @@ const getDtl = (row) => {
 const getDtlOne = (row) => {
   modalType.value = "edit";
   formData.dataOne = {
+    warehouseId: row.id,
     name: row.name,
     keeperId: row.keeperId,
-    list:[]
+    warehouseLocationInfoList: [],
   };
   dialogVisibleOne.value = true;
+  proxy
+    .post("/warehouseLocationInfo/list", { warehouseId: row.id })
+    .then((res) => {
+      for (let i = 0; i < res.length; i++) {
+        const e = res[i];
+        if (e.productIds) {
+          e.productIds = e.productIds.split(",");
+        }
+      }
+      formData.dataOne = {
+        warehouseId: row.id,
+        name: row.name,
+        keeperId: row.keeperId,
+        warehouseLocationInfoList: [],
+      };
+      dialogVisibleOne.value = true;
+    });
 };
 
-const warehouseType = ref([]);
 const getDict = () => {
-  // // 币种数据
+  proxy.getDictOne(["warehouse_type"]).then((res) => {
+    warehouseType.value = res["warehouse_type"].map((x) => ({
+      label: x.dictValue,
+      value: x.dictKey,
+    }));
+  });
   proxy
-    .post("/dictTenantData/page", {
+    .post("/productInfo/page", {
       pageNum: 1,
-      pageSize: 999,
-      tenantId: useUserStore().user.tenantId,
-      dictCode: "warehouse_type",
+      pageSize: 99999,
+      definition: "",
     })
     .then((res) => {
-      warehouseType.value = res.rows;
-      selectConfig[0].data = res.rows.map((x) => ({
-        label: x.dictValue,
-        value: x.dictKey,
-      }));
-      formConfig[0].data = res.rows.map((x) => ({
-        label: x.dictValue,
-        value: x.dictKey,
-      }));
+      productList.value = res.rows;
     });
 };
 getList();
 getDict();
 
 const clickAdd = () => {
-  formData.dataOne.list.push({
-    type: [],
+  formData.dataOne.warehouseLocationInfoList.push({
+    code: "",
+    name: "",
+    productIds: [],
   });
 };
 const clickDelete = (index) => {
-  formData.dataOne.list.splice(index, 1);
+  formData.dataOne.warehouseLocationInfoList.splice(index, 1);
 };
 </script>
   

+ 1688 - 0
src/views/WDLY/basic/customer/index.vue

@@ -0,0 +1,1688 @@
+<template>
+  <div class="tenant">
+    <div style="padding: 20px; background: #fff; margin-bottom: 20px">
+      <el-button type="primary" style="margin-left: 10px" @click="openModal()"
+        >添加客户</el-button
+      >
+    </div>
+    <div
+      style="padding: 20px 20px 0 20px; background: #fff; margin-bottom: 20px"
+    >
+      <div style="display: flex">
+        <div style="font-size: 14px; cursor: pointer" class="by-dropdown">
+          <div class="by-dropdown-title">
+            <span>{{
+              dictValueLabel(
+                sourceList.paginationTwo.statisticsType,
+                statisticsType
+              )
+            }}</span>
+            <el-icon style="margin-left: 5px; font-size: 16px"
+              ><CaretBottom
+            /></el-icon>
+          </div>
+          <ul class="by-dropdown-lists">
+            <li
+              v-for="item in statisticsType"
+              :key="item.value"
+              @click="searchItemSelect(item.value)"
+              style="
+                display: flex;
+                align-items: center;
+                justify-content: center;
+              "
+            >
+              {{ item.label }}
+            </li>
+          </ul>
+        </div>
+      </div>
+      <div
+        style="
+          display: flex;
+          width: 100%;
+          margin: 10px 0 0 10px;
+          flex-wrap: wrap;
+        "
+      >
+        <div
+          style="
+            padding: 20px;
+            border-radius: 10px;
+            width: 200px;
+            background-color: #d1caff59;
+            margin: 0 20px 20px 0;
+          "
+        >
+          <div style="margin-bottom: 10px; display: flex">
+            <div
+              style="
+                width: 8px;
+                height: 8px;
+                background-color: #5bacff;
+                border-radius: 50px;
+                margin-top: 6px;
+              "
+            ></div>
+            <span style="padding-left: 8px">合计</span>
+          </div>
+          <div style="color: black; font-size: 20px; font-weight: 700">
+            {{ statisticalData.countAmount }}
+          </div>
+        </div>
+        <template v-if="sourceList.paginationTwo.statisticsType === 1">
+          <div
+            style="
+              padding: 20px;
+              border-radius: 10px;
+              width: 200px;
+              background-color: #a2d8ff70;
+              margin: 0 20px 20px 0;
+            "
+            v-for="(item, index) in customerSource"
+            :key="index"
+          >
+            <div style="margin-bottom: 10px; display: flex">
+              <div
+                style="
+                  width: 8px;
+                  height: 8px;
+                  background-color: #5bacff;
+                  border-radius: 50px;
+                  margin-top: 6px;
+                "
+              ></div>
+              <div class="statistics-text">
+                <el-tooltip class="box-item" effect="light" placement="bottom">
+                  <template #content>
+                    <div
+                      style="
+                        max-width: 400px;
+                        max-height: 50vh;
+                        word-break: break-all;
+                      "
+                    >
+                      {{ item.label }}
+                    </div>
+                  </template>
+                  <span style="cursor: pointer">{{ item.label }}</span>
+                </el-tooltip>
+              </div>
+            </div>
+            <div style="color: black; font-size: 20px; font-weight: 700">
+              {{ getNum(item.value) }}
+            </div>
+          </div>
+        </template>
+        <template v-else-if="sourceList.paginationTwo.statisticsType === 2">
+          <div
+            style="
+              padding: 20px;
+              border-radius: 10px;
+              width: 200px;
+              background-color: #a2d8ff70;
+              margin: 0 20px 20px 0;
+            "
+            v-for="(item, index) in customerStatus"
+            :key="index"
+          >
+            <div style="margin-bottom: 10px; display: flex">
+              <div
+                style="
+                  width: 8px;
+                  height: 8px;
+                  background-color: #5bacff;
+                  border-radius: 50px;
+                  margin-top: 6px;
+                "
+              ></div>
+              <div class="statistics-text">
+                <el-tooltip class="box-item" effect="light" placement="bottom">
+                  <template #content>
+                    <div
+                      style="
+                        max-width: 400px;
+                        max-height: 50vh;
+                        word-break: break-all;
+                      "
+                    >
+                      {{ item.label }}
+                    </div>
+                  </template>
+                  <span style="cursor: pointer">{{ item.label }}</span>
+                </el-tooltip>
+              </div>
+            </div>
+            <div style="color: black; font-size: 20px; font-weight: 700">
+              {{ getNum(item.value) }}
+            </div>
+          </div>
+        </template>
+        <template v-else-if="sourceList.paginationTwo.statisticsType === 3">
+          <div
+            style="
+              padding: 20px;
+              border-radius: 10px;
+              width: 200px;
+              background-color: #a2d8ff70;
+              margin: 0 20px 20px 0;
+            "
+            v-for="(item, index) in userList"
+            :key="index"
+          >
+            <div style="margin-bottom: 10px; display: flex">
+              <div
+                style="
+                  width: 8px;
+                  height: 8px;
+                  background-color: #5bacff;
+                  border-radius: 50px;
+                  margin-top: 6px;
+                "
+              ></div>
+              <div class="statistics-text">
+                <el-tooltip class="box-item" effect="light" placement="bottom">
+                  <template #content>
+                    <div
+                      style="
+                        max-width: 400px;
+                        max-height: 50vh;
+                        word-break: break-all;
+                      "
+                    >
+                      {{ item.label }}
+                    </div>
+                  </template>
+                  <span style="cursor: pointer">{{ item.label }}</span>
+                </el-tooltip>
+              </div>
+            </div>
+            <div style="color: black; font-size: 20px; font-weight: 700">
+              {{ getNum(item.value) }}
+            </div>
+          </div>
+        </template>
+      </div>
+    </div>
+    <byTable
+      :source="sourceList.data"
+      :pagination="sourceList.pagination"
+      :config="config"
+      :loading="loading"
+      :selectConfig="selectConfig"
+      highlight-current-row
+      @get-list="getList"
+    >
+      <template #isTop="{ item }">
+        <div>
+          <img
+            style="cursor: pointer; width: 20px; transform: translateY(5px)"
+            :src="'/img/isTop.png'"
+            @click="deleteTop(item)"
+            v-if="item.isTop === 1"
+          />
+          <img
+            style="cursor: pointer; width: 20px; transform: translateY(5px)"
+            :src="'/img/noTop.png'"
+            @click="addTop(item)"
+            v-else
+          />
+        </div>
+      </template>
+      <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 }">
+        <!-- style="cursor: pointer; color: #409eff" @click="handleClickName(item)" -->
+        <div>
+          {{ item.name }}
+        </div>
+      </template>
+      <template #tags="{ item }">
+        <div style="width: 100%">
+          <el-tag
+            style="margin-right: 8px"
+            type="success"
+            v-for="(tag, index) in item.tag"
+            closable
+            :key="index"
+            @close="tagClose(tag, item)"
+          >
+            {{ dictValueLabel(tag, customerTag) }}
+          </el-tag>
+          <template v-if="item.tag.length !== customerTag.length">
+            <el-select
+              v-if="item.addTagShow"
+              v-model="addTag"
+              style="width: 100%"
+              @change="
+                (val) => {
+                  return changeTag(val, item);
+                }
+              "
+            >
+              <el-option
+                v-for="tag in customerTag"
+                :key="tag.value"
+                :label="tag.label"
+                :value="tag.value"
+                :disabled="judgeTagSelect(item.tag, tag.value)"
+              />
+            </el-select>
+            <el-tag
+              style="cursor: pointer"
+              type="success"
+              @click="showSelect(item)"
+              v-else
+            >
+              +
+            </el-tag>
+          </template>
+        </div>
+      </template>
+      <template #follow="{ item }">
+        <div :class="'getWidth' + item.id" style="width: 100%">
+          <div style="width: 100%; display: flex">
+            <template
+              v-if="
+                item.customerFollowRecordsList &&
+                item.customerFollowRecordsList.length > 0
+              "
+            >
+              <div
+                :style="
+                  index > 2
+                    ? 'line-height: 32px; margin-right: 8px; padding: 0 8px; background-color: #eeeeee; border-radius: 4px; cursor: pointer; display: none'
+                    : 'line-height: 32px; margin-right: 8px; padding: 0 8px; background-color: #eeeeee; border-radius: 4px; cursor: pointer'
+                "
+                v-for="(record, index) in item.customerFollowRecordsList"
+                :key="record.id"
+              >
+                <el-popover
+                  placement="bottom"
+                  :width="300"
+                  trigger="hover"
+                  @show="recordShow(record)"
+                >
+                  <template #reference>
+                    <div>
+                      <span v-if="record.date">{{
+                        record.date.substr(0, 10)
+                      }}</span>
+                      <el-icon
+                        style="margin-left: 8px; transform: translateY(2px)"
+                        @click="deleteFollow(record)"
+                        ><DeleteFilled
+                      /></el-icon>
+                    </div>
+                  </template>
+                  <template #default>
+                    <div style="width: 100%">
+                      <div style="color: #909399; margin: 8px 0">
+                        跟进时间: {{ record.date }}
+                      </div>
+                      <div
+                        style="word-wrap: break-word; margin: 8px 0"
+                        v-html="getStyle(record.content)"
+                        v-if="record.content"
+                      ></div>
+                      <div v-else>跟进记录:</div>
+                      <div
+                        style="margin: 8px 0; display: flex"
+                        v-if="record.fileList && record.fileList.length > 0"
+                      >
+                        <div style="width: 36px">附件:</div>
+                        <div style="width: calc(100% - 36px)">
+                          <div
+                            v-for="(file, index) in record.fileList"
+                            :key="index"
+                          >
+                            <a
+                              style="color: #409eff; cursor: pointer"
+                              @click="openFile(file.fileUrl)"
+                              >{{ file.fileName }}</a
+                            >
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                  </template>
+                </el-popover>
+              </div>
+              <div
+                style="
+                  line-height: 32px;
+                  margin-right: 8px;
+                  padding: 0 8px;
+                  background-color: #eeeeee;
+                  border-radius: 4px;
+                  cursor: pointer;
+                "
+                @click="clickMore(item)"
+                v-if="item.customerFollowRecordsList.length >= 3"
+              >
+                更多
+              </div>
+            </template>
+          </div>
+        </div>
+      </template>
+    </byTable>
+
+    <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 #allAddress>
+          <el-row style="width: 100%">
+            <el-col :span="8">
+              <el-form-item prop="countryId">
+                <el-select
+                  v-model="formData.data.countryId"
+                  placeholder="国家"
+                  filterable
+                  allow-create
+                  @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="provinceName">
+                <selectCity
+                  placeholder="省/洲"
+                  @change="(val) => getCityData(val, '30', true)"
+                  addressId="provinceId"
+                  addressName="provinceName"
+                  v-model="formData.data"
+                  :data="provinceData"
+                >
+                </selectCity>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item prop="cityName">
+                <selectCity
+                  placeholder="城市"
+                  addressId="cityId"
+                  addressName="cityName"
+                  v-model="formData.data"
+                  :data="cityData"
+                ></selectCity>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <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-form-item>
+            </el-col>
+          </el-row>
+        </template>
+        <template #person>
+          <div style="width: 100%">
+            <el-button type="primary" @click="clickAddPerson">添 加</el-button>
+            <el-table
+              :data="formData.data.customerUserList"
+              style="width: 100%; margin-top: 16px"
+            >
+              <el-table-column label="联系人" width="160">
+                <template #default="{ row, $index }">
+                  <div style="width: 100%">
+                    <el-form-item
+                      :prop="'customerUserList.' + $index + '.name'"
+                      :rules="rules.name2"
+                      :inline-message="true"
+                    >
+                      <el-input v-model="row.name" placeholder="请输入联系人" />
+                    </el-form-item>
+                  </div>
+                </template>
+              </el-table-column>
+              <el-table-column label="电子邮箱">
+                <template #default="{ row, $index }">
+                  <div style="width: 100%">
+                    <el-form-item
+                      :prop="'customerUserList.' + $index + '.email'"
+                      :rules="rules.email"
+                      :inline-message="true"
+                    >
+                      <el-input
+                        v-model="row.email"
+                        placeholder="请输入电子邮箱"
+                      />
+                    </el-form-item>
+                  </div>
+                </template>
+              </el-table-column>
+              <el-table-column
+                align="center"
+                label="操作"
+                width="120"
+                fixed="right"
+              >
+                <template #default="{ row, $index }">
+                  <el-button
+                    type="primary"
+                    link
+                    @click="clickInformationMore(row, $index)"
+                    >更多</el-button
+                  >
+                  <el-button type="primary" link @click="clickDelete($index)"
+                    >删除</el-button
+                  >
+                </template>
+              </el-table-column>
+            </el-table>
+          </div>
+        </template>
+      </byForm>
+      <template #footer>
+        <el-button @click="dialogVisible = false" size="large">取 消</el-button>
+        <el-button
+          type="primary"
+          @click="submitForm()"
+          size="large"
+          :loading="submitLoading"
+          >确 定</el-button
+        >
+      </template>
+    </el-dialog>
+
+    <el-dialog
+      title="更多联系方式"
+      v-if="openPerson"
+      v-model="openPerson"
+      width="700"
+    >
+      <el-form
+        :label-position="'top'"
+        :model="formPerson.data"
+        :rules="rulesPerson"
+        ref="person"
+      >
+        <el-form-item label="联系人" prop="name">
+          <el-input v-model="formPerson.data.name" />
+        </el-form-item>
+        <el-form-item label="电子邮箱" prop="email">
+          <el-input v-model="formPerson.data.email" />
+        </el-form-item>
+        <el-form-item label="更多联系方式">
+          <div style="width: 100%">
+            <el-button type="primary" @click="clickAddMoreInformation"
+              >添 加</el-button
+            >
+            <el-table
+              :data="formPerson.data.contact"
+              style="width: 100%; margin-top: 16px"
+            >
+              <el-table-column label="类型" width="180">
+                <template #default="{ row, $index }">
+                  <div style="width: 100%">
+                    <el-form-item
+                      :prop="'contact.' + $index + '.type'"
+                      :rules="rulesPerson.type"
+                      :inline-message="true"
+                    >
+                      <el-select
+                        v-model="row.type"
+                        placeholder="请选择类型"
+                        style="width: 100%"
+                      >
+                        <el-option
+                          v-for="item in contactType"
+                          :key="item.value"
+                          :label="item.label"
+                          :value="item.value"
+                        />
+                      </el-select>
+                    </el-form-item>
+                  </div>
+                </template>
+              </el-table-column>
+              <el-table-column label="联系号码">
+                <template #default="{ row, $index }">
+                  <div style="width: 100%">
+                    <el-form-item
+                      :prop="'contact.' + $index + '.contactNo'"
+                      :rules="rulesPerson.contactNo"
+                      :inline-message="true"
+                    >
+                      <el-input
+                        v-model="row.contactNo"
+                        placeholder="请输入联系号码"
+                      />
+                    </el-form-item>
+                  </div>
+                </template>
+              </el-table-column>
+              <el-table-column
+                align="center"
+                label="操作"
+                width="120"
+                fixed="right"
+              >
+                <template #default="{ $index }">
+                  <el-button
+                    type="primary"
+                    link
+                    @click="clickInformationDelete($index)"
+                    >删除</el-button
+                  >
+                </template>
+              </el-table-column>
+            </el-table>
+          </div>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="openPerson = false" size="large">取 消</el-button>
+        <el-button type="primary" @click="submitPerson()" size="large"
+          >确 定</el-button
+        >
+      </template>
+    </el-dialog>
+
+    <el-dialog
+      title="分配"
+      v-if="openAllocation"
+      v-model="openAllocation"
+      width="300"
+    >
+      <byForm
+        :formConfig="formConfigAllocation"
+        :formOption="formOption"
+        v-model="formAllocation.data"
+        :rules="rulesAllocation"
+        ref="allocation"
+      >
+      </byForm>
+      <template #footer>
+        <el-button @click="openAllocation = false" size="large"
+          >取 消</el-button
+        >
+        <el-button type="primary" @click="submitAllocation()" size="large"
+          >确 定</el-button
+        >
+      </template>
+    </el-dialog>
+
+    <el-dialog
+      title="添加跟进记录"
+      v-if="openFollow"
+      v-model="openFollow"
+      width="500"
+      destroy-on-close
+    >
+      <byForm
+        :formConfig="formConfigAFollow"
+        :formOption="formOption"
+        v-model="formFollow.data"
+        :rules="rulesFollow"
+        ref="follow"
+      >
+        <template #fileSlot>
+          <div style="width: 100%">
+            <el-upload
+              v-model:fileList="fileList"
+              action="https://winfaster.obs.cn-south-1.myhuaweicloud.com"
+              :data="uploadData"
+              multiple
+              :before-upload="uploadFile"
+              :on-preview="onPreviewFile"
+            >
+              <el-button type="primary">文件上传</el-button>
+            </el-upload>
+          </div>
+        </template>
+      </byForm>
+      <template #footer>
+        <el-button @click="openFollow = false" size="large">取 消</el-button>
+        <el-button type="primary" @click="submitFollow()" size="large"
+          >确 定</el-button
+        >
+      </template>
+    </el-dialog>
+
+    <el-dialog
+      title="跟进记录"
+      v-if="openRecordMore"
+      v-model="openRecordMore"
+      width="800"
+      destroy-on-close
+    >
+      <div>
+        <div style="padding: 8px 0">
+          <el-button type="primary" @click="clickFollowUp(rowData)" plain
+            >添加跟进记录</el-button
+          >
+        </div>
+        <div style="padding-top: 16px">
+          <div
+            v-infinite-scroll="infiniteScroll"
+            class="infinite-scroll"
+            :infinite-scroll-disabled="judgeTotal()"
+          >
+            <el-timeline>
+              <el-timeline-item
+                v-for="(record, index) in recordList"
+                :key="index"
+                :timestamp="record.date"
+                hide-timestamp
+              >
+                <div>
+                  <div
+                    style="
+                      padding: 0 0 8px 0;
+                      display: flex;
+                      justify-content: space-between;
+                    "
+                  >
+                    <span>{{
+                      dictValueLabel(record.createUser, userList)
+                    }}</span>
+                    <span>{{ record.date }}</span>
+                  </div>
+                  <div
+                    style="word-wrap: break-word; margin: 8px 0"
+                    v-html="getStyle(record.content)"
+                    v-if="record.content"
+                  ></div>
+                  <div style="margin: 8px 0" v-else>跟进记录:</div>
+                  <div
+                    style="margin: 8px 0; display: flex"
+                    v-if="record.fileList && record.fileList.length > 0"
+                  >
+                    <div style="width: 36px">附件:</div>
+                    <div style="width: calc(100% - 36px)">
+                      <div
+                        v-for="(file, index) in record.fileList"
+                        :key="index"
+                      >
+                        <a
+                          style="color: #409eff; cursor: pointer"
+                          @click="openFile(file.fileUrl)"
+                          >{{ file.fileName }}</a
+                        >
+                      </div>
+                    </div>
+                  </div>
+                </div>
+              </el-timeline-item>
+            </el-timeline>
+          </div>
+        </div>
+      </div>
+      <template #footer>
+        <el-button @click="openRecordMore = false" size="large"
+          >关 闭</el-button
+        >
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { ElMessage, ElMessageBox } from "element-plus";
+import byTable from "@/components/byTable/index";
+import byForm from "@/components/byForm/index";
+import { computed, ref } from "vue";
+import useUserStore from "@/store/modules/user";
+import selectCity from "@/components/selectCity/index.vue";
+
+const { proxy } = getCurrentInstance();
+const loading = ref(false);
+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 contactType = ref([]);
+const userList = ref([]);
+const fileList = ref([]);
+const uploadData = ref({});
+const statisticsType = ref([
+  {
+    label: "客户来源统计",
+    value: 1,
+  },
+  {
+    label: "客户类型统计",
+    value: 2,
+  },
+  {
+    label: "业务员统计",
+    value: 3,
+  },
+]);
+const sourceList = ref({
+  data: [],
+  pagination: {
+    total: 0,
+    pageNum: 1,
+    pageSize: 10,
+    keyword: "",
+    status: "",
+    source: "",
+    type: "",
+  },
+  paginationTwo: {
+    statisticsType: 1,
+    type: null,
+  },
+});
+const selectConfig = computed(() => {
+  return [
+    {
+      label: "客户状态",
+      prop: "type",
+      data: [
+        {
+          label: "公海",
+          value: "0",
+        },
+        {
+          label: "私海",
+          value: "1",
+        },
+      ],
+    },
+    {
+      label: "客户来源",
+      prop: "source",
+      data: customerSource.value,
+    },
+    {
+      label: "客户类型",
+      prop: "status",
+      data: customerStatus.value,
+    },
+  ];
+});
+const config = computed(() => {
+  return [
+    {
+      attrs: {
+        label: "",
+        slot: "isTop",
+        fixed: "left",
+        width: 60,
+        align: "center",
+      },
+    },
+    {
+      attrs: {
+        label: "客户名称",
+        prop: "name",
+        slot: "name",
+        fixed: "left",
+        width: 180,
+      },
+    },
+    {
+      attrs: {
+        label: "所在城市",
+        slot: "address",
+        width: 160,
+      },
+    },
+    {
+      attrs: {
+        label: "客户代码",
+        prop: "customerCode",
+        width: 120,
+      },
+    },
+    {
+      attrs: {
+        label: "客户来源",
+        prop: "source",
+        width: 120,
+      },
+      render(type) {
+        return proxy.dictValueLabel(type, customerSource.value);
+      },
+    },
+    {
+      attrs: {
+        label: "客户类型",
+        prop: "status",
+        width: 120,
+      },
+      render(type) {
+        return proxy.dictValueLabel(type, customerStatus.value);
+      },
+    },
+    {
+      attrs: {
+        label: "客户标签",
+        slot: "tags",
+      },
+    },
+    // {
+    //   attrs: {
+    //     label: "业务员",
+    //     prop: "userId",
+    //     width: 140,
+    //   },
+    //   render(type) {
+    //     let data = userList.value.filter((item) => item.value == type);
+    //     if (data && data.length > 0) {
+    //       return data[0].label;
+    //     } else {
+    //       return "";
+    //     }
+    //   },
+    // },
+    // {
+    //   attrs: {
+    //     label: "跟进",
+    //     slot: "follow",
+    //     "min-width": 440,
+    //   },
+    // },
+    {
+      attrs: {
+        label: "操作",
+        width: 120,
+        align: "center",
+        fixed: "right",
+      },
+      renderHTML(row) {
+        return [
+          // {
+          //   attrs: {
+          //     label: "分配",
+          //     type: "primary",
+          //     text: true,
+          //   },
+          //   el: "button",
+          //   click() {
+          //     formAllocation.data = {
+          //       id: row.id,
+          //       userId: row.userId,
+          //     };
+          //     openAllocation.value = true;
+          //   },
+          // },
+          // {
+          //   attrs: {
+          //     label: "跟进",
+          //     type: "primary",
+          //     text: true,
+          //   },
+          //   el: "button",
+          //   click() {
+          //     clickFollowUp(row);
+          //   },
+          // },
+          {
+            attrs: {
+              label: "修改",
+              type: "primary",
+              text: true,
+            },
+            el: "button",
+            click() {
+              update(row);
+            },
+          },
+          {
+            attrs: {
+              label: "删除",
+              type: "primary",
+              text: true,
+            },
+            el: "button",
+            click() {
+              ElMessageBox.confirm(
+                "此操作将永久删除该数据, 是否继续?",
+                "提示",
+                {
+                  confirmButtonText: "确定",
+                  cancelButtonText: "取消",
+                  type: "warning",
+                }
+              ).then(() => {
+                proxy
+                  .post("/customer/delete", {
+                    id: row.id,
+                  })
+                  .then(() => {
+                    ElMessage({
+                      message: "删除成功",
+                      type: "success",
+                    });
+                    getList();
+                    obtainStatisticalData();
+                  });
+              });
+            },
+          },
+        ];
+      },
+    },
+  ];
+});
+const modalType = ref("add");
+const dialogVisible = ref(false);
+const formData = reactive({
+  data: {
+    countryId: "44",
+  },
+});
+const openFollow = ref(false);
+const formPerson = reactive({
+  data: {},
+});
+const formAllocation = reactive({
+  data: {},
+});
+const formFollow = reactive({
+  data: {},
+});
+const formOption = reactive({
+  inline: true,
+  labelWidth: 100,
+  itemWidth: 100,
+  rules: [],
+});
+const formConfig = computed(() => {
+  return [
+    {
+      type: "input",
+      prop: "name",
+      label: "客户名称",
+      required: true,
+      itemWidth: 100,
+      itemType: "text",
+    },
+    {
+      type: "slot",
+      slotName: "allAddress",
+      label: "详细地址",
+    },
+    {
+      type: "input",
+      prop: "customerCode",
+      label: "客户代码",
+      required: true,
+      itemWidth: 100,
+      itemType: "text",
+    },
+    {
+      type: "select",
+      label: "客户来源",
+      prop: "source",
+      itemWidth: 50,
+      data: customerSource.value,
+    },
+    {
+      type: "select",
+      label: "客户类型",
+      prop: "status",
+      itemWidth: 50,
+      data: customerStatus.value,
+    },
+    {
+      type: "select",
+      label: "业务员",
+      prop: "userId",
+      itemWidth: 100,
+      data: userList.value,
+      clearable: true,
+    },
+    {
+      type: "select",
+      label: "客户标签",
+      prop: "tags",
+      itemWidth: 100,
+      multiple: true,
+      data: customerTag.value,
+      style: {
+        width: "100%",
+      },
+    },
+    {
+      type: "slot",
+      slotName: "person",
+      label: "客户联系人",
+    },
+  ];
+});
+const rules = ref({
+  name: [{ required: true, message: "请输入客户名称", trigger: "blur" }],
+  name2: [{ required: true, message: "请输入联系人", trigger: "blur" }],
+  email: [{ required: true, message: "请输入电子邮箱", trigger: "blur" }],
+  countryId: [{ required: true, message: "请选择国家", trigger: "change" }],
+  source: [{ required: true, message: "请选择客户来源", trigger: "change" }],
+  status: [{ required: true, message: "请选择类型", trigger: "change" }],
+});
+const formConfigAllocation = computed(() => {
+  return [
+    {
+      type: "select",
+      label: "业务员",
+      prop: "userId",
+      itemWidth: 100,
+      data: userList.value,
+      clearable: true,
+    },
+  ];
+});
+const rulesAllocation = ref({
+  userId: [{ required: true, message: "请选择业务员", trigger: "change" }],
+});
+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 rulesPerson = ref({
+  name: [{ required: true, message: "请输入联系人", trigger: "blur" }],
+  email: [{ required: true, message: "请输入电子邮箱", trigger: "blur" }],
+  type: [{ required: true, message: "请选择类型", trigger: "change" }],
+  contactNo: [{ required: true, message: "请输入联系号码", trigger: "blur" }],
+});
+const 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) => {
+      x.addTagShow = false;
+      if (x.tag) {
+        x.tag = x.tag.split(",");
+      } else {
+        x.tag = [];
+      }
+    });
+    sourceList.value.data = res.rows;
+    sourceList.value.pagination.total = res.total;
+    setTimeout(() => {
+      loading.value = false;
+    }, 200);
+  });
+};
+const countryData = ref([]);
+const provinceData = ref([]);
+const cityData = ref([]);
+const getCityData = (id, type, isChange) => {
+  proxy.post("/customizeArea/list", { parentId: id }).then((res) => {
+    if (type === "20") {
+      provinceData.value = res;
+      if (isChange) {
+        formData.data.provinceId = "";
+        formData.data.provinceName = "";
+        formData.data.cityId = "";
+        formData.data.cityName = "";
+      }
+    } else if (type === "30") {
+      cityData.value = res;
+      if (isChange) {
+        formData.data.cityId = "";
+        formData.data.cityName = "";
+      }
+    } else {
+      countryData.value = res;
+    }
+  });
+};
+getCityData("0");
+const openModal = () => {
+  modalType.value = "add";
+  formData.data = {
+    countryId: "44",
+    tags: [],
+  };
+  getCityData(formData.data.countryId, "20");
+  loadingOperation.value = false;
+  dialogVisible.value = true;
+};
+const clickAddPerson = () => {
+  if (
+    formData.data.customerUserList &&
+    formData.data.customerUserList.length > 0
+  ) {
+    formData.data.customerUserList.push({
+      name: "",
+      email: "",
+    });
+  } else {
+    formData.data.customerUserList = [
+      {
+        name: "",
+        email: "",
+      },
+    ];
+  }
+};
+const submitAllocation = () => {
+  allocation.value.handleSubmit(() => {
+    proxy.post("/customer/CustomerAllocation", formAllocation.data).then(() => {
+      ElMessage({
+        message: "分配成功",
+        type: "success",
+      });
+      openAllocation.value = false;
+      getList();
+      obtainStatisticalData();
+    });
+  });
+};
+const submitFollow = () => {
+  follow.value.handleSubmit(() => {
+    if (fileList.value && fileList.value.length > 0) {
+      formFollow.data.fileList = fileList.value.map((item) => {
+        return {
+          id: item.raw.id,
+          fileName: item.raw.fileName,
+          fileUrl: item.raw.fileUrl,
+        };
+      });
+    } else {
+      formFollow.data.fileList = [];
+    }
+    proxy
+      .post("/customerFollowRecords/" + modalType.value, formFollow.data)
+      .then(
+        () => {
+          ElMessage({
+            message: modalType.value == "add" ? "添加成功" : "编辑成功",
+            type: "success",
+          });
+          openFollow.value = false;
+          getList();
+        },
+        (err) => {
+          console.log(err);
+        }
+      );
+  });
+};
+const submitForm = () => {
+  submit.value.handleSubmit(() => {
+    if (
+      formData.data.customerUserList &&
+      formData.data.customerUserList.length > 0
+    ) {
+      formData.data.tag = formData.data.tags.join(",");
+      submitLoading.value = true;
+      proxy.post("/customer/" + modalType.value, formData.data).then(
+        () => {
+          ElMessage({
+            message: modalType.value == "add" ? "添加成功" : "编辑成功",
+            type: "success",
+          });
+          dialogVisible.value = false;
+          submitLoading.value = false;
+          getList();
+          obtainStatisticalData();
+        },
+        (err) => {
+          console.log(err);
+          submitLoading.value = false;
+        }
+      );
+    } else {
+      ElMessage("请添加客户联系人");
+    }
+  });
+};
+const getDict = () => {
+  proxy
+    .getDictOne([
+      "customer_tag",
+      "customer_source",
+      "customer_status",
+      "contact_type",
+    ])
+    .then((res) => {
+      customerTag.value = res["customer_tag"].map((x) => ({
+        label: x.dictValue,
+        value: x.dictKey,
+      }));
+      customerSource.value = res["customer_source"].map((x) => ({
+        label: x.dictValue,
+        value: x.dictKey,
+      }));
+      customerStatus.value = res["customer_status"].map((x) => ({
+        label: x.dictValue,
+        value: x.dictKey,
+      }));
+      contactType.value = res["contact_type"].map((x) => ({
+        label: x.dictValue,
+        value: x.dictKey,
+      }));
+    });
+  proxy
+    .get("/tenantUser/list", {
+      pageNum: 1,
+      pageSize: 10000,
+      tenantId: useUserStore().user.tenantId,
+    })
+    .then((res) => {
+      userList.value = res.rows.map((item) => {
+        return {
+          label: item.nickName,
+          value: item.userId,
+        };
+      });
+    });
+};
+getDict();
+getList();
+const handleClickName = (row) => {
+  proxy.$router.push({
+    path: "/ERP/customer/portrait",
+    query: {
+      id: row.id,
+    },
+  });
+};
+const deleteFollow = (data) => {
+  ElMessageBox.confirm("是否确认删除该跟进?", "提示", {
+    confirmButtonText: "确定",
+    cancelButtonText: "取消",
+    type: "warning",
+  }).then(() => {
+    proxy
+      .post("/customerFollowRecords/delete", {
+        id: data.id,
+      })
+      .then(() => {
+        ElMessage({
+          message: "删除成功",
+          type: "success",
+        });
+        getList();
+      });
+  });
+};
+const addTag = ref("");
+const judgeTagSelect = (data, val) => {
+  if (data && data.length > 0) {
+    if (data.includes(val)) {
+      return true;
+    }
+  }
+  return false;
+};
+const changeTag = (val, item) => {
+  let data = {
+    id: item.id,
+    tag: JSON.parse(JSON.stringify(item.tag)),
+  };
+  data.tag.push(val);
+  data.tag = data.tag.join(",");
+  proxy.post("/customer/editTag", data).then(() => {
+    ElMessage({
+      message: "添加成功",
+      type: "success",
+    });
+    item.addTagShow = false;
+    addTag.value = "";
+    getList();
+  });
+};
+const tagClose = (val, item) => {
+  let data = {
+    id: item.id,
+    tag: JSON.parse(JSON.stringify(item.tag)),
+  };
+  data.tag = data.tag.filter((row) => row !== val);
+  if (data.tag && data.tag.length > 0) {
+    data.tag = data.tag.join(",");
+  } else {
+    data.tag = "";
+  }
+  proxy.post("/customer/editTag", data).then(() => {
+    ElMessage({
+      message: "添加成功",
+      type: "success",
+    });
+    item.addTagShow = false;
+    addTag.value = "";
+    getList();
+  });
+};
+const showSelect = (item) => {
+  item.addTagShow = true;
+};
+const clickFollowUp = (item) => {
+  formFollow.data = {
+    customerId: item.id,
+    fileList: [],
+  };
+  fileList.value = [];
+  modalType.value = "add";
+  openFollow.value = true;
+  openRecordMore.value = false;
+};
+const uploadFile = async (file) => {
+  const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
+  uploadData.value = res.uploadBody;
+  file.id = res.id;
+  file.fileName = res.fileName;
+  file.fileUrl = res.fileUrl;
+  return true;
+};
+const onPreviewFile = (file) => {
+  window.open(file.raw.fileUrl, "_blank");
+};
+const getStyle = (val) => {
+  if (val) {
+    return "跟进记录: " + val.replace(/\n|\r\n/g, "<br>");
+  } else {
+    return "";
+  }
+};
+const recordShow = (item) => {
+  if (!(item.fileList && item.fileList.length > 0)) {
+    proxy
+      .post("/fileInfo/getList", { businessIdList: [item.id] })
+      .then((fileObj) => {
+        item.fileList = fileObj[item.id] || [];
+      });
+  }
+};
+const openFile = (path) => {
+  window.open(path, "_blank");
+};
+const recordList = ref([]);
+const rowData = ref({});
+const openRecordMore = ref(false);
+const queryParams = ref({
+  total: 0,
+  pageNum: 1,
+  pageSize: 10,
+  customerId: "",
+});
+const clickMore = (item) => {
+  if (openRecordMore.value === false) {
+    queryParams.value.pageNum = 1;
+    recordList.value = [];
+    rowData.value = item;
+    queryParams.value.customerId = item.id;
+  }
+  proxy.post("/customerFollowRecords/page", queryParams.value).then((res) => {
+    recordList.value = recordList.value.concat(res.rows);
+    queryParams.value.total = res.total;
+    proxy
+      .post("/fileInfo/getList", {
+        businessIdList: res.rows.map((rows) => rows.id),
+      })
+      .then((fileObj) => {
+        for (let i = 0; i < res.rows.length; i++) {
+          recordList.value[
+            parseInt(
+              i + (queryParams.value.pageNum - 1) * queryParams.value.pageSize
+            )
+          ].fileList =
+            fileObj[
+              recordList.value[
+                parseInt(
+                  i +
+                    (queryParams.value.pageNum - 1) * queryParams.value.pageSize
+                )
+              ].id
+            ] || [];
+        }
+      });
+  });
+  openRecordMore.value = true;
+};
+const infiniteScroll = () => {
+  queryParams.value.pageNum++;
+  clickMore();
+};
+const judgeTotal = () => {
+  if (
+    queryParams.value.pageNum * queryParams.value.pageSize >=
+    queryParams.value.total
+  ) {
+    return true;
+  }
+  return false;
+};
+const moreIndex = ref(0);
+const clickInformationMore = (item, index) => {
+  moreIndex.value = index;
+  if (item.contactJson) {
+    item.contact = JSON.parse(item.contactJson);
+  } else {
+    item.contact = [];
+  }
+  formPerson.data = proxy.deepClone(item);
+  openPerson.value = true;
+};
+const clickDelete = (index) => {
+  formData.data.customerUserList.splice(index, 1);
+};
+const clickAddMoreInformation = () => {
+  if (formPerson.data.contact && formPerson.data.contact.length > 0) {
+    formPerson.data.contact.push({
+      type: "",
+      contactNo: "",
+    });
+  } else {
+    formPerson.data.contact = [
+      {
+        type: "",
+        contactNo: "",
+      },
+    ];
+  }
+};
+const clickInformationDelete = (index) => {
+  formPerson.data.contact.splice(index, 1);
+};
+const submitPerson = () => {
+  person.value.validate((valid) => {
+    if (valid) {
+      formPerson.data.contactJson = JSON.stringify(formPerson.data.contact);
+      formData.data.customerUserList[moreIndex.value] = formPerson.data;
+      openPerson.value = false;
+    }
+  });
+};
+const deleteTop = (item) => {
+  proxy.post("/customerTop/delete", { customerId: item.id }).then(() => {
+    item.isTop = 0;
+  });
+};
+const addTop = (item) => {
+  proxy.post("/customerTop/add", { customerId: item.id }).then(() => {
+    item.isTop = 1;
+  });
+};
+const searchItemSelect = (val) => {
+  sourceList.value.paginationTwo.statisticsType = val;
+  obtainStatisticalData();
+};
+const statisticalData = ref({
+  countAmount: 0,
+  customerList: [],
+});
+const obtainStatisticalData = () => {
+  proxy
+    .post("/customer/sourceStatistics", sourceList.value.paginationTwo)
+    .then((res) => {
+      statisticalData.value = res;
+    });
+};
+obtainStatisticalData();
+const getNum = (val) => {
+  let num = 0;
+  if (
+    statisticalData.value.customerList &&
+    statisticalData.value.customerList.length > 0
+  ) {
+    statisticalData.value.customerList.map((item) => {
+      if (sourceList.value.paginationTwo.statisticsType === 1) {
+        if (item.source === val) {
+          num = item.count;
+        }
+      } else if (sourceList.value.paginationTwo.statisticsType === 2) {
+        if (item.status === val) {
+          num = item.count;
+        }
+      } else if (sourceList.value.paginationTwo.statisticsType === 3) {
+        if (item.userId === val) {
+          num = item.count;
+        }
+      }
+    });
+  }
+  return num;
+};
+const update = (row) => {
+  modalType.value = "edit";
+  loadingOperation.value = true;
+  proxy.post("/customer/detail", { id: row.id }).then((res) => {
+    if (res.tag) {
+      res.tags = res.tag.split(",");
+    } else {
+      res.tags = [];
+    }
+    formData.data = res;
+    getCityData(formData.data.countryId, "20");
+    getCityData(formData.data.provinceId, "30");
+    loadingOperation.value = false;
+    dialogVisible.value = true;
+  });
+};
+</script>
+
+<style lang="scss" scoped>
+.tenant {
+  padding: 20px;
+}
+.infinite-scroll {
+  max-height: calc(89vh - 94px - 70px - 58px - 16px);
+  overflow-y: auto;
+  &::-webkit-scrollbar {
+    width: 0px;
+  }
+}
+.by-dropdown {
+  position: relative;
+  text-align: left;
+  height: 32px;
+  z-index: 1010;
+  padding: 0 10px;
+  transition: all 0.5s ease;
+  cursor: pointer;
+  line-height: 32px;
+  .by-dropdown-title {
+    font-size: 14px;
+    background-color: #fff;
+  }
+  ul {
+    position: absolute;
+    left: 0;
+    top: 32px;
+    padding: 0;
+    margin: 0;
+    z-index: 1200;
+    display: none;
+    white-space: nowrap;
+    background-color: #fff;
+    li {
+      list-style: none;
+      z-index: 1200;
+      font-size: 12px;
+      height: 30px;
+      padding: 0 10px;
+    }
+    li:hover {
+      background-color: #eff6ff;
+      color: #0084ff;
+    }
+  }
+}
+.by-dropdown::before {
+  display: block;
+  width: 1px;
+  content: " ";
+  position: absolute;
+  height: 14px;
+  top: 8px;
+  background-color: #ddd;
+  right: 0;
+  z-index: 1011;
+}
+.by-dropdown:hover {
+  background: #ffffff;
+  border-radius: 2px 2px 2px 2px;
+  opacity: 1;
+  ul {
+    background: #ffffff;
+    box-shadow: 0px 2px 16px 1px rgba(0, 0, 0, 0.06);
+    border-radius: 2px 2px 2px 2px;
+    opacity: 1;
+    display: block;
+    text-align: left;
+  }
+}
+.by-dropdown-lists {
+  max-height: 50vh;
+  overflow-y: auto;
+  line-height: 1;
+}
+.statistics-text {
+  padding-left: 8px;
+  width: 152px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+</style>

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

@@ -413,6 +413,15 @@ const config = computed(() => {
     },
     {
       attrs: {
+        label: "是否组合",
+        prop: "combination",
+      },
+      render(combination) {
+        return combination == 1 ? "是" : combination == 0 ? "否" : "";
+      },
+    },
+    {
+      attrs: {
         label: "图片",
         prop: "unit",
         slot: "pic",

+ 4 - 2
src/views/WDLY/basic/supplier/index.vue

@@ -23,8 +23,9 @@
       >
         <template #address="{ item }">
           <div>
-            {{ item.countryName }}, {{ item.provinceName }} ,
-            {{ item.cityName }}, {{ item.areaDetail }}
+            <span v-if="item.countryName"> {{ item.countryName }} ,</span
+            ><span v-if="item.provinceName">{{ item.provinceName }} ,</span>
+            <span v-if="item.cityName">{{ item.cityName }}</span>
           </div>
         </template>
       </byTable>
@@ -249,6 +250,7 @@ const config = computed(() => {
         label: "所在城市",
         prop: "remarks",
         slot: "address",
+        width: 150,
       },
     },
     {

+ 136 - 15
src/views/WDLY/purchaseManage/alreadyPurchase/index.vue

@@ -24,6 +24,19 @@
           </div>
         </template>
 
+        <template #arrivalStatus="{ item }">
+          <!-- v-if="item.arrivalStatus != '0'" -->
+          <div
+            style="cursor: pointer; color: #409eff"
+            @click="handleClickArrivalStatus(item)"
+          >
+            {{ dictValueLabel(item.arrivalStatus, arrivalStatus) }}
+          </div>
+          <!-- <div v-else>
+            {{ dictValueLabel(item.arrivalStatus, arrivalStatus) }}
+          </div> -->
+        </template>
+
         <template #btn="{ item }">
           <div>
             <el-button
@@ -180,6 +193,74 @@
         </el-button>
       </template>
     </el-dialog>
+
+    <el-dialog
+      :title="'到货详情'"
+      v-model="dialogVisibleOne"
+      width="80%"
+      v-loading="loadingOne"
+      destroy-on-close
+    >
+      <byForm
+        :formConfig="formConfigOne"
+        :formOption="formOption"
+        v-model="formData.dataOne"
+        :rules="rules"
+        ref="byformOne"
+      >
+        <template #detailSlot>
+          <div style="width: 100%">
+            <el-table :data="formData.dataOne.arrivalDetailList">
+              <el-table-column prop="productCode" label="物品编码" />
+              <el-table-column prop="productName" label="物品名称" />
+              <el-table-column prop="count" label="采购数量" />
+              <el-table-column prop="shipmentQuantity" label="已发货">
+                <template #default="{ row }">
+                  <div>
+                    <el-popover
+                      placement="bottom-start"
+                      title="发货详情"
+                      :width="500"
+                      trigger="hover"
+                    >
+                      <div default>
+                        <el-table :data="row.quantityList">
+                          <el-table-column
+                            label="发货时间"
+                            prop="createTime"
+                            width="150"
+                          />
+                          <el-table-column label="物流单号" prop="code" />
+                          <el-table-column
+                            label="数量"
+                            prop="shipmentQuantity"
+                            width="100"
+                          />
+                        </el-table>
+                      </div>
+                      <template #reference>
+                        <div style="cursor: pointer; color: #0084ff">
+                          {{ row.shipmentQuantity }}
+                        </div>
+                      </template>
+                    </el-popover>
+                  </div>
+                </template>
+              </el-table-column>
+              <el-table-column prop="count" label="已到货" />
+              <el-table-column prop="count" label="退货" />
+              <el-table-column prop="count" 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>
   
@@ -187,6 +268,7 @@
 import { ElMessage, ElMessageBox } from "element-plus";
 import byTable from "@/components/byTable/index";
 import byForm from "@/components/byForm/index";
+import { computed } from "vue";
 const loading = ref(false);
 const submitLoading = ref(false);
 const sourceList = ref({
@@ -198,6 +280,7 @@ const sourceList = ref({
   },
 });
 const dialogVisible = ref(false);
+const dialogVisibleOne = ref(false);
 const modalType = ref("add");
 let rules = ref({
   deliverGoodsId: [
@@ -337,10 +420,7 @@ const config = computed(() => {
       attrs: {
         label: "到货状态",
         prop: "arrivalStatus",
-      },
-      render(status) {
-        const current = arrivalStatus.find((x) => x.value == status);
-        if (current) return current.label;
+        slot: "arrivalStatus",
       },
     },
     {
@@ -372,6 +452,36 @@ const formOption = reactive({
 });
 const byform = ref(null);
 let formConfig = reactive([]);
+let formConfigOne = computed(() => [
+  {
+    type: "title",
+    title: "基础信息",
+  },
+  {
+    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 = [
   [
     {
@@ -607,7 +717,7 @@ const handleArrival = (row, type) => {
       formData.data = {
         purchaseId: row.id,
         supplyName: row.supplyName,
-        purchaseCode: row.code,
+        purchaseCode: row.contractCode,
         supplyId: res.supplyId,
         code: "",
         logisticsCompanyCode: "",
@@ -633,7 +743,7 @@ const handleArrival = (row, type) => {
       formData.data = {
         purchaseId: row.id,
         supplyName: row.supplyName,
-        purchaseCode: row.code,
+        purchaseCode: row.contractCode,
         supplyId: row.supplyId,
         code: "",
         logisticsCompanyCode: "",
@@ -675,18 +785,29 @@ watch(
 );
 
 const handleClickContractCode = (row) => {
-  proxy.post("/deliverGoodsDetails/detail", { id: row.id }).then((res) => {
-    proxy.$router.push({
-      path: "/platform_manage/process/processApproval",
-      query: {
-        flowKey: row.processInstanceId,
-        id: row.flowId,
-        processType: 20,
-      },
-    });
+  proxy.$router.push({
+    path: "/platform_manage/process/processApproval",
+    query: {
+      flowKey: row.processInstanceId,
+      id: row.flowId,
+      processType: 20,
+    },
   });
 };
 
+const handleClickArrivalStatus = (row) => {
+  // formData.dataOne = {
+  //   supplyName: row.supplyName,
+  //   purchaseCode: row.contractCode,
+  //   arrivalDetailList: [
+  //     {
+  //       shipmentQuantity: "3",
+  //       quantityList: [],
+  //     },
+  //   ],
+  // };
+  // dialogVisibleOne.value = true;
+};
 getList();
 getLogisticsData();
 </script>

+ 1 - 1
src/views/WDLY/purchaseManage/arrival/index.vue

@@ -188,7 +188,7 @@ const config = computed(() => {
     {
       attrs: {
         label: "采购单号",
-        prop: "purchaseCode",
+        prop: "contractCode",
       },
     },
     {

+ 14 - 0
src/views/WDLY/purchaseManage/purchase/index.vue

@@ -94,6 +94,11 @@ const selectConfig = reactive([
     prop: "receiptWarehouseId",
     data: [],
   },
+  {
+    label: "产品归属部门",
+    prop: "deptId",
+    data: [],
+  },
 ]);
 const config = computed(() => {
   return [
@@ -324,6 +329,8 @@ const start = (type) => {
 
 const warehouseList = ref([]);
 const productUnit = ref([]);
+const deptData = ref([]);
+
 const getDict = () => {
   proxy.getDict(["unit"]).then((res) => {
     productUnit.value = res["unit"];
@@ -340,6 +347,13 @@ const getDict = () => {
         value: x.id,
       }));
     });
+  proxy.get("/subscribe/getDepts").then((res) => {
+    deptData.value = res;
+    selectConfig[2].data = res.map((x) => ({
+      label: x.deptName,
+      value: x.deptId,
+    }));
+  });
 };
 getDict();
 getList();

+ 21 - 0
src/views/WDLY/purchaseManage/subscribe/index.vue

@@ -21,6 +21,14 @@
         ]"
         @get-list="getList"
       >
+        <template #code="{ item }">
+          <div
+            style="cursor: pointer; color: #409eff"
+            @click="handleClickCode(item)"
+          >
+            {{ item.subscribeCode }}
+          </div>
+        </template>
       </byTable>
     </div>
     <el-dialog
@@ -101,6 +109,7 @@ const config = computed(() => {
       attrs: {
         label: "申购单号",
         prop: "subscribeCode",
+        slot: "code",
       },
     },
     {
@@ -330,6 +339,18 @@ const getDict = () => {
 };
 getDict();
 getList();
+
+const handleClickCode = (row) => {
+  proxy.$router.push({
+    path: "/platform_manage/process/processApproval",
+    query: {
+      flowKey: "wdly_apply_purchase",
+      id: row.flowId,
+      subscribeId: row.subscribeId,
+      processType: 20,
+    },
+  });
+};
 </script>
   
 <style lang="scss" scoped>

+ 17 - 21
src/views/WDLY/salesMange/afterSale/index.vue

@@ -197,6 +197,7 @@
       title="跟进记录"
       width="500"
       append-to-body
+      destroy-on-close
     >
       <div style="padding-left: 40px; margin-bottom: 20px">
         <el-button size="mini" @click="openModal('edit')">
@@ -214,7 +215,9 @@
             <div>
               跟进人:{{ activity.handleUserName }}
               <span
-                >({{ dictDataEcho(activity.status, afterSalesStatus) }})</span
+                >({{
+                  dictValueLabel(activity.status, afterSalesStatus)
+                }})</span
               >
             </div>
             <div style="margin-top: 5px">跟进记录: {{ activity.remark }}</div>
@@ -300,16 +303,18 @@ let rules = ref({
   ],
 });
 const { proxy } = getCurrentInstance();
-const selectConfig = reactive([
+const afterSalesType = ref([]);
+const afterSalesStatus = ref([]);
+const selectConfig = computed(() => [
   {
     label: "售后类型",
     prop: "type",
-    data: [],
+    data: afterSalesType.value,
   },
   {
     label: "售后状态",
     prop: "status",
-    data: [],
+    data: afterSalesStatus.value,
   },
 ]);
 const config = computed(() => {
@@ -320,7 +325,7 @@ const config = computed(() => {
         prop: "type",
       },
       render(type) {
-        return proxy.dictDataEcho(type, afterSalesType.value);
+        return proxy.dictValueLabel(type, afterSalesType.value);
       },
     },
     {
@@ -353,8 +358,8 @@ const config = computed(() => {
         label: "售后状态",
         prop: "status",
       },
-      render(type) {
-        return proxy.dictDataEcho(type, afterSalesStatus.value);
+      render(status) {
+        return proxy.dictValueLabel(status, afterSalesStatus.value);
       },
     },
 
@@ -475,6 +480,7 @@ const configData = [
       label: "售后状态",
       required: true,
       itemWidth: 51,
+      data: [],
     },
     {
       type: "select",
@@ -740,29 +746,19 @@ const handleRemove = (index) => {
     type: "success",
   });
 };
-const afterSalesType = ref([]);
-const afterSalesStatus = ref([]);
 
 const getDict = () => {
   proxy.getDict(["after_sale_type", "after_sale_status"]).then((res) => {
-    afterSalesType.value = res["after_sale_type"];
-    configData[0][0].data = afterSalesType.value.map((x) => ({
-      label: x.dictValue,
-      value: x.dictKey,
-    }));
-    selectConfig[0].data = afterSalesType.value.map((x) => ({
-      label: x.dictValue,
-      value: x.dictKey,
-    }));
-    afterSalesStatus.value = res["after_sale_status"];
-    configData[1][0].data = afterSalesStatus.value.map((x) => ({
+    afterSalesType.value = res["after_sale_type"].map((x) => ({
       label: x.dictValue,
       value: x.dictKey,
     }));
-    selectConfig[1].data = afterSalesStatus.value.map((x) => ({
+    configData[0][1].data = afterSalesType.value;
+    afterSalesStatus.value = res["after_sale_status"].map((x) => ({
       label: x.dictValue,
       value: x.dictKey,
     }));
+    configData[1][0].data = afterSalesStatus.value;
   });
 };
 getCityData("0");

+ 15 - 3
src/views/WDLY/stockManage/query/index.vue

@@ -188,6 +188,9 @@ const configData = [
         label: "单位",
         prop: "productUnit",
       },
+      render(unit) {
+        return proxy.dictValueLabel(unit, productUnit.value);
+      },
     },
     {
       attrs: {
@@ -272,6 +275,9 @@ const configData = [
         label: "单位",
         prop: "productUnit",
       },
+      render(unit) {
+        return proxy.dictValueLabel(unit, productUnit.value);
+      },
     },
     {
       attrs: {
@@ -461,8 +467,14 @@ const handleChange = () => {
 };
 
 const warehouseList = ref([]);
-const warehouseListData = () => {
-  // // 币种数据
+const productUnit = ref([]);
+const getDict = () => {
+  proxy.getDictOne(["unit"]).then((res) => {
+    productUnit.value = res["unit"].map((x) => ({
+      label: x.dictValue,
+      value: x.dictKey,
+    }));
+  });
   proxy
     .post("/warehouse/page", {
       pageNum: 1,
@@ -477,7 +489,7 @@ const warehouseListData = () => {
       }));
     });
 };
-warehouseListData();
+getDict();
 </script>
   
 <style lang="scss" scoped>

+ 2 - 2
src/views/process/processApproval/index.vue

@@ -28,7 +28,7 @@
 
         <ServiceContract ref="makeDom" v-else-if="flowForm.flowKey == 'service_contract_flow'" :queryData="queryData.data"></ServiceContract>
         <!-- 维多利亚 -->
-        <SendSubscribeWDLY ref="makeDom" v-else-if="flowForm.flowKey == 'wdly_apply_purchase'"></SendSubscribeWDLY>
+        <SendSubscribeWDLY ref="makeDom" v-else-if="flowForm.flowKey == 'wdly_apply_purchase'" :queryData="queryData.data"></SendSubscribeWDLY>
         <SendPurchaseWDLY ref="makeDom" v-else-if="flowForm.flowKey == 'wdly_purchase'" :queryData="queryData.data"></SendPurchaseWDLY>
       </div>
       <div class="bottom" v-if="route.query.processType != 20">
@@ -465,7 +465,7 @@ onMounted(() => {
   //processType 10 为修改 20为查看
   if (route.query.processType == 10 || route.query.processType == 20) {
     proxy.post("/flowProcess/getStartData", { flowId: route.query.id }).then((res) => {
-      console.log(res);
+      console.log(res,'adawwww');
       queryData.data = { ...res };
     });
   } else {

+ 17 - 1
src/views/purchaseSales/stockManage/inventory/index.vue

@@ -59,7 +59,13 @@
             <el-table :data="formData.data.list" :row-class-name="changeClass">
               <el-table-column prop="productCode" label="物品编码" />
               <el-table-column prop="productName" label="物品名称" />
-              <el-table-column prop="productUnit" label="单位" />
+              <el-table-column
+                prop="productUnit"
+                label="单位"
+                :formatter="
+                  (row) => dictValueLabel(row.productUnit, productUnit)
+                "
+              />
               <el-table-column prop="quantity" label="库存数量" />
               <el-table-column
                 prop="checkQuantity"
@@ -369,6 +375,16 @@ const getDtl = (row) => {
   });
 };
 
+const productUnit = ref([]);
+const getDict = () => {
+  proxy.getDictOne(["unit"]).then((res) => {
+    productUnit.value = res["unit"].map((x) => ({
+      label: x.dictValue,
+      value: x.dictKey,
+    }));
+  });
+};
+getDict();
 getList();
 
 const handleSelect = (row) => {