|
|
@@ -352,7 +352,7 @@
|
|
|
append-to-body
|
|
|
:close-on-click-modal="false"
|
|
|
>
|
|
|
- <TinyMceEditor v-model="quoteContent" :height="600" :disabled="isPreviewMode" :toolbar="!isPreviewMode" />
|
|
|
+ <TinyMceEditor v-model="quoteContent" :height="600" :disabled="isPreviewMode" :toolbar="!isPreviewMode" :supplier-code="currentSupplierCode" />
|
|
|
<template #footer>
|
|
|
<div class="dialog-footer">
|
|
|
<el-button @click="generateQuoteDialog.visible = false">关 闭</el-button>
|
|
|
@@ -476,9 +476,7 @@
|
|
|
<div class="detail-header">
|
|
|
<span class="detail-title">{{ detailQuote?.quoteNo }} - {{ detailQuote?.quoteTitle }}</span>
|
|
|
<div class="detail-actions">
|
|
|
- <el-button type="success" icon="Document" @click="handleGenerateQuote(detailQuote)"
|
|
|
- >生成报价单</el-button
|
|
|
- >
|
|
|
+ <el-button type="success" icon="Document" @click="handleGenerateQuote(detailQuote)">生成报价单</el-button>
|
|
|
<el-button type="default" icon="Edit" @click="handleDetailEdit" v-if="detailQuote?.status === 'draft'">修改</el-button>
|
|
|
<el-button type="danger" icon="Delete" @click="handleDetailDelete" v-if="detailQuote?.status !== 'invalid'">删除</el-button>
|
|
|
<el-button type="warning" icon="Check" @click="handleDetailSubmit" v-if="detailQuote?.status === 'draft'">提交审批</el-button>
|
|
|
@@ -512,6 +510,7 @@
|
|
|
</span>
|
|
|
</el-descriptions-item>
|
|
|
<el-descriptions-item label="负责人">{{ detailQuote?.ownerUserName }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="报价主体">{{ detailQuote?.supplierName || '-' }}</el-descriptions-item>
|
|
|
<el-descriptions-item label="创建时间">{{ parseTime(detailQuote?.createTime) }}</el-descriptions-item>
|
|
|
</el-descriptions>
|
|
|
|
|
|
@@ -813,6 +812,7 @@ import request from '@/utils/request';
|
|
|
import TinyMceEditor from '@/components/TinyMceEditor/index.vue';
|
|
|
import ImagePreview from '@/components/ImagePreview/index.vue';
|
|
|
import CustomerDetail from '@/views/crm/customer/detail.vue';
|
|
|
+import { getSupplierInfo, type SupplierInfoVO } from '@/api/crm/supplierInfo';
|
|
|
import logoImg from '@/assets/images/logo.gif';
|
|
|
import html2canvas from 'html2canvas';
|
|
|
import jsPDF from 'jspdf';
|
|
|
@@ -1056,6 +1056,7 @@ const quoteContent = ref('');
|
|
|
const isPreviewMode = ref(false);
|
|
|
const pdfGenerating = ref(false);
|
|
|
const currentQuoteId = ref<string | number>(); // 当前报价单ID,用于保存模板
|
|
|
+const currentSupplierCode = ref<string>('SX'); // 当前供应商编码,用于控制背景图片和Logo显示
|
|
|
|
|
|
// 审批对话框
|
|
|
const approvalDialog = reactive({
|
|
|
@@ -1529,7 +1530,7 @@ const getExpireDays = (expireDate: string): number => {
|
|
|
};
|
|
|
|
|
|
/** 生成报价单HTML模版 */
|
|
|
-const generateQuoteTemplate = (quote: QuoteVO): string => {
|
|
|
+const generateQuoteTemplate = (quote: QuoteVO, supplierInfo?: SupplierInfoVO): string => {
|
|
|
// 辅助函数:安全地将值转换为数字并格式化
|
|
|
const formatNumber = (value: any, decimals: number = 2): string => {
|
|
|
const num = parseFloat(value || 0);
|
|
|
@@ -1566,6 +1567,17 @@ const generateQuoteTemplate = (quote: QuoteVO): string => {
|
|
|
return `${year}/${month}/${day}`;
|
|
|
};
|
|
|
|
|
|
+ // 获取供应商编码,默认为SX
|
|
|
+ const supplierCode = supplierInfo?.supplierCode || quote.supplierCode || 'SX';
|
|
|
+ // 获取供应商简称和名称
|
|
|
+ const supplierShortName = supplierInfo?.shortName || quote.supplierShortName || '';
|
|
|
+ const supplierName = supplierInfo?.supplierName || quote.supplierName || '安庆市山峡化工有限公司';
|
|
|
+
|
|
|
+ // 根据供应商编码决定是否显示Logo和背景图片
|
|
|
+ const showLogo = supplierCode === 'SX';
|
|
|
+ // 根据供应商编码决定标题
|
|
|
+ const quoteTitle = supplierCode === 'SX' ? '山峡销售报价单' : `${supplierShortName || supplierName}销售报价单`;
|
|
|
+
|
|
|
// 构建产品明细表格行
|
|
|
const productRows =
|
|
|
quote.productList
|
|
|
@@ -1590,13 +1602,17 @@ const generateQuoteTemplate = (quote: QuoteVO): string => {
|
|
|
// 注意:水印已在TinyMCE编辑器中统一设置,这里无需重复添加
|
|
|
return `
|
|
|
<div style="max-width: 794px; margin: 0 auto; padding: 20px; font-family: Arial, '微软雅黑', sans-serif; font-size: 13px;">
|
|
|
- <!-- Logo和标题 -->
|
|
|
+ ${
|
|
|
+ showLogo
|
|
|
+ ? `<!-- Logo和标题 -->
|
|
|
<div style="text-align: left; margin-bottom: 20px;">
|
|
|
<img src="${logoImg}" alt="山峡化工" style="height: 30px; vertical-align: middle;" />
|
|
|
- </div>
|
|
|
+ </div>`
|
|
|
+ : ''
|
|
|
+ }
|
|
|
|
|
|
<!-- 标题 -->
|
|
|
- <h1 style="text-align: center; font-size: 28px; margin-bottom: 40px; font-weight: bold;">山峡销售报价单</h1>
|
|
|
+ <h1 style="text-align: center; font-size: 28px; margin-bottom: 40px; font-weight: bold;">${quoteTitle}</h1>
|
|
|
|
|
|
<!-- 报价单基本信息 -->
|
|
|
<div style="margin-bottom: 30px; font-size: 14px; line-height: 1.2; display: flex; justify-content: center;">
|
|
|
@@ -1607,7 +1623,7 @@ const generateQuoteTemplate = (quote: QuoteVO): string => {
|
|
|
</div>
|
|
|
<div style="display: flex; justify-content: space-between; margin-bottom: 3px;">
|
|
|
<div style="flex: 1; text-align: left;">需 方: ${quote.customerName}</div>
|
|
|
- <div style="flex: 1; text-align: left;">供 方: 安庆市山峡化工有限公司</div>
|
|
|
+ <div style="flex: 1; text-align: left;">供 方: ${supplierName}</div>
|
|
|
</div>
|
|
|
<div style="display: flex; justify-content: space-between;">
|
|
|
<div style="flex: 1; text-align: left;">联系人: ${addSpaceBetweenChars(quote.contactName || '')}</div>
|
|
|
@@ -1708,6 +1724,23 @@ const handleGenerateQuote = async (row?: QuoteVO) => {
|
|
|
|
|
|
console.log('报价单详情数据:', quoteDetail);
|
|
|
|
|
|
+ // 获取供应商详细信息
|
|
|
+ let supplierInfo: SupplierInfoVO | undefined = undefined;
|
|
|
+ if (quoteDetail.supplierId) {
|
|
|
+ try {
|
|
|
+ const supplierRes = await getSupplierInfo(quoteDetail.supplierId);
|
|
|
+ supplierInfo = supplierRes.data;
|
|
|
+ console.log('供应商信息:', supplierInfo);
|
|
|
+ // 设置当前供应商编码,用于控制TinyMCE编辑器的背景图片和Logo显示
|
|
|
+ currentSupplierCode.value = supplierInfo?.supplierCode || 'SX';
|
|
|
+ } catch (error) {
|
|
|
+ console.warn('获取供应商信息失败:', error);
|
|
|
+ currentSupplierCode.value = 'SX'; // 默认值
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ currentSupplierCode.value = 'SX'; // 默认值
|
|
|
+ }
|
|
|
+
|
|
|
// 先尝试从数据库获取已保存的模板
|
|
|
let htmlContent = '';
|
|
|
try {
|
|
|
@@ -1720,13 +1753,13 @@ const handleGenerateQuote = async (row?: QuoteVO) => {
|
|
|
console.log('✅ 从数据库加载模板成功,长度:', htmlContent.length);
|
|
|
} else {
|
|
|
// 如果没有保存的模板,则生成新的HTML内容
|
|
|
- htmlContent = generateQuoteTemplate(quoteDetail);
|
|
|
+ htmlContent = generateQuoteTemplate(quoteDetail, supplierInfo);
|
|
|
console.log('❌ 数据库无模板,生成新的HTML内容,长度:', htmlContent.length);
|
|
|
}
|
|
|
} catch (error) {
|
|
|
// 如果获取模板失败,则生成新的HTML内容
|
|
|
console.warn('⚠️ 获取模板失败,将生成新模板:', error);
|
|
|
- htmlContent = generateQuoteTemplate(quoteDetail);
|
|
|
+ htmlContent = generateQuoteTemplate(quoteDetail, supplierInfo);
|
|
|
console.log('生成新的HTML内容,长度:', htmlContent.length);
|
|
|
}
|
|
|
|
|
|
@@ -1750,24 +1783,16 @@ const handleGenerateQuote = async (row?: QuoteVO) => {
|
|
|
|
|
|
/** 打印报价单 */
|
|
|
const handlePrint = () => {
|
|
|
- // 获取完整的水印图片URL
|
|
|
+ // 根据供应商编码决定是否显示背景图片
|
|
|
+ const showBackground = currentSupplierCode.value === 'SX';
|
|
|
const watermarkUrl = window.location.origin + '/watermask.jpg';
|
|
|
|
|
|
// 创建打印窗口
|
|
|
const printWindow = window.open('', '_blank');
|
|
|
if (printWindow) {
|
|
|
- printWindow.document.write(`
|
|
|
- <!DOCTYPE html>
|
|
|
- <html>
|
|
|
- <head>
|
|
|
- <meta charset="utf-8">
|
|
|
- <title>打印报价单</title>
|
|
|
- <style>
|
|
|
- body {
|
|
|
- margin: 0;
|
|
|
- padding: 20px;
|
|
|
- position: relative;
|
|
|
- }
|
|
|
+ // 根据供应商编码生成不同的样式
|
|
|
+ const backgroundStyle = showBackground
|
|
|
+ ? `
|
|
|
/* 水印层 - 使用完整URL */
|
|
|
body::before {
|
|
|
content: '';
|
|
|
@@ -1790,10 +1815,6 @@ const handlePrint = () => {
|
|
|
z-index: 1;
|
|
|
}
|
|
|
@media print {
|
|
|
- body {
|
|
|
- margin: 0;
|
|
|
- padding: 20px;
|
|
|
- }
|
|
|
/* 打印时也显示水印 */
|
|
|
body::before {
|
|
|
position: absolute;
|
|
|
@@ -1801,6 +1822,34 @@ const handlePrint = () => {
|
|
|
-webkit-print-color-adjust: exact;
|
|
|
}
|
|
|
}
|
|
|
+ `
|
|
|
+ : `
|
|
|
+ /* 非SX编码时不显示背景图片 */
|
|
|
+ body > * {
|
|
|
+ position: relative;
|
|
|
+ z-index: 1;
|
|
|
+ }
|
|
|
+ `;
|
|
|
+
|
|
|
+ printWindow.document.write(`
|
|
|
+ <!DOCTYPE html>
|
|
|
+ <html>
|
|
|
+ <head>
|
|
|
+ <meta charset="utf-8">
|
|
|
+ <title>打印报价单</title>
|
|
|
+ <style>
|
|
|
+ body {
|
|
|
+ margin: 0;
|
|
|
+ padding: 20px;
|
|
|
+ position: relative;
|
|
|
+ }
|
|
|
+ ${backgroundStyle}
|
|
|
+ @media print {
|
|
|
+ body {
|
|
|
+ margin: 0;
|
|
|
+ padding: 20px;
|
|
|
+ }
|
|
|
+ }
|
|
|
</style>
|
|
|
</head>
|
|
|
<body>
|
|
|
@@ -1887,6 +1936,9 @@ const handleDownloadHtml = () => {
|
|
|
const handleGeneratePdf = async () => {
|
|
|
pdfGenerating.value = true;
|
|
|
try {
|
|
|
+ // 根据供应商编码决定是否显示背景图片
|
|
|
+ const showBackground = currentSupplierCode.value === 'SX';
|
|
|
+
|
|
|
// 创建临时容器
|
|
|
const tempDiv = document.createElement('div');
|
|
|
tempDiv.style.position = 'absolute';
|
|
|
@@ -1896,36 +1948,38 @@ const handleGeneratePdf = async () => {
|
|
|
tempDiv.style.background = 'white';
|
|
|
tempDiv.style.padding = '20px';
|
|
|
|
|
|
- // 创建带水印的HTML结构
|
|
|
- const watermarkDiv = document.createElement('div');
|
|
|
- watermarkDiv.style.position = 'relative';
|
|
|
- watermarkDiv.style.width = '100%';
|
|
|
-
|
|
|
- // 添加水印背景层
|
|
|
- const watermarkBg = document.createElement('div');
|
|
|
- watermarkBg.style.cssText = `
|
|
|
- position: absolute;
|
|
|
- top: 0;
|
|
|
- left: 0;
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- background-image: url('/watermask.jpg');
|
|
|
- background-repeat: no-repeat;
|
|
|
- background-position: center center;
|
|
|
- background-size: 50%;
|
|
|
- opacity: 0.15;
|
|
|
- z-index: 0;
|
|
|
- pointer-events: none;
|
|
|
- `;
|
|
|
+ // 创建HTML结构
|
|
|
+ const containerDiv = document.createElement('div');
|
|
|
+ containerDiv.style.position = 'relative';
|
|
|
+ containerDiv.style.width = '100%';
|
|
|
+
|
|
|
+ // 如果是SX编码,添加水印背景层
|
|
|
+ if (showBackground) {
|
|
|
+ const watermarkBg = document.createElement('div');
|
|
|
+ watermarkBg.style.cssText = `
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ background-image: url('/watermask.jpg');
|
|
|
+ background-repeat: no-repeat;
|
|
|
+ background-position: center center;
|
|
|
+ background-size: 50%;
|
|
|
+ opacity: 0.15;
|
|
|
+ z-index: 0;
|
|
|
+ pointer-events: none;
|
|
|
+ `;
|
|
|
+ containerDiv.appendChild(watermarkBg);
|
|
|
+ }
|
|
|
|
|
|
// 添加内容层
|
|
|
const contentDiv = document.createElement('div');
|
|
|
contentDiv.style.cssText = 'position: relative; z-index: 1;';
|
|
|
contentDiv.innerHTML = quoteContent.value;
|
|
|
|
|
|
- watermarkDiv.appendChild(watermarkBg);
|
|
|
- watermarkDiv.appendChild(contentDiv);
|
|
|
- tempDiv.appendChild(watermarkDiv);
|
|
|
+ containerDiv.appendChild(contentDiv);
|
|
|
+ tempDiv.appendChild(containerDiv);
|
|
|
document.body.appendChild(tempDiv);
|
|
|
|
|
|
// 使用html2canvas转换为canvas
|