forked from wangziqi/gongxue-base
chore: commit oxfmt formatting changes and verify artifacts
This commit is contained in:
@@ -1,6 +1,25 @@
|
||||
import React, { useEffect, useState, useMemo } from 'react';
|
||||
import { Table, Button, Modal, Form, DatePicker, Space, message, Tag, Descriptions, Popconfirm, Input, Select, Tooltip } from 'antd';
|
||||
import { FileTextOutlined, DeleteOutlined, DownloadOutlined, FilePdfOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
Table,
|
||||
Button,
|
||||
Modal,
|
||||
Form,
|
||||
DatePicker,
|
||||
Space,
|
||||
message,
|
||||
Tag,
|
||||
Descriptions,
|
||||
Popconfirm,
|
||||
Input,
|
||||
Select,
|
||||
Tooltip,
|
||||
} from 'antd';
|
||||
import {
|
||||
FileTextOutlined,
|
||||
DeleteOutlined,
|
||||
DownloadOutlined,
|
||||
FilePdfOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import dayjs from 'dayjs';
|
||||
import api from '../../api';
|
||||
import PermissionButton from '../../components/PermissionButton';
|
||||
@@ -13,7 +32,14 @@ const statusMap: Record<string, { text: string; color: string }> = {
|
||||
paid: { text: '已支付', color: 'green' },
|
||||
};
|
||||
|
||||
const typeMap: Record<string, string> = { water: '水费', electricity: '电费', cleaning: '保洁费', damage: '损坏赔偿', penalty: '罚款', other: '其他' };
|
||||
const typeMap: Record<string, string> = {
|
||||
water: '水费',
|
||||
electricity: '电费',
|
||||
cleaning: '保洁费',
|
||||
damage: '损坏赔偿',
|
||||
penalty: '罚款',
|
||||
other: '其他',
|
||||
};
|
||||
|
||||
const BillsPage: React.FC = () => {
|
||||
const [bills, setBills] = useState<any[]>([]);
|
||||
@@ -30,11 +56,15 @@ const BillsPage: React.FC = () => {
|
||||
try {
|
||||
const res: any = await api.get('/bills');
|
||||
setBills(res);
|
||||
} catch (e) { console.error(e); }
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => { fetchData(); }, []);
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
const filteredBills = useMemo(() => {
|
||||
return bills.filter((b: any) => {
|
||||
@@ -60,14 +90,18 @@ const BillsPage: React.FC = () => {
|
||||
setGenerateModal(false);
|
||||
generateForm.resetFields();
|
||||
fetchData();
|
||||
} catch (e: any) { message.error(e?.message || '生成失败'); }
|
||||
} catch (e: any) {
|
||||
message.error(e?.message || '生成失败');
|
||||
}
|
||||
};
|
||||
|
||||
const showDetail = async (id: number) => {
|
||||
try {
|
||||
const res = await api.get(`/bills/${id}`);
|
||||
setDetailModal(res);
|
||||
} catch (e) { console.error(e); }
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
const updateStatus = async (id: number, status: string) => {
|
||||
@@ -78,7 +112,9 @@ const BillsPage: React.FC = () => {
|
||||
if (detailModal?.id === id) {
|
||||
setDetailModal({ ...detailModal, status });
|
||||
}
|
||||
} catch (e: any) { message.error(e?.message || '操作失败'); }
|
||||
} catch (e: any) {
|
||||
message.error(e?.message || '操作失败');
|
||||
}
|
||||
};
|
||||
|
||||
const batchUpdateStatus = async (status: string) => {
|
||||
@@ -88,7 +124,9 @@ const BillsPage: React.FC = () => {
|
||||
message.success(`已批量更新 ${selectedRows.length} 条账单`);
|
||||
setSelectedRows([]);
|
||||
fetchData();
|
||||
} catch (e: any) { message.error(e?.message || '操作失败'); }
|
||||
} catch (e: any) {
|
||||
message.error(e?.message || '操作失败');
|
||||
}
|
||||
};
|
||||
|
||||
const handleDelete = async (id: number) => {
|
||||
@@ -96,7 +134,9 @@ const BillsPage: React.FC = () => {
|
||||
await api.delete(`/bills/${id}`);
|
||||
message.success('账单已删除');
|
||||
fetchData();
|
||||
} catch (e: any) { message.error(e?.message || '删除失败'); }
|
||||
} catch (e: any) {
|
||||
message.error(e?.message || '删除失败');
|
||||
}
|
||||
};
|
||||
|
||||
const batchDelete = async () => {
|
||||
@@ -106,18 +146,22 @@ const BillsPage: React.FC = () => {
|
||||
message.success(`已删除 ${selectedRows.length} 条账单`);
|
||||
setSelectedRows([]);
|
||||
fetchData();
|
||||
} catch (e: any) { message.error(e?.message || '操作失败'); }
|
||||
} catch (e: any) {
|
||||
message.error(e?.message || '操作失败');
|
||||
}
|
||||
};
|
||||
|
||||
const handleExportExcel = () => {
|
||||
const baseURL = import.meta.env.PROD ? '/api' : `http://localhost:${import.meta.env.VITE_API_PORT || 3002}/api`;
|
||||
const baseURL = import.meta.env.PROD
|
||||
? '/api'
|
||||
: `http://localhost:${import.meta.env.VITE_API_PORT || 3002}/api`;
|
||||
const token = localStorage.getItem('token');
|
||||
const url = `${baseURL}/bills/export/excel`;
|
||||
const a = document.createElement('a');
|
||||
// 使用 fetch 来携带 token
|
||||
fetch(url, { headers: { Authorization: `Bearer ${token}` } })
|
||||
.then(res => res.blob())
|
||||
.then(blob => {
|
||||
.then((res) => res.blob())
|
||||
.then((blob) => {
|
||||
const blobUrl = URL.createObjectURL(blob);
|
||||
a.href = blobUrl;
|
||||
a.download = `账单导出_${dayjs().format('YYYYMMDD_HHmmss')}.xlsx`;
|
||||
@@ -129,11 +173,15 @@ const BillsPage: React.FC = () => {
|
||||
};
|
||||
|
||||
const handleExportPdf = (billId: number) => {
|
||||
const baseURL = import.meta.env.PROD ? '/api' : `http://localhost:${import.meta.env.VITE_API_PORT || 3002}/api`;
|
||||
const baseURL = import.meta.env.PROD
|
||||
? '/api'
|
||||
: `http://localhost:${import.meta.env.VITE_API_PORT || 3002}/api`;
|
||||
const token = localStorage.getItem('token');
|
||||
fetch(`${baseURL}/bills/export/pdf/${billId}`, { headers: { Authorization: `Bearer ${token}` } })
|
||||
.then(res => res.blob())
|
||||
.then(blob => {
|
||||
fetch(`${baseURL}/bills/export/pdf/${billId}`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
})
|
||||
.then((res) => res.blob())
|
||||
.then((blob) => {
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
@@ -147,15 +195,30 @@ const BillsPage: React.FC = () => {
|
||||
const columns = [
|
||||
{ title: '学生', render: (_: any, r: any) => r.student?.name || '-' },
|
||||
{ title: '账单周期', render: (_: any, r: any) => `${r.periodStart} ~ ${r.periodEnd}` },
|
||||
{ title: '分摊费用', dataIndex: 'sharedAmount', render: (v: number) => `¥${Number(v).toFixed(2)}` },
|
||||
{ title: '个人费用', dataIndex: 'personalAmount', render: (v: number) => `¥${Number(v).toFixed(2)}` },
|
||||
{ title: '总计', dataIndex: 'totalAmount', render: (v: number) => <strong>¥{Number(v).toFixed(2)}</strong> },
|
||||
{
|
||||
title: '分摊费用',
|
||||
dataIndex: 'sharedAmount',
|
||||
render: (v: number) => `¥${Number(v).toFixed(2)}`,
|
||||
},
|
||||
{
|
||||
title: '个人费用',
|
||||
dataIndex: 'personalAmount',
|
||||
render: (v: number) => `¥${Number(v).toFixed(2)}`,
|
||||
},
|
||||
{
|
||||
title: '总计',
|
||||
dataIndex: 'totalAmount',
|
||||
render: (v: number) => <strong>¥{Number(v).toFixed(2)}</strong>,
|
||||
},
|
||||
{
|
||||
title: '可用押金',
|
||||
dataIndex: 'availableDeposit',
|
||||
render: (v: number) => v > 0
|
||||
? <span style={{ color: '#52c41a' }}>¥{Number(v).toFixed(2)}</span>
|
||||
: <span style={{ color: '#999' }}>-</span>,
|
||||
render: (v: number) =>
|
||||
v > 0 ? (
|
||||
<span style={{ color: '#52c41a' }}>¥{Number(v).toFixed(2)}</span>
|
||||
) : (
|
||||
<span style={{ color: '#999' }}>-</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '抵扣后应付',
|
||||
@@ -173,21 +236,65 @@ const BillsPage: React.FC = () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '状态', dataIndex: 'status',
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
render: (s: string) => <Tag color={statusMap[s]?.color}>{statusMap[s]?.text}</Tag>,
|
||||
},
|
||||
{ title: '生成时间', dataIndex: 'generatedAt', render: (v: string) => dayjs(v).format('YYYY-MM-DD HH:mm') },
|
||||
{
|
||||
title: '操作', width: 320,
|
||||
title: '生成时间',
|
||||
dataIndex: 'generatedAt',
|
||||
render: (v: string) => dayjs(v).format('YYYY-MM-DD HH:mm'),
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
width: 320,
|
||||
render: (_: any, record: any) => (
|
||||
<Space>
|
||||
<PermissionButton permission="bill:view" size="small" type="link" onClick={() => showDetail(record.id)}>详情</PermissionButton>
|
||||
{record.status === 'draft' && <PermissionButton permission="bill:confirm" size="small" onClick={() => updateStatus(record.id, 'confirmed')}>确认</PermissionButton>}
|
||||
{record.status === 'confirmed' && <PermissionButton permission="bill:confirm" size="small" type="primary" onClick={() => updateStatus(record.id, 'paid')}>标记已付</PermissionButton>}
|
||||
<PermissionButton permission="bill:export-pdf" size="small" icon={<FilePdfOutlined />} onClick={() => handleExportPdf(record.id)}>PDF</PermissionButton>
|
||||
<PermissionButton
|
||||
permission="bill:view"
|
||||
size="small"
|
||||
type="link"
|
||||
onClick={() => showDetail(record.id)}
|
||||
>
|
||||
详情
|
||||
</PermissionButton>
|
||||
{record.status === 'draft' && (
|
||||
<PermissionButton
|
||||
permission="bill:confirm"
|
||||
size="small"
|
||||
onClick={() => updateStatus(record.id, 'confirmed')}
|
||||
>
|
||||
确认
|
||||
</PermissionButton>
|
||||
)}
|
||||
{record.status === 'confirmed' && (
|
||||
<PermissionButton
|
||||
permission="bill:confirm"
|
||||
size="small"
|
||||
type="primary"
|
||||
onClick={() => updateStatus(record.id, 'paid')}
|
||||
>
|
||||
标记已付
|
||||
</PermissionButton>
|
||||
)}
|
||||
<PermissionButton
|
||||
permission="bill:export-pdf"
|
||||
size="small"
|
||||
icon={<FilePdfOutlined />}
|
||||
onClick={() => handleExportPdf(record.id)}
|
||||
>
|
||||
PDF
|
||||
</PermissionButton>
|
||||
<PermissionButton permission="bill:delete">
|
||||
<Popconfirm title="确定删除此账单?" onConfirm={() => handleDelete(record.id)} okText="删除" cancelText="取消">
|
||||
<Button size="small" danger icon={<DeleteOutlined />}>删除</Button>
|
||||
<Popconfirm
|
||||
title="确定删除此账单?"
|
||||
onConfirm={() => handleDelete(record.id)}
|
||||
okText="删除"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Button size="small" danger icon={<DeleteOutlined />}>
|
||||
删除
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
</PermissionButton>
|
||||
</Space>
|
||||
@@ -197,40 +304,85 @@ const BillsPage: React.FC = () => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={{ marginBottom: 16, display: 'flex', justifyContent: 'space-between', flexWrap: 'wrap', gap: 8 }}>
|
||||
<div
|
||||
style={{
|
||||
marginBottom: 16,
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
flexWrap: 'wrap',
|
||||
gap: 8,
|
||||
}}
|
||||
>
|
||||
<Space wrap>
|
||||
<Input.Search
|
||||
placeholder="搜索学生姓名或账单周期"
|
||||
allowClear
|
||||
style={{ width: 220 }}
|
||||
onSearch={v => setSearchText(v)}
|
||||
onChange={e => { if (!e.target.value) setSearchText(''); }}
|
||||
onSearch={(v) => setSearchText(v)}
|
||||
onChange={(e) => {
|
||||
if (!e.target.value) setSearchText('');
|
||||
}}
|
||||
/>
|
||||
<Select
|
||||
placeholder="状态筛选"
|
||||
allowClear
|
||||
style={{ width: 120 }}
|
||||
value={filterStatus}
|
||||
onChange={v => setFilterStatus(v)}
|
||||
onChange={(v) => setFilterStatus(v)}
|
||||
options={[
|
||||
{ value: 'draft', label: '草稿' },
|
||||
{ value: 'confirmed', label: '已确认' },
|
||||
{ value: 'paid', label: '已支付' },
|
||||
]}
|
||||
/>
|
||||
<PermissionButton permission="bill:confirm" onClick={() => batchUpdateStatus('confirmed')} disabled={selectedRows.length === 0}>批量确认</PermissionButton>
|
||||
<PermissionButton permission="bill:confirm" type="primary" onClick={() => batchUpdateStatus('paid')} disabled={selectedRows.length === 0}>批量标记已付</PermissionButton>
|
||||
<PermissionButton
|
||||
permission="bill:confirm"
|
||||
onClick={() => batchUpdateStatus('confirmed')}
|
||||
disabled={selectedRows.length === 0}
|
||||
>
|
||||
批量确认
|
||||
</PermissionButton>
|
||||
<PermissionButton
|
||||
permission="bill:confirm"
|
||||
type="primary"
|
||||
onClick={() => batchUpdateStatus('paid')}
|
||||
disabled={selectedRows.length === 0}
|
||||
>
|
||||
批量标记已付
|
||||
</PermissionButton>
|
||||
<PermissionButton permission="bill:delete">
|
||||
<Popconfirm title={`确定删除选中的 ${selectedRows.length} 条账单?`} onConfirm={batchDelete} okText="删除" cancelText="取消" disabled={selectedRows.length === 0}>
|
||||
<Button danger disabled={selectedRows.length === 0} icon={<DeleteOutlined />}>批量删除</Button>
|
||||
<Popconfirm
|
||||
title={`确定删除选中的 ${selectedRows.length} 条账单?`}
|
||||
onConfirm={batchDelete}
|
||||
okText="删除"
|
||||
cancelText="取消"
|
||||
disabled={selectedRows.length === 0}
|
||||
>
|
||||
<Button danger disabled={selectedRows.length === 0} icon={<DeleteOutlined />}>
|
||||
批量删除
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
</PermissionButton>
|
||||
</Space>
|
||||
<Space>
|
||||
<PermissionButton permission="bill:generate" type="primary" icon={<FileTextOutlined />} onClick={() => { generateForm.resetFields(); setGenerateModal(true); }}>
|
||||
<PermissionButton
|
||||
permission="bill:generate"
|
||||
type="primary"
|
||||
icon={<FileTextOutlined />}
|
||||
onClick={() => {
|
||||
generateForm.resetFields();
|
||||
setGenerateModal(true);
|
||||
}}
|
||||
>
|
||||
生成账单
|
||||
</PermissionButton>
|
||||
<PermissionButton permission="bill:export-excel" icon={<DownloadOutlined />} onClick={handleExportExcel}>导出Excel</PermissionButton>
|
||||
<PermissionButton
|
||||
permission="bill:export-excel"
|
||||
icon={<DownloadOutlined />}
|
||||
onClick={handleExportExcel}
|
||||
>
|
||||
导出Excel
|
||||
</PermissionButton>
|
||||
</Space>
|
||||
</div>
|
||||
<Table
|
||||
@@ -245,10 +397,25 @@ const BillsPage: React.FC = () => {
|
||||
}}
|
||||
/>
|
||||
|
||||
<Modal title="生成账单" open={generateModal} onOk={handleGenerate} onCancel={() => setGenerateModal(false)} okText="生成">
|
||||
<Modal
|
||||
title="生成账单"
|
||||
open={generateModal}
|
||||
onOk={handleGenerate}
|
||||
onCancel={() => setGenerateModal(false)}
|
||||
okText="生成"
|
||||
>
|
||||
<Form form={generateForm} layout="vertical">
|
||||
<Form.Item name="period" label="账单周期" rules={[{ required: true, message: '请选择账单周期' }]} extra="选择费用对应的时间段,系统将自动计算每个学生的分摊费用">
|
||||
<RangePicker style={{ width: '100%' }} placeholder={['开始日期', '结束日期']} format="YYYY-MM-DD" />
|
||||
<Form.Item
|
||||
name="period"
|
||||
label="账单周期"
|
||||
rules={[{ required: true, message: '请选择账单周期' }]}
|
||||
extra="选择费用对应的时间段,系统将自动计算每个学生的分摊费用"
|
||||
>
|
||||
<RangePicker
|
||||
style={{ width: '100%' }}
|
||||
placeholder={['开始日期', '结束日期']}
|
||||
format="YYYY-MM-DD"
|
||||
/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
@@ -264,20 +431,62 @@ const BillsPage: React.FC = () => {
|
||||
<>
|
||||
<Descriptions bordered size="small" column={2} style={{ marginBottom: 16 }}>
|
||||
<Descriptions.Item label="学生">{detailModal.student?.name}</Descriptions.Item>
|
||||
<Descriptions.Item label="状态"><Tag color={statusMap[detailModal.status]?.color}>{statusMap[detailModal.status]?.text}</Tag></Descriptions.Item>
|
||||
<Descriptions.Item label="账单周期">{detailModal.periodStart} ~ {detailModal.periodEnd}</Descriptions.Item>
|
||||
<Descriptions.Item label="生成时间">{dayjs(detailModal.generatedAt).format('YYYY-MM-DD HH:mm')}</Descriptions.Item>
|
||||
<Descriptions.Item label="分摊费用">¥{Number(detailModal.sharedAmount).toFixed(2)}</Descriptions.Item>
|
||||
<Descriptions.Item label="个人费用">¥{Number(detailModal.personalAmount).toFixed(2)}</Descriptions.Item>
|
||||
<Descriptions.Item label="合计" span={2}><strong style={{ fontSize: 18, color: '#007AFF' }}>¥{Number(detailModal.totalAmount).toFixed(2)}</strong></Descriptions.Item>
|
||||
<Descriptions.Item label="状态">
|
||||
<Tag color={statusMap[detailModal.status]?.color}>
|
||||
{statusMap[detailModal.status]?.text}
|
||||
</Tag>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="账单周期">
|
||||
{detailModal.periodStart} ~ {detailModal.periodEnd}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="生成时间">
|
||||
{dayjs(detailModal.generatedAt).format('YYYY-MM-DD HH:mm')}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="分摊费用">
|
||||
¥{Number(detailModal.sharedAmount).toFixed(2)}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="个人费用">
|
||||
¥{Number(detailModal.personalAmount).toFixed(2)}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="合计" span={2}>
|
||||
<strong style={{ fontSize: 18, color: '#007AFF' }}>
|
||||
¥{Number(detailModal.totalAmount).toFixed(2)}
|
||||
</strong>
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
{Number(detailModal.availableDeposit || 0) > 0 && (
|
||||
<div style={{ marginBottom: 16, padding: 12, background: '#f6ffed', border: '1px solid #b7eb8f', borderRadius: 8 }}>
|
||||
<div style={{ fontSize: 13, color: '#666', marginBottom: 6 }}>押金联动(不影响实际押金状态,仅作收款参考)</div>
|
||||
<div
|
||||
style={{
|
||||
marginBottom: 16,
|
||||
padding: 12,
|
||||
background: '#f6ffed',
|
||||
border: '1px solid #b7eb8f',
|
||||
borderRadius: 8,
|
||||
}}
|
||||
>
|
||||
<div style={{ fontSize: 13, color: '#666', marginBottom: 6 }}>
|
||||
押金联动(不影响实际押金状态,仅作收款参考)
|
||||
</div>
|
||||
<Space size={24} wrap>
|
||||
<span>当前可用押金:<strong style={{ color: '#52c41a' }}>¥{Number(detailModal.availableDeposit).toFixed(2)}</strong></span>
|
||||
<span>本账单可抵扣:<strong style={{ color: '#fa8c16' }}>-¥{Number(detailModal.depositApplied || 0).toFixed(2)}</strong></span>
|
||||
<span>抵扣后实付:<strong style={{ color: '#fa541c', fontSize: 16 }}>¥{Number(detailModal.amountAfterDeposit ?? detailModal.totalAmount).toFixed(2)}</strong></span>
|
||||
<span>
|
||||
当前可用押金:
|
||||
<strong style={{ color: '#52c41a' }}>
|
||||
¥{Number(detailModal.availableDeposit).toFixed(2)}
|
||||
</strong>
|
||||
</span>
|
||||
<span>
|
||||
本账单可抵扣:
|
||||
<strong style={{ color: '#fa8c16' }}>
|
||||
-¥{Number(detailModal.depositApplied || 0).toFixed(2)}
|
||||
</strong>
|
||||
</span>
|
||||
<span>
|
||||
抵扣后实付:
|
||||
<strong style={{ color: '#fa541c', fontSize: 16 }}>
|
||||
¥
|
||||
{Number(detailModal.amountAfterDeposit ?? detailModal.totalAmount).toFixed(2)}
|
||||
</strong>
|
||||
</span>
|
||||
</Space>
|
||||
</div>
|
||||
)}
|
||||
@@ -290,10 +499,26 @@ const BillsPage: React.FC = () => {
|
||||
columns={[
|
||||
{ title: '类型', dataIndex: 'expenseType', render: (v: string) => typeMap[v] || v },
|
||||
{ title: '说明', dataIndex: 'description' },
|
||||
{ title: '计费天数', dataIndex: 'days', render: (v: number) => v > 0 ? `${v}天` : '-' },
|
||||
{ title: '宿舍总人天', dataIndex: 'totalRoomDays', render: (v: number) => v > 0 ? `${v}天` : '-' },
|
||||
{ title: '宿舍总费用', dataIndex: 'roomTotalAmount', render: (v: number) => `¥${Number(v).toFixed(2)}` },
|
||||
{ title: '应分摊', dataIndex: 'studentAmount', render: (v: number) => <strong>¥{Number(v).toFixed(2)}</strong> },
|
||||
{
|
||||
title: '计费天数',
|
||||
dataIndex: 'days',
|
||||
render: (v: number) => (v > 0 ? `${v}天` : '-'),
|
||||
},
|
||||
{
|
||||
title: '宿舍总人天',
|
||||
dataIndex: 'totalRoomDays',
|
||||
render: (v: number) => (v > 0 ? `${v}天` : '-'),
|
||||
},
|
||||
{
|
||||
title: '宿舍总费用',
|
||||
dataIndex: 'roomTotalAmount',
|
||||
render: (v: number) => `¥${Number(v).toFixed(2)}`,
|
||||
},
|
||||
{
|
||||
title: '应分摊',
|
||||
dataIndex: 'studentAmount',
|
||||
render: (v: number) => <strong>¥{Number(v).toFixed(2)}</strong>,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user