界面优化

dev_na
puz 2026-06-26 14:04:24 +08:00
parent 77fe6d4e77
commit bf40b13383
2 changed files with 58 additions and 53 deletions

View File

@ -138,6 +138,7 @@ export default function Users() {
const [filterTenantId, setFilterTenantId] = useState<number | undefined>(undefined); const [filterTenantId, setFilterTenantId] = useState<number | undefined>(undefined);
const [drawerOpen, setDrawerOpen] = useState(false); const [drawerOpen, setDrawerOpen] = useState(false);
const [editing, setEditing] = useState<SysUser | null>(null); const [editing, setEditing] = useState<SysUser | null>(null);
const [roleSelectOpen, setRoleSelectOpen] = useState(false);
const [form] = Form.useForm(); const [form] = Form.useForm();
const [resetPasswordOpen, setResetPasswordOpen] = useState(false); const [resetPasswordOpen, setResetPasswordOpen] = useState(false);
const [resetPasswordLoading, setResetPasswordLoading] = useState(false); const [resetPasswordLoading, setResetPasswordLoading] = useState(false);
@ -264,6 +265,7 @@ export default function Users() {
const openCreate = () => { const openCreate = () => {
setEditing(null); setEditing(null);
setRoleSelectOpen(false);
form.resetFields(); form.resetFields();
form.setFieldsValue({ form.setFieldsValue({
status: 1, status: 1,
@ -277,6 +279,7 @@ export default function Users() {
const openEdit = async (record: SysUser) => { const openEdit = async (record: SysUser) => {
setEditing(record); setEditing(record);
setRoleSelectOpen(false);
try { try {
const detail = await getUserDetail(record.userId); const detail = await getUserDetail(record.userId);
const roleIds = await listUserRoles(record.userId); const roleIds = await listUserRoles(record.userId);
@ -594,10 +597,13 @@ export default function Users() {
</Form.Item> </Form.Item>
) : null} ) : null}
<Form.Item label={t("users.roles")} name="roleIds" <Form.Item label={t("users.roles")} name="roleIds"
rules={[{required: true, message: t("users.roles")}]}><Select mode="multiple" rules={[{required: true, message: t("users.roles")}]}><Select mode="multiple"
placeholder={t("users.roles")} placeholder={t("users.roles")}
options={roleOptions} options={roleOptions}
optionFilterProp={isPlatformMode ? "searchText" : "label"}/></Form.Item> open={roleSelectOpen}
onDropdownVisibleChange={setRoleSelectOpen}
onChange={() => setRoleSelectOpen(false)}
optionFilterProp={isPlatformMode ? "searchText" : "label"}/></Form.Item>
{!isPlatformMode && <Form.Item label={t("users.orgNode")} name="orgId"><TreeSelect {!isPlatformMode && <Form.Item label={t("users.orgNode")} name="orgId"><TreeSelect
placeholder={t("usersExt.selectOrgPlaceholder")} allowClear treeData={orgTreeData}/></Form.Item>} placeholder={t("usersExt.selectOrgPlaceholder")} allowClear treeData={orgTreeData}/></Form.Item>}
<Row gutter={16}> <Row gutter={16}>

View File

@ -10,7 +10,6 @@
InfoCircleOutlined, InfoCircleOutlined,
PauseCircleOutlined, PauseCircleOutlined,
PlusOutlined, PlusOutlined,
RightOutlined,
SearchOutlined, SearchOutlined,
SettingOutlined, SettingOutlined,
SyncOutlined, SyncOutlined,
@ -136,6 +135,9 @@ const shouldPollMeetingCard = (item: MeetingVO) =>
const getUnifiedStatusCode = (progress: MeetingProgress | null | undefined) => const getUnifiedStatusCode = (progress: MeetingProgress | null | undefined) =>
progress?.unifiedStatus?.statusCode; progress?.unifiedStatus?.statusCode;
const isWaitingUploadProgress = (progress: MeetingProgress | null | undefined) =>
getUnifiedStatusCode(progress) === "WAITING_UPLOAD";
const getEffectiveStatus = (item: MeetingVO, progress: MeetingProgress | null) => { const getEffectiveStatus = (item: MeetingVO, progress: MeetingProgress | null) => {
const unifiedStatusCode = getUnifiedStatusCode(progress); const unifiedStatusCode = getUnifiedStatusCode(progress);
if (unifiedStatusCode === "WAITING_UPLOAD") { if (unifiedStatusCode === "WAITING_UPLOAD") {
@ -285,12 +287,17 @@ const MeetingCardItem: React.FC<{
}> = ({ item, config, progress, onOpenMeeting, onRetrySchedule, onDelete, retrying }) => { }> = ({ item, config, progress, onOpenMeeting, onRetrySchedule, onDelete, retrying }) => {
const effectiveStatus = getEffectiveStatus(item, progress); const effectiveStatus = getEffectiveStatus(item, progress);
const isProcessing = shouldTrackGenerationProgress(item); const isProcessing = shouldTrackGenerationProgress(item);
const isWaitingUpload = isWaitingUploadProgress(progress) || effectiveStatus === 8;
const isPaused = effectiveStatus === PAUSED_DISPLAY_STATUS; const isPaused = effectiveStatus === PAUSED_DISPLAY_STATUS;
const isRealtimeActive = effectiveStatus === REALTIME_ACTIVE_DISPLAY_STATUS; const isRealtimeActive = effectiveStatus === REALTIME_ACTIVE_DISPLAY_STATUS;
const isRealtimeIdle = effectiveStatus === REALTIME_IDLE_DISPLAY_STATUS; const isRealtimeIdle = effectiveStatus === REALTIME_IDLE_DISPLAY_STATUS;
const isCrossPlatformRealtime = (isPaused || isRealtimeActive || isRealtimeIdle) && !canControlRealtimeFromCurrentPlatform(item); const isCrossPlatformRealtime = (isPaused || isRealtimeActive || isRealtimeIdle) && !canControlRealtimeFromCurrentPlatform(item);
const crossPlatformHint = `${getRealtimeSourceLabel(item)} 继续`; const crossPlatformHint = `${getRealtimeSourceLabel(item)} 继续`;
const canRetry = canRetryQueuedMeeting(item, progress); const canRetry = canRetryQueuedMeeting(item, progress);
const ownerName = item.creatorName || "未知";
const processingMessage = isWaitingUpload
? (progress?.message || progress?.unifiedStatus?.message || config.text)
: (progress?.unifiedStatus?.message || progress?.message || "深度分析中...");
const sourceColor = item.meetingSource === "ANDROID" ? "#10b981" : "#3b82f6"; const sourceColor = item.meetingSource === "ANDROID" ? "#10b981" : "#3b82f6";
@ -375,26 +382,28 @@ const MeetingCardItem: React.FC<{
fontSize: "12px" fontSize: "12px"
}} }}
> >
<div style={{ display: "flex", alignItems: "center", gap: "6px", color: config.color, fontWeight: 600 }}> <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: "10px" }}>
{isProcessing ? <SyncOutlined spin /> : <InfoCircleOutlined />} <div style={{ display: "flex", alignItems: "center", gap: "6px", minWidth: 0, color: config.color, fontWeight: 600 }}>
<span style={{ fontSize: "12px" }}> {isProcessing ? <SyncOutlined spin /> : <InfoCircleOutlined />}
{isProcessing ? (progress?.message || "深度分析中...") : (isCrossPlatformRealtime ? crossPlatformHint : config.text)} <span style={{ fontSize: "12px", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
</span> {isProcessing ? processingMessage : (isCrossPlatformRealtime ? crossPlatformHint : config.text)}
</span>
</div>
{canRetry && (
<Button
type="link"
size="small"
loading={retrying}
onClick={(event) => {
event.stopPropagation();
onRetrySchedule(item);
}}
style={{ paddingInline: 0, height: 18, lineHeight: "18px", flexShrink: 0, fontSize: "12px", fontWeight: 600 }}
>
</Button>
)}
</div> </div>
{canRetry && (
<Button
type="link"
size="small"
loading={retrying}
onClick={(event) => {
event.stopPropagation();
onRetrySchedule(item);
}}
style={{ paddingInline: 0, height: "auto" }}
>
</Button>
)}
</div> </div>
) : ( ) : (
<div style={{ display: "flex", flexWrap: "wrap", gap: "12px", color: "#8c8c8c", fontSize: "12px" }}> <div style={{ display: "flex", flexWrap: "wrap", gap: "12px", color: "#8c8c8c", fontSize: "12px" }}>
@ -402,10 +411,6 @@ const MeetingCardItem: React.FC<{
<CalendarOutlined style={{ fontSize: "13px", opacity: 0.7 }} /> <CalendarOutlined style={{ fontSize: "13px", opacity: 0.7 }} />
<span>{dayjs(item.meetingTime).format("MM-DD HH:mm")}</span> <span>{dayjs(item.meetingTime).format("MM-DD HH:mm")}</span>
</div> </div>
<div style={{ display: "flex", alignItems: "center", gap: "4px" }}>
<UserOutlined style={{ fontSize: "13px", opacity: 0.7 }} />
<span style={{ maxWidth: "80px", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{item.creatorName || "未知"}</span>
</div>
</div> </div>
)} )}
</div> </div>
@ -433,34 +438,30 @@ const MeetingCardItem: React.FC<{
</span> </span>
)) || <span style={{ fontSize: "11px", color: "#bfbfbf" }}></span>} )) || <span style={{ fontSize: "11px", color: "#bfbfbf" }}></span>}
</div> </div>
<div <div
style={{ style={{
height: "28px", height: "28px",
borderRadius: "8px", maxWidth: "112px",
background: "rgba(95, 81, 255, 0.1)",
color: "var(--primary-blue)",
display: "flex",
alignItems: "center",
justifyContent: "center",
transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
padding: "0 10px", padding: "0 10px",
borderRadius: "8px",
background: "rgba(15, 23, 42, 0.04)",
color: "#6b7280",
display: "flex",
alignItems: "center",
justifyContent: "center",
gap: "5px",
overflow: "hidden", overflow: "hidden",
whiteSpace: "nowrap", whiteSpace: "nowrap",
minWidth: "28px" flexShrink: 0,
fontSize: "11px",
fontWeight: 600
}} }}
className="card-arrow" title={`所属用户:${ownerName}`}
> >
<RightOutlined style={{ fontSize: "10px", flexShrink: 0 }} /> <UserOutlined style={{ fontSize: "12px", opacity: 0.75, flexShrink: 0 }} />
<span className="view-detail-text" style={{ <span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
fontSize: "11px", {ownerName}
fontWeight: 700, </span>
maxWidth: 0,
opacity: 0,
transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
marginLeft: 0,
overflow: 'hidden',
display: 'inline-block'
}}></span>
</div> </div>
</div> </div>
</Card> </Card>
@ -1001,8 +1002,6 @@ const Meetings: React.FC = () => {
<style>{` <style>{`
.meeting-card-v2:hover { transform: translateY(-3px); box-shadow: 0 12px 24px rgba(95, 81, 255, 0.08) !important; border-color: rgba(95, 81, 255, 0.15) !important; } .meeting-card-v2:hover { transform: translateY(-3px); box-shadow: 0 12px 24px rgba(95, 81, 255, 0.08) !important; border-color: rgba(95, 81, 255, 0.15) !important; }
.meeting-card-v2:hover .card-arrow { background: var(--primary-blue) !important; color: white !important; padding: 0 12px; }
.meeting-card-v2:hover .view-detail-text { max-width: 60px; opacity: 1; margin-left: 6px; }
.status-bar-active { animation: statusBreathing 2s infinite ease-in-out; } .status-bar-active { animation: statusBreathing 2s infinite ease-in-out; }
@keyframes statusBreathing { 0% { opacity: 1; } 50% { opacity: 0.4; } 100% { opacity: 1; } } @keyframes statusBreathing { 0% { opacity: 1; } 50% { opacity: 0.4; } 100% { opacity: 1; } }
.meetings-list-table.ant-table-wrapper, .meetings-list-table.ant-table-wrapper,