refactor: 移除 `ExistingOfflineMeetingException` 并更新相关逻辑
- 移除 `ExistingOfflineMeetingException` 类 - 更新 `AndroidMeetingController` 中的异常处理,使用 `BusinessException` 和 `BusinessErrorCodeEnum` - 优化 `AndroidDeviceHomeServiceImpl`,添加 `TenantMeetingPointsSettingService` 依赖并更新积分校验逻辑 - 将 `AboutPage` 页面移至 `ProfilePage` 的模态框中 - 更新 `MeetingUnifiedStatusServiceImpl` 的代码格式和逻辑顺序dev_na
parent
fd9ef5c885
commit
c64c8b5690
|
|
@ -1,13 +0,0 @@
|
|||
package com.imeeting.common.exception;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class ExistingOfflineMeetingException extends RuntimeException {
|
||||
private final Long meetingId;
|
||||
|
||||
public ExistingOfflineMeetingException(Long meetingId) {
|
||||
super("有未结束会议");
|
||||
this.meetingId = meetingId;
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,6 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.imeeting.common.MeetingConstants;
|
||||
import com.imeeting.common.SysParamKeys;
|
||||
import com.imeeting.common.exception.ExistingOfflineMeetingException;
|
||||
import com.imeeting.dto.android.AndroidAuthContext;
|
||||
import com.imeeting.dto.android.AndroidOfflineMeetingCreateCommand;
|
||||
import com.imeeting.dto.android.AndroidMeetingCreateResponse;
|
||||
|
|
@ -28,6 +27,7 @@ import com.imeeting.dto.biz.UnifiedMeetingStatusVO;
|
|||
import com.imeeting.entity.biz.AiTask;
|
||||
import com.imeeting.entity.biz.Meeting;
|
||||
import com.imeeting.entity.biz.PromptTemplate;
|
||||
import com.imeeting.enums.BusinessErrorCodeEnum;
|
||||
import com.imeeting.enums.MeetingStatusEnum;
|
||||
import com.imeeting.service.android.AndroidAuthService;
|
||||
import com.imeeting.service.android.AndroidChunkUploadService;
|
||||
|
|
@ -37,6 +37,7 @@ import com.imeeting.service.biz.*;
|
|||
import com.unisbase.annotation.Anonymous;
|
||||
import com.unisbase.common.ApiResponse;
|
||||
import com.unisbase.common.annotation.Log;
|
||||
import com.unisbase.common.exception.BusinessException;
|
||||
import com.unisbase.dto.PageResult;
|
||||
import com.unisbase.entity.SysTenant;
|
||||
import com.unisbase.entity.SysUser;
|
||||
|
|
@ -166,16 +167,13 @@ public class AndroidMeetingController {
|
|||
AndroidAuthContext authContext = androidAuthService.authenticateHttp(request);
|
||||
resolvePublicDeviceTenantId(request, command, authContext);
|
||||
LoginUser loginUser = authContext.isAnonymous() ? null : AndroidLoginUserSupport.requireLoginUser(authContext);
|
||||
try {
|
||||
|
||||
// Meeting existingMeeting = findLatestUnfinishedMeetingByDevice(authContext.getDeviceId());
|
||||
// if (existingMeeting != null) {
|
||||
// return new ApiResponse<>("409", "设备端已有会议", meetingQueryService.getDetailIgnoreTenant(existingMeeting.getId()));
|
||||
// }
|
||||
MeetingVO meeting = legacyMeetingAdapterService.createMeeting(command, authContext, loginUser);
|
||||
return ApiResponse.ok(buildAndroidMeetingCreateResponse(meeting));
|
||||
} catch (ExistingOfflineMeetingException ex) {
|
||||
return new ApiResponse<>("409", "有未结束会议", new AndroidOfflineMeetingConflictVO(ex.getMeetingId()));
|
||||
}
|
||||
}
|
||||
|
||||
@Operation(summary = "上传Android会议音频")
|
||||
|
|
@ -292,23 +290,8 @@ public class AndroidMeetingController {
|
|||
return ApiResponse.ok(buildAndroidMeetingListPage(result));
|
||||
}
|
||||
|
||||
@Operation(summary = "查询Android会议预览数据")
|
||||
@ApiResponses({
|
||||
@io.swagger.v3.oas.annotations.responses.ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "返回会议预览结果,包含已完成摘要或处理中状态信息",
|
||||
content = @Content(schema = @Schema(implementation = LegacyMeetingPreviewDataResponse.class))
|
||||
)
|
||||
})
|
||||
@GetMapping("/{meetingId}/preview-data")
|
||||
public ApiResponse<LegacyMeetingPreviewDataResponse> previewData(HttpServletRequest request, @PathVariable Long meetingId) {
|
||||
AndroidRequestLogHelper.logRequest(log, "Android会议", "查询会议预览数据接口", "meetingId", meetingId);
|
||||
androidAuthService.authenticateHttp(request);
|
||||
LegacyMeetingPreviewResult result = buildPreviewResult(meetingId);
|
||||
return new ApiResponse<>(result.getCode(), result.getMessage(), result.getData());
|
||||
}
|
||||
|
||||
@Operation(summary = "查询Android会议统一状态")
|
||||
@Operation(summary = "查询Android会议统一状态")
|
||||
@ApiResponses({
|
||||
@io.swagger.v3.oas.annotations.responses.ApiResponse(
|
||||
responseCode = "200",
|
||||
|
|
@ -560,7 +543,7 @@ public class AndroidMeetingController {
|
|||
private MeetingVO requireOperableOfflineMeeting(Long meetingId, AndroidAuthContext authContext, LoginUser loginUser) {
|
||||
MeetingVO meeting = meetingQueryService.getDetailIgnoreTenant(meetingId);
|
||||
if (meeting == null) {
|
||||
throw new RuntimeException("会议不存在");
|
||||
throw new BusinessException(BusinessErrorCodeEnum.MEETING_NOT_FOUND.getCode(), "会议不存在");
|
||||
}
|
||||
if (!MeetingConstants.TYPE_OFFLINE.equals(meeting.getMeetingType())) {
|
||||
throw new RuntimeException("当前会议不是离线会议");
|
||||
|
|
@ -588,107 +571,6 @@ public class AndroidMeetingController {
|
|||
&& MeetingConstants.OFFLINE_RECORDING_UPLOAD_FINISHED.equalsIgnoreCase(command.getFinishStage());
|
||||
}
|
||||
|
||||
private LegacyMeetingPreviewResult buildPreviewResult(Long meetingId) {
|
||||
Meeting meeting = meetingService.getById(meetingId);
|
||||
if (meeting == null) {
|
||||
return new LegacyMeetingPreviewResult("404", "会议不存在", null);
|
||||
}
|
||||
|
||||
AiTask asrTask = findLatestTask(meetingId, "ASR");
|
||||
AiTask summaryTask = findLatestTask(meetingId, "SUMMARY");
|
||||
boolean summaryCompleted = summaryTask != null && Integer.valueOf(2).equals(summaryTask.getStatus());
|
||||
MeetingVO detail = (MeetingStatusEnum.isCode(meeting.getStatus(), MeetingStatusEnum.COMPLETED) || summaryCompleted)
|
||||
? meetingQueryService.getDetail(meetingId)
|
||||
: null;
|
||||
boolean hasSummary = detail != null && detail.getSummaryContent() != null && !detail.getSummaryContent().isBlank();
|
||||
|
||||
if (hasSummary) {
|
||||
return new LegacyMeetingPreviewResult("200", "success", buildCompletedPreview(meeting, detail, summaryTask));
|
||||
}
|
||||
if (summaryCompleted) {
|
||||
return new LegacyMeetingPreviewResult(
|
||||
"504",
|
||||
"处理已完成,但摘要尚未同步,请稍后重试",
|
||||
buildProcessingPreview(meeting, summaryTask, processingStatus("摘要已生成,可查看详情", 100, STAGE_COMPLETED))
|
||||
);
|
||||
}
|
||||
if (isFailed(asrTask)) {
|
||||
return new LegacyMeetingPreviewResult(
|
||||
"503",
|
||||
buildFailureMessage(asrTask, "转写"),
|
||||
buildProcessingPreview(meeting, summaryTask, processingStatus("转写或总结失败", 50, STAGE_AUDIO_TRANSCRIPTION))
|
||||
);
|
||||
}
|
||||
if (isFailed(summaryTask)) {
|
||||
return new LegacyMeetingPreviewResult(
|
||||
"503",
|
||||
buildFailureMessage(summaryTask, "总结"),
|
||||
buildProcessingPreview(meeting, summaryTask, processingStatus("转写或总结失败", 75, STAGE_SUMMARY_GENERATION))
|
||||
);
|
||||
}
|
||||
|
||||
Integer realtimeProgress = resolveRealtimeProgress(meetingId);
|
||||
if (asrTask != null && Integer.valueOf(0).equals(asrTask.getStatus()) && realtimeProgress != null && realtimeProgress <= 0) {
|
||||
return new LegacyMeetingPreviewResult(
|
||||
"400",
|
||||
"会议正在处理中",
|
||||
buildProcessingPreview(meeting, summaryTask, processingStatus("会议数据准备中", 25, STAGE_DATA_INITIALIZATION))
|
||||
);
|
||||
}
|
||||
if (realtimeProgress != null) {
|
||||
if (realtimeProgress >= 100) {
|
||||
MeetingVO completedDetail = detail != null ? detail : meetingQueryService.getDetail(meetingId);
|
||||
boolean completedHasSummary = completedDetail != null
|
||||
&& completedDetail.getSummaryContent() != null
|
||||
&& !completedDetail.getSummaryContent().isBlank();
|
||||
if (completedHasSummary) {
|
||||
return new LegacyMeetingPreviewResult("200", "success", buildCompletedPreview(meeting, completedDetail, summaryTask));
|
||||
}
|
||||
return new LegacyMeetingPreviewResult(
|
||||
"504",
|
||||
"处理已完成,但摘要尚未同步,请稍后重试",
|
||||
buildProcessingPreview(meeting, summaryTask, processingStatus("摘要已生成,可查看详情", 100, STAGE_COMPLETED))
|
||||
);
|
||||
}
|
||||
if (realtimeProgress < 90) {
|
||||
return new LegacyMeetingPreviewResult(
|
||||
"400",
|
||||
"会议正在处理中",
|
||||
buildProcessingPreview(meeting, summaryTask, processingStatus("正在转写音频", 50, STAGE_AUDIO_TRANSCRIPTION))
|
||||
);
|
||||
}
|
||||
if (realtimeProgress >= 90) {
|
||||
return new LegacyMeetingPreviewResult(
|
||||
"400",
|
||||
"会议正在处理中",
|
||||
buildProcessingPreview(meeting, summaryTask, processingStatus("正在生成总结", 75, STAGE_SUMMARY_GENERATION))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
boolean isSummaryStage = isSummaryStage(meeting.getStatus(), summaryTask);
|
||||
boolean isAsrStage = isAsrStage(meeting.getStatus(), asrTask, hasAudio(meeting), isSummaryStage);
|
||||
|
||||
if (!isAsrStage && !isSummaryStage) {
|
||||
return new LegacyMeetingPreviewResult(
|
||||
"400",
|
||||
"会议正在处理中",
|
||||
buildProcessingPreview(meeting, summaryTask, processingStatus("会议数据准备中", 25, STAGE_DATA_INITIALIZATION))
|
||||
);
|
||||
}
|
||||
if (!isSummaryStage) {
|
||||
return new LegacyMeetingPreviewResult(
|
||||
"400",
|
||||
"会议正在处理中",
|
||||
buildProcessingPreview(meeting, summaryTask, processingStatus("正在转写音频", 50, STAGE_AUDIO_TRANSCRIPTION))
|
||||
);
|
||||
}
|
||||
return new LegacyMeetingPreviewResult(
|
||||
"400",
|
||||
"会议正在处理中",
|
||||
buildProcessingPreview(meeting, summaryTask, processingStatus("正在生成总结", 75, STAGE_SUMMARY_GENERATION))
|
||||
);
|
||||
}
|
||||
|
||||
private LegacyMeetingPreviewDataResponse buildCompletedPreview(Meeting meeting, MeetingVO detail, AiTask summaryTask) {
|
||||
LegacyMeetingPreviewDataResponse data = new LegacyMeetingPreviewDataResponse();
|
||||
|
|
|
|||
|
|
@ -33,4 +33,6 @@ public class AndroidDeviceHomeStatsVO {
|
|||
|
||||
@Schema(description = "是否已登录")
|
||||
private Boolean loggedIn;
|
||||
@Schema(description = "是否开启余额校验")
|
||||
private Boolean balanceCheckEnabled;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
package com.imeeting.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum BusinessErrorCodeEnum {
|
||||
MEETING_NOT_FOUND("40001", "会议不存在"),
|
||||
;
|
||||
|
||||
|
||||
private final String code;
|
||||
private final String desc;
|
||||
|
||||
BusinessErrorCodeEnum(String code, String desc) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
}
|
||||
|
|
@ -28,6 +28,7 @@ public class AndroidAuthServiceImpl implements AndroidAuthService {
|
|||
|
||||
private static final String HEADER_DEVICE_ID = "X-Android-Device-Id";
|
||||
private static final String HEADER_APP_ID = "X-Android-App-Id";
|
||||
private static final String HEADER_TENANT_CODE = "X-Tenant-Code";
|
||||
private static final String HEADER_APP_VERSION = "X-Android-App-Version";
|
||||
private static final String HEADER_PLATFORM = "X-Android-Platform";
|
||||
private static final String HEADER_AUTHORIZATION = "Authorization";
|
||||
|
|
|
|||
|
|
@ -11,12 +11,14 @@ import com.imeeting.dto.android.AndroidDeviceWeatherCacheValue;
|
|||
import com.imeeting.dto.biz.MeetingPointsBalanceVO;
|
||||
import com.imeeting.entity.biz.DeviceInfoEntity;
|
||||
import com.imeeting.entity.biz.LicenseEntity;
|
||||
import com.imeeting.entity.biz.TenantMeetingPointsSetting;
|
||||
import com.imeeting.mapper.DeviceInfoMapper;
|
||||
import com.imeeting.mapper.DeviceLoginLogMapper;
|
||||
import com.imeeting.mapper.LicenseMapper;
|
||||
import com.imeeting.mapper.biz.MeetingMapper;
|
||||
import com.imeeting.service.android.AndroidDeviceHomeService;
|
||||
import com.imeeting.service.biz.MeetingPointsService;
|
||||
import com.imeeting.service.biz.TenantMeetingPointsSettingService;
|
||||
import com.imeeting.support.RedisSupport;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
|
@ -55,8 +57,9 @@ public class AndroidDeviceHomeServiceImpl implements AndroidDeviceHomeService {
|
|||
private final RedisSupport redisSupport;
|
||||
private final com.unisbase.service.SysParamService sysParamService;
|
||||
private final ObjectMapper objectMapper;
|
||||
private final TenantMeetingPointsSettingService tenantMeetingPointsSettingService;
|
||||
|
||||
@Value("${imeeting.h5.base-url:}")
|
||||
@Value("${imeeting.h5.base-url:}")
|
||||
private String h5BaseUrl;
|
||||
|
||||
private final HttpClient httpClient = HttpClient.newBuilder()
|
||||
|
|
@ -95,7 +98,11 @@ public class AndroidDeviceHomeServiceImpl implements AndroidDeviceHomeService {
|
|||
vo.setRemainingMinutes(calculateRemainingMinutes(tenantId, authContext.getUserId(), authContext.isAnonymous()));
|
||||
vo.setWeather(resolveWeather(device.getWeatherCityName()));
|
||||
vo.setLoggedIn(!authContext.isAnonymous() && authContext.getUserId() != null);
|
||||
return vo;
|
||||
TenantMeetingPointsSetting byTenantId = tenantMeetingPointsSettingService.getByTenantId(authContext.getTenantId());
|
||||
vo.setBalanceCheckEnabled(byTenantId == null || byTenantId.getBalanceCheckEnabled() == 1);
|
||||
|
||||
|
||||
return vo;
|
||||
}
|
||||
|
||||
private Long calculateRemainingMinutes(Long tenantId, Long userId, boolean anonymous) {
|
||||
|
|
|
|||
|
|
@ -97,7 +97,8 @@ public class LegacyMeetingAdapterServiceImpl implements LegacyMeetingAdapterServ
|
|||
|
||||
Meeting existingMeeting = findLatestBlockingOfflineMeeting(authContext == null ? null : authContext.getDeviceId(), creatorUserId);
|
||||
if (existingMeeting != null) {
|
||||
throw new ExistingOfflineMeetingException(existingMeeting.getId());
|
||||
existingMeeting.setOfflineRecordingStatus(MeetingConstants.OFFLINE_RECORDING_PRE_END);
|
||||
meetingService.updateById(existingMeeting);
|
||||
}
|
||||
|
||||
Long requestedSummaryModelId = request instanceof AndroidOfflineMeetingCreateCommand androidCommand
|
||||
|
|
|
|||
|
|
@ -26,260 +26,260 @@ import java.util.Objects;
|
|||
@RequiredArgsConstructor
|
||||
public class MeetingUnifiedStatusServiceImpl implements MeetingUnifiedStatusService {
|
||||
|
||||
private final MeetingMapper meetingMapper;
|
||||
private final AiTaskMapper aiTaskMapper;
|
||||
private final MeetingTranscriptMapper meetingTranscriptMapper;
|
||||
private final MeetingTranscriptChapterVersionMapper chapterVersionMapper;
|
||||
private final MeetingProgressCache meetingProgressCache;
|
||||
private final MeetingMapper meetingMapper;
|
||||
private final AiTaskMapper aiTaskMapper;
|
||||
private final MeetingTranscriptMapper meetingTranscriptMapper;
|
||||
private final MeetingTranscriptChapterVersionMapper chapterVersionMapper;
|
||||
private final MeetingProgressCache meetingProgressCache;
|
||||
|
||||
@Override
|
||||
public UnifiedMeetingStatusVO resolve(MeetingVO meeting, MeetingProgressSnapshot snapshot) {
|
||||
if (meeting == null || meeting.getId() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
UnifiedMeetingStatusStage stage = resolveStage(meeting, snapshot);
|
||||
UnifiedMeetingStatusStage failedStage = resolveFailedStage(meeting);
|
||||
boolean failed = failedStage != null;
|
||||
UnifiedMeetingStatusStage effectiveStage = failed ? failedStage : stage;
|
||||
|
||||
return UnifiedMeetingStatusVO.builder()
|
||||
.meetingId(meeting.getId())
|
||||
.statusCode(effectiveStage.getCode())
|
||||
.statusText(effectiveStage.getText())
|
||||
.percent(resolvePercent(snapshot, effectiveStage))
|
||||
.message(resolveMessage(meeting, snapshot, effectiveStage))
|
||||
.eta(snapshot == null ? null : snapshot.getEta())
|
||||
.failedStageCode(failedStage == null ? null : failedStage.getCode())
|
||||
.failedStageText(failedStage == null ? null : failedStage.getText())
|
||||
.canViewTranscript(canViewTranscript(meeting.getId()))
|
||||
.canViewAiChapters(canViewAiChapters(meeting.getId()))
|
||||
.canViewSummary(canViewSummary(meeting))
|
||||
.build();
|
||||
@Override
|
||||
public UnifiedMeetingStatusVO resolve(MeetingVO meeting, MeetingProgressSnapshot snapshot) {
|
||||
if (meeting == null || meeting.getId() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnifiedMeetingStatusVO resolve(Long meetingId) {
|
||||
if (meetingId == null) {
|
||||
return null;
|
||||
}
|
||||
Meeting meeting = meetingMapper.selectByIdIgnoreTenant(meetingId);
|
||||
if (meeting == null) {
|
||||
return null;
|
||||
}
|
||||
return resolve(toMeetingVO(meeting), meetingProgressCache.getSnapshot(meetingId));
|
||||
UnifiedMeetingStatusStage stage = resolveStage(meeting, snapshot);
|
||||
UnifiedMeetingStatusStage failedStage = resolveFailedStage(meeting);
|
||||
boolean failed = failedStage != null;
|
||||
UnifiedMeetingStatusStage effectiveStage = failed ? failedStage : stage;
|
||||
|
||||
return UnifiedMeetingStatusVO.builder()
|
||||
.meetingId(meeting.getId())
|
||||
.statusCode(effectiveStage.getCode())
|
||||
.statusText(effectiveStage.getText())
|
||||
.percent(resolvePercent(snapshot, effectiveStage))
|
||||
.message(resolveMessage(meeting, snapshot, effectiveStage))
|
||||
.eta(snapshot == null ? null : snapshot.getEta())
|
||||
.failedStageCode(failedStage == null ? null : failedStage.getCode())
|
||||
.failedStageText(failedStage == null ? null : failedStage.getText())
|
||||
.canViewTranscript(canViewTranscript(meeting.getId()))
|
||||
.canViewAiChapters(canViewAiChapters(meeting.getId()))
|
||||
.canViewSummary(canViewSummary(meeting))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnifiedMeetingStatusVO resolve(Long meetingId) {
|
||||
if (meetingId == null) {
|
||||
return null;
|
||||
}
|
||||
Meeting meeting = meetingMapper.selectByIdIgnoreTenant(meetingId);
|
||||
if (meeting == null) {
|
||||
return null;
|
||||
}
|
||||
return resolve(toMeetingVO(meeting), meetingProgressCache.getSnapshot(meetingId));
|
||||
}
|
||||
|
||||
private MeetingUnifiedStageContext buildStageContext(Long meetingId, MeetingProgressSnapshot snapshot) {
|
||||
AiTask latestAsr = findLatestTask(meetingId, "ASR");
|
||||
AiTask latestChapter = findLatestTask(meetingId, "CHAPTER");
|
||||
AiTask latestSummary = findLatestTask(meetingId, "SUMMARY");
|
||||
return new MeetingUnifiedStageContext(latestAsr, latestChapter, latestSummary, snapshot);
|
||||
}
|
||||
|
||||
private UnifiedMeetingStatusStage resolveStage(MeetingVO meeting, MeetingProgressSnapshot snapshot) {
|
||||
if (meeting == null) {
|
||||
return UnifiedMeetingStatusStage.INITIALIZING;
|
||||
}
|
||||
if (MeetingStatusEnum.isCode(meeting.getStatus(), MeetingStatusEnum.COMPLETED)) {
|
||||
return UnifiedMeetingStatusStage.COMPLETED;
|
||||
}
|
||||
if (isAndroidOfflineMeetingWaitingUpload(meeting)) {
|
||||
return UnifiedMeetingStatusStage.WAITING_UPLOAD;
|
||||
}
|
||||
UnifiedMeetingStatusStage stageFromSnapshot = resolveStageFromSnapshot(snapshot);
|
||||
if (stageFromSnapshot != null) {
|
||||
return stageFromSnapshot;
|
||||
}
|
||||
|
||||
private MeetingUnifiedStageContext buildStageContext(Long meetingId, MeetingProgressSnapshot snapshot) {
|
||||
AiTask latestAsr = findLatestTask(meetingId, "ASR");
|
||||
AiTask latestChapter = findLatestTask(meetingId, "CHAPTER");
|
||||
AiTask latestSummary = findLatestTask(meetingId, "SUMMARY");
|
||||
return new MeetingUnifiedStageContext(latestAsr, latestChapter, latestSummary, snapshot);
|
||||
MeetingUnifiedStageContext context = buildStageContext(meeting.getId(), snapshot);
|
||||
if (isTranscribing(context)) {
|
||||
return UnifiedMeetingStatusStage.TRANSCRIBING;
|
||||
}
|
||||
if (isSummarizing(context)) {
|
||||
return UnifiedMeetingStatusStage.SUMMARIZING;
|
||||
}
|
||||
|
||||
private UnifiedMeetingStatusStage resolveStage(MeetingVO meeting, MeetingProgressSnapshot snapshot) {
|
||||
if (meeting == null) {
|
||||
return UnifiedMeetingStatusStage.INITIALIZING;
|
||||
}
|
||||
if (MeetingStatusEnum.isCode(meeting.getStatus(), MeetingStatusEnum.COMPLETED)) {
|
||||
return UnifiedMeetingStatusStage.COMPLETED;
|
||||
}
|
||||
if (isAndroidOfflineMeetingWaitingUpload(meeting)) {
|
||||
return UnifiedMeetingStatusStage.WAITING_UPLOAD;
|
||||
}
|
||||
UnifiedMeetingStatusStage stageFromSnapshot = resolveStageFromSnapshot(snapshot);
|
||||
if (stageFromSnapshot != null) {
|
||||
return stageFromSnapshot;
|
||||
}
|
||||
return UnifiedMeetingStatusStage.INITIALIZING;
|
||||
}
|
||||
|
||||
MeetingUnifiedStageContext context = buildStageContext(meeting.getId(), snapshot);
|
||||
if (isTranscribing(context)) {
|
||||
return UnifiedMeetingStatusStage.TRANSCRIBING;
|
||||
}
|
||||
if (isSummarizing(context)) {
|
||||
return UnifiedMeetingStatusStage.SUMMARIZING;
|
||||
}
|
||||
private UnifiedMeetingStatusStage resolveStageFromSnapshot(MeetingProgressSnapshot snapshot) {
|
||||
if (snapshot == null || snapshot.getStage() == null || snapshot.getStage().isBlank()) {
|
||||
return null;
|
||||
}
|
||||
return switch (snapshot.getStage()) {
|
||||
case "failed" -> null;
|
||||
case "completed" -> UnifiedMeetingStatusStage.COMPLETED;
|
||||
case "summary_running", "chapter_running" -> UnifiedMeetingStatusStage.SUMMARIZING;
|
||||
case "asr_running", "asr_completed", "asr_submitted" -> UnifiedMeetingStatusStage.TRANSCRIBING;
|
||||
case "queued" -> UnifiedMeetingStatusStage.INITIALIZING;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
return UnifiedMeetingStatusStage.INITIALIZING;
|
||||
private UnifiedMeetingStatusStage resolveFailedStage(MeetingVO meeting) {
|
||||
if (meeting == null || !MeetingStatusEnum.isCode(meeting.getStatus(), MeetingStatusEnum.FAILED)) {
|
||||
return null;
|
||||
}
|
||||
AiTask asrTask = findLatestTask(meeting.getId(), "ASR");
|
||||
if (isTaskFailed(asrTask)) {
|
||||
return UnifiedMeetingStatusStage.FAILED_TRANSCRIBING;
|
||||
}
|
||||
AiTask summaryTask = findLatestTask(meeting.getId(), "SUMMARY");
|
||||
if (isTaskFailed(summaryTask)) {
|
||||
return UnifiedMeetingStatusStage.FAILED_SUMMARIZING;
|
||||
}
|
||||
AiTask chapterTask = findLatestTask(meeting.getId(), "CHAPTER");
|
||||
if (isTaskFailed(chapterTask)) {
|
||||
return UnifiedMeetingStatusStage.FAILED_SUMMARIZING;
|
||||
}
|
||||
|
||||
private UnifiedMeetingStatusStage resolveStageFromSnapshot(MeetingProgressSnapshot snapshot) {
|
||||
if (snapshot == null || snapshot.getStage() == null || snapshot.getStage().isBlank()) {
|
||||
return null;
|
||||
}
|
||||
return switch (snapshot.getStage()) {
|
||||
case "failed" -> null;
|
||||
case "completed" -> UnifiedMeetingStatusStage.COMPLETED;
|
||||
case "summary_running", "chapter_running" -> UnifiedMeetingStatusStage.SUMMARIZING;
|
||||
case "asr_running", "asr_completed", "asr_submitted" -> UnifiedMeetingStatusStage.TRANSCRIBING;
|
||||
case "queued" -> UnifiedMeetingStatusStage.INITIALIZING;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
return UnifiedMeetingStatusStage.FAILED_INITIALIZING;
|
||||
}
|
||||
|
||||
private UnifiedMeetingStatusStage resolveFailedStage(MeetingVO meeting) {
|
||||
if (meeting == null || !MeetingStatusEnum.isCode(meeting.getStatus(), MeetingStatusEnum.FAILED)) {
|
||||
return null;
|
||||
}
|
||||
private boolean isAndroidOfflineMeetingWaitingUpload(MeetingVO meeting) {
|
||||
return meeting != null
|
||||
&& MeetingConstants.TYPE_OFFLINE.equalsIgnoreCase(meeting.getMeetingType())
|
||||
&& MeetingConstants.SOURCE_ANDROID.equalsIgnoreCase(meeting.getMeetingSource())
|
||||
&& !MeetingConstants.OFFLINE_RECORDING_UPLOAD_FINISHED.equalsIgnoreCase(meeting.getOfflineRecordingStatus());
|
||||
}
|
||||
|
||||
AiTask summaryTask = findLatestTask(meeting.getId(), "SUMMARY");
|
||||
if (isTaskFailed(summaryTask)) {
|
||||
return UnifiedMeetingStatusStage.FAILED_SUMMARIZING;
|
||||
}
|
||||
AiTask chapterTask = findLatestTask(meeting.getId(), "CHAPTER");
|
||||
if (isTaskFailed(chapterTask)) {
|
||||
return UnifiedMeetingStatusStage.FAILED_SUMMARIZING;
|
||||
}
|
||||
AiTask asrTask = findLatestTask(meeting.getId(), "ASR");
|
||||
if (isTaskFailed(asrTask)) {
|
||||
return UnifiedMeetingStatusStage.FAILED_TRANSCRIBING;
|
||||
}
|
||||
return UnifiedMeetingStatusStage.FAILED_INITIALIZING;
|
||||
}
|
||||
private boolean isSummarizing(MeetingUnifiedStageContext context) {
|
||||
return isTaskRunning(context.summaryTask())
|
||||
|| isTaskRunning(context.chapterTask())
|
||||
|| isTaskCompleted(context.chapterTask())
|
||||
|| isTaskCompleted(context.summaryTask());
|
||||
}
|
||||
|
||||
private boolean isAndroidOfflineMeetingWaitingUpload(MeetingVO meeting) {
|
||||
return meeting != null
|
||||
&& MeetingConstants.TYPE_OFFLINE.equalsIgnoreCase(meeting.getMeetingType())
|
||||
&& MeetingConstants.SOURCE_ANDROID.equalsIgnoreCase(meeting.getMeetingSource())
|
||||
&& !MeetingConstants.OFFLINE_RECORDING_UPLOAD_FINISHED.equalsIgnoreCase(meeting.getOfflineRecordingStatus());
|
||||
private boolean isTranscribing(MeetingUnifiedStageContext context) {
|
||||
if (isTaskRunningOrQueued(context.summaryTask()) || isTaskRunningOrQueued(context.chapterTask())) {
|
||||
return false;
|
||||
}
|
||||
return isTaskRunningOrQueued(context.asrTask()) || isTaskCompleted(context.asrTask());
|
||||
}
|
||||
|
||||
private boolean isSummarizing(MeetingUnifiedStageContext context) {
|
||||
return isTaskRunning(context.summaryTask())
|
||||
|| isTaskRunning(context.chapterTask())
|
||||
|| isTaskCompleted(context.chapterTask())
|
||||
|| isTaskCompleted(context.summaryTask());
|
||||
private Integer resolvePercent(MeetingProgressSnapshot snapshot, UnifiedMeetingStatusStage stage) {
|
||||
if (snapshot != null && snapshot.getPercent() != null) {
|
||||
return snapshot.getPercent();
|
||||
}
|
||||
return switch (stage) {
|
||||
case WAITING_UPLOAD -> 0;
|
||||
case INITIALIZING -> 5;
|
||||
case TRANSCRIBING -> 50;
|
||||
case SUMMARIZING -> 90;
|
||||
case COMPLETED -> 100;
|
||||
case FAILED_INITIALIZING, FAILED_TRANSCRIBING, FAILED_SUMMARIZING -> -1;
|
||||
};
|
||||
}
|
||||
|
||||
private boolean isTranscribing(MeetingUnifiedStageContext context) {
|
||||
if (isTaskRunningOrQueued(context.summaryTask()) || isTaskRunningOrQueued(context.chapterTask())) {
|
||||
return false;
|
||||
}
|
||||
return isTaskRunningOrQueued(context.asrTask()) || isTaskCompleted(context.asrTask());
|
||||
private String resolveMessage(MeetingVO meeting, MeetingProgressSnapshot snapshot, UnifiedMeetingStatusStage stage) {
|
||||
if (stage == UnifiedMeetingStatusStage.WAITING_UPLOAD) {
|
||||
return "待上传录音文件";
|
||||
}
|
||||
if (snapshot != null && snapshot.getMessage() != null && !snapshot.getMessage().isBlank() && !Objects.equals(snapshot.getMessage(), "Waiting...")) {
|
||||
return snapshot.getMessage();
|
||||
}
|
||||
if (stage == UnifiedMeetingStatusStage.FAILED_INITIALIZING
|
||||
|| stage == UnifiedMeetingStatusStage.FAILED_TRANSCRIBING
|
||||
|| stage == UnifiedMeetingStatusStage.FAILED_SUMMARIZING) {
|
||||
return resolveFailureMessage(meeting);
|
||||
}
|
||||
return switch (stage) {
|
||||
case WAITING_UPLOAD -> "待上传录音文件";
|
||||
case INITIALIZING -> "数据初始化";
|
||||
case TRANSCRIBING -> "转译音频";
|
||||
case SUMMARIZING -> "生成总结";
|
||||
case COMPLETED -> "处理完成";
|
||||
case FAILED_INITIALIZING -> "数据初始化失败";
|
||||
case FAILED_TRANSCRIBING -> "转译音频失败";
|
||||
case FAILED_SUMMARIZING -> "生成总结失败";
|
||||
};
|
||||
}
|
||||
|
||||
private Integer resolvePercent(MeetingProgressSnapshot snapshot, UnifiedMeetingStatusStage stage) {
|
||||
if (snapshot != null && snapshot.getPercent() != null) {
|
||||
return snapshot.getPercent();
|
||||
}
|
||||
return switch (stage) {
|
||||
case WAITING_UPLOAD -> 0;
|
||||
case INITIALIZING -> 5;
|
||||
case TRANSCRIBING -> 50;
|
||||
case SUMMARIZING -> 90;
|
||||
case COMPLETED -> 100;
|
||||
case FAILED_INITIALIZING, FAILED_TRANSCRIBING, FAILED_SUMMARIZING -> -1;
|
||||
};
|
||||
private String resolveFailureMessage(MeetingVO meeting) {
|
||||
if (meeting == null) {
|
||||
return "处理失败";
|
||||
}
|
||||
if (meeting.getLatestSummaryAttemptErrorMsg() != null && !meeting.getLatestSummaryAttemptErrorMsg().isBlank()) {
|
||||
return meeting.getLatestSummaryAttemptErrorMsg();
|
||||
}
|
||||
if (meeting.getLatestChapterAttemptErrorMsg() != null && !meeting.getLatestChapterAttemptErrorMsg().isBlank()) {
|
||||
return meeting.getLatestChapterAttemptErrorMsg();
|
||||
}
|
||||
return "处理失败";
|
||||
}
|
||||
|
||||
private String resolveMessage(MeetingVO meeting, MeetingProgressSnapshot snapshot, UnifiedMeetingStatusStage stage) {
|
||||
if (stage == UnifiedMeetingStatusStage.WAITING_UPLOAD) {
|
||||
return "待上传录音文件";
|
||||
}
|
||||
if (snapshot != null && snapshot.getMessage() != null && !snapshot.getMessage().isBlank() && !Objects.equals(snapshot.getMessage(), "Waiting...")) {
|
||||
return snapshot.getMessage();
|
||||
}
|
||||
if (stage == UnifiedMeetingStatusStage.FAILED_INITIALIZING
|
||||
|| stage == UnifiedMeetingStatusStage.FAILED_TRANSCRIBING
|
||||
|| stage == UnifiedMeetingStatusStage.FAILED_SUMMARIZING) {
|
||||
return resolveFailureMessage(meeting);
|
||||
}
|
||||
return switch (stage) {
|
||||
case WAITING_UPLOAD -> "待上传录音文件";
|
||||
case INITIALIZING -> "数据初始化";
|
||||
case TRANSCRIBING -> "转译音频";
|
||||
case SUMMARIZING -> "生成总结";
|
||||
case COMPLETED -> "处理完成";
|
||||
case FAILED_INITIALIZING -> "数据初始化失败";
|
||||
case FAILED_TRANSCRIBING -> "转译音频失败";
|
||||
case FAILED_SUMMARIZING -> "生成总结失败";
|
||||
};
|
||||
}
|
||||
private boolean canViewTranscript(Long meetingId) {
|
||||
return meetingId != null && meetingTranscriptMapper.selectCount(new LambdaQueryWrapper<MeetingTranscript>()
|
||||
.eq(MeetingTranscript::getMeetingId, meetingId)) > 0;
|
||||
}
|
||||
|
||||
private String resolveFailureMessage(MeetingVO meeting) {
|
||||
if (meeting == null) {
|
||||
return "处理失败";
|
||||
}
|
||||
if (meeting.getLatestSummaryAttemptErrorMsg() != null && !meeting.getLatestSummaryAttemptErrorMsg().isBlank()) {
|
||||
return meeting.getLatestSummaryAttemptErrorMsg();
|
||||
}
|
||||
if (meeting.getLatestChapterAttemptErrorMsg() != null && !meeting.getLatestChapterAttemptErrorMsg().isBlank()) {
|
||||
return meeting.getLatestChapterAttemptErrorMsg();
|
||||
}
|
||||
return "处理失败";
|
||||
}
|
||||
private boolean canViewAiChapters(Long meetingId) {
|
||||
return meetingId != null && chapterVersionMapper.selectCount(new LambdaQueryWrapper<MeetingTranscriptChapterVersion>()
|
||||
.eq(MeetingTranscriptChapterVersion::getMeetingId, meetingId)
|
||||
.eq(MeetingTranscriptChapterVersion::getIsCurrent, 1)
|
||||
.eq(MeetingTranscriptChapterVersion::getStatus, 2)) > 0;
|
||||
}
|
||||
|
||||
private boolean canViewTranscript(Long meetingId) {
|
||||
return meetingId != null && meetingTranscriptMapper.selectCount(new LambdaQueryWrapper<MeetingTranscript>()
|
||||
.eq(MeetingTranscript::getMeetingId, meetingId)) > 0;
|
||||
}
|
||||
private boolean canViewSummary(MeetingVO meeting) {
|
||||
return meeting != null && meeting.getSummaryContent() != null && !meeting.getSummaryContent().isBlank();
|
||||
}
|
||||
|
||||
private boolean canViewAiChapters(Long meetingId) {
|
||||
return meetingId != null && chapterVersionMapper.selectCount(new LambdaQueryWrapper<MeetingTranscriptChapterVersion>()
|
||||
.eq(MeetingTranscriptChapterVersion::getMeetingId, meetingId)
|
||||
.eq(MeetingTranscriptChapterVersion::getIsCurrent, 1)
|
||||
.eq(MeetingTranscriptChapterVersion::getStatus, 2)) > 0;
|
||||
}
|
||||
private AiTask findLatestTask(Long meetingId, String taskType) {
|
||||
return aiTaskMapper.selectOne(new LambdaQueryWrapper<AiTask>()
|
||||
.eq(AiTask::getMeetingId, meetingId)
|
||||
.eq(AiTask::getTaskType, taskType)
|
||||
.orderByDesc(AiTask::getId)
|
||||
.last("LIMIT 1"));
|
||||
}
|
||||
|
||||
private boolean canViewSummary(MeetingVO meeting) {
|
||||
return meeting != null && meeting.getSummaryContent() != null && !meeting.getSummaryContent().isBlank();
|
||||
}
|
||||
private boolean isTaskRunningOrQueued(AiTask task) {
|
||||
return task != null && (Integer.valueOf(0).equals(task.getStatus()) || Integer.valueOf(1).equals(task.getStatus()));
|
||||
}
|
||||
|
||||
private AiTask findLatestTask(Long meetingId, String taskType) {
|
||||
return aiTaskMapper.selectOne(new LambdaQueryWrapper<AiTask>()
|
||||
.eq(AiTask::getMeetingId, meetingId)
|
||||
.eq(AiTask::getTaskType, taskType)
|
||||
.orderByDesc(AiTask::getId)
|
||||
.last("LIMIT 1"));
|
||||
}
|
||||
private boolean isTaskRunning(AiTask task) {
|
||||
return task != null && Integer.valueOf(1).equals(task.getStatus());
|
||||
}
|
||||
|
||||
private boolean isTaskRunningOrQueued(AiTask task) {
|
||||
return task != null && (Integer.valueOf(0).equals(task.getStatus()) || Integer.valueOf(1).equals(task.getStatus()));
|
||||
}
|
||||
private boolean isTaskCompleted(AiTask task) {
|
||||
return task != null && Integer.valueOf(2).equals(task.getStatus());
|
||||
}
|
||||
|
||||
private boolean isTaskRunning(AiTask task) {
|
||||
return task != null && Integer.valueOf(1).equals(task.getStatus());
|
||||
}
|
||||
private boolean isTaskFailed(AiTask task) {
|
||||
return task != null && Integer.valueOf(3).equals(task.getStatus());
|
||||
}
|
||||
|
||||
private boolean isTaskCompleted(AiTask task) {
|
||||
return task != null && Integer.valueOf(2).equals(task.getStatus());
|
||||
}
|
||||
private MeetingVO toMeetingVO(Meeting meeting) {
|
||||
MeetingVO vo = new MeetingVO();
|
||||
vo.setId(meeting.getId());
|
||||
vo.setTenantId(meeting.getTenantId());
|
||||
vo.setCreatorId(meeting.getCreatorId());
|
||||
vo.setCreatorName(meeting.getCreatorName());
|
||||
vo.setHostUserId(meeting.getHostUserId());
|
||||
vo.setHostName(meeting.getHostName());
|
||||
vo.setTitle(meeting.getTitle());
|
||||
vo.setMeetingTime(meeting.getMeetingTime());
|
||||
vo.setParticipants(meeting.getParticipants());
|
||||
vo.setTags(meeting.getTags());
|
||||
vo.setAudioUrl(meeting.getAudioUrl());
|
||||
vo.setMeetingType(meeting.getMeetingType());
|
||||
vo.setMeetingSource(meeting.getMeetingSource());
|
||||
vo.setSourceDeviceCode(meeting.getSourceDeviceCode());
|
||||
vo.setSourceDeviceMode(meeting.getSourceDeviceMode());
|
||||
vo.setOfflineRecordingStatus(meeting.getOfflineRecordingStatus());
|
||||
vo.setSummaryDetailLevel(meeting.getSummaryDetailLevel());
|
||||
vo.setAudioSaveStatus(meeting.getAudioSaveStatus());
|
||||
vo.setAudioSaveMessage(meeting.getAudioSaveMessage());
|
||||
vo.setAccessPassword(meeting.getAccessPassword());
|
||||
vo.setEffectiveAudioDurationSeconds(meeting.getEffectiveAudioDurationSeconds());
|
||||
vo.setStatus(meeting.getStatus());
|
||||
vo.setCreatedAt(meeting.getCreatedAt());
|
||||
return vo;
|
||||
}
|
||||
|
||||
private boolean isTaskFailed(AiTask task) {
|
||||
return task != null && Integer.valueOf(3).equals(task.getStatus());
|
||||
}
|
||||
|
||||
private MeetingVO toMeetingVO(Meeting meeting) {
|
||||
MeetingVO vo = new MeetingVO();
|
||||
vo.setId(meeting.getId());
|
||||
vo.setTenantId(meeting.getTenantId());
|
||||
vo.setCreatorId(meeting.getCreatorId());
|
||||
vo.setCreatorName(meeting.getCreatorName());
|
||||
vo.setHostUserId(meeting.getHostUserId());
|
||||
vo.setHostName(meeting.getHostName());
|
||||
vo.setTitle(meeting.getTitle());
|
||||
vo.setMeetingTime(meeting.getMeetingTime());
|
||||
vo.setParticipants(meeting.getParticipants());
|
||||
vo.setTags(meeting.getTags());
|
||||
vo.setAudioUrl(meeting.getAudioUrl());
|
||||
vo.setMeetingType(meeting.getMeetingType());
|
||||
vo.setMeetingSource(meeting.getMeetingSource());
|
||||
vo.setSourceDeviceCode(meeting.getSourceDeviceCode());
|
||||
vo.setSourceDeviceMode(meeting.getSourceDeviceMode());
|
||||
vo.setOfflineRecordingStatus(meeting.getOfflineRecordingStatus());
|
||||
vo.setSummaryDetailLevel(meeting.getSummaryDetailLevel());
|
||||
vo.setAudioSaveStatus(meeting.getAudioSaveStatus());
|
||||
vo.setAudioSaveMessage(meeting.getAudioSaveMessage());
|
||||
vo.setAccessPassword(meeting.getAccessPassword());
|
||||
vo.setEffectiveAudioDurationSeconds(meeting.getEffectiveAudioDurationSeconds());
|
||||
vo.setStatus(meeting.getStatus());
|
||||
vo.setCreatedAt(meeting.getCreatedAt());
|
||||
return vo;
|
||||
}
|
||||
|
||||
private record MeetingUnifiedStageContext(AiTask asrTask,
|
||||
AiTask chapterTask,
|
||||
AiTask summaryTask,
|
||||
MeetingProgressSnapshot snapshot) {
|
||||
}
|
||||
private record MeetingUnifiedStageContext(AiTask asrTask,
|
||||
AiTask chapterTask,
|
||||
AiTask summaryTask,
|
||||
MeetingProgressSnapshot snapshot) {
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ const MeetingDetailPage = lazy(() => import("@/pages/meeting-detail"));
|
|||
const MeetingPreviewPage = lazy(() => import("@/pages/meeting-preview"));
|
||||
const ProfilePage = lazy(() => import("@/pages/profile"));
|
||||
const PasswordPage = lazy(() => import("@/pages/password"));
|
||||
const AboutPage = lazy(() => import("@/pages/about"));
|
||||
const ScanConfirmPage = lazy(() => import("@/pages/scan-confirm"));
|
||||
|
||||
function HomeRedirect() {
|
||||
|
|
@ -67,16 +66,6 @@ export default function App() {
|
|||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/about"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<MainLayout>
|
||||
<AboutPage />
|
||||
</MainLayout>
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/scan-confirm/:sessionId"
|
||||
element={
|
||||
|
|
|
|||
|
|
@ -1,31 +0,0 @@
|
|||
import { Card, Typography } from "antd";
|
||||
|
||||
import { usePlatformConfig } from "@/components/PlatformConfigProvider";
|
||||
import usePageTitle from "@/hooks/usePageTitle";
|
||||
import PageHeader from "@/components/PageHeader";
|
||||
|
||||
const { Paragraph, Title } = Typography;
|
||||
|
||||
export default function AboutPage() {
|
||||
const { platformConfig } = usePlatformConfig();
|
||||
usePageTitle("关于我们");
|
||||
|
||||
return (
|
||||
<div className="page-stack">
|
||||
<PageHeader title="关于我们" back />
|
||||
<Card className="surface-card">
|
||||
<Title level={4}>{platformConfig?.projectName || "iMeeting H5"}</Title>
|
||||
<Paragraph>
|
||||
iMeeting H5 是面向移动端的会议查看入口,提供登录、我的会议、会议详情、分享预览、安卓扫码确认与个人中心等能力。
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
第一版页面以快速访问和移动端阅读体验为优先,聚焦“查看”和“确认”两类核心动作,不混入后台管理功能。
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
联系邮箱:support@imeeting.example.com
|
||||
</Paragraph>
|
||||
<Paragraph type="secondary">{platformConfig?.copyrightInfo || "Copyright © iMeeting"}</Paragraph>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { App, Avatar, Button, Card, Space, Typography } from "antd";
|
||||
import {App, Avatar, Button, Card, Modal, Space, Typography} from "antd";
|
||||
import { InfoCircleOutlined, LockOutlined, LogoutOutlined, RightOutlined } from "@ant-design/icons";
|
||||
import { useEffect, useState, type ReactNode } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
|
@ -6,6 +6,7 @@ import { useNavigate } from "react-router-dom";
|
|||
import { getCurrentUser } from "@/api/user";
|
||||
import LoadingScreen from "@/components/LoadingScreen";
|
||||
import PageHeader from "@/components/PageHeader";
|
||||
import {usePlatformConfig} from "@/components/PlatformConfigProvider";
|
||||
import usePageTitle from "@/hooks/usePageTitle";
|
||||
import type { UserProfile } from "@/types";
|
||||
import { clearAuth, saveProfile } from "@/utils/auth";
|
||||
|
|
@ -38,9 +39,11 @@ function ProfileAction({
|
|||
export default function ProfilePage() {
|
||||
const { message } = App.useApp();
|
||||
const navigate = useNavigate();
|
||||
const {platformConfig} = usePlatformConfig();
|
||||
usePageTitle("个人中心");
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [profile, setProfile] = useState<UserProfile | null>(null);
|
||||
const [aboutVisible, setAboutVisible] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const loadProfile = async () => {
|
||||
|
|
@ -95,7 +98,7 @@ export default function ProfilePage() {
|
|||
<Card className="surface-card">
|
||||
<Space direction="vertical" size={12} style={{ width: "100%" }}>
|
||||
<ProfileAction icon={<LockOutlined />} label="个人设置" onClick={() => navigate("/profile/password")} />
|
||||
<ProfileAction icon={<InfoCircleOutlined />} label="关于我们" onClick={() => navigate("/about")} />
|
||||
<ProfileAction icon={<InfoCircleOutlined/>} label="关于我们" onClick={() => setAboutVisible(true)}/>
|
||||
<ProfileAction icon={<LogoutOutlined />} label="退出当前账号" onClick={handleLogout} danger />
|
||||
</Space>
|
||||
</Card>
|
||||
|
|
@ -103,6 +106,40 @@ export default function ProfilePage() {
|
|||
<Paragraph type="secondary" className="profile-footer">
|
||||
登录用户可直接查看自己的会议详情。分享给外部访问者时,可在会议详情中单独设置访问密码。
|
||||
</Paragraph>
|
||||
|
||||
<Modal
|
||||
title="关于我们"
|
||||
open={aboutVisible}
|
||||
onCancel={() => setAboutVisible(false)}
|
||||
footer={null}
|
||||
centered
|
||||
width="90%"
|
||||
styles={{body: {textAlign: "center", padding: "24px 16px"}}}
|
||||
>
|
||||
{/*<img src={platformConfig?.logoUrl || "/logo.svg"} alt="logo" style={{ width: 64, height: 64, marginBottom: 16 }} />*/}
|
||||
<Title level={4} style={{marginBottom: 20}}>
|
||||
{platformConfig?.projectName || "iMeeting H5"}
|
||||
</Title>
|
||||
{/*<Paragraph type="secondary" style={{ marginBottom: 16 }}>*/}
|
||||
{/* 版本号:v0.1.0*/}
|
||||
{/*</Paragraph>*/}
|
||||
<Paragraph style={{textAlign: "left"}}>
|
||||
智听云由紫光汇紫信息技术有限公司倾力打
|
||||
造,是一款专注企业级智能会议体验的AI助
|
||||
手。我们支持实时语音转写、内容智能摘要
|
||||
与会议纪要自动生成,显著提升会议效率与
|
||||
信息沉淀能力。
|
||||
</Paragraph>
|
||||
{/*<Paragraph style={{ textAlign: "left" }}>*/}
|
||||
{/* 第一版页面以快速访问和移动端阅读体验为优先,聚焦“查看”和“确认”两类核心动作,不混入后台管理功能。*/}
|
||||
{/*</Paragraph>*/}
|
||||
{/*<Paragraph style={{ textAlign: "left", marginBottom: 24 }}>*/}
|
||||
{/* 联系邮箱:support@imeeting.example.com*/}
|
||||
{/*</Paragraph>*/}
|
||||
<Paragraph type="secondary" style={{fontSize: "12px"}}>
|
||||
{platformConfig?.copyrightInfo || "Copyright © iMeeting"}
|
||||
</Paragraph>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue