feat: 财务单据完善

This commit is contained in:
砂糖
2025-08-16 14:14:57 +08:00
parent 2e1d4f7a6f
commit e5137b4c0f
6 changed files with 219 additions and 83 deletions

View File

@@ -38,6 +38,7 @@
},
methods: {
getFinancialAccounts() {
console.log(this.financialAccounts, 'financialAccounts');
this.options = this.financialAccounts.map(item => ({
label: item.accountName,
value: item.accountId

View File

@@ -13,7 +13,8 @@ const mutations = {
const actions = {
getFinancialAccounts({ commit }) {
listAccount({ pageSize: 1000 }).then(response => {
commit('SET_FINANCIAL_ACCOUNTS', response.rows);
console.log(response.data, 'finance.response.rows');
commit('SET_FINANCIAL_ACCOUNTS', response.data);
});
}
}

View File

@@ -0,0 +1,124 @@
<template>
<div class="finance-voucher-component">
<div
v-for="(voucher, index) in voucherData"
:key="index"
class="voucher-item"
>
<!-- 主单据信息行 -->
<div class="voucher-header">
<div class="header-cell">
<el-checkbox v-model="voucher.checked"></el-checkbox>
</div>
<div class="header-cell">日期: {{ formatDate(voucher.docDate) }}</div>
<div class="header-cell">单据编号: {{ voucher.docNo }}</div>
<div class="header-cell">单据类型: {{ voucher.docType }}</div>
<div class="header-cell operation-group">
<el-button type="text" size="mini" @click.stop="handleView(voucher)">查看</el-button>
<el-button type="text" size="mini" @click.stop="handleDelete(voucher)">删除</el-button>
</div>
</div>
<!-- 凭证明细表格 -->
<el-table :data="voucher.detailList || []" border style="width: 100%;">
<el-table-column label="摘要" prop="voucherNo" />
<el-table-column label="科目" prop="accountId" />
<el-table-column label="借方金额" prop="debitAmount" align="right" />
<el-table-column label="贷方金额" prop="creditAmount" align="right" />
</el-table>
<!-- 总计行 -->
<div class="total-row">
<div class="total-cell" :colspan="3">总计</div>
<div class="total-cell" align="right">{{ calculateTotal(voucher.detailList, 'debitAmount') }}</div>
<div class="total-cell" align="right">{{ calculateTotal(voucher.detailList, 'creditAmount') }}</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "FinanceVoucherComponent",
props: {
voucherData: {
type: Array,
default: () => [],
},
},
data() {
return {
// 用于存储选中状态,若父组件需控制,可改为 prop 或 sync 修饰符
internalVoucherData: [],
};
},
watch: {
voucherData: {
handler(val) {
this.internalVoucherData = val.map((v) => ({
...v,
checked: false,
}));
},
immediate: true,
},
},
methods: {
handleView(voucher) {
this.$emit("view-voucher", voucher);
},
handleDelete(voucher) {
this.$emit("delete-voucher", voucher);
},
formatDate(dateStr) {
if (!dateStr) return "";
return new Date(dateStr).toLocaleDateString();
},
calculateTotal(detailList, field) {
if (!detailList || detailList.length === 0) return "0.00";
return detailList.reduce(
(sum, item) => sum + parseFloat(item[field] || 0),
0
).toFixed(2);
},
},
};
</script>
<style scoped>
.finance-voucher-component {
padding: 16px;
}
.voucher-item {
border: 1px solid #e6e6e6;
border-radius: 4px;
margin-bottom: 16px;
}
.voucher-header {
display: flex;
align-items: center;
background-color: #f5f5f5;
padding: 8px 16px;
}
.header-cell {
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.operation-group {
display: flex;
gap: 8px;
}
.total-row {
display: flex;
align-items: center;
background-color: #f0f9ff;
padding: 8px 16px;
font-weight: bold;
}
.total-cell {
flex: 1;
text-align: left;
}
</style>

View File

@@ -13,6 +13,11 @@
<el-form-item label="关联订单" prop="relatedOrderId">
<el-input v-model="form.relatedOrderId" placeholder="请输入关联订单" />
</el-form-item>
<el-form-item label="单据类型" prop="docType">
<el-select v-model="form.docType" placeholder="请选择单据类型">
<el-option v-for="item in dict.type.finance_voucher_type" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
</el-form>
</el-row>
@@ -94,18 +99,20 @@
<script>
import AmountSelect from '@/components/KLPService/AmountSelect/index.vue';
import { addFinancialDocumentWithDetail, updateFinancialDocument } from "@/api/finance/financialDocument";
import { updateJournalEntry } from "@/api/finance/jouneryEntry";
import { updateJournalEntry, addJournalEntry } from "@/api/finance/jouneryEntry";
export default {
components: {
AmountSelect
},
dicts: ['finance_voucher_type'],
data() {
return {
form: {
docNo: undefined,
docDate: undefined,
relatedOrderId: undefined
relatedOrderId: undefined,
docType: undefined
},
tableData: [{
voucherNo: '',
@@ -167,24 +174,26 @@ export default {
initData: {
handler(newVal) {
console.log(newVal, 'watchData');
if (newVal) {
if (newVal.detailList) {
this.tableData = newVal.detailList;
} else {
this.tableData = [{
voucherNo: '',
accountId: undefined,
debitAmount: 0,
creditAmount: 0,
remark: '',
voucherNo: ''
}]
}
if (newVal && newVal.detailList) {
this.tableData = newVal.detailList;
this.form.docNo = newVal.docNo;
this.form.docDate = newVal.docDate;
this.form.relatedOrderId = newVal.relatedOrderId;
this.form.docType = newVal.docType;
this.isCreate = false;
} else {
this.form.docNo = undefined;
this.form.docDate = undefined;
this.form.relatedOrderId = undefined;
this.form.docType = undefined;
this.tableData = [{
voucherNo: '',
accountId: undefined,
debitAmount: 0,
creditAmount: 0,
remark: '',
voucherNo: ''
}]
this.isCreate = true;
}
},
@@ -312,6 +321,38 @@ export default {
},
handleCreate() {
if (!this.validateTableData()) {
return;
}
// 6. 提交数据
addFinancialDocumentWithDetail({
docNo: form.docNo,
docDate: form.docDate,
// 保持变量名一致
relatedOrderId: form.relatedOrderId,
amount: this.debitAmount,
details: validData.map((row, idx) => ({
// voucherNo: row.voucherNo,
voucherNo: row.voucherNo,
// 保持变量名一致
accountId: row.accountId,
debitAmount: row.debitAmount,
creditAmount: row.creditAmount,
remark: row.remark,
lineNo: idx + 1,
entryDate: form.docDate
}))
}).then(response => {
this.$message.success('凭证创建成功');
this.$emit('success');
}).catch(error => {
this.$message.error('凭证创建失败:' + (error.message || '未知错误'));
this.$emit('error', error);
});
},
validateTableData() {
// 收集所有错误信息
const errors = [];
const { form, tableData } = this;
@@ -321,6 +362,7 @@ export default {
if (!form.docDate) errors.push('单据日期必填');
// 注意原模板中是relatedOrderId保持变量名一致
if (!form.relatedOrderId) errors.push('关联订单必填');
if (!form.docType) errors.push('单据类型必填');
// 2. 过滤有效行并检查基本存在性
const validData = tableData.filter(row => this.isRowNotEmpty(row));
@@ -365,47 +407,37 @@ export default {
message: errors.map(error => `<p>${error}</p>`).join(''),
type: 'error'
})
return;
return false;
}
// 6. 提交数据
addFinancialDocumentWithDetail({
docNo: form.docNo,
docDate: form.docDate,
// 保持变量名一致
relatedOrderId: form.relatedOrderId,
amount: this.debitAmount,
details: validData.map((row, idx) => ({
// voucherNo: row.voucherNo,
voucherNo: row.voucherNo,
// 保持变量名一致
accountId: row.accountId,
debitAmount: row.debitAmount,
creditAmount: row.creditAmount,
remark: row.remark,
lineNo: idx + 1,
entryDate: form.docDate
}))
}).then(response => {
this.$message.success('凭证创建成功');
this.$emit('success');
}).catch(error => {
this.$message.error('凭证创建失败:' + (error.message || '未知错误'));
this.$emit('error', error);
});
return true;
},
handleEdit(index) {
// 找到对应的列变更
const row = this.tableData[index];
updateJournalEntry(row).then(response => {
this.$message.success('明细变更成功');
}).catch(error => {
this.$message.error('明细变更失败:' + (error.message || '未知错误'));
});
if (row.entryId) {
updateJournalEntry(row).then(response => {
this.$message.success('明细变更成功');
}).catch(error => {
this.$message.error('明细变更失败:' + (error.message || '未知错误'));
});
} else {
addJournalEntry({
...row,
documentId: this.initData.documentId,
}).then(response => {
this.$message.success('明细变更成功');
}).catch(error => {
this.$message.error('明细变更失败:' + (error.message || '未知错误'));
})
}
},
handleChange() {
if (!this.validateTableData()) {
return;
}
updateFinancialDocument({
documentId: this.initData.documentId,
docNo: this.form.docNo,

View File

@@ -73,37 +73,11 @@
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="financialDocumentList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="单据ID" align="center" prop="documentId" v-if="true"/>
<el-table-column label="单据编号" align="center" prop="docNo" />
<el-table-column label="单据类型" align="center" prop="docType" />
<el-table-column label="单据日期" align="center" prop="docDate" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.docDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="单据金额" align="center" prop="amount" />
<el-table-column label="关联订单ID" align="center" prop="relatedOrderId" />
<el-table-column label="单据状态" align="center" prop="status" />
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<FinanceVoucherTable
:voucher-data="financialDocumentList"
@view-voucher="handleUpdate"
@delete-voucher="handleDelete"
/>
<pagination
v-show="total > 0"
@@ -123,11 +97,13 @@
<script>
import { listFinancialDocumentWithDetail, getFinancialDocument, delFinancialDocument, addFinancialDocument, updateFinancialDocument } from "@/api/finance/financialDocument";
import CreateDocument from "./components/Voucher.vue";
import FinanceVoucherTable from "./components/FinanceVoucherTable.vue"; // 引入定制表格
export default {
name: "FinancialDocument",
components: {
CreateDocument
CreateDocument,
FinanceVoucherTable
},
data() {
return {
@@ -227,6 +203,8 @@ export default {
handleAdd() {
this.reset();
this.open = true;
this.currentRow = {}
// this.isCreate = true;
this.title = "添加财务单据";
},
/** 修改按钮操作 */

View File

@@ -1,10 +1,10 @@
<template>
<div style="position: relative; padding-top: 60px;">
<div style="position: relative;">
<div style="position: absolute; top: 10px; left: 10px;">
<!-- 策略切换单选框 -->
<el-radio-group
v-model="currentStrategy"
size="small"
size="mini"
>
<el-radio label="stockIo">盘点单</el-radio>
<el-radio label="order">订单</el-radio>
@@ -16,6 +16,7 @@
v-model="currentId"
:placeholder="`请选择${strategyLabels[currentStrategy]}`"
style="width: 200px;"
size="mini"
>
<el-option
v-for="item in currentList"
@@ -26,7 +27,6 @@
</el-select>
</div>
<div class="print-container" v-loading="loading">
<BarCode :barcodes="drawerBarcodeData" />
</div>