Merge: feat(报销/拨款) 发票明细与附件双向联动
This commit is contained in:
@@ -54,8 +54,9 @@
|
||||
<!-- 拨款单据附件(OCR触发区) -->
|
||||
<el-form-item label="拨款单据附件" prop="accessoryApplyIds">
|
||||
<file-upload v-model="form.accessoryApplyIds" :limit="50" :file-size="50"
|
||||
:file-type="['pdf', 'jpg', 'jpeg', 'png', 'doc', 'docx']" multiple />
|
||||
<div class="hint-text">上传发票、收据、付款截图等(支持 PDF/图片,上传后自动识别)</div>
|
||||
:file-type="['pdf', 'jpg', 'jpeg', 'png', 'doc', 'docx']" multiple
|
||||
@delete="onFileDelete" />
|
||||
<div class="hint-text">上传发票、收据、付款截图等(支持 PDF/图片,上传后自动识别明细)</div>
|
||||
</el-form-item>
|
||||
|
||||
<!-- OCR 识别中提示 -->
|
||||
@@ -67,9 +68,9 @@
|
||||
<!-- 发票明细条目表 -->
|
||||
<div class="block-title">
|
||||
拨款明细
|
||||
<span class="block-title-hint">(上传发票后自动填充,也可手动添加)</span>
|
||||
<span class="block-title-hint">(上传发票后自动识别,删除条目将同步移除对应文件)</span>
|
||||
</div>
|
||||
<div class="invoice-table">
|
||||
<div class="invoice-table" v-if="invoiceItems.length">
|
||||
<div class="invoice-table-header">
|
||||
<span class="col-reason">事由说明</span>
|
||||
<span class="col-amount">金额(元)</span>
|
||||
@@ -95,8 +96,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="invoice-table-footer">
|
||||
<el-button size="mini" type="primary" plain icon="el-icon-plus" @click="addInvoiceItem">添加条目</el-button>
|
||||
<span class="total-hint" v-if="invoiceItems.length">
|
||||
<span class="total-hint">
|
||||
合计:<b>¥{{ invoiceTotalFormatted }}</b>(已自动更新拨款总金额)
|
||||
</span>
|
||||
</div>
|
||||
@@ -350,23 +350,27 @@ export default {
|
||||
try {
|
||||
const res = await ocrAppropriationInvoice(ossId)
|
||||
if (res.code === 200 && res.data) {
|
||||
const { items, totalAmount } = res.data
|
||||
const { items, totalAmount, sellerName, invoiceDate, invoiceType } = res.data
|
||||
// 拼接发票头部信息作为事由前缀:发票类型 · 销售方 · 开票日期
|
||||
const prefix = [invoiceType, sellerName, invoiceDate].filter(Boolean).join(' · ')
|
||||
if (items && items.length) {
|
||||
const startIdx = this.invoiceItems.length
|
||||
items.forEach((item, i) => {
|
||||
const reason = [prefix, item.itemName].filter(Boolean).join(' / ')
|
||||
this.invoiceItems.push({
|
||||
ossId: Number(ossId),
|
||||
itemName: item.itemName || '',
|
||||
reason: item.itemName || '',
|
||||
reason,
|
||||
amount: item.amount || 0,
|
||||
sortNo: startIdx + i
|
||||
})
|
||||
})
|
||||
} else if (totalAmount) {
|
||||
// 没有明细时用总金额创建一条,事由取发票头部信息
|
||||
this.invoiceItems.push({
|
||||
ossId: Number(ossId),
|
||||
itemName: '',
|
||||
reason: '',
|
||||
itemName: sellerName || '',
|
||||
reason: prefix || '',
|
||||
amount: totalAmount,
|
||||
sortNo: this.invoiceItems.length
|
||||
})
|
||||
@@ -382,12 +386,24 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
addInvoiceItem () {
|
||||
this.invoiceItems.push({ ossId: null, itemName: '', reason: '', amount: 0, sortNo: this.invoiceItems.length })
|
||||
removeInvoiceItem (idx) {
|
||||
const item = this.invoiceItems[idx]
|
||||
if (item.ossId) {
|
||||
// 删除该文件下所有条目
|
||||
const ossId = String(item.ossId)
|
||||
this.invoiceItems = this.invoiceItems.filter(it => String(it.ossId) !== ossId)
|
||||
// 从附件 CSV 中移除该文件
|
||||
const ids = (this.form.accessoryApplyIds || '').split(',').filter(id => id && id !== ossId)
|
||||
this.form.accessoryApplyIds = ids.join(',')
|
||||
} else {
|
||||
this.invoiceItems.splice(idx, 1)
|
||||
}
|
||||
this.recalcTotal()
|
||||
},
|
||||
|
||||
removeInvoiceItem (idx) {
|
||||
this.invoiceItems.splice(idx, 1)
|
||||
onFileDelete (deletedFile) {
|
||||
const ossId = String(deletedFile.ossId)
|
||||
this.invoiceItems = this.invoiceItems.filter(item => String(item.ossId) !== ossId)
|
||||
this.recalcTotal()
|
||||
},
|
||||
|
||||
|
||||
@@ -54,8 +54,9 @@
|
||||
<!-- 报销单据附件(OCR触发区) -->
|
||||
<el-form-item label="报销单据附件" prop="accessoryApplyIds">
|
||||
<file-upload v-model="form.accessoryApplyIds" :limit="200" :file-size="50"
|
||||
:file-type="['pdf', 'jpg', 'jpeg', 'png', 'doc', 'docx']" multiple />
|
||||
<div class="hint-text">上传发票、收据、付款截图等(支持 PDF/图片,上传后自动识别)</div>
|
||||
:file-type="['pdf', 'jpg', 'jpeg', 'png', 'doc', 'docx']" multiple
|
||||
@delete="onFileDelete" />
|
||||
<div class="hint-text">上传发票、收据、付款截图等(支持 PDF/图片,上传后自动识别明细)</div>
|
||||
</el-form-item>
|
||||
|
||||
<!-- OCR 识别中提示 -->
|
||||
@@ -67,9 +68,9 @@
|
||||
<!-- 发票明细条目表 -->
|
||||
<div class="block-title">
|
||||
发票明细
|
||||
<span class="block-title-hint">(上传发票后自动填充,也可手动添加)</span>
|
||||
<span class="block-title-hint">(上传发票后自动识别,删除条目将同步移除对应文件)</span>
|
||||
</div>
|
||||
<div class="invoice-table">
|
||||
<div class="invoice-table" v-if="invoiceItems.length">
|
||||
<div class="invoice-table-header">
|
||||
<span class="col-reason">事由说明</span>
|
||||
<span class="col-amount">金额(元)</span>
|
||||
@@ -95,8 +96,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="invoice-table-footer">
|
||||
<el-button size="mini" type="primary" plain icon="el-icon-plus" @click="addInvoiceItem">添加条目</el-button>
|
||||
<span class="total-hint" v-if="invoiceItems.length">
|
||||
<span class="total-hint">
|
||||
合计:<b>¥{{ invoiceTotalFormatted }}</b>(已自动更新报销总金额)
|
||||
</span>
|
||||
</div>
|
||||
@@ -325,24 +325,27 @@ export default {
|
||||
try {
|
||||
const res = await ocrReimburseInvoice(ossId)
|
||||
if (res.code === 200 && res.data) {
|
||||
const { items, totalAmount } = res.data
|
||||
const { items, totalAmount, sellerName, invoiceDate, invoiceType } = res.data
|
||||
// 拼接发票头部信息作为事由前缀:发票类型 · 销售方 · 开票日期
|
||||
const prefix = [invoiceType, sellerName, invoiceDate].filter(Boolean).join(' · ')
|
||||
if (items && items.length) {
|
||||
const startIdx = this.invoiceItems.length
|
||||
items.forEach((item, i) => {
|
||||
const reason = [prefix, item.itemName].filter(Boolean).join(' / ')
|
||||
this.invoiceItems.push({
|
||||
ossId: Number(ossId),
|
||||
itemName: item.itemName || '',
|
||||
reason: item.itemName || '',
|
||||
reason,
|
||||
amount: item.amount || 0,
|
||||
sortNo: startIdx + i
|
||||
})
|
||||
})
|
||||
} else if (totalAmount) {
|
||||
// 没有明细时用总金额创建一条
|
||||
// 没有明细时用总金额创建一条,事由取发票头部信息
|
||||
this.invoiceItems.push({
|
||||
ossId: Number(ossId),
|
||||
itemName: '',
|
||||
reason: '',
|
||||
itemName: sellerName || '',
|
||||
reason: prefix || '',
|
||||
amount: totalAmount,
|
||||
sortNo: this.invoiceItems.length
|
||||
})
|
||||
@@ -358,12 +361,24 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
addInvoiceItem () {
|
||||
this.invoiceItems.push({ ossId: null, itemName: '', reason: '', amount: 0, sortNo: this.invoiceItems.length })
|
||||
removeInvoiceItem (idx) {
|
||||
const item = this.invoiceItems[idx]
|
||||
if (item.ossId) {
|
||||
// 删除该文件下所有条目
|
||||
const ossId = String(item.ossId)
|
||||
this.invoiceItems = this.invoiceItems.filter(it => String(it.ossId) !== ossId)
|
||||
// 从附件 CSV 中移除该文件
|
||||
const ids = (this.form.accessoryApplyIds || '').split(',').filter(id => id && id !== ossId)
|
||||
this.form.accessoryApplyIds = ids.join(',')
|
||||
} else {
|
||||
this.invoiceItems.splice(idx, 1)
|
||||
}
|
||||
this.recalcTotal()
|
||||
},
|
||||
|
||||
removeInvoiceItem (idx) {
|
||||
this.invoiceItems.splice(idx, 1)
|
||||
onFileDelete (deletedFile) {
|
||||
const ossId = String(deletedFile.ossId)
|
||||
this.invoiceItems = this.invoiceItems.filter(item => String(item.ossId) !== ossId)
|
||||
this.recalcTotal()
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user