feat: 优化会议创建表单和卡片显示
- 重构会议创建表单,增加录音上传、AI分析配置和参会人员选择 - 更新会议卡片组件,集成进度背景和状态标签,优化样式和交互体验 - 增加分页功能和多语言支持 - 修复和优化多处代码逻辑和样式问题dev_na
parent
423327c61d
commit
11ab76f2ed
|
|
@ -84,7 +84,7 @@ public class AiTaskServiceImpl extends ServiceImpl<AiTaskMapper, AiTask> impleme
|
|||
} catch (Exception e) {
|
||||
log.error("Meeting {} AI Task Flow failed", meetingId, e);
|
||||
updateMeetingStatus(meetingId, 4); // Overall Failed
|
||||
updateProgress(meetingId, -1, "分析失败: " + e.getMessage());
|
||||
updateProgress(meetingId, -1, "分析失败: " + e.getMessage(), 0);
|
||||
} finally {
|
||||
redisTemplate.delete(lockKey);
|
||||
}
|
||||
|
|
@ -115,7 +115,7 @@ public class AiTaskServiceImpl extends ServiceImpl<AiTaskMapper, AiTask> impleme
|
|||
|
||||
private String processAsrTask(Meeting meeting) throws Exception {
|
||||
updateMeetingStatus(meeting.getId(), 1); // 识别中
|
||||
updateProgress(meeting.getId(), 5, "已提交识别请求...");
|
||||
updateProgress(meeting.getId(), 5, "已提交识别请求...", 0);
|
||||
|
||||
AiModel asrModel = aiModelService.getById(meeting.getAsrModelId());
|
||||
if (asrModel == null) throw new RuntimeException("ASR Model config not found");
|
||||
|
|
@ -177,7 +177,7 @@ public class AiTaskServiceImpl extends ServiceImpl<AiTaskMapper, AiTask> impleme
|
|||
if ("completed".equalsIgnoreCase(status)) {
|
||||
resultNode = data.path("result");
|
||||
updateAiTaskSuccess(taskRecord, statusNode);
|
||||
updateProgress(meeting.getId(), 85, "语音转录完成,准备进行总结...");
|
||||
updateProgress(meeting.getId(), 85, "语音转录完成,准备进行总结...", 0);
|
||||
break;
|
||||
} else if ("failed".equalsIgnoreCase(status)) {
|
||||
updateAiTaskFail(taskRecord, "ASR reported failure: " + queryResp);
|
||||
|
|
@ -186,10 +186,11 @@ public class AiTaskServiceImpl extends ServiceImpl<AiTaskMapper, AiTask> impleme
|
|||
// 处理中:同步进度到 Redis
|
||||
int currentPercent = data.path("percentage").asInt();
|
||||
String message = data.path("message").asText();
|
||||
int eta = data.path("eta").asInt(0);
|
||||
|
||||
// 缩放到 0-85% 范围
|
||||
int scaledPercent = (int)(currentPercent * 0.85);
|
||||
updateProgress(meeting.getId(), Math.max(5, scaledPercent), message);
|
||||
updateProgress(meeting.getId(), Math.max(5, scaledPercent), message, eta);
|
||||
|
||||
// 防死循环逻辑:如果进度长时间不动且不是 0
|
||||
if (currentPercent > 0 && currentPercent == lastPercent) {
|
||||
|
|
@ -241,7 +242,7 @@ public class AiTaskServiceImpl extends ServiceImpl<AiTaskMapper, AiTask> impleme
|
|||
|
||||
private void processSummaryTask(Meeting meeting, String asrText) throws Exception {
|
||||
updateMeetingStatus(meeting.getId(), 2); // 总结中
|
||||
updateProgress(meeting.getId(), 90, "正在进行 AI 智能总结...");
|
||||
updateProgress(meeting.getId(), 90, "正在进行 AI 智能总结...", 0);
|
||||
|
||||
AiModel llmModel = aiModelService.getById(meeting.getSummaryModelId());
|
||||
if (llmModel == null) return;
|
||||
|
|
@ -273,18 +274,19 @@ public class AiTaskServiceImpl extends ServiceImpl<AiTaskMapper, AiTask> impleme
|
|||
meeting.setStatus(3); // Finished
|
||||
meetingMapper.updateById(meeting);
|
||||
updateAiTaskSuccess(taskRecord, respNode);
|
||||
updateProgress(meeting.getId(), 100, "分析已完成");
|
||||
updateProgress(meeting.getId(), 100, "分析已完成", 0);
|
||||
} else {
|
||||
updateAiTaskFail(taskRecord, "LLM failed: " + response.body());
|
||||
throw new RuntimeException("AI总结生成失败");
|
||||
}
|
||||
}
|
||||
|
||||
private void updateProgress(Long meetingId, int percent, String msg) {
|
||||
private void updateProgress(Long meetingId, int percent, String msg, int eta) {
|
||||
try {
|
||||
Map<String, Object> progress = new HashMap<>();
|
||||
progress.put("percent", percent);
|
||||
progress.put("message", msg);
|
||||
progress.put("eta", eta);
|
||||
progress.put("updateAt", System.currentTimeMillis());
|
||||
redisTemplate.opsForValue().set(RedisKeys.meetingProgressKey(meetingId),
|
||||
objectMapper.writeValueAsString(progress), 1, TimeUnit.HOURS);
|
||||
|
|
|
|||
|
|
@ -39,6 +39,15 @@ const MeetingProgressDisplay: React.FC<{ meetingId: number; onComplete: () => vo
|
|||
const percent = progress?.percent || 0;
|
||||
const isError = percent < 0;
|
||||
|
||||
// 格式化剩余时间 (ETA)
|
||||
const formatETA = (seconds?: number) => {
|
||||
if (!seconds || seconds <= 0) return '即将完成';
|
||||
if (seconds < 60) return `${seconds}秒`;
|
||||
const m = Math.floor(seconds / 60);
|
||||
const s = seconds % 60;
|
||||
return s > 0 ? `${m}分${s}秒` : `${m}分钟`;
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
height: '100%', display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center',
|
||||
|
|
@ -71,7 +80,7 @@ const MeetingProgressDisplay: React.FC<{ meetingId: number; onComplete: () => vo
|
|||
<Col span={8}>
|
||||
<Space direction="vertical" size={0}>
|
||||
<Text type="secondary" size="small">预计剩余</Text>
|
||||
<Title level={4} style={{ margin: 0 }}>{isError ? '--' : (percent > 90 ? '即将完成' : '计算中')}</Title>
|
||||
<Title level={4} style={{ margin: 0 }}>{isError ? '--' : formatETA(progress?.eta)}</Title>
|
||||
</Space>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
|
|
|
|||
|
|
@ -293,22 +293,25 @@ const MeetingCardItem: React.FC<{ item: MeetingVO, config: any, fetchData: () =>
|
|||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
background: item.status === 1 ? '#e6f7ff' : '#fff7e6',
|
||||
padding: '6px 12px', // 增加内边距,更聚拢
|
||||
padding: '6px 10px',
|
||||
borderRadius: 6,
|
||||
marginTop: 4,
|
||||
width: 'calc(100% - 12px)', // 留出右侧与卡片边缘的距离
|
||||
width: '100%', // 占满 Space 容器
|
||||
overflow: 'hidden',
|
||||
boxSizing: 'border-box'
|
||||
boxSizing: 'border-box',
|
||||
minWidth: 0 // 关键:允许 flex 子项收缩
|
||||
}}>
|
||||
<InfoCircleOutlined style={{ marginRight: 8, flexShrink: 0 }} />
|
||||
<InfoCircleOutlined style={{ marginRight: 6, flexShrink: 0 }} />
|
||||
<Text
|
||||
ellipsis={{ tooltip: progress?.message || '处理中...' }}
|
||||
ellipsis={{ tooltip: progress?.message || '分析中...' }}
|
||||
style={{
|
||||
color: 'inherit',
|
||||
fontSize: '12px',
|
||||
flex: 1,
|
||||
minWidth: 0,
|
||||
fontWeight: 500
|
||||
minWidth: 0, // 关键:触发文本截断
|
||||
maxWidth: 250, // 关键:触发文本截断
|
||||
fontWeight: 500,
|
||||
whiteSpace: 'nowrap'
|
||||
}}
|
||||
>
|
||||
{progress?.message || '等待引擎调度...'}
|
||||
|
|
|
|||
Loading…
Reference in New Issue