From f4a4737d69746268f3648effcf66e1c1c83e64e1 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期三, 29 四月 2026 14:03:23 +0800
Subject: [PATCH] 公司7004 1.标书台账页面开发与联调 2.客户管理添加客户类型字段
---
src/views/basicData/customerFile/index.vue | 31 ++
src/views/salesManagement/opportunityManagement/index.vue | 37 +
src/api/salesManagement/bidWinningLedger.js | 56 +++
src/views/salesManagement/bidWinningLedger/index.vue | 724 ++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 835 insertions(+), 13 deletions(-)
diff --git a/src/api/salesManagement/bidWinningLedger.js b/src/api/salesManagement/bidWinningLedger.js
new file mode 100644
index 0000000..4a2f28e
--- /dev/null
+++ b/src/api/salesManagement/bidWinningLedger.js
@@ -0,0 +1,56 @@
+import request from "@/utils/request";
+
+export function getProvinceList() {
+ return request({
+ url: "/sales/bidWinningLedger/getProvinceList",
+ method: "get",
+ });
+}
+
+export function getCityList(params) {
+ return request({
+ url: "/sales/bidWinningLedger/getCityList",
+ method: "get",
+ params,
+ });
+}
+
+export function bidWinningLedgerListPage(params) {
+ return request({
+ url: "/sales/bidWinningLedger/listPage",
+ method: "get",
+ params,
+ });
+}
+
+export function bidWinningLedgerDetail(params) {
+ return request({
+ url: "/sales/bidWinningLedger/detail",
+ method: "get",
+ params,
+ });
+}
+
+export function bidWinningLedgerAdd(data) {
+ return request({
+ url: "/sales/bidWinningLedger/add",
+ method: "post",
+ data,
+ });
+}
+
+export function bidWinningLedgerUpdate(data) {
+ return request({
+ url: "/sales/bidWinningLedger/update",
+ method: "post",
+ data,
+ });
+}
+
+export function bidWinningLedgerDelete(data) {
+ return request({
+ url: "/sales/bidWinningLedger/delete",
+ method: "delete",
+ data,
+ });
+}
diff --git a/src/views/basicData/customerFile/index.vue b/src/views/basicData/customerFile/index.vue
index 8043d1a..e358b53 100644
--- a/src/views/basicData/customerFile/index.vue
+++ b/src/views/basicData/customerFile/index.vue
@@ -122,6 +122,19 @@
/>
</el-form-item>
</el-col>
+ <el-col :span="12">
+ <el-form-item label="瀹㈡埛绫诲瀷锛�" prop="customerType">
+ <el-select
+ v-model="form.customerType"
+ placeholder="璇烽�夋嫨"
+ clearable
+ style="width: 100%"
+ >
+ <el-option label="鏅�氬鎴�" :value="1" />
+ <el-option label="涓皬瀹㈡埛" :value="2" />
+ </el-select>
+ </el-form-item>
+ </el-col>
</el-row>
<el-row :gutter="30" v-for="(contact, index) in formYYs.contactList" :key="index">
<el-col :span="12">
@@ -247,6 +260,22 @@
const userStore = useUserStore();
const tableColumn = ref([
+ {
+ label: "瀹㈡埛绫诲瀷",
+ prop: "customerType",
+ width: 120,
+ dataType: "tag",
+ formatData: (value) => {
+ if (String(value) === "1") return "鏅�氬鎴�";
+ if (String(value) === "2") return "涓皬瀹㈡埛";
+ return "";
+ },
+ formatType: (value) => {
+ if (String(value) === "1") return "primary";
+ if (String(value) === "2") return "success";
+ return "info";
+ },
+ },
{
label: "瀹㈡埛鍚嶇О",
prop: "customerName",
@@ -342,6 +371,7 @@
},
form: {
customerName: "",
+ customerType: undefined,
taxpayerIdentificationNumber: "",
companyAddress: "",
companyPhone: "",
@@ -355,6 +385,7 @@
},
rules: {
customerName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ customerType: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
taxpayerIdentificationNumber: [
{ required: true, message: "璇疯緭鍏�", trigger: "blur" },
],
diff --git a/src/views/salesManagement/bidWinningLedger/index.vue b/src/views/salesManagement/bidWinningLedger/index.vue
new file mode 100644
index 0000000..870f1be
--- /dev/null
+++ b/src/views/salesManagement/bidWinningLedger/index.vue
@@ -0,0 +1,724 @@
+<template>
+ <div class="app-container">
+ <div class="search_form">
+ <el-form :model="searchForm" :inline="true">
+ <el-form-item label="鐪佷唤">
+ <el-select
+ v-model="searchForm.provinceId"
+ placeholder="璇烽�夋嫨鐪佷唤"
+ clearable
+ filterable
+ style="width: 180px"
+ @change="handleSearchProvinceChange"
+ >
+ <el-option
+ v-for="item in provinceOptions"
+ :key="item.id"
+ :label="item.name"
+ :value="item.id"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="鍩庡競">
+ <el-select
+ v-model="searchForm.cityId"
+ placeholder="璇烽�夋嫨鍩庡競"
+ clearable
+ filterable
+ style="width: 180px"
+ @change="handleQuery"
+ >
+ <el-option
+ v-for="item in searchCityOptions"
+ :key="item.id"
+ :label="item.name"
+ :value="item.id"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="瀹㈡埛鍚嶇О">
+ <el-select
+ v-model="searchForm.customerName"
+ placeholder="璇烽�夋嫨瀹㈡埛鍚嶇О"
+ clearable
+ filterable
+ style="width: 200px"
+ @change="handleQuery"
+ >
+ <el-option
+ v-for="item in customerOptions"
+ :key="item.id || item.customerName"
+ :label="item.customerName"
+ :value="item.customerName"
+ >
+ {{ item.customerName }}{{ item.taxpayerIdentificationNumber ? ` - ${item.taxpayerIdentificationNumber}` : "" }}
+ </el-option>
+ </el-select>
+ </el-form-item>
+ <el-form-item label="褰曞叆浜�">
+ <el-input
+ v-model="searchForm.entryPerson"
+ placeholder="璇疯緭鍏ュ綍鍏ヤ汉"
+ clearable
+ style="width: 180px"
+ @change="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="褰曞叆鏃ユ湡">
+ <el-date-picker
+ v-model="searchForm.entryDateRange"
+ type="daterange"
+ value-format="YYYY-MM-DD"
+ format="YYYY-MM-DD"
+ range-separator="-"
+ start-placeholder="寮�濮嬫棩鏈�"
+ end-placeholder="缁撴潫鏃ユ湡"
+ clearable
+ @change="changeDateRange"
+ />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="handleQuery">鎼滅储</el-button>
+ <el-button @click="resetQuery">閲嶇疆</el-button>
+ <el-button type="primary" @click="handleAdd">鏂板</el-button>
+ <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
+ </el-form-item>
+ </el-form>
+ </div>
+
+ <div class="table_list">
+ <el-table
+ :data="tableData"
+ border
+ stripe
+ v-loading="tableLoading"
+ height="calc(100vh - 18.5em)"
+ @selection-change="handleSelectionChange"
+ >
+ <el-table-column type="selection" width="55" align="center" fixed="left" />
+ <el-table-column type="index" label="搴忓彿" width="60" align="center" fixed="left" />
+ <el-table-column prop="province" label="鐪佷唤" min-width="120" />
+ <el-table-column prop="city" label="鍩庡競" min-width="120" />
+ <el-table-column prop="customerName" label="瀹㈡埛鍚嶇О" min-width="220" show-overflow-tooltip />
+ <el-table-column prop="contractAmount" label="涓爣閲戦" min-width="130" />
+ <el-table-column prop="bidBond" label="鎶曟爣淇濊瘉閲�" min-width="130" />
+ <el-table-column prop="winningServiceFee" label="涓爣鏈嶅姟璐�" min-width="130" />
+ <el-table-column prop="remark" label="澶囨敞" min-width="180" show-overflow-tooltip />
+ <el-table-column prop="entryPerson" label="褰曞叆浜�" min-width="100" />
+ <el-table-column prop="entryDate" label="褰曞叆鏃ユ湡" min-width="120" />
+ <el-table-column prop="updateTime" label="淇敼鏃堕棿" min-width="170" />
+ <el-table-column fixed="right" label="鎿嶄綔" width="180" align="center">
+ <template #default="{ row }">
+ <el-button link type="primary" size="small" @click="handleEdit(row)">
+ 缂栬緫
+ </el-button>
+ <el-button link type="primary" size="small" @click="handleDetail(row)">
+ 璇︽儏
+ </el-button>
+ <el-button link type="danger" size="small" @click="handleDelete(row)">
+ 鍒犻櫎
+ </el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <pagination
+ v-show="total > 0"
+ :total="total"
+ layout="total, sizes, prev, pager, next, jumper"
+ :page="page.current"
+ :limit="page.size"
+ @pagination="paginationChange"
+ />
+ </div>
+
+ <el-dialog
+ v-model="dialogVisible"
+ :title="dialogTitle"
+ width="900px"
+ @close="closeDialog"
+ >
+ <el-form
+ ref="formRef"
+ :model="form"
+ :rules="rules"
+ label-width="100px"
+ :disabled="dialogMode === 'detail'"
+ >
+ <el-row :gutter="20">
+ <el-col :span="24">
+ <el-form-item label="瀹㈡埛鍚嶇О" prop="customerName">
+ <el-select
+ v-model="form.customerName"
+ placeholder="璇烽�夋嫨瀹㈡埛鍚嶇О"
+ clearable
+ filterable
+ style="width: 100%"
+ >
+ <el-option
+ v-for="item in customerOptions"
+ :key="item.id || item.customerName"
+ :label="item.customerName"
+ :value="item.customerName"
+ >
+ {{ item.customerName }}{{ item.taxpayerIdentificationNumber ? ` - ${item.taxpayerIdentificationNumber}` : "" }}
+ </el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="鐪佷唤" prop="provinceId">
+ <el-select
+ v-model="form.provinceId"
+ placeholder="璇烽�夋嫨鐪佷唤"
+ filterable
+ style="width: 100%"
+ @change="handleFormProvinceChange"
+ >
+ <el-option
+ v-for="item in provinceOptions"
+ :key="item.id"
+ :label="item.name"
+ :value="item.id"
+ />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鍩庡競" prop="cityId">
+ <el-select
+ v-model="form.cityId"
+ placeholder="璇烽�夋嫨鍩庡競"
+ filterable
+ style="width: 100%"
+ >
+ <el-option
+ v-for="item in cityOptions"
+ :key="item.id"
+ :label="item.name"
+ :value="item.id"
+ />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="涓爣閲戦" prop="contractAmount">
+ <el-input-number
+ v-model="form.contractAmount"
+ :min="0"
+ :precision="2"
+ style="width: 100%"
+ controls-position="right"
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鎶曟爣淇濊瘉閲�" prop="bidBond">
+ <el-input-number
+ v-model="form.bidBond"
+ :min="0"
+ :precision="2"
+ style="width: 100%"
+ controls-position="right"
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="涓爣鏈嶅姟璐�" prop="winningServiceFee">
+ <el-input-number
+ v-model="form.winningServiceFee"
+ :min="0"
+ :precision="2"
+ style="width: 100%"
+ controls-position="right"
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="褰曞叆浜�" prop="entryPerson">
+ <el-select
+ v-model="form.entryPerson"
+ placeholder="璇烽�夋嫨褰曞叆浜�"
+ filterable
+ allow-create
+ default-first-option
+ style="width: 100%"
+ >
+ <el-option
+ v-for="item in userOptions"
+ :key="item.userId || item.nickName"
+ :label="item.nickName"
+ :value="item.nickName"
+ />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="褰曞叆鏃ユ湡" prop="entryDate">
+ <el-date-picker
+ v-model="form.entryDate"
+ type="date"
+ value-format="YYYY-MM-DD"
+ format="YYYY-MM-DD"
+ placeholder="璇烽�夋嫨褰曞叆鏃ユ湡"
+ style="width: 100%"
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <el-form-item label="澶囨敞" prop="remark">
+ <el-input
+ v-model="form.remark"
+ type="textarea"
+ :rows="3"
+ placeholder="璇疯緭鍏ュ娉�"
+ />
+ </el-form-item>
+
+ <el-form-item label="闄勪欢" v-if="dialogMode !== 'detail'">
+ <el-upload
+ ref="fileUploadRef"
+ v-model:file-list="fileList"
+ :action="upload.url"
+ :headers="upload.headers"
+ :data="upload.data"
+ multiple
+ auto-upload
+ :before-upload="handleBeforeUpload"
+ :on-success="handleUploadSuccess"
+ :on-error="handleUploadError"
+ :on-remove="handleRemove"
+ >
+ <el-button type="primary">涓婁紶闄勪欢</el-button>
+ <template #tip>
+ <div class="el-upload__tip">鏀寔甯歌鍔炲叕鏂囨。涓庡浘鐗囨牸寮�</div>
+ </template>
+ </el-upload>
+ </el-form-item>
+
+ </el-form>
+
+ <div v-if="dialogMode === 'detail'">
+ <el-divider content-position="left">闄勪欢</el-divider>
+ <el-table :data="form.commonFiles || []" border stripe empty-text="鏆傛棤闄勪欢">
+ <el-table-column prop="name" label="闄勪欢鍚嶇О" min-width="300" show-overflow-tooltip />
+ <el-table-column label="鎿嶄綔" width="160" align="center">
+ <template #default="{ row }">
+ <el-button link type="primary" size="small" @click="downloadFile(row)">
+ 涓嬭浇
+ </el-button>
+ <el-button link type="primary" size="small" @click="previewFile(row)">
+ 棰勮
+ </el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ </div>
+ <filePreview ref="filePreviewRef" />
+
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button @click="closeDialog">鍙栨秷</el-button>
+ <el-button type="primary" v-if="dialogMode !== 'detail'" @click="submitForm">
+ 纭畾
+ </el-button>
+ </div>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup>
+import { computed, getCurrentInstance, onMounted, reactive, ref } from "vue";
+import dayjs from "dayjs";
+import { ElMessageBox } from "element-plus";
+import pagination from "@/components/PIMTable/Pagination.vue";
+import filePreview from "@/components/filePreview/index.vue";
+import useUserStore from "@/store/modules/user";
+import { getToken } from "@/utils/auth";
+import { userListNoPage } from "@/api/system/user";
+import { customerList } from "@/api/salesManagement/salesLedger";
+import {
+ bidWinningLedgerAdd,
+ bidWinningLedgerDelete,
+ bidWinningLedgerDetail,
+ bidWinningLedgerListPage,
+ bidWinningLedgerUpdate,
+ getCityList,
+ getProvinceList,
+} from "@/api/salesManagement/bidWinningLedger";
+
+const { proxy } = getCurrentInstance();
+const userStore = useUserStore();
+
+const tableData = ref([]);
+const tableLoading = ref(false);
+const selectedRows = ref([]);
+const total = ref(0);
+const userOptions = ref([]);
+const customerOptions = ref([]);
+const provinceOptions = ref([]);
+const cityOptions = ref([]);
+const searchCityOptions = ref([]);
+const dialogVisible = ref(false);
+const dialogMode = ref("add");
+const formRef = ref();
+const fileUploadRef = ref();
+const filePreviewRef = ref();
+const fileList = ref([]);
+
+const upload = reactive({
+ url: `${import.meta.env.VITE_APP_BASE_API}/file/upload`,
+ headers: {
+ Authorization: `Bearer ${getToken()}`,
+ },
+ data: {
+ type: 10,
+ },
+});
+
+const page = reactive({
+ current: 1,
+ size: 20,
+});
+
+const createSearchForm = () => ({
+ provinceId: "",
+ cityId: "",
+ customerName: "",
+ entryPerson: "",
+ entryDateRange: [],
+ entryDateStart: "",
+ entryDateEnd: "",
+});
+
+const createFormData = () => ({
+ id: undefined,
+ province: "",
+ city: "",
+ provinceId: "",
+ cityId: "",
+ customerName: "",
+ contractAmount: undefined,
+ bidBond: undefined,
+ winningServiceFee: undefined,
+ remark: "",
+ entryPerson: userStore.nickName || "",
+ entryDate: dayjs().format("YYYY-MM-DD"),
+ commonFiles: [],
+ tempFileIds: [],
+});
+
+const searchForm = reactive(createSearchForm());
+const form = reactive(createFormData());
+
+const rules = reactive({
+ provinceId: [{ required: true, message: "璇烽�夋嫨鐪佷唤", trigger: "change" }],
+ cityId: [{ required: true, message: "璇烽�夋嫨鍩庡競", trigger: "change" }],
+ customerName: [{ required: true, message: "璇烽�夋嫨瀹㈡埛鍚嶇О", trigger: "change" }],
+ entryPerson: [{ required: true, message: "璇烽�夋嫨褰曞叆浜�", trigger: "change" }],
+ entryDate: [{ required: true, message: "璇烽�夋嫨褰曞叆鏃ユ湡", trigger: "change" }],
+});
+
+const dialogTitle = computed(() => {
+ if (dialogMode.value === "add") return "鏂板涓爣鍙拌处";
+ if (dialogMode.value === "edit") return "缂栬緫涓爣鍙拌处";
+ return "涓爣鍙拌处璇︽儏";
+});
+
+const getOptionName = (options, id) => {
+ const target = options.find((item) => String(item.id) === String(id));
+ return target?.name || "";
+};
+
+const buildQueryParams = () => {
+ const params = {
+ current: page.current,
+ size: page.size,
+ customerName: searchForm.customerName,
+ entryPerson: searchForm.entryPerson,
+ province: getOptionName(provinceOptions.value, searchForm.provinceId),
+ city: getOptionName(searchCityOptions.value, searchForm.cityId),
+ };
+
+ if (searchForm.entryDateStart) {
+ params.entryDateStart = searchForm.entryDateStart;
+ }
+ if (searchForm.entryDateEnd) {
+ params.entryDateEnd = searchForm.entryDateEnd;
+ }
+
+ Object.keys(params).forEach((key) => {
+ if (params[key] === "" || params[key] === undefined || params[key] === null) {
+ delete params[key];
+ }
+ });
+
+ return params;
+};
+
+const getList = async () => {
+ tableLoading.value = true;
+ try {
+ const res = await bidWinningLedgerListPage(buildQueryParams());
+ tableData.value = res?.data?.records || [];
+ total.value = res?.data?.total || 0;
+ } finally {
+ tableLoading.value = false;
+ }
+};
+
+const loadProvinceOptions = async () => {
+ const res = await getProvinceList();
+ provinceOptions.value = res?.data || [];
+};
+
+const loadCityOptions = async (provinceId, target = "form") => {
+ if (!provinceId) {
+ if (target === "form") {
+ cityOptions.value = [];
+ } else {
+ searchCityOptions.value = [];
+ }
+ return [];
+ }
+ const res = await getCityList({ provinceId });
+ const list = res?.data || [];
+ if (target === "form") {
+ cityOptions.value = list;
+ } else {
+ searchCityOptions.value = list;
+ }
+ return list;
+};
+
+const loadUserOptions = async () => {
+ const res = await userListNoPage();
+ userOptions.value = res?.data || [];
+};
+
+const loadCustomerOptions = async () => {
+ const res = await customerList();
+ customerOptions.value = res || [];
+};
+
+const changeDateRange = (value) => {
+ if (value?.length === 2) {
+ searchForm.entryDateStart = value[0];
+ searchForm.entryDateEnd = value[1];
+ } else {
+ searchForm.entryDateStart = "";
+ searchForm.entryDateEnd = "";
+ }
+ handleQuery();
+};
+
+const handleSearchProvinceChange = async () => {
+ searchForm.cityId = "";
+ await loadCityOptions(searchForm.provinceId, "search");
+ handleQuery();
+};
+
+const handleFormProvinceChange = async () => {
+ form.cityId = "";
+ await loadCityOptions(form.provinceId, "form");
+};
+
+const handleQuery = () => {
+ page.current = 1;
+ getList();
+};
+
+const resetQuery = async () => {
+ Object.assign(searchForm, createSearchForm());
+ searchCityOptions.value = [];
+ page.current = 1;
+ await getList();
+};
+
+const paginationChange = ({ page: current, limit }) => {
+ page.current = current;
+ page.size = limit;
+ getList();
+};
+
+const handleSelectionChange = (rows) => {
+ selectedRows.value = rows;
+};
+
+const resetFormState = () => {
+ Object.assign(form, createFormData());
+ cityOptions.value = [];
+ fileList.value = [];
+ formRef.value?.clearValidate();
+};
+
+const mapNameToId = (options, name) => {
+ const target = options.find((item) => item.name === name);
+ return target?.id || "";
+};
+
+const openDialog = async (mode, row) => {
+ dialogMode.value = mode;
+ resetFormState();
+ await Promise.all([loadUserOptions(), loadProvinceOptions(), loadCustomerOptions()]);
+
+ if (mode === "add") {
+ dialogVisible.value = true;
+ return;
+ }
+
+ const res = await bidWinningLedgerDetail({ id: row.id });
+ const detail = res?.data || {};
+
+ Object.assign(form, detail, {
+ entryDate: detail.entryDate ? dayjs(detail.entryDate).format("YYYY-MM-DD") : "",
+ commonFiles: detail.commonFiles || [],
+ });
+
+ form.provinceId = mapNameToId(provinceOptions.value, detail.province);
+ await loadCityOptions(form.provinceId, "form");
+ form.cityId = mapNameToId(cityOptions.value, detail.city);
+ fileList.value = (detail.commonFiles || []).map((item) => ({
+ name: item.name,
+ url: item.url,
+ id: item.id,
+ }));
+ dialogVisible.value = true;
+};
+
+const handleAdd = () => {
+ openDialog("add");
+};
+
+const handleEdit = (row) => {
+ openDialog("edit", row);
+};
+
+const handleDetail = (row) => {
+ openDialog("detail", row);
+};
+
+const buildSubmitData = () => {
+ const tempFileIds = fileList.value
+ .map((item) => item.tempId)
+ .filter((item) => item !== undefined && item !== null && item !== "");
+
+ return {
+ id: form.id,
+ province: getOptionName(provinceOptions.value, form.provinceId),
+ city: getOptionName(cityOptions.value, form.cityId),
+ customerName: form.customerName,
+ contractAmount: form.contractAmount,
+ bidBond: form.bidBond,
+ winningServiceFee: form.winningServiceFee,
+ remark: form.remark,
+ entryPerson: form.entryPerson,
+ entryDate: form.entryDate,
+ tempFileIds,
+ };
+};
+
+const submitForm = () => {
+ formRef.value.validate(async (valid) => {
+ if (!valid) {
+ return;
+ }
+
+ const api = dialogMode.value === "edit" ? bidWinningLedgerUpdate : bidWinningLedgerAdd;
+ await api(buildSubmitData());
+ proxy.$modal.msgSuccess(dialogMode.value === "edit" ? "淇敼鎴愬姛" : "鏂板鎴愬姛");
+ closeDialog();
+ getList();
+ });
+};
+
+const handleDelete = (row) => {
+ const ids = row ? [row.id] : selectedRows.value.map((item) => item.id);
+ if (!ids.length) {
+ proxy.$modal.msgWarning("璇烽�夋嫨瑕佸垹闄ょ殑涓爣鍙拌处");
+ return;
+ }
+
+ ElMessageBox.confirm("纭鍒犻櫎閫変腑鐨勪腑鏍囧彴璐﹀悧锛�", "鎻愮ず", {
+ confirmButtonText: "纭畾",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(async () => {
+ await bidWinningLedgerDelete(ids);
+ proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+ getList();
+ })
+ .catch(() => {});
+};
+
+const closeDialog = () => {
+ dialogVisible.value = false;
+ resetFormState();
+};
+
+const handleBeforeUpload = () => {
+ proxy.$modal.loading("姝e湪涓婁紶鏂囦欢锛岃绋嶅��...");
+ return true;
+};
+
+const handleUploadSuccess = (res, file) => {
+ proxy.$modal.closeLoading();
+ if (res.code === 200) {
+ file.tempId = res.data?.tempId;
+ proxy.$modal.msgSuccess("涓婁紶鎴愬姛");
+ } else {
+ proxy.$modal.msgError(res.msg || "涓婁紶澶辫触");
+ fileUploadRef.value?.handleRemove(file);
+ }
+};
+
+const handleUploadError = () => {
+ proxy.$modal.closeLoading();
+ proxy.$modal.msgError("涓婁紶澶辫触");
+};
+
+const handleRemove = () => {};
+
+const downloadFile = (row) => {
+ if (row?.url) {
+ proxy.$download.name(row.url);
+ }
+};
+
+const previewFile = (row) => {
+ if (row?.url) {
+ filePreviewRef.value.open(row.url);
+ }
+};
+
+onMounted(async () => {
+ await Promise.all([loadProvinceOptions(), loadUserOptions(), loadCustomerOptions()]);
+ getList();
+});
+</script>
+
+<style scoped lang="scss">
+.table_list {
+ margin-top: unset;
+}
+
+.dialog-footer {
+ text-align: right;
+}
+
+:deep(.el-input-number) {
+ width: 100%;
+}
+</style>
diff --git a/src/views/salesManagement/opportunityManagement/index.vue b/src/views/salesManagement/opportunityManagement/index.vue
index 8547ffb..900f5ec 100644
--- a/src/views/salesManagement/opportunityManagement/index.vue
+++ b/src/views/salesManagement/opportunityManagement/index.vue
@@ -456,7 +456,9 @@
const userList = ref([])
const customerOption = ref([])
const DEFAULT_USER_QUERY = { postCode: 'Market_Sales' }
+const DEFAULT_CUSTOMER_QUERY = { customerType: 2 }
let userListPromise = null
+let customerListPromise = null
const loadUserList = async (query = DEFAULT_USER_QUERY) => {
if (userListPromise) return userListPromise
@@ -473,6 +475,23 @@
}
})()
return userListPromise
+}
+
+const loadCustomerList = async (query = DEFAULT_CUSTOMER_QUERY) => {
+ if (customerListPromise) return customerListPromise
+ customerListPromise = (async () => {
+ try {
+ const res = await customerList(query)
+ customerOption.value = res || []
+ return customerOption.value
+ } catch (err) {
+ console.error('鑾峰彇瀹㈡埛鍒楄〃澶辫触:', err)
+ customerOption.value = []
+ customerListPromise = null
+ throw err
+ }
+ })()
+ return customerListPromise
}
// 鍒嗛〉閰嶇疆
@@ -703,9 +722,7 @@
// 鍔犺浇鐢ㄦ埛鍒楄〃鍜屽鎴峰垪琛�
await loadUserList()
- customerList().then((res) => {
- customerOption.value = res
- })
+ await loadCustomerList()
getProvinceList().then(res => {
provinceOptions.value = res.data
})
@@ -724,9 +741,7 @@
// 鍔犺浇鐢ㄦ埛鍒楄〃鍜屽鎴峰垪琛�
await loadUserList()
- customerList().then((res) => {
- customerOption.value = res
- })
+ await loadCustomerList()
// 浣跨敤褰撳墠琛屾暟鎹綔涓哄熀纭�锛屼絾鍙兘淇敼鐘舵�佸拰鎷滆璁板綍锛涗粯娆炬弿杩般�佹敼閫犲唴瀹圭瓑淇濈暀鍙嶆樉
Object.assign(form, row, {
@@ -745,9 +760,7 @@
// 鍔犺浇鐢ㄦ埛鍒楄〃鍜屽鎴峰垪琛�
await loadUserList()
- customerList().then((res) => {
- customerOption.value = res
- })
+ await loadCustomerList()
// 浣跨敤updateTime浣滀负褰曞叆鏃堕棿鍙嶆樉
Object.assign(form, row, {
@@ -787,9 +800,7 @@
// 鍔犺浇鐢ㄦ埛鍒楄〃鍜屽鎴峰垪琛�
await loadUserList()
- customerList().then((res) => {
- customerOption.value = res
- })
+ await loadCustomerList()
// 鍔犺浇鐪佷唤鍒楄〃
await getProvinceList().then(res => {
@@ -1162,4 +1173,4 @@
}
}
}
-</style>
\ No newline at end of file
+</style>
--
Gitblit v1.9.3