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:
69
apps/admin/src/components/NextStepHint.tsx
Normal file
69
apps/admin/src/components/NextStepHint.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Button, Card, Flex, Typography } from 'antd';
|
||||
import { CloseOutlined, RightOutlined, StepForwardOutlined } from '@ant-design/icons';
|
||||
|
||||
export interface NextStepHintProps {
|
||||
/** 提示标题,如「下一步:分班」 */
|
||||
title: string;
|
||||
/** 补充说明 */
|
||||
description?: string;
|
||||
/** 主操作按钮(跳转到下一步) */
|
||||
action?: { label: string; onClick: () => void };
|
||||
/** 是否可关闭,默认 true */
|
||||
closable?: boolean;
|
||||
/** 关闭回调 */
|
||||
onClose?: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* 「下一步」引导卡片:在操作成功后或空状态下提示用户业务闭环的下一步,
|
||||
* 让用户始终知道接下来该做什么。
|
||||
*/
|
||||
export const NextStepHint: React.FC<NextStepHintProps> = ({
|
||||
title,
|
||||
description,
|
||||
action,
|
||||
closable = true,
|
||||
onClose,
|
||||
}) => {
|
||||
const [dismissed, setDismissed] = useState(false);
|
||||
if (dismissed) return null;
|
||||
|
||||
return (
|
||||
<Card
|
||||
size="small"
|
||||
className="next-step-hint"
|
||||
style={{ marginBottom: 16, borderColor: '#b7d4ff', background: '#f0f7ff' }}
|
||||
styles={{ body: { padding: '10px 16px' } }}
|
||||
>
|
||||
<Flex align="center" justify="space-between" gap={8} wrap>
|
||||
<Flex align="center" gap={8} wrap>
|
||||
<StepForwardOutlined style={{ color: '#1677ff' }} />
|
||||
<Typography.Text strong>{title}</Typography.Text>
|
||||
{description ? <Typography.Text type="secondary">{description}</Typography.Text> : null}
|
||||
</Flex>
|
||||
<Flex gap={4} align="center">
|
||||
{action ? (
|
||||
<Button type="primary" size="small" onClick={action.onClick}>
|
||||
{action.label} <RightOutlined />
|
||||
</Button>
|
||||
) : null}
|
||||
{closable ? (
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<CloseOutlined />}
|
||||
aria-label="关闭提示"
|
||||
onClick={() => {
|
||||
setDismissed(true);
|
||||
onClose?.();
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default NextStepHint;
|
||||
Reference in New Issue
Block a user