src/views/basicData/customerFile/index.vue
@@ -15,10 +15,10 @@
                   style="width: 240px"
                   clearable
                   @change="handleQuery">
          <el-option label="零售客户"
                     value="零售客户" />
          <el-option label="进销商客户"
                     value="进销商客户" />
          <el-option v-for="dict in customer_type"
                     :key="dict.value"
                     :label="dict.label"
                     :value="dict.value" />
        </el-select>
        <el-button type="primary"
                   @click="handleQuery"
@@ -27,6 +27,9 @@
      <div>
        <el-button type="primary"
                   @click="openForm('add')">新增客户</el-button>
        <el-button type="primary"
                   plain
                   @click="back">流入公海</el-button>
        <el-button @click="handleOut">导出</el-button>
        <el-button type="info"
                   plain
@@ -45,7 +48,16 @@
                :isSelection="true"
                @selection-change="handleSelectionChange"
                :tableLoading="tableLoading"
                @pagination="pagination"></PIMTable>
                @pagination="pagination">
        <template #depositAmountSlot="{ row }">
          <el-tooltip v-if="row.exceedsTrustFund"
                      :content="`代储金额合计已超出该客户信托基金(信托基金:${row.trustFund})`"
                      placement="top">
            <el-text type="danger">{{ formatAmount(row.depositTotalAmount) }}</el-text>
          </el-tooltip>
          <span v-else>{{ formatAmount(row.depositTotalAmount) }}</span>
        </template>
      </PIMTable>
    </div>
    <el-dialog v-model="dialogFormVisible"
               :title="operationType === 'add' ? '新增客户信息' : '编辑客户信息'"
@@ -125,11 +137,24 @@
              <el-select v-model="form.customerType"
                         placeholder="请选择"
                         clearable>
                <el-option label="零售客户"
                           value="零售客户" />
                <el-option label="进销商客户"
                           value="进销商客户" />
                <el-option v-for="dict in customer_type"
                           :key="dict.value"
                           :label="dict.label"
                           :value="dict.value" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="信托基金(元):"
                          prop="trustFund">
              <el-input-number v-model="form.trustFund"
                               :min="0"
                               :precision="2"
                               :controls="false"
                               placeholder="请输入,可为空"
                               style="width: 100%" />
            </el-form-item>
          </el-col>
        </el-row>
@@ -211,7 +236,8 @@
                 :limit="1"
                 accept=".xlsx, .xls"
                 :headers="upload.headers"
                 :action="upload.url + '?updateSupport=' + upload.updateSupport"
                 :action="upload.url"
                 :data="upload.data"
                 :disabled="upload.isUploading"
                 :before-upload="upload.beforeUpload"
                 :on-progress="upload.onProgress"
@@ -457,6 +483,32 @@
              </div>
            </el-col>
          </el-row>
          <el-row :gutter="20">
            <el-col :span="12">
              <div class="info-item">
                <span class="info-label">信托基金(元):</span>
                <span class="info-value">{{ formatAmount(detailForm.trustFund) }}</span>
              </div>
            </el-col>
            <el-col :span="12">
              <div class="info-item">
                <span class="info-label">代储金额(元):</span>
                <span class="info-value"
                      :class="{ 'text-danger': detailForm.exceedsTrustFund }">
                  {{ formatAmount(detailForm.depositTotalAmount) }}
                </span>
              </div>
            </el-col>
          </el-row>
          <el-row v-if="detailForm.exceedsTrustFund"
                  :gutter="20">
            <el-col :span="24">
              <el-alert type="warning"
                        show-icon
                        :closable="false"
                        :title="`该客户代储金额合计 ${formatAmount(detailForm.depositTotalAmount)} 元,已超出信托基金 ${formatAmount(detailForm.trustFund)} 元`" />
            </el-col>
          </el-row>
        </div>
      </div>
      <!-- 洽谈进度记录 -->
@@ -612,20 +664,20 @@
  import { onMounted, ref, reactive, getCurrentInstance, toRefs } from "vue";
  import { Search, Paperclip, Upload } from "@element-plus/icons-vue";
  import {
    delCustomerPrivate,
    addCustomerFollow,
    updateCustomerFollow,
    delCustomerFollow,
    addReturnVisit,
    getReturnVisit,
  } from "@/api/basicData/customerFile.js";
  import {listCustomer, getCustomer, addCustomer, updateCustomer, delCustomer} from "@/api/basicData/customer.js";
  import {listCustomer, getCustomer, addCustomer, updateCustomer, delCustomer, backCustomer} from "@/api/basicData/customer.js";
  import { ElMessageBox } from "element-plus";
  import { userListNoPage } from "@/api/system/user.js";
  import useUserStore from "@/store/modules/user";
  import { getToken } from "@/utils/auth.js";
  const { proxy } = getCurrentInstance();
  const userStore = useUserStore();
  const { customer_type } = proxy.useDict("customer_type");
  // 回访提醒相关
  const reminderDialogVisible = ref(false);
