feat(admin): 用户体验体系化提升与高危缺陷修复
UX 缺陷修复: - 校验失败不再卡死弹窗按钮(Users/Roles/Bills) - 押金收取/批量收取/添加分期防重复提交;切换房型重置勾选 - AI 表单/批量确认不再出现"假成功" - Dashboard 各数据模块独立加载,单接口失败不再整页清零 - 房间可视化加载失败显示错误态而非永久转圈 - 学生编辑表单回填前重置,避免字段残留污染 - 覆盖式导入增加二次确认;恢复默认考勤时段确认并同步表单 - 金数据匹配关闭前确认,同步中禁止误关 体验提升: - 新增统一 QueryErrorState/QueryEmpty,20+ 页面加载失败显示错误态与重试 - 全局 ErrorBoundary + RouteKeeper 逐页兜底 - 新增 usePageVisible/useVisibleRefetch,保活页面切回自动刷新数据 - 新增首次登录角色引导 RoleTour 与业务闭环 NextStepHint 引导卡 - 重构 A2UI:useSubmissionState/useXCardSurface 收敛状态与命令生命周期, ArtifactErrorBoundary 渲染降级,图表空数据占位 - AI 助手欢迎语与建议话术按角色定制,会话列表空态引导 - 更新 a2ui-contract.md 契约文档说明实现现状
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useImmer } from 'use-immer';
|
||||
import { Button, Form, Input, Modal, Select, Spin, Steps, Typography } from 'antd';
|
||||
import { App, Button, Form, Input, Modal, Select, Spin, Steps, Typography } from 'antd';
|
||||
import { CloudUploadOutlined, EditOutlined, PlusOutlined, SearchOutlined } from '@ant-design/icons';
|
||||
import api from '../api';
|
||||
import { message } from '../ui/app-message';
|
||||
@@ -30,6 +30,7 @@ interface MatchModalProps {
|
||||
}
|
||||
|
||||
const JinshujuMatchModal: React.FC<MatchModalProps> = ({ open, onClose, onApplied }) => {
|
||||
const { modal } = App.useApp();
|
||||
const { hasPermission, hasAllPermissions, permissionsReady } = usePermission();
|
||||
const canTriggerSync = hasPermission('sync:trigger');
|
||||
const canEnterModal = permissionsReady && hasAllPermissions('sync:read', 'sync:trigger');
|
||||
@@ -168,6 +169,22 @@ const JinshujuMatchModal: React.FC<MatchModalProps> = ({ open, onClose, onApplie
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
// 已进入匹配步骤且存在待处理数据时,关闭会丢失全部决策,需先确认
|
||||
const hasPendingWork = step === 'match' && (entries.length > 0 || decisions.size > 0);
|
||||
if (hasPendingWork) {
|
||||
modal.confirm({
|
||||
title: '放弃当前匹配?',
|
||||
content: '已确认的匹配决策将全部丢失,且不会写入系统。',
|
||||
okText: '放弃',
|
||||
okButtonProps: { danger: true },
|
||||
cancelText: '继续匹配',
|
||||
onOk: () => {
|
||||
reset();
|
||||
onClose();
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
reset();
|
||||
onClose();
|
||||
};
|
||||
@@ -330,6 +347,7 @@ const JinshujuMatchModal: React.FC<MatchModalProps> = ({ open, onClose, onApplie
|
||||
onCancel={handleClose}
|
||||
width={step === 'match' || step === 'applying' ? 900 : 640}
|
||||
mask={{ closable: false }}
|
||||
closable={step !== 'applying'}
|
||||
footer={
|
||||
step === 'connection'
|
||||
? [
|
||||
@@ -380,7 +398,12 @@ const JinshujuMatchModal: React.FC<MatchModalProps> = ({ open, onClose, onApplie
|
||||
{step === 'rule' ? renderRuleStep() : null}
|
||||
{step === 'match' ? renderMatchStep() : null}
|
||||
{step === 'applying' ? (
|
||||
<Spin description="正在同步..." style={{ display: 'block', margin: '48px auto' }} />
|
||||
<>
|
||||
<Spin description="正在同步,请勿关闭窗口..." style={{ display: 'block', margin: '48px auto' }} />
|
||||
<Typography.Text type="secondary" style={{ display: 'block', textAlign: 'center' }}>
|
||||
数据正在写入,关闭窗口不会中断同步
|
||||
</Typography.Text>
|
||||
</>
|
||||
) : null}
|
||||
</Modal>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user