@@ -100,6 +102,16 @@
class="col-amount"
@change="recalcTotal"
/>
+
+
+
+
+
+
+
+
@@ -235,6 +247,7 @@ import { addReimburseReq, checkReimburseOcrHealth, listFlowNode, listFlowTemplat
import { getEmployeeByUserId } from '@/api/hrm/employee';
import { ccFlowTask } from '@/api/hrm/flow';
import FileUpload from '@/components/FileUpload';
+import { getToken } from '@/utils/auth';
import UserMultiSelect from '@/components/UserSelect/multi.vue';
import UserSelect from '@/components/UserSelect/single.vue';
@@ -256,6 +269,8 @@ export default {
reimburseTypeOptions: ['差旅费', '招待费', '办公费', '交通费', '通讯费', '其他'],
// OCR服务状态:null=检测中,true=正常,false=不可用
ocrAvailable: null,
+ uploadFileUrl: process.env.VUE_APP_BASE_API + '/system/oss/upload',
+ uploadHeaders: { Authorization: 'Bearer ' + getToken() },
// 发票明细条目
invoiceItems: [],
// OCR加载状态 { ossId: true/false }
@@ -342,6 +357,7 @@ export default {
async triggerOcr (ossId) {
if (this.ocrDoneSet.has(ossId)) return
+ this.ocrDoneSet.add(ossId)
this.$set(this.ocrLoadingMap, ossId, true)
try {
const res = await ocrReimburseInvoice(ossId)
@@ -370,13 +386,19 @@ export default {
amount: totalAmount,
sortNo: this.invoiceItems.length
})
+ } else {
+ // OCR返回无内容,添加空条目供手动填写
+ this.invoiceItems.push({ ossId: ossId, itemName: '', reason: '', amount: 0, sortNo: this.invoiceItems.length })
}
this.recalcTotal()
+ } else {
+ // 接口无有效数据,添加空条目供手动填写
+ this.invoiceItems.push({ ossId: ossId, itemName: '', reason: '', amount: 0, sortNo: this.invoiceItems.length })
}
- this.ocrDoneSet.add(ossId)
} catch (e) {
console.error('[OCR] 识别失败', e)
this.$message.warning('发票识别失败,请手动填写事由和金额')
+ this.invoiceItems.push({ ossId: ossId, itemName: '', reason: '', amount: 0, sortNo: this.invoiceItems.length })
} finally {
this.$set(this.ocrLoadingMap, ossId, false)
}
@@ -403,6 +425,21 @@ export default {
this.recalcTotal()
},
+ addManualItem () {
+ this.invoiceItems.push({ ossId: null, itemName: '', reason: '', amount: 0, sortNo: this.invoiceItems.length })
+ },
+
+ onRowFileSuccess (res, idx) {
+ if (res.code === 200 && res.data) {
+ const ossId = res.data.ossId
+ this.ocrDoneSet.add(ossId)
+ this.$set(this.invoiceItems[idx], 'ossId', ossId)
+ const ids = (this.form.accessoryApplyIds || '').split(',').filter(Boolean)
+ ids.push(ossId)
+ this.form.accessoryApplyIds = ids.join(',')
+ }
+ },
+
recalcTotal () {
const total = this.invoiceItems.reduce((sum, item) => sum + (parseFloat(item.amount) || 0), 0)
this.form.totalAmount = parseFloat(total.toFixed(2))
@@ -655,6 +692,14 @@ export default {
flex-shrink: 0;
}
+.col-file {
+ width: 64px;
+ flex-shrink: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
.col-action {
width: 32px;
flex-shrink: 0;
@@ -664,8 +709,11 @@ export default {
.invoice-table-header .col-reason { flex: 1; }
.invoice-table-header .col-amount { width: 140px; }
+.invoice-table-header .col-file { width: 64px; }
.invoice-table-header .col-action { width: 32px; }
+.row-upload { display: inline-flex; }
+
.invoice-table-footer {
display: flex;
align-items: center;