145 lines
6.1 KiB
Vue
145 lines
6.1 KiB
Vue
<template>
|
|
<PageContainer title="财务管理">
|
|
<QueryToolbar>
|
|
<el-input-number v-model="form.projectId" :min="1" placeholder="项目ID" />
|
|
<el-input-number v-model="form.meetingId" :min="1" placeholder="会议ID" />
|
|
<el-input-number v-model="form.amountCent" :min="1" placeholder="金额(分)" />
|
|
<el-input v-model="form.paymentVoucherOssKey" placeholder="凭证OSS Key" class="w-input-lg" />
|
|
<el-input-number v-model="form.expectedAmountCent" :min="0" placeholder="对账应收(分)" />
|
|
<el-input v-model="form.lockReason" placeholder="锁账原因" class="w-input-md" />
|
|
<el-button v-if="canConfirm" type="primary" @click="handleConfirm">支付确认</el-button>
|
|
<el-button @click="load">刷新</el-button>
|
|
<el-button v-if="canExportLedger" @click="handleExportLedger">导出台账</el-button>
|
|
<el-button v-if="canReconcile" @click="handleReconcile">发起对账</el-button>
|
|
<el-button v-if="canLock" @click="handleLock">锁账</el-button>
|
|
<el-button v-if="canUnlock" @click="handleUnlock">解锁</el-button>
|
|
</QueryToolbar>
|
|
|
|
<el-table :data="rows" class="mt-md" empty-text="暂无数据">
|
|
<el-table-column prop="projectId" label="项目名称" min-width="160" :formatter="projectNameFormatter" />
|
|
<el-table-column prop="meetingId" label="会议名称" min-width="160" :formatter="meetingNameFormatter" />
|
|
<el-table-column prop="amountCent" label="支付金额(分)" />
|
|
<el-table-column prop="status" label="支付状态" width="140" :formatter="statusFormatter" />
|
|
</el-table>
|
|
<el-divider />
|
|
<el-row :gutter="12">
|
|
<el-col :span="12">
|
|
<SectionTitle>对账记录</SectionTitle>
|
|
<el-table :data="reconciliationRows" empty-text="暂无数据">
|
|
<el-table-column prop="projectId" label="项目名称" min-width="140" :formatter="projectNameFormatter" />
|
|
<el-table-column prop="expectedAmountCent" label="应收(分)" />
|
|
<el-table-column prop="actualAmountCent" label="实收(分)" />
|
|
<el-table-column prop="diffAmountCent" label="差额(分)" />
|
|
<el-table-column prop="resultStatus" label="结果" width="90" :formatter="statusFormatter" />
|
|
</el-table>
|
|
</el-col>
|
|
<el-col :span="12">
|
|
<SectionTitle>锁账记录</SectionTitle>
|
|
<el-table :data="lockLogRows" empty-text="暂无数据">
|
|
<el-table-column prop="projectId" label="项目名称" min-width="140" :formatter="projectNameFormatter" />
|
|
<el-table-column prop="lockStatus" label="状态" width="100" :formatter="statusFormatter" />
|
|
<el-table-column prop="reason" label="原因" />
|
|
<el-table-column prop="createdAt" label="时间" width="170" />
|
|
</el-table>
|
|
</el-col>
|
|
</el-row>
|
|
</PageContainer>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed, ref, onMounted } from "vue";
|
|
import PageContainer from "../../components/PageContainer.vue";
|
|
import QueryToolbar from "../../components/QueryToolbar.vue";
|
|
import SectionTitle from "../../components/SectionTitle.vue";
|
|
import { ElMessage } from "element-plus";
|
|
import {
|
|
confirmPayment,
|
|
exportFinanceLedger,
|
|
fetchFinanceProjects,
|
|
fetchFinanceReconciliationList,
|
|
lockFinance,
|
|
reconcileFinance,
|
|
unlockFinance,
|
|
} from "../../api/modules";
|
|
import { PERMS } from "../../constants/permissions";
|
|
import { useAuthStore } from "../../stores/auth";
|
|
import { toZhStatus } from "../../utils/status";
|
|
|
|
const authStore = useAuthStore();
|
|
const rows = ref<any[]>([]);
|
|
const canConfirm = computed(() => authStore.hasPermission(PERMS.finance.paymentConfirm));
|
|
const canExportLedger = computed(() => authStore.hasPermission(PERMS.finance.ledgerExport));
|
|
const canReconcile = computed(() => authStore.hasPermission(PERMS.finance.reconciliation));
|
|
const canLock = computed(() => authStore.hasPermission(PERMS.finance.lock));
|
|
const canUnlock = computed(() => authStore.hasPermission(PERMS.finance.unlock));
|
|
const reconciliationRows = ref<any[]>([]);
|
|
const lockLogRows = ref<any[]>([]);
|
|
const form = ref({
|
|
projectId: 1001,
|
|
meetingId: 2001,
|
|
amountCent: 100000,
|
|
paymentVoucherOssKey: "1/1001/2001/finance/202603/voucher.pdf",
|
|
expectedAmountCent: 100000,
|
|
lockReason: "月结锁账",
|
|
});
|
|
const statusFormatter = (_row: any, _column: any, value: unknown) => toZhStatus(value);
|
|
const projectNameFormatter = (row: any) => row?.projectName || row?.project || `项目#${row?.projectId || "-"}`;
|
|
const meetingNameFormatter = (row: any) => row?.meetingTopic || row?.meetingName || `会议#${row?.meetingId || "-"}`;
|
|
|
|
const load = async () => {
|
|
const resp = await fetchFinanceProjects();
|
|
rows.value = resp?.data?.list || [];
|
|
if (canReconcile.value || canLock.value || canUnlock.value) {
|
|
const recResp = await fetchFinanceReconciliationList({ projectId: form.value.projectId });
|
|
reconciliationRows.value = recResp?.data?.reconciliation || [];
|
|
lockLogRows.value = recResp?.data?.lockLogs || [];
|
|
}
|
|
};
|
|
|
|
const handleConfirm = async () => {
|
|
await confirmPayment({
|
|
...form.value,
|
|
idempotencyKey: `pay-${Date.now()}-${form.value.meetingId}`,
|
|
});
|
|
ElMessage.success("支付确认成功");
|
|
await load();
|
|
};
|
|
|
|
const handleExportLedger = async () => {
|
|
const resp = await exportFinanceLedger();
|
|
ElMessage.success(`导出成功,共 ${resp?.data?.total || 0} 条`);
|
|
};
|
|
|
|
const handleReconcile = async () => {
|
|
await reconcileFinance({
|
|
idempotencyKey: `recon-${Date.now()}-${form.value.projectId}`,
|
|
projectId: form.value.projectId,
|
|
expectedAmountCent: form.value.expectedAmountCent,
|
|
});
|
|
ElMessage.success("对账完成");
|
|
await load();
|
|
};
|
|
|
|
const handleLock = async () => {
|
|
await lockFinance({
|
|
idempotencyKey: `lock-${Date.now()}-${form.value.projectId}`,
|
|
projectId: form.value.projectId,
|
|
reason: form.value.lockReason || "锁账",
|
|
});
|
|
ElMessage.success("锁账成功");
|
|
await load();
|
|
};
|
|
|
|
const handleUnlock = async () => {
|
|
await unlockFinance({
|
|
idempotencyKey: `unlock-${Date.now()}-${form.value.projectId}`,
|
|
projectId: form.value.projectId,
|
|
reason: form.value.lockReason || "解锁",
|
|
});
|
|
ElMessage.success("解锁成功");
|
|
await load();
|
|
};
|
|
|
|
onMounted(load);
|
|
</script>
|