feat(finance): 实现附件批量上传和多文件预览功能

- 修改附件字段从单个attachment为attachments数组
- 实现多文件上传功能支持同时上传多个附件
- 添加全局文件预览组件支持PDF和图片预览
- 更新下载功能支持批量下载多个附件
- 重构发票对话框中的附件展示和下载逻辑
- 修改后端服务接口支持多文件上传处理
- 更新数据库查询逻辑适配多附件关联关系
dev_1.0.1
chenhao 2025-12-29 20:54:57 +08:00
parent f992b2b29e
commit f0294212b2
11 changed files with 222 additions and 80 deletions

View File

@ -0,0 +1,64 @@
<template>
<div>
<el-dialog :visible.sync="pdfPreviewVisible" width="80%" append-to-body top="5vh" title="PDF预览">
<iframe :src="currentPdfUrl" width="100%" height="600px" frameborder="0"></iframe>
</el-dialog>
<el-dialog :visible.sync="imagePreviewVisible" width="60%" append-to-body top="5vh" title="图片预览">
<img :src="currentImageUrl" style="width: 100%;max-height: 60vh" />
</el-dialog>
</div>
</template>
<script>
import request from '@/utils/request';
export default {
name: "GlobalFilePreview",
data() {
return {
pdfPreviewVisible: false,
currentPdfUrl: '',
imagePreviewVisible: false,
currentImageUrl: ''
};
},
methods: {
isPdf(filePath) {
return filePath && filePath.toLowerCase().endsWith('.pdf');
},
getImageUrl(resource) {
return process.env.VUE_APP_BASE_API + "/common/download/resource?resource=" + resource;
},
handlePreview(attachment) {
if (!attachment) return;
if (this.isPdf(attachment.filePath)) {
request({
url: '/common/download/resource',
method: 'get',
params: { resource: attachment.filePath },
responseType: 'blob'
}).then(res => {
const blob = new Blob([res.data], { type: 'application/pdf' });
this.currentPdfUrl = URL.createObjectURL(blob);
this.pdfPreviewVisible = true;
});
} else {
this.currentImageUrl = this.getImageUrl(attachment.filePath);
this.imagePreviewVisible = true;
}
},
downloadFile(attachment){
if (attachment){
const link = document.createElement('a');
link.href = process.env.VUE_APP_BASE_API + "/common/download/resource?resource=" +attachment.filePath;
link.download = attachment.fileName || 'file';
link.style.display = 'none';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
},
}
};
</script>

View File

@ -8,11 +8,11 @@
<el-button type="primary" v-hasPermi="['finance:invoice:upload']"icon="el-icon-upload" @click="openUploadDialog">{{ titleText }}</el-button> <el-button type="primary" v-hasPermi="['finance:invoice:upload']"icon="el-icon-upload" @click="openUploadDialog">{{ titleText }}</el-button>
</div> </div>
<el-timeline v-if="attachments.length > 0"> <el-timeline v-if="groupedAttachments.length > 0">
<el-timeline-item <el-timeline-item
v-for="attachment in attachments" v-for="group in groupedAttachments"
:key="attachment.id" :key="group.createTime"
:timestamp="parseTime(attachment.createTime, '{y}-{m}-{d} {h}:{i}:{s}')" :timestamp="parseTime(group.createTime, '{y}-{m}-{d} {h}:{i}:{s}')"
placement="top" placement="top"
> >
<el-card> <el-card>
@ -24,7 +24,9 @@
</div> </div>
<div class="detail-item"> <div class="detail-item">
<span class="item-label">{{ titleText }}</span> <span class="item-label">{{ titleText }}</span>
<div class="item-value"> <div class="item-value" style="display: block;">
<div style="display: flex; flex-wrap: wrap; gap: 10px;">
<div v-for="attachment in group.items" :key="attachment.id" class="attachment-item">
<div class="image-wrapper"> <div class="image-wrapper">
<el-image <el-image
v-if="!isPdf(attachment.filePath)" v-if="!isPdf(attachment.filePath)"
@ -41,12 +43,15 @@
</div> </div>
<div v-if="attachment.delFlag === '2'" class="void-overlay"></div> <div v-if="attachment.delFlag === '2'" class="void-overlay"></div>
</div> </div>
</div>
</div>
<el-button <el-button
size="mini" size="mini"
type="primary" type="primary"
class="download-btn" class="download-btn"
icon="el-icon-download" icon="el-icon-download"
@click="downloadFile(attachment)" @click="downloadFiles(group.items)"
style="margin-top: 10px;"
>下载{{ titleText }}</el-button> >下载{{ titleText }}</el-button>
</div> </div>
</div> </div>
@ -77,7 +82,7 @@
</div> --> </div> -->
<div class="detail-item"> <div class="detail-item">
<span class="item-label">备注</span> <span class="item-label">备注</span>
<span class="item-value">{{ attachment.remark }}</span> <span class="item-value">{{ group.remark }}</span>
</div> </div>
</div> </div>
</div> </div>
@ -123,7 +128,7 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="开票附件" prop="file" required> <el-form-item label="开票附件" prop="file" >
<div style="display: flex; flex-direction: column; align-items: flex-start;"> <div style="display: flex; flex-direction: column; align-items: flex-start;">
<el-upload <el-upload
ref="upload" ref="upload"
@ -131,10 +136,12 @@
:auto-upload="false" :auto-upload="false"
:on-change="handleFileChange" :on-change="handleFileChange"
:on-remove="handleFileRemove" :on-remove="handleFileRemove"
:show-file-list="false" :file-list="fileList"
multiple
:show-file-list="true"
accept=".jpg,.jpeg,.png,.pdf" accept=".jpg,.jpeg,.png,.pdf"
> >
<el-button size="small" type="primary" icon="el-icon-upload2">{{ uploadForm.file ? '重新上传' : '点击上传' }}</el-button> <el-button size="small" type="primary" icon="el-icon-upload2">点击上传</el-button>
</el-upload> </el-upload>
<div class="el-upload__tip" style="line-height: 1.5; margin-top: 5px;">支持上传PNGJPGPDF文件格式</div> <div class="el-upload__tip" style="line-height: 1.5; margin-top: 5px;">支持上传PNGJPGPDF文件格式</div>
</div> </div>
@ -168,16 +175,21 @@
</el-form> </el-form>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<div class="upload-preview-container" style="height: 70vh;"> <div class="upload-preview-container" style="height: 70vh; overflow-y: auto; display: block; padding: 10px;">
<div v-if="previewUrl" class="preview-content"> <div v-if="fileList.length > 0" class="preview-list">
<img v-if="!isPreviewPdf" :src="previewUrl" class="preview-image" /> <div v-for="(file, index) in fileList" :key="index" class="preview-item" style="margin-bottom: 20px; border-bottom: 1px dashed #ccc; padding-bottom: 10px;">
<iframe v-else :src="previewUrl" width="100%" height="100%" frameborder="0"></iframe> <div class="preview-content" style="height: 350px;">
<img v-if="!isPdf(file.name)" :src="file.url" class="preview-image" style="max-width: 100%; max-height: 100%; object-fit: contain;" />
<iframe v-else :src="file.url" width="100%" height="100%" frameborder="0"></iframe>
</div> </div>
<div v-else class="preview-placeholder"> <div class="file-info" style="margin-top: 5px; text-align: center; color: #666; font-size: 12px;">{{ file.name }}</div>
</div>
</div>
<div v-else class="preview-placeholder" style="height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center;">
<div class="placeholder-icon"> <div class="placeholder-icon">
<i class="el-icon-picture"></i> <i class="el-icon-picture"></i>
</div> </div>
<div class="placeholder-text">点击图片进入预览</div> <div class="placeholder-text">上传文件后在此预览</div>
</div> </div>
</div> </div>
</el-col> </el-col>
@ -225,8 +237,8 @@ export default {
invoiceAmount: '', invoiceAmount: '',
invoiceType: this.invoiceData.invoiceType, invoiceType: this.invoiceData.invoiceType,
remark: '', remark: '',
file: null
}, },
fileList: [],
rules: { rules: {
invoicePriceWithTax: [ invoicePriceWithTax: [
{ required: true, message: "请输入发票含税总价", trigger: "blur" } { required: true, message: "请输入发票含税总价", trigger: "blur" }
@ -238,8 +250,6 @@ export default {
{ required: true, message: "请输入发票税额", trigger: "blur" } { required: true, message: "请输入发票税额", trigger: "blur" }
] ]
}, },
previewUrl: '',
isPreviewPdf: false,
// PDF Preview Data // PDF Preview Data
pdfUrls: {}, pdfUrls: {},
pdfPreviewVisible: false, pdfPreviewVisible: false,
@ -260,6 +270,24 @@ export default {
.filter(att => !this.isPdf(att.filePath)) .filter(att => !this.isPdf(att.filePath))
.map(att => this.getImageUrl(att.filePath)); .map(att => this.getImageUrl(att.filePath));
}, },
groupedAttachments() {
if (!this.attachments || this.attachments.length === 0) return [];
const groups = {};
this.attachments.forEach(att => {
const time = att.createTime;
if (!groups[time]) {
groups[time] = {
createTime: time,
items: [],
remark: att.remark
};
}
groups[time].items.push(att);
});
return Object.values(groups).sort((a, b) => new Date(b.createTime) - new Date(a.createTime));
},
canUpload() { canUpload() {
if (!this.attachments || this.attachments.length === 0) { if (!this.attachments || this.attachments.length === 0) {
return true; return true;
@ -284,7 +312,7 @@ export default {
getInvoiceAttachments(this.invoiceData.id, { type: 'invoice' }) getInvoiceAttachments(this.invoiceData.id, { type: 'invoice' })
.then(response => { .then(response => {
const data = response.data || []; const data = response.data || [];
data.sort((a, b) => new Date(b.createTime) - new Date(a.createTime)); // data.sort((a, b) => new Date(b.createTime) - new Date(a.createTime)); // Sorting is handled in groupedAttachments
this.attachments = data; this.attachments = data;
this.loadPdfPreviews(); this.loadPdfPreviews();
this.loading = false; this.loading = false;
@ -321,6 +349,12 @@ export default {
isPdf(filePath) { isPdf(filePath) {
return filePath && filePath.toLowerCase().endsWith('.pdf'); return filePath && filePath.toLowerCase().endsWith('.pdf');
}, },
downloadFiles(items) {
if (!items || items.length === 0) return;
items.forEach(item => {
this.downloadFile(item);
});
},
downloadFile(attachment) { downloadFile(attachment) {
const link = document.createElement('a'); const link = document.createElement('a');
link.href = this.getImageUrl(attachment.filePath); link.href = this.getImageUrl(attachment.filePath);
@ -344,19 +378,19 @@ export default {
invoiceAmount: '', invoiceAmount: '',
invoiceType: this.invoiceData.invoiceType, invoiceType: this.invoiceData.invoiceType,
remark: '', remark: '',
file: null
}; };
if (this.$refs.uploadForm) { if (this.$refs.uploadForm) {
this.$refs.uploadForm.clearValidate(); this.$refs.uploadForm.clearValidate();
} }
this.previewUrl = ''; this.fileList = [];
this.isPreviewPdf = false;
this.uploadDialogVisible = true; this.uploadDialogVisible = true;
}, },
closeUploadDialog() { closeUploadDialog() {
this.uploadDialogVisible = false; this.uploadDialogVisible = false;
this.uploadForm.file = null; this.fileList.forEach(file => {
this.previewUrl = ''; if (file.url) URL.revokeObjectURL(file.url);
});
this.fileList = [];
}, },
handleTypeChange(val) { handleTypeChange(val) {
if (val === '2') { if (val === '2') {
@ -378,32 +412,34 @@ export default {
this.uploadForm.invoicePriceWithoutTax = (total - tax).toFixed(2); this.uploadForm.invoicePriceWithoutTax = (total - tax).toFixed(2);
} }
}, },
handleFileChange(file) { handleFileChange(file, fileList) {
const isLt2M = file.size / 1024 / 1024 < 2; const isLt2M = file.size / 1024 / 1024 < 2;
const isAcceptedType = ['image/jpeg', 'image/png', 'application/pdf'].includes(file.raw.type); const isAcceptedType = ['image/jpeg', 'image/png', 'application/pdf'].includes(file.raw.type);
if (!isAcceptedType) { if (!isAcceptedType) {
this.$message.error('上传文件只能是 JPG/PNG/PDF 格式!'); this.$message.error('上传文件只能是 JPG/PNG/PDF 格式!');
const index = fileList.indexOf(file);
if (index > -1) fileList.splice(index, 1);
return; return;
} }
if (!isLt2M) { if (!isLt2M) {
this.$message.error('上传文件大小不能超过 2MB!'); this.$message.error('上传文件大小不能超过 2MB!');
const index = fileList.indexOf(file);
if (index > -1) fileList.splice(index, 1);
return; return;
} }
this.uploadForm.file = file.raw; file.url = URL.createObjectURL(file.raw);
this.isPreviewPdf = file.raw.type === 'application/pdf'; this.fileList = fileList;
this.previewUrl = URL.createObjectURL(file.raw);
}, },
handleFileRemove() { handleFileRemove(file, fileList) {
this.uploadForm.file = null; if (file.url) URL.revokeObjectURL(file.url);
this.previewUrl = ''; this.fileList = fileList;
}, },
submitNewUpload() { submitNewUpload() {
this.$refs.uploadForm.validate(valid => { this.$refs.uploadForm.validate(valid => {
if (valid) { if (valid) {
if (!this.uploadForm.file) { if (this.fileList.length === 0) {
this.$message.warning("请选择要上传的文件"); this.$message.warning("请选择要上传的文件");
return; return;
} }
@ -442,9 +478,14 @@ export default {
} }
} }
} }
if ((this.fileList||[]).length <=0 ){
this.$message.warning("文件不能为空");
return;
}
const formData = new FormData(); const formData = new FormData();
formData.append("file", this.uploadForm.file); this.fileList.forEach(file => {
formData.append("file", file.raw);
});
formData.append("id", this.invoiceData.id); formData.append("id", this.invoiceData.id);
formData.append("remark", this.uploadForm.remark); formData.append("remark", this.uploadForm.remark);
formData.append("invoicePriceWithTax", this.uploadForm.invoicePriceWithTax); formData.append("invoicePriceWithTax", this.uploadForm.invoicePriceWithTax);

View File

@ -147,10 +147,10 @@
<el-table-column prop="invoiceBillCode" label="销售-开票单编号"></el-table-column> <el-table-column prop="invoiceBillCode" label="销售-开票单编号"></el-table-column>
<el-table-column label="发票/红冲发票"> <el-table-column label="发票/红冲发票">
<template slot-scope="scope"> <template slot-scope="scope">
<span v-if="scope.row.attachment"> <span v-if="scope.row.attachments">
<el-button type="text" size="mini" icon="el-icon-view" @click="handlePreview(scope.row.attachment)"></el-button> <!-- <el-button type="text" size="mini" icon="el-icon-view" @click="handlePreview(scope.row.attachments)"></el-button>-->
<el-button type="text" size="mini" icon="el-icon-download" <el-button type="text" size="mini" icon="el-icon-download"
@click="downloadFile(scope.row.attachment)">下载</el-button> @click="downloadFile(scope.row.attachments)">下载</el-button>
</span> </span>
<span v-else>-</span> <span v-else>-</span>
</template> </template>
@ -224,8 +224,11 @@ export default {
handlePreview(attachment) { handlePreview(attachment) {
this.$refs.filePreview.handlePreview(attachment); this.$refs.filePreview.handlePreview(attachment);
}, },
downloadFile(attachment) { downloadFile(attachments) {
attachments?.forEach(attachment => {
this.$refs.filePreview.downloadFile(attachment); this.$refs.filePreview.downloadFile(attachment);
})
}, },
getDetails() { getDetails() {
getReceivable(this.data.id).then(res => { getReceivable(this.data.id).then(res => {

View File

@ -169,7 +169,7 @@ public class OmsInvoiceBillController extends BaseController
@Log(title = "上传开票回执单", businessType = BusinessType.UPDATE) @Log(title = "上传开票回执单", businessType = BusinessType.UPDATE)
@PostMapping("/uploadReceipt") @PostMapping("/uploadReceipt")
@ResponseBody @ResponseBody
public AjaxResult uploadReceipt(OmsInvoiceBill invoiceBill, @RequestParam("file") MultipartFile file) public AjaxResult uploadReceipt(OmsInvoiceBill invoiceBill, @RequestParam("file") MultipartFile[] file)
{ {
try { try {
return omsInvoiceBillService.uploadReceipt(invoiceBill, file); return omsInvoiceBillService.uploadReceipt(invoiceBill, file);

View File

@ -65,7 +65,7 @@ public class OmsReceivableInvoiceDetail extends BaseEntity
private String invoiceStatus; private String invoiceStatus;
private Long invoiceBillId; private Long invoiceBillId;
private Date actualInvoiceTime; private Date actualInvoiceTime;
private OmsFinAttachment attachment; private List<OmsFinAttachment> attachments;
private Long writeOffId; private Long writeOffId;
private List<Long> writeOffIdList; private List<Long> writeOffIdList;

View File

@ -71,9 +71,9 @@ public interface IOmsFinAttachmentService
*/ */
default OmsFinAttachment uploadAttachment(MultipartFile file, Long invoiceReceiptBillId, OmsFinAttachment.RelatedBillTypeEnum type) throws Exception default OmsFinAttachment uploadAttachment(MultipartFile file, Long invoiceReceiptBillId, OmsFinAttachment.RelatedBillTypeEnum type) throws Exception
{ {
return uploadAttachment(file, invoiceReceiptBillId, type,null); return uploadAttachment(new MultipartFile[]{file}, invoiceReceiptBillId, type,null).get(0);
} }
public OmsFinAttachment uploadAttachment(MultipartFile file, Long invoiceReceiptBillId, OmsFinAttachment.RelatedBillTypeEnum type,String remark) throws Exception; public List<OmsFinAttachment> uploadAttachment(MultipartFile[] file, Long invoiceReceiptBillId, OmsFinAttachment.RelatedBillTypeEnum type,String remark) throws Exception;
List<OmsFinAttachment> list(List<Long> ids, String type); List<OmsFinAttachment> list(List<Long> ids, String type);

View File

@ -72,7 +72,7 @@ public interface IOmsInvoiceBillService
* @param file * @param file
* @return * @return
*/ */
public AjaxResult uploadReceipt(OmsInvoiceBill bill, MultipartFile file) throws Exception; public AjaxResult uploadReceipt(OmsInvoiceBill bill, MultipartFile[] file) throws Exception;
/** /**
* *

View File

@ -1,6 +1,8 @@
package com.ruoyi.sip.service.impl; package com.ruoyi.sip.service.impl;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Date;
import java.util.List; import java.util.List;
import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -26,11 +28,14 @@ public class OmsFinAttachmentServiceImpl implements IOmsFinAttachmentService
private OmsFinAttachmentMapper omsFinAttachmentMapper; private OmsFinAttachmentMapper omsFinAttachmentMapper;
@Override @Override
public OmsFinAttachment uploadAttachment(MultipartFile file, Long relatedBillId, OmsFinAttachment.RelatedBillTypeEnum type,String remark) throws Exception public List<OmsFinAttachment> uploadAttachment(MultipartFile[] fileArray, Long relatedBillId, OmsFinAttachment.RelatedBillTypeEnum type,String remark) throws Exception
{ {
// 上传文件路径 // 上传文件路径
String filePath = RuoYiConfig.getUploadPath(); String filePath = RuoYiConfig.getUploadPath();
Date nowDate = DateUtils.getNowDate();
List<OmsFinAttachment> resultList=new ArrayList<>();
// 上传并返回新文件名称 // 上传并返回新文件名称
for (MultipartFile file : fileArray) {
String fileName = FileUploadUtils.upload(filePath, file); String fileName = FileUploadUtils.upload(filePath, file);
OmsFinAttachment attachment = new OmsFinAttachment(); OmsFinAttachment attachment = new OmsFinAttachment();
@ -41,9 +46,13 @@ public class OmsFinAttachmentServiceImpl implements IOmsFinAttachmentService
attachment.setRelatedBillType(type.getCode()); attachment.setRelatedBillType(type.getCode());
attachment.setRelatedBillId(relatedBillId); attachment.setRelatedBillId(relatedBillId);
attachment.setRemark(remark); attachment.setRemark(remark);
attachment.setCreateTime(nowDate);
attachment.setCreateBy(com.ruoyi.common.utils.ShiroUtils.getLoginName()); attachment.setCreateBy(com.ruoyi.common.utils.ShiroUtils.getLoginName());
this.insertOmsFinAttachment(attachment); this.insertOmsFinAttachment(attachment);
return attachment; resultList.add( attachment);
}
return resultList;
} }
@Override @Override
@ -97,7 +106,9 @@ public class OmsFinAttachmentServiceImpl implements IOmsFinAttachmentService
@Override @Override
public int insertOmsFinAttachment(OmsFinAttachment omsFinAttachment) public int insertOmsFinAttachment(OmsFinAttachment omsFinAttachment)
{ {
if (omsFinAttachment.getCreateTime()==null) {
omsFinAttachment.setCreateTime(DateUtils.getNowDate()); omsFinAttachment.setCreateTime(DateUtils.getNowDate());
}
return omsFinAttachmentMapper.insertOmsFinAttachment(omsFinAttachment); return omsFinAttachmentMapper.insertOmsFinAttachment(omsFinAttachment);
} }

View File

@ -9,12 +9,14 @@ import java.util.stream.Collectors;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.config.flow.ProcessConfig; import com.ruoyi.common.config.flow.ProcessConfig;
import com.ruoyi.common.enums.ApproveStatusEnum; import com.ruoyi.common.enums.ApproveStatusEnum;
import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ShiroUtils; import com.ruoyi.common.utils.ShiroUtils;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.sip.domain.*; import com.ruoyi.sip.domain.*;
import com.ruoyi.sip.domain.dto.InvoiceProductDto; import com.ruoyi.sip.domain.dto.InvoiceProductDto;
import com.ruoyi.sip.domain.dto.ReceiptDetailDTO; import com.ruoyi.sip.domain.dto.ReceiptDetailDTO;
@ -192,7 +194,7 @@ public class OmsInvoiceBillServiceImpl implements IOmsInvoiceBillService, TodoCo
*/ */
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public AjaxResult uploadReceipt(OmsInvoiceBill bill, MultipartFile file) throws Exception { public AjaxResult uploadReceipt(OmsInvoiceBill bill, MultipartFile[] fileArray) throws Exception {
OmsInvoiceBill existBill = selectOmsInvoiceBillById(bill.getId()); OmsInvoiceBill existBill = selectOmsInvoiceBillById(bill.getId());
if (existBill == null) { if (existBill == null) {
throw new ServiceException("开票单不存在"); throw new ServiceException("开票单不存在");
@ -204,7 +206,27 @@ public class OmsInvoiceBillServiceImpl implements IOmsInvoiceBillService, TodoCo
} }
// 这里可以添加上传附件的逻辑 // 这里可以添加上传附件的逻辑
omsFinAttachmentService.uploadAttachment(file, existBill.getId(), OmsFinAttachment.RelatedBillTypeEnum.RECEIVE_INVOICE, bill.getRemark()); // 上传文件路径
String filePath = RuoYiConfig.getUploadPath();
Date nowDate = DateUtils.getNowDate();
// 上传并返回新文件名称
for (MultipartFile file : fileArray) {
String fileName = FileUploadUtils.upload(filePath, file);
OmsFinAttachment attachment = new OmsFinAttachment();
attachment.setFileName(fileName);
attachment.setFilePath(fileName);
attachment.setFileSize(file.getSize());
attachment.setFileType(file.getContentType());
attachment.setRelatedBillType(OmsFinAttachment.RelatedBillTypeEnum.RECEIVE_INVOICE.getCode());
attachment.setRelatedBillId(existBill.getId());
attachment.setRemark(bill.getRemark());
attachment.setCreateTime(nowDate);
attachment.setCreateBy(ShiroUtils.getUserId().toString());
attachment.setPriceWithoutTax(bill.getInvoicePriceWithoutTax());
attachment.setPriceWithTax(bill.getInvoicePriceWithTax());
omsFinAttachmentService.insertOmsFinAttachment(attachment);
}
existBill.setActualInvoiceTime(DateUtils.getNowDate()); existBill.setActualInvoiceTime(DateUtils.getNowDate());
existBill.setInvoiceStatus(OmsInvoiceBill.InvoiceStatusEnum.INVOICE.getCode()); existBill.setInvoiceStatus(OmsInvoiceBill.InvoiceStatusEnum.INVOICE.getCode());
existBill.setInvoicePriceWithTax(bill.getInvoicePriceWithTax()); existBill.setInvoicePriceWithTax(bill.getInvoicePriceWithTax());

View File

@ -126,9 +126,9 @@ public class OmsReceivableInvoiceDetailServiceImpl implements IOmsReceivableInvo
omsFinAttachment.setRelatedBillType(OmsFinAttachment.RelatedBillTypeEnum.RECEIVE_INVOICE.getCode()); omsFinAttachment.setRelatedBillType(OmsFinAttachment.RelatedBillTypeEnum.RECEIVE_INVOICE.getCode());
omsFinAttachment.setDelFlag("0"); omsFinAttachment.setDelFlag("0");
List<OmsFinAttachment> attachmentList = finAttachmentService.selectOmsFinAttachmentList(omsFinAttachment); List<OmsFinAttachment> attachmentList = finAttachmentService.selectOmsFinAttachmentList(omsFinAttachment);
Map<Long, OmsFinAttachment> collect = attachmentList.stream().collect(Collectors.toMap(OmsFinAttachment::getRelatedBillId, Function.identity())); Map<Long, List<OmsFinAttachment>> collect = attachmentList.stream().collect(Collectors.groupingBy(OmsFinAttachment::getRelatedBillId));
for (OmsReceivableInvoiceDetail detail : list) { for (OmsReceivableInvoiceDetail detail : list) {
detail.setAttachment(collect.get(detail.getInvoiceBillId())); detail.setAttachments(collect.get(detail.getInvoiceBillId()));
} }
} }

View File

@ -96,8 +96,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
select t1.receipt_amount, t2.receivable_bill_code, t4.project_name, t4.project_code, t2.total_price_with_tax,t2.product_type select t1.receipt_amount, t2.receivable_bill_code, t4.project_name, t4.project_code, t2.total_price_with_tax,t2.product_type
from (SELECT sum(invoice_amount) receipt_amount, from (SELECT sum(invoice_amount) receipt_amount,
receivable_bill_id receivable_bill_id
FROM oms_receivable_invoice_detail FROM oms_receivable_invoice_detail t1
WHERE write_off_id is null and invoice_bill_code in left join oms_receivable_invoice_write_off t2 on t1.write_off_id=t2.id
WHERE (t1.write_off_id is null or t1.invoice_bill_code=t2.invoice_bill_code) and t1.invoice_bill_code in
<foreach item="item" collection="list" separator="," open="(" close=")" index=""> <foreach item="item" collection="list" separator="," open="(" close=")" index="">
#{item} #{item}
</foreach> </foreach>