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

@@ -60,7 +60,7 @@ const NotificationsPage: React.FC = () => {
const fetchData = async () => {
setLoading(true);
try {
const data = await api.get('/notifications?limit=50') as unknown as NotificationItem[];
const data = (await api.get('/notifications?limit=50')) as unknown as NotificationItem[];
setNotifications(data);
} catch (e: any) {
console.error('加载通知失败', e);
@@ -91,18 +91,15 @@ const NotificationsPage: React.FC = () => {
const handleMarkAll = async () => {
try {
await api.put('/notifications/read-all');
setNotifications((prev) =>
prev.map((n) => ({ ...n, isRead: true })),
);
setNotifications((prev) => prev.map((n) => ({ ...n, isRead: true })));
} catch (e: any) {
console.error('全部已读失败', e);
message.error(e?.message || '操作失败');
}
};
const filtered = filter === 'all'
? notifications
: notifications.filter((n) => n.type === filter);
const filtered =
filter === 'all' ? notifications : notifications.filter((n) => n.type === filter);
const filterItems = [
{ key: 'all', icon: <BellOutlined />, label: '全部' },
@@ -126,7 +123,9 @@ const NotificationsPage: React.FC = () => {
)}
<Content className="notifications-content" style={{ padding: isMobile ? 0 : 24 }}>
<div className="notifications-header">
<Typography.Title level={4} style={{ margin: 0 }}></Typography.Title>
<Typography.Title level={4} style={{ margin: 0 }}>
</Typography.Title>
<Button onClick={handleMarkAll}></Button>
</div>
{isMobile && (
@@ -181,10 +180,7 @@ const NotificationsPage: React.FC = () => {
}
title={
<Space wrap size={[8, 2]}>
<Typography.Text
strong={!item.isRead}
style={{ fontSize: 15 }}
>
<Typography.Text strong={!item.isRead} style={{ fontSize: 15 }}>
{formatNotificationText(item.title)}
</Typography.Text>
<Typography.Text type="secondary" style={{ fontSize: 12 }}>