<template>
|
<div class="app-container">
|
<el-form :model="filters" :inline="true">
|
<el-form-item label="会计科目:">
|
<el-cascader v-model="filters.subject" :options="subjectOptions" :props="{ label: 'name', value: 'code' }" placeholder="请选择会计科目" clearable style="width: 250px;" filterable />
|
</el-form-item>
|
<el-form-item label="辅助核算:">
|
<el-select v-model="filters.auxiliary" placeholder="请选择辅助核算" clearable style="width: 180px;">
|
<el-option label="客户" value="customer" />
|
<el-option label="供应商" value="supplier" />
|
<el-option label="部门" value="department" />
|
<el-option label="员工" value="employee" />
|
<el-option label="项目" value="project" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="核算对象:">
|
<el-select v-model="filters.auxiliaryItem" placeholder="请选择核算对象" clearable style="width: 200px;" :disabled="!filters.auxiliary">
|
<el-option v-for="item in auxiliaryItems" :key="item.value" :label="item.label" :value="item.value" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="期间:">
|
<el-date-picker v-model="filters.startMonth" type="month" placeholder="开始月份" value-format="YYYY-MM" style="width: 140px;" />
|
<span style="margin: 0 10px;">至</span>
|
<el-date-picker v-model="filters.endMonth" type="month" placeholder="结束月份" value-format="YYYY-MM" style="width: 140px;" />
|
</el-form-item>
|
<el-form-item>
|
<el-button type="primary" @click="getTableData">查询</el-button>
|
<el-button @click="resetFilters">重置</el-button>
|
<el-button @click="handlePrint" icon="Printer">打印</el-button>
|
<el-button @click="handleOut" icon="Download">导出</el-button>
|
</el-form-item>
|
</el-form>
|
|
<div class="ledger-header" v-if="currentSubject">
|
<h2>科目明细账</h2>
|
<p>科目: {{ currentSubject.code }} {{ currentSubject.name }}</p>
|
<p v-if="filters.auxiliary && filters.auxiliaryItem">辅助核算: {{ getAuxiliaryLabel() }}</p>
|
<p>期间: {{ filters.startMonth }} 至 {{ filters.endMonth }}</p>
|
</div>
|
|
<div class="table_list">
|
<el-table :data="dataList" border style="width: 100%" show-summary :summary-method="getSummaries">
|
<el-table-column prop="date" label="日期" width="120" />
|
<el-table-column prop="voucherNo" label="凭证字号" width="120" />
|
<el-table-column prop="summary" label="摘要" min-width="200" show-overflow-tooltip />
|
<el-table-column prop="debit" label="借方" width="150">
|
<template #default="{ row }">
|
<span v-if="row.debit > 0" class="text-danger">¥{{ formatMoney(row.debit) }}</span>
|
<span v-else>-</span>
|
</template>
|
</el-table-column>
|
<el-table-column prop="credit" label="贷方" width="150">
|
<template #default="{ row }">
|
<span v-if="row.credit > 0" class="text-success">¥{{ formatMoney(row.credit) }}</span>
|
<span v-else>-</span>
|
</template>
|
</el-table-column>
|
<el-table-column label="方向" width="80">
|
<template #default="{ row }">
|
<el-tag :type="row.direction === '借' ? 'success' : 'danger'" size="small">{{ row.direction }}</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column label="余额" width="150">
|
<template #default="{ row }">
|
<span :class="row.balance >= 0 ? 'text-primary' : 'text-warning'">¥{{ formatMoney(Math.abs(row.balance)) }}</span>
|
</template>
|
</el-table-column>
|
</el-table>
|
</div>
|
|
<el-empty v-if="!currentSubject" description="请选择会计科目查询" style="margin-top: 50px;" />
|
</div>
|
</template>
|
|
<script setup>
|
import { ref, reactive, onMounted, computed, watch } from "vue";
|
import { ElMessage } from "element-plus";
|
import { listAccountSubject } from "@/api/financialManagement/accountSubject";
|
import { getDetailLedger } from "@/api/financialManagement/ledger";
|
|
defineOptions({
|
name: "科目明细账",
|
});
|
|
const filters = reactive({
|
subject: [],
|
auxiliary: "",
|
auxiliaryItem: "",
|
startMonth: "2024-01",
|
endMonth: "2024-03",
|
});
|
|
const dataList = ref([]);
|
const subjectOptions = ref([]);
|
|
const fallbackSubjects = [
|
{ code: "1122", name: "应收账款" },
|
{ code: "2202", name: "应付账款" },
|
{ code: "6602", name: "管理费用" },
|
];
|
|
const loadSubjectOptions = async () => {
|
try {
|
const { data } = await listAccountSubject({
|
current: 1,
|
size: 1000,
|
});
|
const records = data?.records || [];
|
if (records.length > 0) {
|
subjectOptions.value = records
|
.filter(item => item.subjectCode && item.subjectName)
|
.map(item => ({
|
code: item.subjectCode,
|
name: item.subjectName,
|
children: [],
|
}));
|
return;
|
}
|
} catch (error) {
|
// 全局拦截器已提示,下面走兜底科目
|
}
|
subjectOptions.value = fallbackSubjects.map(item => ({ ...item, children: [] }));
|
};
|
|
const auxiliaryItems = computed(() => {
|
const map = {
|
customer: [
|
{ value: "1", label: "北京科技有限公司" },
|
{ value: "2", label: "上海贸易公司" },
|
{ value: "3", label: "广州实业有限公司" },
|
],
|
supplier: [
|
{ value: "1", label: "北京原材料供应商" },
|
{ value: "2", label: "上海电子元器件公司" },
|
{ value: "3", label: "广州包装材料厂" },
|
],
|
department: [
|
{ value: "1", label: "财务部" },
|
{ value: "2", label: "销售部" },
|
{ value: "3", label: "采购部" },
|
],
|
employee: [
|
{ value: "1", label: "张三" },
|
{ value: "2", label: "李四" },
|
{ value: "3", label: "王五" },
|
],
|
project: [
|
{ value: "1", label: "项目A" },
|
{ value: "2", label: "项目B" },
|
{ value: "3", label: "项目C" },
|
],
|
};
|
return map[filters.auxiliary] || [];
|
});
|
|
watch(() => filters.auxiliary, () => {
|
filters.auxiliaryItem = "";
|
});
|
|
const currentSubject = computed(() => {
|
if (!filters.subject || filters.subject.length === 0) return null;
|
const code = filters.subject[filters.subject.length - 1];
|
return findSubject(subjectOptions.value, code);
|
});
|
|
const findSubject = (options, code) => {
|
for (const item of options) {
|
if (item.code === code) return item;
|
if (item.children && item.children.length > 0) {
|
const found = findSubject(item.children, code);
|
if (found) return found;
|
}
|
}
|
return null;
|
};
|
|
const getAuxiliaryLabel = () => {
|
const item = auxiliaryItems.value.find(i => i.value === filters.auxiliaryItem);
|
return item ? item.label : "";
|
};
|
|
const formatMoney = (value) => {
|
if (value === undefined || value === null) return "0.00";
|
return Number(value).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
};
|
|
// 联调约定:明细账接口可按辅助核算过滤(auxiliaryType/auxiliaryId)
|
const getTableData = async () => {
|
if (!currentSubject.value) {
|
dataList.value = [];
|
return;
|
}
|
try {
|
const { data } = await getDetailLedger({
|
subjectCode: currentSubject.value.code,
|
auxiliaryType: filters.auxiliary,
|
auxiliaryId: filters.auxiliaryItem,
|
startMonth: filters.startMonth,
|
endMonth: filters.endMonth,
|
});
|
dataList.value = Array.isArray(data) ? data : data?.records || [];
|
} catch (error) {
|
// 提示由全局请求拦截器处理,这里仅防止未捕获异常
|
}
|
};
|
|
const resetFilters = () => {
|
filters.subject = [];
|
filters.auxiliary = "";
|
filters.auxiliaryItem = "";
|
filters.startMonth = "2024-01";
|
filters.endMonth = "2024-03";
|
dataList.value = [];
|
};
|
|
const getSummaries = (param) => {
|
const { columns, data } = param;
|
const sums = [];
|
columns.forEach((column, index) => {
|
if (index === 0) {
|
sums[index] = "合计";
|
return;
|
}
|
if (column.property === "debit") {
|
const values = data.map(item => Number(item.debit));
|
const sum = values.reduce((prev, curr) => prev + curr, 0);
|
sums[index] = "¥" + formatMoney(sum);
|
} else if (column.property === "credit") {
|
const values = data.map(item => Number(item.credit));
|
const sum = values.reduce((prev, curr) => prev + curr, 0);
|
sums[index] = "¥" + formatMoney(sum);
|
} else {
|
sums[index] = "";
|
}
|
});
|
return sums;
|
};
|
|
const handlePrint = () => {
|
ElMessage.info("打印功能");
|
};
|
|
const handleOut = () => {
|
ElMessage.success("导出成功");
|
};
|
|
onMounted(async () => {
|
await loadSubjectOptions();
|
});
|
</script>
|
|
<style lang="scss" scoped>
|
.ledger-header {
|
text-align: center;
|
margin-bottom: 20px;
|
h2 {
|
margin: 0 0 10px 0;
|
}
|
p {
|
color: #606266;
|
margin: 5px 0;
|
}
|
}
|
|
.text-primary {
|
color: #409eff;
|
font-weight: bold;
|
}
|
|
.text-success {
|
color: #67c23a;
|
font-weight: bold;
|
}
|
|
.text-danger {
|
color: #f56c6c;
|
font-weight: bold;
|
}
|
|
.text-warning {
|
color: #e6a23c;
|
font-weight: bold;
|
}
|
</style>
|