From 913e7cd145459ca10e80392819aa052454927103 Mon Sep 17 00:00:00 2001
From: ZN <zhang_12370@163.com>
Date: 星期三, 18 三月 2026 17:56:34 +0800
Subject: [PATCH] feat: 新增销售合同导出功能并增强多个模块交互
---
src/views/basicData/customerFile/index.vue | 462 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 440 insertions(+), 22 deletions(-)
diff --git a/src/views/basicData/customerFile/index.vue b/src/views/basicData/customerFile/index.vue
index 1437beb..4e9f87a 100644
--- a/src/views/basicData/customerFile/index.vue
+++ b/src/views/basicData/customerFile/index.vue
@@ -112,6 +112,14 @@
</el-row>
<el-row :gutter="30">
<el-col :span="12">
+ <el-form-item label="寮�鎴烽摱琛岋細"
+ prop="bankName">
+ <el-input v-model="form.bankName"
+ placeholder="璇疯緭鍏�"
+ clearable />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
<el-form-item label="寮�鎴疯鍙凤細"
prop="bankCode">
<el-input v-model="form.bankCode"
@@ -119,6 +127,8 @@
clearable />
</el-form-item>
</el-col>
+ </el-row>
+ <el-row :gutter="30">
<el-col :span="12">
<el-form-item label="瀹㈡埛鍒嗙被锛�"
prop="customerType">
@@ -130,6 +140,47 @@
<el-option label="杩涢攢鍟嗗鎴�"
value="杩涢攢鍟嗗鎴�" />
</el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="娉曚汉"
+ prop="corporation">
+ <el-input v-model="form.corporation"
+ placeholder="璇疯緭鍏�"
+ clearable />
+ </el-form-item>
+ </el-col>
+
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="浠g悊浜�"
+ prop="agent">
+ <el-select v-model="form.agent"
+ placeholder="璇烽�夋嫨浠g悊浜�"
+ clearable
+ filterable
+ :disabled="agentOptions.length === 0"
+ :no-data-text="agentNoDataText">
+ <el-option v-for="(contact, index) in agentOptions"
+ :key="getAgentOptionKey(contact, index)"
+ :label="getAgentLabel(contact)"
+ :value="contact.contactPhone"
+ :disabled="!contact.contactPhone">
+ <span>{{ contact.contactPerson || "-" }}</span>
+ <span style="float: right; color: var(--el-text-color-secondary); font-size: 12px;">
+ {{ contact.contactPhone || "" }}
+ </span>
+ </el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="浼犵湡"
+ prop="fax">
+ <el-input v-model="form.fax"
+ placeholder="璇疯緭鍏�"
+ clearable />
</el-form-item>
</el-col>
</el-row>
@@ -267,9 +318,9 @@
<el-form-item label="鎻愰啋鏃堕棿锛�"
prop="reminderTime">
<el-date-picker v-model="reminderForm.reminderTime"
- type="date"
- value-format="YYYY-MM-DD"
- format="YYYY-MM-DD"
+ type="datetime"
+ value-format="YYYY-MM-DD HH:mm:ss"
+ format="YYYY-MM-DD HH:mm:ss"
placeholder="璇烽�夋嫨鎻愰啋鏃堕棿"
style="width: 100%" />
</el-form-item>
@@ -369,7 +420,7 @@
<!-- 瀹㈡埛璇︽儏瀵硅瘽妗� -->
<el-dialog title="瀹㈡埛璇︽儏"
v-model="detailDialogVisible"
- width="800px"
+ width="1000px"
@close="closeDetailDialog">
<!-- 瀹㈡埛鍩烘湰淇℃伅 -->
<div class="detail-section">
@@ -418,12 +469,7 @@
</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">{{ detailForm.bankAccount }}</span>
- </div>
- </el-col>
+
<el-col :span="12">
<div class="info-item">
<span class="info-label">寮�鎴疯鍙凤細</span>
@@ -481,14 +527,29 @@
label="璺熻繘鏂瑰紡"
width="100" />
<el-table-column prop="followUpLevel"
- label="璺熻繘绋嬪害"
- width="120" />
+ label="璺熻繘绋嬪害" />
<el-table-column prop="followerUserName"
label="璺熻繘浜�"
width="100" />
<el-table-column prop="content"
label="鍐呭"
show-overflow-tooltip />
+ <el-table-column label="闄勪欢"
+ width="100"
+ align="center">
+ <template #default="{ row }">
+ <el-button type="info"
+ link
+ size="small"
+ @click="openAttachmentDialog(row)">
+ <el-icon>
+ <Paperclip />
+ </el-icon>
+ 闄勪欢
+ <!-- {{ row.fileList && row.fileList.length > 0 ? row.fileList.length : '涓婁紶' }} -->
+ </el-button>
+ </template>
+ </el-table-column>
<el-table-column label="鎿嶄綔"
width="150"
align="center">
@@ -519,12 +580,90 @@
</div>
</template>
</el-dialog>
+ <!-- 闄勪欢涓婁紶寮圭獥 -->
+ <el-dialog title="闄勪欢绠$悊"
+ v-model="attachmentDialogVisible"
+ width="600px"
+ @close="closeAttachmentDialog">
+ <div class="attachment-section">
+ <div class="upload-area">
+ <el-upload ref="attachmentUploadRef"
+ :action="getAttachmentUploadUrl()"
+ :headers="attachmentUploadHeaders"
+ :file-list="currentAttachmentList"
+ :on-success="handleAttachmentSuccess"
+ :on-error="handleAttachmentError"
+ :on-remove="handleAttachmentRemove"
+ :before-upload="beforeAttachmentUpload"
+ multiple
+ :limit="10"
+ name="files">
+ <el-button type="primary">
+ <el-icon>
+ <Upload />
+ </el-icon>
+ 涓婁紶闄勪欢
+ </el-button>
+ <template #tip>
+ <div class="el-upload__tip">
+ 鏀寔涓婁紶鍥剧墖銆佹枃妗g瓑鏂囦欢锛屽崟涓枃浠朵笉瓒呰繃50MB
+ </div>
+ </template>
+ </el-upload>
+ </div>
+ <div v-if="currentAttachmentList.length > 0"
+ class="attachment-list">
+ <h4>宸蹭笂浼犻檮浠讹細</h4>
+ <el-table :data="currentAttachmentList"
+ border
+ size="small">
+ <el-table-column prop="name"
+ label="鏂囦欢鍚�"
+ show-overflow-tooltip />
+ <el-table-column prop="size"
+ label="澶у皬"
+ width="100">
+ <template #default="{ row }">
+ {{ formatFileSize(row.size) }}
+ </template>
+ </el-table-column>
+ <el-table-column label="鎿嶄綔"
+ width="120"
+ align="center">
+ <template #default="{ row, $index }">
+ <el-button type="primary"
+ link
+ size="small"
+ @click="downloadAttachment(row)">
+ 涓嬭浇
+ </el-button>
+ <el-button type="danger"
+ link
+ size="small"
+ @click="deleteAttachment(row, $index)">
+ 鍒犻櫎
+ </el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ </div>
+ <div v-else
+ class="no-attachment">
+ 鏆傛棤闄勪欢
+ </div>
+ </div>
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button @click="closeAttachmentDialog">鍏抽棴</el-button>
+ </div>
+ </template>
+ </el-dialog>
</div>
</template>
<script setup>
- import { onMounted, ref, reactive, getCurrentInstance, toRefs } from "vue";
- import { Search } from "@element-plus/icons-vue";
+ import { onMounted, ref, reactive, getCurrentInstance, toRefs, computed, watch } from "vue";
+ import { Search, Paperclip, Upload } from "@element-plus/icons-vue";
import {
addCustomer,
delCustomer,
@@ -534,6 +673,8 @@
addCustomerFollow,
updateCustomerFollow,
delCustomerFollow,
+ addReturnVisit,
+ getReturnVisit,
} from "@/api/basicData/customerFile.js";
import { ElMessageBox } from "element-plus";
import { userListNoPage } from "@/api/system/user.js";
@@ -545,6 +686,7 @@
// 鍥炶鎻愰啋鐩稿叧
const reminderDialogVisible = ref(false);
const reminderFormRef = ref();
+ const currentCustomerId = ref();
const reminderForm = reactive({
customerName: "",
reminderSwitch: false,
@@ -594,6 +736,8 @@
companyPhone: "",
companyAddress: "",
basicBankAccount: "",
+ corporation: "",
+ fax: "",
bankAccount: "",
bankCode: "",
contactPerson: "",
@@ -602,6 +746,22 @@
maintenanceTime: "",
});
const negotiationRecords = ref([]);
+
+ // 闄勪欢鐩稿叧
+ const attachmentDialogVisible = ref(false);
+ const attachmentUploadRef = ref();
+ const currentAttachmentList = ref([]);
+ const currentFollowRecord = ref({});
+ const attachmentUploadHeaders = { Authorization: "Bearer " + getToken() };
+
+ // 鍔ㄦ�佹瀯寤轰笂浼燯RL
+ const getAttachmentUploadUrl = () => {
+ const baseUrl =
+ import.meta.env.VITE_APP_BASE_API + "/basic/customer-follow/upload";
+ return currentFollowRecord.value.id
+ ? `${baseUrl}/${currentFollowRecord.value.id}`
+ : baseUrl;
+ };
const tableColumn = ref([
{
@@ -656,6 +816,16 @@
{
label: "寮�鎴疯鍙�",
prop: "bankCode",
+ width: 220,
+ },
+ {
+ label: "娉曚汉浠h〃",
+ prop: "corporation",
+ width: 220,
+ },
+ {
+ label: "浼犵湡",
+ prop: "fax",
width: 220,
},
{
@@ -744,6 +914,8 @@
maintenanceTime: "",
basicBankAccount: "",
bankAccount: "",
+ fax: "",
+ corporation: "",
bankCode: "",
customerType: "",
},
@@ -762,6 +934,9 @@
],
basicBankAccount: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
bankAccount: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ corporation: [{ required: true, message: "璇疯緭鍏ユ硶浜轰唬琛�", trigger: "blur" }],
+ agent: [{ required: true, message: "璇烽�夋嫨浠g悊浜�", trigger: "change" }],
+ bankName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
bankCode: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
customerType: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
},
@@ -822,6 +997,39 @@
},
});
const { searchForm, form, rules } = toRefs(data);
+
+ const agentOptions = computed(() => {
+ const list = formYYs.value?.contactList || [];
+ return list.filter(item => item && (item.contactPerson || item.contactPhone));
+ });
+
+ const agentNoDataText = computed(() => {
+ if (agentOptions.value.length === 0) return "璇峰厛鏂板鑱旂郴浜�";
+ return "鏃犲尮閰嶈仈绯讳汉";
+ });
+
+ const getAgentLabel = contact => {
+ const person = (contact?.contactPerson || "").trim();
+ const phone = (contact?.contactPhone || "").trim();
+ if (person && phone) return `${person}锛�${phone}锛塦;
+ return person || phone || "-";
+ };
+
+ const getAgentOptionKey = (contact, index) => {
+ return contact?.contactPhone || contact?.contactPerson || index;
+ };
+
+ watch(
+ () => agentOptions.value.map(item => item.contactPhone),
+ phones => {
+ const val = form.value?.agent;
+ if (!val) return;
+ if (!phones.includes(val)) {
+ form.value.agent = "";
+ }
+ }
+ );
+
const addNewContact = () => {
formYYs.value.contactList.push({
contactPerson: "",
@@ -1003,10 +1211,25 @@
// 鎵撳紑鍥炶鎻愰啋寮圭獥
const openReminderDialog = row => {
+ currentCustomerId.value = row.id;
reminderForm.customerName = row.customerName;
reminderForm.reminderSwitch = false;
reminderForm.reminderContent = "";
reminderForm.reminderTime = "";
+
+ // 灏濊瘯鑾峰彇宸叉湁鐨勫洖璁挎彁閱�
+ getReturnVisit(row.id)
+ .then(res => {
+ if (res.code === 200 && res.data) {
+ reminderForm.reminderSwitch = res.data.isEnabled === 1;
+ reminderForm.reminderContent = res.data.content;
+ reminderForm.reminderTime = res.data.reminderTime;
+ reminderForm.id = res.data.id;
+ }
+ })
+ .catch(error => {
+ console.error("鑾峰彇鍥炶鎻愰啋澶辫触:", error);
+ });
reminderDialogVisible.value = true;
};
@@ -1016,20 +1239,48 @@
proxy.resetForm("reminderFormRef");
reminderDialogVisible.value = false;
};
+ const submitvalue = ref({});
// 鎻愪氦鍥炶鎻愰啋
const submitReminderForm = () => {
+ console.log("鎻愪氦鍥炶鎻愰啋鏁版嵁:", userStore.id, userStore);
proxy.$refs.reminderFormRef.validate(valid => {
if (valid) {
- // 杩欓噷鍋囪涓�涓帴鍙f潵鎻愪氦鍥炶鎻愰啋鏁版嵁
- // 瀹為檯椤圭洰涓渶瑕佹牴鎹悗绔帴鍙h繘琛岃皟鏁�
- console.log("鎻愪氦鍥炶鎻愰啋鏁版嵁:", reminderForm);
+ if (reminderForm.id) {
+ submitvalue.value = {
+ id: reminderForm.id,
+ customerId: currentCustomerId.value,
+ isEnabled: reminderForm.reminderSwitch ? 1 : 0,
+ content: reminderForm.reminderContent,
+ reminderTime: reminderForm.reminderTime,
+ remindUserId: userStore.id,
+ };
+ } else {
+ submitvalue.value = {
+ customerId: currentCustomerId.value,
+ isEnabled: reminderForm.reminderSwitch ? 1 : 0,
+ content: reminderForm.reminderContent,
+ reminderTime: reminderForm.reminderTime,
+ remindUserId: userStore.id,
+ };
+ }
- // 妯℃嫙鎺ュ彛璋冪敤
- setTimeout(() => {
- proxy.$modal.msgSuccess("鍥炶鎻愰啋璁剧疆鎴愬姛");
- closeReminderDialog();
- }, 1000);
+ console.log("鎻愪氦鍥炶鎻愰啋鏁版嵁:", submitvalue.value);
+
+ // 璋冪敤鎺ュ彛
+ addReturnVisit(submitvalue.value)
+ .then(res => {
+ if (res.code === 200) {
+ proxy.$modal.msgSuccess("鍥炶鎻愰啋璁剧疆鎴愬姛");
+ closeReminderDialog();
+ } else {
+ proxy.$modal.msgError(res.msg || "璁剧疆澶辫触");
+ }
+ })
+ .catch(error => {
+ console.error("璁剧疆鍥炶鎻愰啋澶辫触:", error);
+ proxy.$modal.msgError("璁剧疆澶辫触");
+ });
}
});
};
@@ -1188,6 +1439,143 @@
});
};
+ // 鎵撳紑闄勪欢寮圭獥
+ const openAttachmentDialog = row => {
+ currentFollowRecord.value = row;
+ // 杞崲涓虹鍚圗lement Plus fileList鏍煎紡鐨勬暟缁�
+ currentAttachmentList.value = (row.fileList || []).map((file, index) => ({
+ name: file.fileName,
+ url: file.fileUrl,
+ size: file.fileSize,
+ id: file.id,
+ uid: file.id || index,
+ status: "success",
+ }));
+
+ attachmentDialogVisible.value = true;
+ };
+
+ // 鍏抽棴闄勪欢寮圭獥
+ const closeAttachmentDialog = () => {
+ attachmentDialogVisible.value = false;
+ currentFollowRecord.value = {};
+ currentAttachmentList.value = [];
+ };
+
+ // 闄勪欢涓婁紶鎴愬姛
+ const handleAttachmentSuccess = (response, file, fileList) => {
+ if (response.code === 200) {
+ proxy.$modal.msgSuccess("涓婁紶鎴愬姛");
+ // 鏇存柊褰撳墠璁板綍鐨勯檮浠跺垪琛�
+ currentAttachmentList.value = fileList.map(item => ({
+ name: item.name,
+ size: item.size,
+ url: item.response?.data?.url || item.url,
+ id: item.response?.data?.id,
+ uid: item.uid,
+ status: "success",
+ }));
+ // 鏇存柊鍘熻褰曚腑鐨刦iles瀛楁
+ if (currentFollowRecord.value) {
+ currentFollowRecord.value.files = [...currentAttachmentList.value];
+ }
+ } else {
+ proxy.$modal.msgError(response.msg || "涓婁紶澶辫触");
+ }
+ };
+
+ // 闄勪欢涓婁紶澶辫触
+ const handleAttachmentError = (error, file, fileList) => {
+ console.error("涓婁紶澶辫触:", error);
+ proxy.$modal.msgError("涓婁紶澶辫触");
+ };
+
+ // 闄勪欢绉婚櫎
+ const handleAttachmentRemove = (file, fileList) => {
+ currentAttachmentList.value = fileList;
+ // 鏇存柊鍘熻褰曚腑鐨刦iles瀛楁
+ if (currentFollowRecord.value) {
+ currentFollowRecord.value.files = [...fileList];
+ }
+ };
+
+ // 闄勪欢涓婁紶鍓嶆牎楠�
+ const beforeAttachmentUpload = file => {
+ const maxSize = 50 * 1024 * 1024; // 50MB
+ if (file.size > maxSize) {
+ proxy.$modal.msgError("鏂囦欢澶у皬涓嶈兘瓒呰繃50MB");
+ return false;
+ }
+ return true;
+ };
+
+ // 鏍煎紡鍖栨枃浠跺ぇ灏�
+ const formatFileSize = size => {
+ if (size < 1024) {
+ return size + " B";
+ } else if (size < 1024 * 1024) {
+ return (size / 1024).toFixed(2) + " KB";
+ } else {
+ return (size / (1024 * 1024)).toFixed(2) + " MB";
+ }
+ };
+
+ // 涓嬭浇闄勪欢
+ const downloadAttachment = row => {
+ if (row.url) {
+ // proxy.download(row.url, {}, row.name);
+ proxy.$download.name(row.url);
+ } else {
+ proxy.$modal.msgError("涓嬭浇閾炬帴涓嶅瓨鍦�");
+ }
+ };
+
+ // 鍒犻櫎闄勪欢
+ const deleteAttachment = (row, index) => {
+ ElMessageBox.confirm("纭畾瑕佸垹闄よ繖涓檮浠跺悧锛�", "鍒犻櫎鎻愮ず", {
+ confirmButtonText: "纭畾",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(() => {
+ // 璋冪敤鍚庣鎺ュ彛鍒犻櫎闄勪欢
+ const deleteUrl =
+ import.meta.env.VITE_APP_BASE_API +
+ "/basic/customer-follow/file/" +
+ row.id;
+ fetch(deleteUrl, {
+ method: "DELETE",
+ headers: {
+ Authorization: "Bearer " + getToken(),
+ "Content-Type": "application/json",
+ },
+ })
+ .then(response => response.json())
+ .then(res => {
+ if (res.code === 200) {
+ // 鍒犻櫎鎴愬姛鍚庢洿鏂版湰鍦版枃浠跺垪琛�
+ currentAttachmentList.value.splice(index, 1);
+ // 鏇存柊鍘熻褰曚腑鐨刦iles瀛楁
+ if (currentFollowRecord.value) {
+ currentFollowRecord.value.files = [
+ ...currentAttachmentList.value,
+ ];
+ }
+ proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+ } else {
+ proxy.$modal.msgError(res.msg || "鍒犻櫎澶辫触");
+ }
+ })
+ .catch(error => {
+ console.error("鍒犻櫎闄勪欢澶辫触:", error);
+ proxy.$modal.msgError("鍒犻櫎澶辫触");
+ });
+ })
+ .catch(() => {
+ proxy.$modal.msg("宸插彇娑堝垹闄�");
+ });
+ };
+
// 鑾峰彇褰撳墠鏃ユ湡骞舵牸寮忓寲涓� YYYY-MM-DD
function getCurrentDate() {
const today = new Date();
@@ -1255,4 +1643,34 @@
color: #999;
font-size: 14px;
}
+
+ .attachment-section {
+ .upload-area {
+ margin-bottom: 20px;
+ padding: 20px;
+ background-color: #f9f9f9;
+ border-radius: 4px;
+ border: 1px dashed #d9d9d9;
+
+ .el-upload__tip {
+ margin-top: 10px;
+ color: #909399;
+ }
+ }
+
+ .attachment-list {
+ h4 {
+ margin: 0 0 10px 0;
+ font-size: 14px;
+ color: #606266;
+ }
+ }
+
+ .no-attachment {
+ text-align: center;
+ padding: 40px;
+ color: #909399;
+ font-size: 14px;
+ }
+ }
</style>
--
Gitblit v1.9.3