界面优化
parent
77fe6d4e77
commit
bf40b13383
|
|
@ -138,6 +138,7 @@ export default function Users() {
|
|||
const [filterTenantId, setFilterTenantId] = useState<number | undefined>(undefined);
|
||||
const [drawerOpen, setDrawerOpen] = useState(false);
|
||||
const [editing, setEditing] = useState<SysUser | null>(null);
|
||||
const [roleSelectOpen, setRoleSelectOpen] = useState(false);
|
||||
const [form] = Form.useForm();
|
||||
const [resetPasswordOpen, setResetPasswordOpen] = useState(false);
|
||||
const [resetPasswordLoading, setResetPasswordLoading] = useState(false);
|
||||
|
|
@ -264,6 +265,7 @@ export default function Users() {
|
|||
|
||||
const openCreate = () => {
|
||||
setEditing(null);
|
||||
setRoleSelectOpen(false);
|
||||
form.resetFields();
|
||||
form.setFieldsValue({
|
||||
status: 1,
|
||||
|
|
@ -277,6 +279,7 @@ export default function Users() {
|
|||
|
||||
const openEdit = async (record: SysUser) => {
|
||||
setEditing(record);
|
||||
setRoleSelectOpen(false);
|
||||
try {
|
||||
const detail = await getUserDetail(record.userId);
|
||||
const roleIds = await listUserRoles(record.userId);
|
||||
|
|
@ -594,10 +597,13 @@ export default function Users() {
|
|||
</Form.Item>
|
||||
) : null}
|
||||
<Form.Item label={t("users.roles")} name="roleIds"
|
||||
rules={[{required: true, message: t("users.roles")}]}><Select mode="multiple"
|
||||
placeholder={t("users.roles")}
|
||||
options={roleOptions}
|
||||
optionFilterProp={isPlatformMode ? "searchText" : "label"}/></Form.Item>
|
||||
rules={[{required: true, message: t("users.roles")}]}><Select mode="multiple"
|
||||
placeholder={t("users.roles")}
|
||||
options={roleOptions}
|
||||
open={roleSelectOpen}
|
||||
onDropdownVisibleChange={setRoleSelectOpen}
|
||||
onChange={() => setRoleSelectOpen(false)}
|
||||
optionFilterProp={isPlatformMode ? "searchText" : "label"}/></Form.Item>
|
||||
{!isPlatformMode && <Form.Item label={t("users.orgNode")} name="orgId"><TreeSelect
|
||||
placeholder={t("usersExt.selectOrgPlaceholder")} allowClear treeData={orgTreeData}/></Form.Item>}
|
||||
<Row gutter={16}>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
InfoCircleOutlined,
|
||||
PauseCircleOutlined,
|
||||
PlusOutlined,
|
||||
RightOutlined,
|
||||
SearchOutlined,
|
||||
SettingOutlined,
|
||||
SyncOutlined,
|
||||
|
|
@ -136,6 +135,9 @@ const shouldPollMeetingCard = (item: MeetingVO) =>
|
|||
const getUnifiedStatusCode = (progress: MeetingProgress | null | undefined) =>
|
||||
progress?.unifiedStatus?.statusCode;
|
||||
|
||||
const isWaitingUploadProgress = (progress: MeetingProgress | null | undefined) =>
|
||||
getUnifiedStatusCode(progress) === "WAITING_UPLOAD";
|
||||
|
||||
const getEffectiveStatus = (item: MeetingVO, progress: MeetingProgress | null) => {
|
||||
const unifiedStatusCode = getUnifiedStatusCode(progress);
|
||||
if (unifiedStatusCode === "WAITING_UPLOAD") {
|
||||
|
|
@ -285,12 +287,17 @@ const MeetingCardItem: React.FC<{
|
|||
}> = ({ item, config, progress, onOpenMeeting, onRetrySchedule, onDelete, retrying }) => {
|
||||
const effectiveStatus = getEffectiveStatus(item, progress);
|
||||
const isProcessing = shouldTrackGenerationProgress(item);
|
||||
const isWaitingUpload = isWaitingUploadProgress(progress) || effectiveStatus === 8;
|
||||
const isPaused = effectiveStatus === PAUSED_DISPLAY_STATUS;
|
||||
const isRealtimeActive = effectiveStatus === REALTIME_ACTIVE_DISPLAY_STATUS;
|
||||
const isRealtimeIdle = effectiveStatus === REALTIME_IDLE_DISPLAY_STATUS;
|
||||
const isCrossPlatformRealtime = (isPaused || isRealtimeActive || isRealtimeIdle) && !canControlRealtimeFromCurrentPlatform(item);
|
||||
const crossPlatformHint = `在 ${getRealtimeSourceLabel(item)} 继续`;
|
||||
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";
|
||||
|
||||
|
|
@ -375,26 +382,28 @@ const MeetingCardItem: React.FC<{
|
|||
fontSize: "12px"
|
||||
}}
|
||||
>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: "6px", color: config.color, fontWeight: 600 }}>
|
||||
{isProcessing ? <SyncOutlined spin /> : <InfoCircleOutlined />}
|
||||
<span style={{ fontSize: "12px" }}>
|
||||
{isProcessing ? (progress?.message || "深度分析中...") : (isCrossPlatformRealtime ? crossPlatformHint : config.text)}
|
||||
</span>
|
||||
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: "10px" }}>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: "6px", minWidth: 0, color: config.color, fontWeight: 600 }}>
|
||||
{isProcessing ? <SyncOutlined spin /> : <InfoCircleOutlined />}
|
||||
<span style={{ fontSize: "12px", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
|
||||
{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>
|
||||
{canRetry && (
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
loading={retrying}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
onRetrySchedule(item);
|
||||
}}
|
||||
style={{ paddingInline: 0, height: "auto" }}
|
||||
>
|
||||
重新调度
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<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 }} />
|
||||
<span>{dayjs(item.meetingTime).format("MM-DD HH:mm")}</span>
|
||||
</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>
|
||||
|
|
@ -436,31 +441,27 @@ const MeetingCardItem: React.FC<{
|
|||
<div
|
||||
style={{
|
||||
height: "28px",
|
||||
maxWidth: "112px",
|
||||
padding: "0 10px",
|
||||
borderRadius: "8px",
|
||||
background: "rgba(95, 81, 255, 0.1)",
|
||||
color: "var(--primary-blue)",
|
||||
background: "rgba(15, 23, 42, 0.04)",
|
||||
color: "#6b7280",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
|
||||
padding: "0 10px",
|
||||
gap: "5px",
|
||||
overflow: "hidden",
|
||||
whiteSpace: "nowrap",
|
||||
minWidth: "28px"
|
||||
}}
|
||||
className="card-arrow"
|
||||
>
|
||||
<RightOutlined style={{ fontSize: "10px", flexShrink: 0 }} />
|
||||
<span className="view-detail-text" style={{
|
||||
flexShrink: 0,
|
||||
fontSize: "11px",
|
||||
fontWeight: 700,
|
||||
maxWidth: 0,
|
||||
opacity: 0,
|
||||
transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
|
||||
marginLeft: 0,
|
||||
overflow: 'hidden',
|
||||
display: 'inline-block'
|
||||
}}>查看详情</span>
|
||||
fontWeight: 600
|
||||
}}
|
||||
title={`所属用户:${ownerName}`}
|
||||
>
|
||||
<UserOutlined style={{ fontSize: "12px", opacity: 0.75, flexShrink: 0 }} />
|
||||
<span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
|
||||
{ownerName}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
|
@ -1001,8 +1002,6 @@ const Meetings: React.FC = () => {
|
|||
|
||||
<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 .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; }
|
||||
@keyframes statusBreathing { 0% { opacity: 1; } 50% { opacity: 0.4; } 100% { opacity: 1; } }
|
||||
.meetings-list-table.ant-table-wrapper,
|
||||
|
|
|
|||
Loading…
Reference in New Issue