@@ -671,6 +723,11 @@
    content: [{ required: true, message: "请输入内容", trigger: "blur" }],
  };
  const formatAmount = value => {
    return value === null || value === undefined || value === ""
      ? "-"
      : Number(value).toFixed(2);
  };
  // 详情相关
  const detailDialogVisible = ref(false);
  const detailForm = reactive({
@@ -686,6 +743,9 @@
    contactPhone: "",
    maintainer: "",
    maintenanceTime: "",
    trustFund: "",
    depositTotalAmount: "",
    exceedsTrustFund: false,
  });
  const negotiationRecords = ref([]);
@@ -710,6 +770,7 @@
      label: "客户分类",
      prop: "customerType",
      width: 120,
      formatData: value => proxy.selectDictLabel(customer_type.value, value),
    },
    {
      label: "客户名称",
@@ -756,6 +817,22 @@
      width: 220,
    },
    {
      label: "信托基金(元)",
      prop: "trustFund",
      width: 140,
      formatData: value =>
        value === null || value === undefined || value === ""
          ? "-"
          : Number(value).toFixed(2),
    },
    {
      label: "代储金额(元)",
      prop: "depositTotalAmount",
      dataType: "slot",
      slot: "depositAmountSlot",
      width: 150,
    },
    {
      label: "开户行号",
      prop: "bankCode",
      width: 220,
@@ -797,7 +874,12 @@
        {
          name: "编辑",
          type: "text",
          showHide: row => !isCustomerEditLocked(row),
          clickFun: row => {
            if (isCustomerEditLocked(row)) {
              proxy.$modal.msgWarning("已被销售模块引用的私海客户不能编辑");
              return;
            }
            openForm("edit", row);
          },
        },
@@ -867,6 +949,8 @@
      bankAccount: "",
      bankCode: "",
      customerType: "",
      // 金额字段给 null 而非 "",避免 el-input-number 把空串折算成 0
      trustFund: null,
      type: 0
    },
    rules: {
@@ -898,7 +982,10 @@
    // 设置上传的请求头部
    headers: { Authorization: "Bearer " + getToken() },
    // 上传的地址
    url: import.meta.env.VITE_APP_BASE_API + "/customerPrivate/importData",
    url: import.meta.env.VITE_APP_BASE_API + "/basic/customer/importData",
    data: {
      type: 0
    },
    // 文件上传前的回调
    beforeUpload: file => {
      console.log("文件即将上传", file);
@@ -991,10 +1078,14 @@
  }
  /** 下载模板 */
  function importTemplate() {
    proxy.download("/customerPrivate/downloadTemplate", {}, "客户导入模板.xlsx");
    proxy.download("/basic/customer/downloadTemplate", {}, "客户导入模板.xlsx");
  }
  // 打开弹框
  const openForm = (type, row) => {
    if (type === "edit" && isCustomerEditLocked(row)) {
      proxy.$modal.msgWarning("已被销售模块引用的私海客户不能编辑");
      return;
    }
    operationType.value = type;
    form.value = {};
    form.value.maintainer = userStore.nickName;
@@ -1023,6 +1114,12 @@
      });
    }
    dialogFormVisible.value = true;
  };
  const isCustomerEditLocked = row => {
    const salesReferenced = Number(row?.salesReferenceFlag || 0) === 1;
    const customerType = Number(row?.type);
    const usageStatus = Number(row?.usageStatus || 0);
    return salesReferenced && (customerType === 0 || (customerType === 1 && usageStatus === 1));
  };
  // 提交表单
  const submitForm = () => {
@@ -1080,7 +1177,7 @@
      type: "warning",
    })
      .then(() => {
        proxy.download("/customerPrivate/export", {}, "客户档案.xlsx");
        proxy.download("/basic/customer/export", {type: 0}, "客户档案.xlsx");
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
@@ -1120,6 +1217,36 @@
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
      });
  };
  const back = () => {
    if (selectedRows.value.length === 0) {
      proxy.$modal.msgWarning("请选择数据");
      return;
    }
    const ids = selectedRows.value.map(item => item.id);
    ElMessageBox.confirm("选中的客户将流入公海,是否确认?", "流入公海提示", {
      confirmButtonText: "确认",
      cancelButtonText: "取消",
      type: "warning",
    })
      .then(() => {
        tableLoading.value = true;
        return Promise.all(ids.map(id => backCustomer(id)))
          .then(() => {
            proxy.$modal.msgSuccess("流入公海成功");
            selectedRows.value = [];
            getList();
          })
          .finally(() => {
            tableLoading.value = false;
          });
      })
      .catch(error => {
        if (error === "cancel" || error === "close") {
          proxy.$modal.msg("已取消");
        }
      });
  };
@@ -1410,7 +1537,7 @@
  const downloadAttachment = row => {
    if (row.url) {
      // proxy.download(row.url, {}, row.name);
      proxy.$download.name(row.url);
         proxy.$download.byUrl(row.url, row.originalFilename);
    } else {
      proxy.$modal.msgError("下载链接不存在");
    }
@@ -1523,6 +1650,11 @@
    word-break: break-word;
  }
  .text-danger {
    color: var(--el-color-danger);
    font-weight: 600;
  }
  .no-records {
    text-align: center;
    padding: 30px;