diff --git a/backend/src/main/java/com/imeeting/common/MeetingConstants.java b/backend/src/main/java/com/imeeting/common/MeetingConstants.java index 23052e8..ce8f171 100644 --- a/backend/src/main/java/com/imeeting/common/MeetingConstants.java +++ b/backend/src/main/java/com/imeeting/common/MeetingConstants.java @@ -4,9 +4,6 @@ public final class MeetingConstants { public static final String TYPE_OFFLINE = "OFFLINE"; public static final String TYPE_REALTIME = "REALTIME"; - public static final String SOURCE_WEB = "WEB"; - public static final String SOURCE_ANDROID = "ANDROID"; - public static final String DEVICE_MODE_PUBLIC = "PUBLIC"; public static final String DEVICE_MODE_PRIVATE = "PRIVATE"; diff --git a/backend/src/main/java/com/imeeting/controller/android/AndroidMeetingRealtimeController.java b/backend/src/main/java/com/imeeting/controller/android/AndroidMeetingRealtimeController.java index 90d7136..fe1c74e 100644 --- a/backend/src/main/java/com/imeeting/controller/android/AndroidMeetingRealtimeController.java +++ b/backend/src/main/java/com/imeeting/controller/android/AndroidMeetingRealtimeController.java @@ -12,6 +12,7 @@ import com.imeeting.dto.biz.RealtimeMeetingCompleteDTO; import com.imeeting.dto.biz.RealtimeMeetingRuntimeProfile; import com.imeeting.dto.biz.RealtimeMeetingSessionStatusVO; import com.imeeting.entity.biz.Meeting; +import com.imeeting.enums.MeetingTerminalEnum; import com.imeeting.service.android.AndroidAuthService; import com.imeeting.service.biz.MeetingAccessService; import com.imeeting.service.biz.MeetingAuthorizationService; @@ -96,7 +97,7 @@ public class AndroidMeetingRealtimeController { authContext.getTenantId(), authContext.getUserId(), resolveCreatorName(authContext), - MeetingConstants.SOURCE_ANDROID + MeetingTerminalEnum.CUSTOM_TERMINAL.getCode() ); RealtimeMeetingSessionStatusVO status = realtimeMeetingSessionStateService.getStatus(meeting.getId()); @@ -166,7 +167,7 @@ public class AndroidMeetingRealtimeController { AndroidRequestLogHelper.logRequest(log, "Android实时会议", "暂停实时会议接口", "meetingId", id); AndroidAuthContext authContext = androidAuthService.authenticateHttp(request); Meeting meeting = meetingAccessService.requireMeeting(id); - meetingAuthorizationService.assertCanControlRealtimeMeeting(meeting, authContext, MeetingConstants.SOURCE_ANDROID); + meetingAuthorizationService.assertCanControlRealtimeMeeting(meeting, authContext, MeetingTerminalEnum.CUSTOM_TERMINAL.getCode()); return ApiResponse.ok(realtimeMeetingSessionStateService.pause(id)); } @@ -185,7 +186,7 @@ public class AndroidMeetingRealtimeController { AndroidRequestLogHelper.logRequest(log, "Android实时会议", "完成实时会议接口", "meetingId", id, "request", dto); AndroidAuthContext authContext = androidAuthService.authenticateHttp(request); Meeting meeting = meetingAccessService.requireMeeting(id); - meetingAuthorizationService.assertCanControlRealtimeMeeting(meeting, authContext, MeetingConstants.SOURCE_ANDROID); + meetingAuthorizationService.assertCanControlRealtimeMeeting(meeting, authContext, MeetingTerminalEnum.CUSTOM_TERMINAL.getCode()); meetingCommandService.completeRealtimeMeeting( id, dto != null ? dto.getAudioUrl() : null, diff --git a/backend/src/main/java/com/imeeting/controller/biz/MeetingController.java b/backend/src/main/java/com/imeeting/controller/biz/MeetingController.java index ea4ef80..a1b048e 100644 --- a/backend/src/main/java/com/imeeting/controller/biz/MeetingController.java +++ b/backend/src/main/java/com/imeeting/controller/biz/MeetingController.java @@ -24,6 +24,7 @@ import com.imeeting.dto.biz.UpdateMeetingSummaryCommand; import com.imeeting.dto.biz.UpdateMeetingTranscriptCommand; import com.imeeting.entity.biz.AiTask; import com.imeeting.entity.biz.Meeting; +import com.imeeting.enums.MeetingTerminalEnum; import com.imeeting.service.biz.AiTaskService; import com.imeeting.service.biz.MeetingAccessService; import com.imeeting.service.biz.MeetingCommandService; @@ -242,7 +243,7 @@ public class MeetingController { loginUser.getTenantId(), loginUser.getUserId(), resolveCreatorName(loginUser), - MeetingConstants.SOURCE_WEB + MeetingTerminalEnum.WEB.getCode() )); } @@ -258,7 +259,7 @@ public class MeetingController { loginUser.getTenantId(), loginUser.getUserId(), resolveCreatorName(loginUser), - MeetingConstants.SOURCE_WEB + MeetingTerminalEnum.WEB.getCode() )); } @@ -405,7 +406,7 @@ public class MeetingController { public ApiResponse pauseRealtimeMeeting(@PathVariable Long id) { LoginUser loginUser = currentLoginUser(); Meeting meeting = meetingAccessService.requireMeeting(id); - meetingAccessService.assertCanControlRealtimeMeeting(meeting, loginUser, MeetingConstants.SOURCE_WEB); + meetingAccessService.assertCanControlRealtimeMeeting(meeting, loginUser, MeetingTerminalEnum.WEB.getCode()); return ApiResponse.ok(realtimeMeetingSessionStateService.pause(id)); } @@ -436,7 +437,7 @@ public class MeetingController { public ApiResponse completeRealtimeMeeting(@PathVariable Long id, @RequestBody(required = false) RealtimeMeetingCompleteDTO dto) { LoginUser loginUser = currentLoginUser(); Meeting meeting = meetingAccessService.requireMeeting(id); - meetingAccessService.assertCanControlRealtimeMeeting(meeting, loginUser, MeetingConstants.SOURCE_WEB); + meetingAccessService.assertCanControlRealtimeMeeting(meeting, loginUser, MeetingTerminalEnum.WEB.getCode()); meetingCommandService.completeRealtimeMeeting( id, dto != null ? dto.getAudioUrl() : null, diff --git a/backend/src/main/java/com/imeeting/dto/biz/CreateMeetingCommand.java b/backend/src/main/java/com/imeeting/dto/biz/CreateMeetingCommand.java index fa96e60..7776e8c 100644 --- a/backend/src/main/java/com/imeeting/dto/biz/CreateMeetingCommand.java +++ b/backend/src/main/java/com/imeeting/dto/biz/CreateMeetingCommand.java @@ -29,7 +29,7 @@ public class CreateMeetingCommand { @NotBlank(message = "音频地址不能为空") private String audioUrl; - @NotNull(message = "asrModelId must not be null") + // @NotNull(message = "asrModelId must not be null") private Long asrModelId; @NotNull(message = "summaryModelId must not be null") diff --git a/backend/src/main/java/com/imeeting/service/android/legacy/impl/LegacyMeetingAdapterServiceImpl.java b/backend/src/main/java/com/imeeting/service/android/legacy/impl/LegacyMeetingAdapterServiceImpl.java index 0228c20..6d5fe98 100644 --- a/backend/src/main/java/com/imeeting/service/android/legacy/impl/LegacyMeetingAdapterServiceImpl.java +++ b/backend/src/main/java/com/imeeting/service/android/legacy/impl/LegacyMeetingAdapterServiceImpl.java @@ -13,6 +13,7 @@ import com.imeeting.entity.biz.AiTask; import com.imeeting.entity.biz.LlmModel; import com.imeeting.entity.biz.Meeting; import com.imeeting.entity.biz.MeetingTranscript; +import com.imeeting.enums.MeetingTerminalEnum; import com.imeeting.enums.MeetingStatusEnum; import com.imeeting.mapper.biz.LlmModelMapper; import com.imeeting.mapper.biz.MeetingTranscriptMapper; @@ -137,7 +138,7 @@ public class LegacyMeetingAdapterServiceImpl implements LegacyMeetingAdapterServ normalizeTags(request.getTags()), null, MeetingConstants.TYPE_OFFLINE, - MeetingConstants.SOURCE_ANDROID, + MeetingTerminalEnum.CUSTOM_TERMINAL.getCode(), tenantId, creatorUserId, resolvedCreatorName, diff --git a/backend/src/main/java/com/imeeting/service/biz/MeetingCommandService.java b/backend/src/main/java/com/imeeting/service/biz/MeetingCommandService.java index f781e87..caebfcc 100644 --- a/backend/src/main/java/com/imeeting/service/biz/MeetingCommandService.java +++ b/backend/src/main/java/com/imeeting/service/biz/MeetingCommandService.java @@ -18,6 +18,14 @@ import java.util.List; public interface MeetingCommandService { MeetingVO createMeeting(CreateMeetingCommand command, Long tenantId, Long creatorId, String creatorName, String meetingSource); + MeetingVO createMeeting(CreateMeetingCommand command, + Long tenantId, + Long creatorId, + String creatorName, + String meetingSource, + String sourceDeviceCode, + String sourceDeviceMode); + MeetingVO createRealtimeMeeting(CreateRealtimeMeetingCommand command, Long tenantId, Long creatorId, String creatorName, String meetingSource); MeetingVO createPublicDeviceMeeting(PublicDeviceMeetingCreateCommand command, diff --git a/backend/src/main/java/com/imeeting/service/biz/impl/MeetingAccessServiceImpl.java b/backend/src/main/java/com/imeeting/service/biz/impl/MeetingAccessServiceImpl.java index bbd4c94..7cb1a74 100644 --- a/backend/src/main/java/com/imeeting/service/biz/impl/MeetingAccessServiceImpl.java +++ b/backend/src/main/java/com/imeeting/service/biz/impl/MeetingAccessServiceImpl.java @@ -2,6 +2,7 @@ package com.imeeting.service.biz.impl; import com.imeeting.common.MeetingConstants; import com.imeeting.entity.biz.Meeting; +import com.imeeting.enums.MeetingTerminalEnum; import com.imeeting.mapper.biz.MeetingMapper; import com.imeeting.service.biz.MeetingAccessService; import com.unisbase.security.LoginUser; @@ -106,6 +107,10 @@ public class MeetingAccessServiceImpl implements MeetingAccessService { if (meeting.getMeetingSource() == null || meeting.getMeetingSource().isBlank()) { return; } + if (MeetingTerminalEnum.isCustomTerminalSource(meeting.getMeetingSource()) + && MeetingTerminalEnum.isCustomTerminalSource(currentPlatform)) { + return; + } if (!meeting.getMeetingSource().equalsIgnoreCase(currentPlatform)) { throw new RuntimeException("不允许跨平台接管实时会议"); } diff --git a/backend/src/main/java/com/imeeting/service/biz/impl/MeetingAuthorizationServiceImpl.java b/backend/src/main/java/com/imeeting/service/biz/impl/MeetingAuthorizationServiceImpl.java index 3d068b4..78cfacd 100644 --- a/backend/src/main/java/com/imeeting/service/biz/impl/MeetingAuthorizationServiceImpl.java +++ b/backend/src/main/java/com/imeeting/service/biz/impl/MeetingAuthorizationServiceImpl.java @@ -3,6 +3,7 @@ package com.imeeting.service.biz.impl; import com.imeeting.common.MeetingConstants; import com.imeeting.dto.android.AndroidAuthContext; import com.imeeting.entity.biz.Meeting; +import com.imeeting.enums.MeetingTerminalEnum; import com.imeeting.service.biz.MeetingAccessService; import com.imeeting.service.biz.MeetingAuthorizationService; import com.unisbase.security.LoginUser; @@ -47,7 +48,7 @@ public class MeetingAuthorizationServiceImpl implements MeetingAuthorizationServ } if (meeting.getMeetingSource() != null && !meeting.getMeetingSource().isBlank() - && !meeting.getMeetingSource().equalsIgnoreCase(currentPlatform)) { + && !isSameRealtimePlatform(meeting.getMeetingSource(), currentPlatform)) { throw new RuntimeException("不允许跨平台接管实时会议"); } return; @@ -74,4 +75,8 @@ public class MeetingAuthorizationServiceImpl implements MeetingAuthorizationServ loginUser.setDisplayName(authContext.getDisplayName()); return loginUser; } + + private boolean isSameRealtimePlatform(String meetingSource, String currentPlatform) { + return MeetingTerminalEnum.isSameTerminal(meetingSource, currentPlatform); + } } diff --git a/backend/src/main/java/com/imeeting/service/biz/impl/MeetingCommandServiceImpl.java b/backend/src/main/java/com/imeeting/service/biz/impl/MeetingCommandServiceImpl.java index 9eaf974..a4f8745 100644 --- a/backend/src/main/java/com/imeeting/service/biz/impl/MeetingCommandServiceImpl.java +++ b/backend/src/main/java/com/imeeting/service/biz/impl/MeetingCommandServiceImpl.java @@ -31,6 +31,7 @@ import com.imeeting.entity.biz.Meeting; import com.imeeting.entity.biz.MeetingTranscript; import com.imeeting.entity.biz.MeetingTranscriptChapterVersion; import com.imeeting.enums.BusinessErrorCodeEnum; +import com.imeeting.enums.MeetingTerminalEnum; import com.imeeting.enums.MeetingStatusEnum; import com.imeeting.service.android.AndroidPendingMeetingDraftService; import com.imeeting.service.android.AndroidPushMessageService; @@ -152,6 +153,18 @@ public class MeetingCommandServiceImpl implements MeetingCommandService { @Override @Transactional(rollbackFor = Exception.class) public MeetingVO createMeeting(CreateMeetingCommand command, Long tenantId, Long creatorId, String creatorName, String meetingSource) { + return createMeeting(command, tenantId, creatorId, creatorName, meetingSource, null, null); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public MeetingVO createMeeting(CreateMeetingCommand command, + Long tenantId, + Long creatorId, + String creatorName, + String meetingSource, + String sourceDeviceCode, + String sourceDeviceMode) { RealtimeMeetingRuntimeProfile runtimeProfile = resolveCreateProfile(command, tenantId); Long hostUserId = resolveHostUserId(command.getHostUserId(), creatorId); String resolvedCreatorName = resolveMeetingUserName(creatorId, creatorName); @@ -160,7 +173,7 @@ public class MeetingCommandServiceImpl implements MeetingCommandService { Meeting meeting = meetingDomainSupport.initMeeting(command.getTitle(), command.getMeetingTime(), command.getParticipants(), command.getTags(), command.getAudioUrl(), MeetingConstants.TYPE_OFFLINE, meetingSource, tenantId, creatorId, resolvedCreatorName, hostUserId, hostName, runtimeProfile.getResolvedSummaryModelId(), runtimeProfile.getResolvedPromptId(), - runtimeProfile.getResolvedHotWordGroupId(), summaryDetailLevel, 0); + runtimeProfile.getResolvedHotWordGroupId(), summaryDetailLevel, 0, sourceDeviceCode, sourceDeviceMode); meetingService.save(meeting); AiTask asrTask = new AiTask(); @@ -310,7 +323,7 @@ public class MeetingCommandServiceImpl implements MeetingCommandService { command.getTags(), null, MeetingConstants.TYPE_OFFLINE, - MeetingConstants.SOURCE_ANDROID, + MeetingTerminalEnum.CUSTOM_TERMINAL.getCode(), tenantId, creatorId, resolvedCreatorName, diff --git a/backend/src/main/java/com/imeeting/service/biz/impl/MeetingUnifiedStatusServiceImpl.java b/backend/src/main/java/com/imeeting/service/biz/impl/MeetingUnifiedStatusServiceImpl.java index 14435c8..a03bdbf 100644 --- a/backend/src/main/java/com/imeeting/service/biz/impl/MeetingUnifiedStatusServiceImpl.java +++ b/backend/src/main/java/com/imeeting/service/biz/impl/MeetingUnifiedStatusServiceImpl.java @@ -11,6 +11,7 @@ import com.imeeting.entity.biz.AiTask; import com.imeeting.entity.biz.Meeting; import com.imeeting.entity.biz.MeetingTranscript; import com.imeeting.entity.biz.MeetingTranscriptChapterVersion; +import com.imeeting.enums.MeetingTerminalEnum; import com.imeeting.enums.MeetingStatusEnum; import com.imeeting.mapper.biz.AiTaskMapper; import com.imeeting.mapper.biz.MeetingMapper; @@ -163,17 +164,23 @@ public class MeetingUnifiedStatusServiceImpl implements MeetingUnifiedStatusServ private boolean isAndroidOfflineEmptyUploadFailure(MeetingVO meeting) { return meeting != null && MeetingConstants.TYPE_OFFLINE.equalsIgnoreCase(meeting.getMeetingType()) - && MeetingConstants.SOURCE_ANDROID.equalsIgnoreCase(meeting.getMeetingSource()) + && MeetingTerminalEnum.isCustomTerminalSource(meeting.getMeetingSource()) + && hasNoAudioUrl(meeting) && "FAILED".equalsIgnoreCase(meeting.getAudioSaveStatus()); } private boolean isAndroidOfflineMeetingWaitingUpload(MeetingVO meeting) { return meeting != null && MeetingConstants.TYPE_OFFLINE.equalsIgnoreCase(meeting.getMeetingType()) - && MeetingConstants.SOURCE_ANDROID.equalsIgnoreCase(meeting.getMeetingSource()) + && MeetingTerminalEnum.isCustomTerminalSource(meeting.getMeetingSource()) + && hasNoAudioUrl(meeting) && !MeetingConstants.OFFLINE_RECORDING_UPLOAD_FINISHED.equalsIgnoreCase(meeting.getOfflineRecordingStatus()); } + private boolean hasNoAudioUrl(MeetingVO meeting) { + return meeting.getAudioUrl() == null || meeting.getAudioUrl().isBlank(); + } + private boolean isSummarizing(MeetingUnifiedStageContext context) { return isTaskRunning(context.summaryTask()) || isTaskRunning(context.chapterTask()) diff --git a/backend/src/main/java/com/imeeting/service/biz/impl/RealtimeMeetingSocketSessionServiceImpl.java b/backend/src/main/java/com/imeeting/service/biz/impl/RealtimeMeetingSocketSessionServiceImpl.java index 636d696..c975015 100644 --- a/backend/src/main/java/com/imeeting/service/biz/impl/RealtimeMeetingSocketSessionServiceImpl.java +++ b/backend/src/main/java/com/imeeting/service/biz/impl/RealtimeMeetingSocketSessionServiceImpl.java @@ -7,6 +7,7 @@ import com.imeeting.dto.biz.RealtimeMeetingSessionStatusVO; import com.imeeting.dto.biz.RealtimeSocketSessionData; import com.imeeting.dto.biz.RealtimeSocketSessionVO; import com.imeeting.entity.biz.Meeting; +import com.imeeting.enums.MeetingTerminalEnum; import com.imeeting.service.biz.AiModelService; import com.imeeting.service.biz.MeetingAccessService; import com.imeeting.service.biz.RealtimeMeetingSessionStateService; @@ -49,7 +50,7 @@ public class RealtimeMeetingSocketSessionServiceImpl implements RealtimeMeetingS } Meeting meeting = meetingAccessService.requireMeeting(meetingId); - meetingAccessService.assertCanControlRealtimeMeeting(meeting, loginUser, MeetingConstants.SOURCE_WEB); + meetingAccessService.assertCanControlRealtimeMeeting(meeting, loginUser, MeetingTerminalEnum.WEB.getCode()); realtimeMeetingSessionStateService.initSessionIfAbsent(meetingId, loginUser.getTenantId(), loginUser.getUserId()); realtimeMeetingSessionStateService.assertCanOpenSession(meetingId); diff --git a/backend/src/test/java/com/imeeting/service/biz/impl/MeetingAccessServiceImplTest.java b/backend/src/test/java/com/imeeting/service/biz/impl/MeetingAccessServiceImplTest.java index 7df5833..2738c44 100644 --- a/backend/src/test/java/com/imeeting/service/biz/impl/MeetingAccessServiceImplTest.java +++ b/backend/src/test/java/com/imeeting/service/biz/impl/MeetingAccessServiceImplTest.java @@ -2,6 +2,7 @@ package com.imeeting.service.biz.impl; import com.imeeting.common.MeetingConstants; import com.imeeting.entity.biz.Meeting; +import com.imeeting.enums.MeetingTerminalEnum; import com.imeeting.mapper.biz.MeetingMapper; import com.unisbase.security.LoginUser; import org.junit.jupiter.api.Test; @@ -16,33 +17,41 @@ class MeetingAccessServiceImplTest { @Test void allowsRealtimeControlFromSourcePlatform() { - Meeting meeting = buildMeeting(MeetingConstants.TYPE_REALTIME, MeetingConstants.SOURCE_ANDROID); + Meeting meeting = buildMeeting(MeetingConstants.TYPE_REALTIME, MeetingTerminalEnum.CUSTOM_TERMINAL.getCode()); + LoginUser loginUser = buildLoginUser(); + + assertDoesNotThrow(() -> service.assertCanControlRealtimeMeeting(meeting, loginUser, MeetingTerminalEnum.CUSTOM_TERMINAL.getCode())); + } + + @Test + void allowsCustomTerminalToControlLegacyAndroidRealtimeMeeting() { + Meeting meeting = buildMeeting(MeetingConstants.TYPE_REALTIME, "ANDROID"); LoginUser loginUser = buildLoginUser(); - assertDoesNotThrow(() -> service.assertCanControlRealtimeMeeting(meeting, loginUser, MeetingConstants.SOURCE_ANDROID)); + assertDoesNotThrow(() -> service.assertCanControlRealtimeMeeting(meeting, loginUser, MeetingTerminalEnum.CUSTOM_TERMINAL.getCode())); } @Test void rejectsCrossPlatformRealtimeControl() { - Meeting meeting = buildMeeting(MeetingConstants.TYPE_REALTIME, MeetingConstants.SOURCE_ANDROID); + Meeting meeting = buildMeeting(MeetingConstants.TYPE_REALTIME, MeetingTerminalEnum.CUSTOM_TERMINAL.getCode()); LoginUser loginUser = buildLoginUser(); assertThrows(RuntimeException.class, - () -> service.assertCanControlRealtimeMeeting(meeting, loginUser, MeetingConstants.SOURCE_WEB)); + () -> service.assertCanControlRealtimeMeeting(meeting, loginUser, MeetingTerminalEnum.WEB.getCode())); } @Test void rejectsRealtimeControlForOfflineMeeting() { - Meeting meeting = buildMeeting(MeetingConstants.TYPE_OFFLINE, MeetingConstants.SOURCE_WEB); + Meeting meeting = buildMeeting(MeetingConstants.TYPE_OFFLINE, MeetingTerminalEnum.WEB.getCode()); LoginUser loginUser = buildLoginUser(); assertThrows(RuntimeException.class, - () -> service.assertCanControlRealtimeMeeting(meeting, loginUser, MeetingConstants.SOURCE_WEB)); + () -> service.assertCanControlRealtimeMeeting(meeting, loginUser, MeetingTerminalEnum.WEB.getCode())); } @Test void allowsParticipantToViewAndExportButNotEdit() { - Meeting meeting = buildMeeting(MeetingConstants.TYPE_OFFLINE, MeetingConstants.SOURCE_WEB); + Meeting meeting = buildMeeting(MeetingConstants.TYPE_OFFLINE, MeetingTerminalEnum.WEB.getCode()); meeting.setParticipants("201,202,203"); LoginUser participant = new LoginUser(202L, 100L, "participant", false, false, null); @@ -54,7 +63,7 @@ class MeetingAccessServiceImplTest { @Test void allowsTenantAdminToEditMeeting() { - Meeting meeting = buildMeeting(MeetingConstants.TYPE_OFFLINE, MeetingConstants.SOURCE_WEB); + Meeting meeting = buildMeeting(MeetingConstants.TYPE_OFFLINE, MeetingTerminalEnum.WEB.getCode()); LoginUser tenantAdmin = new LoginUser(300L, 100L, "tenant-admin", false, true, null); assertDoesNotThrow(() -> service.assertCanEditMeeting(meeting, tenantAdmin)); diff --git a/frontend/public/logo.svg b/frontend/public/logo.svg index 37db905..8423d10 100644 --- a/frontend/public/logo.svg +++ b/frontend/public/logo.svg @@ -1,14 +1,33 @@ - - - - + + + + + - + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/api/business/meeting.ts b/frontend/src/api/business/meeting.ts index aa3e6d9..2df2373 100644 --- a/frontend/src/api/business/meeting.ts +++ b/frontend/src/api/business/meeting.ts @@ -5,6 +5,7 @@ const MEETING_UPLOAD_FLOW_TIMEOUT = 600000; const MEETING_DETAIL_TIMEOUT = 120000; export type SummaryDetailLevel = "DETAILED" | "STANDARD" | "BRIEF"; +export type MeetingSource = "WINDOWS" | "MACOS" | "KYLIN" | "UOS" | "HARMONYOS" | "WEB" | "CUSTOM_TERMINAL" | "ANDROID"; export interface MeetingCreateConfig { offlineEnabled: boolean; @@ -30,7 +31,7 @@ export interface MeetingVO { audioUrl: string; playbackAudioUrl?: string; meetingType?: "OFFLINE" | "REALTIME"; - meetingSource?: "WEB" | "ANDROID"; + meetingSource?: MeetingSource; sourceDeviceCode?: string; sourceDeviceMode?: "PUBLIC" | "PRIVATE"; summaryDetailLevel?: SummaryDetailLevel; diff --git a/frontend/src/pages/business/Meetings.tsx b/frontend/src/pages/business/Meetings.tsx index 6677d99..2e336ae 100644 --- a/frontend/src/pages/business/Meetings.tsx +++ b/frontend/src/pages/business/Meetings.tsx @@ -86,6 +86,16 @@ const DEFAULT_CREATE_CONFIG: MeetingCreateConfig = { realtimeEnabled: true, offlineAudioMaxSizeMb: 1024, }; +const MEETING_SOURCE_LABELS: Record = { + WINDOWS: "Windows", + MACOS: "macOS", + KYLIN: "麒麟", + UOS: "统信", + HARMONYOS: "鸿蒙", + WEB: "Web端", + CUSTOM_TERMINAL: "定制终端", + ANDROID: "定制终端", +}; const isRealtimeMeetingCandidate = (item: MeetingVO) => item.meetingType === "REALTIME" || (!item.meetingType && item.status === 0 && !item.audioUrl); @@ -94,7 +104,7 @@ const canControlRealtimeFromCurrentPlatform = (item: MeetingVO) => !item.meetingSource || item.meetingSource === CURRENT_PLATFORM; const getMeetingSourceLabel = (source?: MeetingVO["meetingSource"]) => - source === "ANDROID" ? "安卓端" : "Web端"; + source ? (MEETING_SOURCE_LABELS[source] ?? source) : MEETING_SOURCE_LABELS.WEB; const getRealtimeSourceLabel = (item: MeetingVO) => getMeetingSourceLabel(item.meetingSource); @@ -313,7 +323,7 @@ const MeetingCardItem: React.FC<{ ? (progress?.message || progress?.unifiedStatus?.message || config.text) : (progress?.unifiedStatus?.message || progress?.message || "深度分析中..."); - const sourceColor = item.meetingSource === "ANDROID" ? "#10b981" : "#3b82f6"; + const sourceColor = item.meetingSource === "CUSTOM_TERMINAL" || item.meetingSource === "ANDROID" ? "#10b981" : "#3b82f6"; return ( diff --git a/frontend/src/pages/business/RealtimeAsrSession.tsx b/frontend/src/pages/business/RealtimeAsrSession.tsx index 807fcaa..255c7d7 100644 --- a/frontend/src/pages/business/RealtimeAsrSession.tsx +++ b/frontend/src/pages/business/RealtimeAsrSession.tsx @@ -29,6 +29,16 @@ import { const SAMPLE_RATE = 16000; const CHUNK_SIZE = 1280; const CURRENT_PLATFORM = "WEB" as const; +const MEETING_SOURCE_LABELS: Record = { + WINDOWS: "Windows", + MACOS: "macOS", + KYLIN: "麒麟", + UOS: "统信", + HARMONYOS: "鸿蒙", + WEB: "Web端", + CUSTOM_TERMINAL: "定制终端", + ANDROID: "定制终端", +}; type WsSpeaker = string | { name?: string; user_id?: string | number } | undefined; type WsMessage = { @@ -283,7 +293,7 @@ export function RealtimeAsrSession() { return; } if (detail.meetingSource && detail.meetingSource !== CURRENT_PLATFORM) { - const sourceLabel = detail.meetingSource === "ANDROID" ? "安卓端" : "Web 端"; + const sourceLabel = MEETING_SOURCE_LABELS[detail.meetingSource] ?? detail.meetingSource; message.warning(`该实时会议需在${sourceLabel}继续,当前仅支持查看详情`); navigate(`/meetings/${meetingId}`); return; diff --git a/frontend/src/pages/home/index.tsx b/frontend/src/pages/home/index.tsx index ae370cd..7465271 100644 --- a/frontend/src/pages/home/index.tsx +++ b/frontend/src/pages/home/index.tsx @@ -36,6 +36,16 @@ type RecentCard = { }; const RECENT_CARD_READ_STORAGE_KEY = "home_recent_card_read_ids"; +const MEETING_SOURCE_LABELS: Record = { + WINDOWS: "Windows", + MACOS: "macOS", + KYLIN: "麒麟", + UOS: "统信", + HARMONYOS: "鸿蒙", + WEB: "Web端", + CUSTOM_TERMINAL: "定制终端", + ANDROID: "定制终端", +}; const fallbackRecentCards: RecentCard[] = [ { @@ -314,7 +324,7 @@ export default function HomePage() {
{recentTaskMap.get(String(card.id))?.meetingSource && ( - {recentTaskMap.get(String(card.id))?.meetingSource === "ANDROID" ? "安卓端" : "Web端"} + {MEETING_SOURCE_LABELS[recentTaskMap.get(String(card.id))?.meetingSource ?? "WEB"] ?? "Web端"} )} {card.tags.slice(0, 4).map((tag) => ( diff --git a/imeeting-h5/src/types/index.ts b/imeeting-h5/src/types/index.ts index 7cd919a..ef4aa45 100644 --- a/imeeting-h5/src/types/index.ts +++ b/imeeting-h5/src/types/index.ts @@ -41,7 +41,7 @@ export interface MeetingVO { playbackAudioUrl?: string; duration?: number; meetingType?: "OFFLINE" | "REALTIME"; - meetingSource?: "WEB" | "ANDROID"; + meetingSource?: "WINDOWS" | "MACOS" | "KYLIN" | "UOS" | "HARMONYOS" | "WEB" | "CUSTOM_TERMINAL" | "ANDROID"; sourceDeviceCode?: string; sourceDeviceMode?: "PUBLIC" | "PRIVATE"; summaryDetailLevel?: "DETAILED" | "STANDARD" | "BRIEF";