feat(财务): 新增入账管理模块

新增账单导入和账单核对功能
- 添加账单导入页面,支持微信、支付宝、银行账单文件上传
- 实现账单核对功能,包括自动核对和人工核对
- 添加多种类型订单展示组件(VIP、课程、实物商品等)
- 实现订单选择和提交功能
- 添加CardList组件用于展示可选项和已选项
This commit is contained in:
2026-01-06 18:03:12 +08:00
parent 4163a322d7
commit 75111681b4
29 changed files with 3218 additions and 0 deletions

View File

@@ -0,0 +1,176 @@
<script lang="ts" setup>
import type { CreateOrderType } from '../types';
import { computed, ref, watch } from 'vue';
import { Button } from 'ant-design-vue';
import { reconciliateBillsApi } from '#/api/posting/reconciliate';
import { useCardList } from '#/components/card-list/index';
interface RecommendedUser {
tel: string;
}
const props = withDefaults(
defineProps<{
errorItem: CreateOrderType[];
}>(),
{},
);
const emit = defineEmits(['deletedChecked']);
const errorData = ref<any[]>([]);
watch(
() => props.errorItem,
(newVal) => {
errorData.value = newVal.map((item) => ({
id: item.id,
}));
gridApi.setErrorItems(errorData.value);
},
{ deep: true },
);
const gridOptions = computed(() => ({
columns: [
// { field: 'productName', title: '名称' },
{
field: 'orderType',
title: '类型',
formatter: (value: string) => {
const typeMap: Record<string, string> = {
'0': '充值',
'1': 'VIP',
'2': '课程',
'3': '实物',
'4': '培训班',
};
return typeMap[value] || value;
},
},
{
field: 'come',
title: '来源',
formatter: (value: string) => {
const comeMap: Record<string, string> = {
'0': '一路健康',
'1': '吴门医述',
'2': '手动添加',
};
return comeMap[value] || value;
},
},
{
editRender: {
name: 'SelectDropdownRender',
props: {
fetchOptions: (row: CreateOrderType) =>
reconciliateBillsApi
.getRecommendUser({
paymentId: row.paymentId,
come: row.come,
orderType: row.orderType,
courseId: row.courseId,
vipType: row.vipType ?? '',
})
.then(
(data) =>
data.list.map((item: RecommendedUser) => ({
value: item.tel,
})) || [],
),
allowClear: true,
},
},
field: 'tel',
title: '用户手机号',
},
{ editRender: { name: 'Input' }, field: 'orderMoney', title: '订单金额' },
{ editRender: { name: 'Input' }, field: 'realMoney', title: '实际金额' },
{
editRender: {
name: 'DatePicker',
props: {
valueFormat: 'YYYY-MM-DD',
},
},
// 仅VIP 和课程订单 显示
show: (row: CreateOrderType) => row.orderType === '1' || row.orderType === '2',
field: 'startTime',
title: '开始时间',
},
{
editRender: {
name: 'Select',
props: {
options: [
{ label: '半年', value: '6' },
{ label: '一年', value: '12' },
{ label: '两年', value: '24' },
{ label: '三年', value: '36' },
{ label: '四年', value: '48' },
],
},
},
// 仅VIP 和课程订单 显示
show: (row: CreateOrderType) => row.orderType === '1' || row.orderType === '2',
field: 'endTime',
title: '到期时间',
},
],
showTitle: true,
titleField: 'productName',
gridColumns: 4,
gridHeight: '355px',
cardHeight: '345px',
}));
const [Grid, gridApi] = useCardList<CreateOrderType>({
gridOptions: gridOptions.value,
});
// 添加选中项
function handleAdd(rows: CreateOrderType[]) {
gridApi.insertAt(rows);
}
// 卡片删除触发
function handleDelete(row: CreateOrderType) {
emit('deletedChecked', [row.id]);
}
// 删除数据
function deleteData(id: number) {
const index = getData().findIndex((item) => item.id === id);
gridApi.remove(index);
}
// 清空已选
function clearData() {
gridApi.clear();
}
function getData() {
return gridApi.getData();
}
defineExpose({
getData,
handleAdd,
handleDelete,
clearData,
deleteData,
});
</script>
<template>
<Grid>
<template #card-extra="{ row }">
<Button type="link" size="small" danger @click.stop="handleDelete(row)">删除</Button>
</template>
</Grid>
</template>
<style scoped lang="scss"></style>