feat: refine admin forms, attendance and finance workflows

Squash merge PR #23.

Included changes:
- complete occupancy check-in required fields/default payload
- improve responsive admin management pages
- fix attendance edge cases and attendance period config
- refine wallet/finance-related workflow handling

Checks:
- npm run typecheck -w apps/admin
- npm run typecheck -w apps/server
This commit is contained in:
2026-07-18 12:54:10 +00:00
parent 92d303ed01
commit 375c7ec60b
64 changed files with 5169 additions and 2404 deletions

View File

@@ -15,7 +15,13 @@ import {
Tooltip,
Empty,
} from 'antd';
import { PlusOutlined, UploadOutlined, FileTextOutlined, StopOutlined, CheckOutlined } from '@ant-design/icons';
import {
PlusOutlined,
UploadOutlined,
FileTextOutlined,
StopOutlined,
CheckOutlined,
} from '@ant-design/icons';
import dayjs, { Dayjs } from 'dayjs';
import api from '../../api';
import { downloadBlob } from '../../utils/download';
@@ -392,17 +398,36 @@ const ClassroomRentalsPage: React.FC = () => {
<Space>
{record.effectiveStatus === 'active' && (
<>
<PermissionButton permission="rental:edit" size="small" onClick={() => openEdit(record)}>
<PermissionButton
permission="rental:edit"
size="small"
onClick={() => openEdit(record)}
>
</PermissionButton>
<Popconfirm title="确定取消该租赁?" onConfirm={() => handleRentalAction(record.id, 'cancel')}>
<PermissionButton permission="rental:edit" size="small" danger icon={<StopOutlined />}>
<Popconfirm
title="确定取消该租赁?"
onConfirm={() => handleRentalAction(record.id, 'cancel')}
>
<PermissionButton
permission="rental:edit"
size="small"
danger
icon={<StopOutlined />}
>
</PermissionButton>
</Popconfirm>
{!dayjs(record.startDate).isAfter(dayjs(), 'day') && (
<Popconfirm title="确定今天结束该租赁?" onConfirm={() => handleRentalAction(record.id, 'end')}>
<PermissionButton permission="rental:edit" size="small" icon={<CheckOutlined />}>
<Popconfirm
title="确定今天结束该租赁?"
onConfirm={() => handleRentalAction(record.id, 'end')}
>
<PermissionButton
permission="rental:edit"
size="small"
icon={<CheckOutlined />}
>
</PermissionButton>
</Popconfirm>
@@ -410,8 +435,13 @@ const ClassroomRentalsPage: React.FC = () => {
</>
)}
{record.effectiveStatus !== 'active' && (
<Popconfirm title="确定归档该租赁订单?合同文件会保留。" onConfirm={() => handleDelete(record.id)}>
<PermissionButton permission="rental:delete" size="small" danger></PermissionButton>
<Popconfirm
title="确定归档该租赁订单?合同文件会保留。"
onConfirm={() => handleDelete(record.id)}
>
<PermissionButton permission="rental:delete" size="small" danger>
</PermissionButton>
</Popconfirm>
)}
</Space>
@@ -511,10 +541,12 @@ const ClassroomRentalsPage: React.FC = () => {
optionFilterProp="label"
placeholder="选择教室"
onChange={handleClassroomChange}
options={classrooms.filter((c) => c.status === 'available').map((c) => ({
value: c.id,
label: `${c.building ? c.building + ' · ' : ''}${c.name}${c.roomType}`,
}))}
options={classrooms
.filter((c) => c.status === 'available')
.map((c) => ({
value: c.id,
label: `${c.building ? c.building + ' · ' : ''}${c.name}${c.roomType}`,
}))}
/>
</Form.Item>
<Form.Item name="lessorOrganizationId" label="出租机构" tooltip="默认由本机构出租">
@@ -559,10 +591,10 @@ const ClassroomRentalsPage: React.FC = () => {
/>
</Form.Item>
<Form.Item name="dailyRate" label="日租金(可选)">
<InputNumber min={0} precision={2} style={{ width: '100%' }} prefix="¥" />
<InputNumber min={0.01} precision={2} style={{ width: '100%' }} prefix="¥" />
</Form.Item>
<Form.Item name="totalAmount" label="合同总额(可选)">
<InputNumber min={0} precision={2} style={{ width: '100%' }} prefix="¥" />
<InputNumber min={0.01} precision={2} style={{ width: '100%' }} prefix="¥" />
</Form.Item>
<Form.Item name="notes" label="备注">
<Input.TextArea rows={2} />