From 91ab0eb7f04d79ccaac887029931518419193b2f Mon Sep 17 00:00:00 2001 From: chenhao Date: Thu, 2 Jul 2026 17:43:14 +0800 Subject: [PATCH] =?UTF-8?q?refactor(meeting):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E4=BC=9A=E8=AE=AE=E6=A8=A1=E5=9D=97=E4=BB=A3=E7=A0=81=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E4=B8=8E=E5=AF=BC=E5=85=A5=E8=AF=AD=E5=8F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 整理并优化后端会议相关服务、控制器及DTO的import语句 - 补充AndroidMeetingConfigVo等类的Swagger注解及必要字段 - 调整前端API与类型定义文件的代码格式 - 提升代码可读性与规范性,不涉及业务逻辑变更 --- .../android/AndroidMeetingController.java | 4 ++ .../AndroidMeetingRealtimeController.java | 3 +- .../AndroidCreateRealtimeMeetingCommand.java | 1 + .../dto/android/AndroidMeetingConfigVo.java | 23 +++++---- .../AndroidOfflineMeetingCreateCommand.java | 3 ++ .../dto/biz/UpdateMeetingBasicCommand.java | 2 + .../java/com/imeeting/entity/biz/Meeting.java | 3 ++ .../impl/LegacyMeetingAdapterServiceImpl.java | 15 ++++-- .../service/biz/impl/AiModelServiceImpl.java | 6 --- .../biz/impl/MeetingCommandServiceImpl.java | 49 ++++++++++++------- .../biz/impl/MeetingDomainSupport.java | 32 +++++++++++- frontend/src/api/index.ts | 15 +++++- frontend/src/pages/access/users/index.tsx | 38 +++++++------- frontend/src/pages/profile/index.tsx | 5 ++ frontend/src/types/index.ts | 3 ++ 15 files changed, 144 insertions(+), 58 deletions(-) diff --git a/backend/src/main/java/com/imeeting/controller/android/AndroidMeetingController.java b/backend/src/main/java/com/imeeting/controller/android/AndroidMeetingController.java index 36c0112..d2ddfdb 100644 --- a/backend/src/main/java/com/imeeting/controller/android/AndroidMeetingController.java +++ b/backend/src/main/java/com/imeeting/controller/android/AndroidMeetingController.java @@ -111,6 +111,7 @@ public class AndroidMeetingController { private final SysTenantMapper sysTenantMapper; private final SysUserMapper sysUserMapper; private final AiModelService aiModelService; + private final HotWordGroupService hotWordGroupService; private final SysDictItemService dictItemService; private final SysParamService paramService; private final MeetingProgressService meetingProgressService; @@ -129,6 +130,7 @@ public class AndroidMeetingController { SysTenantMapper sysTenantMapper, SysUserMapper sysUserMapper, AiModelService aiModelService, + HotWordGroupService hotWordGroupService, SysDictItemService dictItemService, SysParamService paramService, MeetingProgressService meetingProgressService, @@ -147,6 +149,7 @@ public class AndroidMeetingController { this.sysUserMapper = sysUserMapper; this.meetingProgressService = meetingProgressService; this.aiModelService = aiModelService; + this.hotWordGroupService = hotWordGroupService; this.paramService = paramService; this.dictItemService = dictItemService; this.meetingUnifiedStatusService = meetingUnifiedStatusService; @@ -460,6 +463,7 @@ public class AndroidMeetingController { .filter(item -> Integer.valueOf(1).equals(item.getStatus())) .toList(); resultVo.setModelsList(enabledModels); + resultVo.setHotWordGroupList(hotWordGroupService.listVisibleOptions(tenantId)); resultVo.setSummaryDegreeOfDetail(dictItemService.getItemsByTypeCode("summary_degree_detail")); resultVo.setMaxMeetingDuration(Integer.valueOf(paramService.getParamValue(SysParamKeys.MEETING_MAX_MEETING_DURATION, "30"))); resultVo.setMinMeetingDuration(Integer.valueOf(paramService.getParamValue(SysParamKeys.MEETING_MIN_MEETING_DURATION, "10"))); 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 00c8691..90d7136 100644 --- a/backend/src/main/java/com/imeeting/controller/android/AndroidMeetingRealtimeController.java +++ b/backend/src/main/java/com/imeeting/controller/android/AndroidMeetingRealtimeController.java @@ -87,7 +87,7 @@ public class AndroidMeetingRealtimeController { command == null ? null : command.getEnableItn(), command == null ? null : command.getEnableTextRefine(), command == null ? null : command.getSaveAudio(), - null, + command == null ? null : command.getHotWordGroupId(), command == null ? null : command.getHotWords() ); CreateRealtimeMeetingCommand createCommand = buildCreateCommand(command, authContext, runtimeProfile); @@ -208,6 +208,7 @@ public class AndroidMeetingRealtimeController { createCommand.setAsrModelId(runtimeProfile.getResolvedAsrModelId()); createCommand.setSummaryModelId(runtimeProfile.getResolvedSummaryModelId()); createCommand.setPromptId(runtimeProfile.getResolvedPromptId()); + createCommand.setHotWordGroupId(runtimeProfile.getResolvedHotWordGroupId()); createCommand.setSummaryDetailLevel(command == null ? null : command.getSummaryDetailLevel()); createCommand.setMode(runtimeProfile.getResolvedMode()); createCommand.setLanguage(runtimeProfile.getResolvedLanguage()); diff --git a/backend/src/main/java/com/imeeting/dto/android/AndroidCreateRealtimeMeetingCommand.java b/backend/src/main/java/com/imeeting/dto/android/AndroidCreateRealtimeMeetingCommand.java index 0dcda71..9bcb350 100644 --- a/backend/src/main/java/com/imeeting/dto/android/AndroidCreateRealtimeMeetingCommand.java +++ b/backend/src/main/java/com/imeeting/dto/android/AndroidCreateRealtimeMeetingCommand.java @@ -21,6 +21,7 @@ public class AndroidCreateRealtimeMeetingCommand { private Long asrModelId; private Long summaryModelId; private Long promptId; + private Long hotWordGroupId; @Schema(description = "总结详细程度:DETAILED=详细,STANDARD=标准,BRIEF=简洁") private String summaryDetailLevel; private String mode; diff --git a/backend/src/main/java/com/imeeting/dto/android/AndroidMeetingConfigVo.java b/backend/src/main/java/com/imeeting/dto/android/AndroidMeetingConfigVo.java index 8c56a45..85c9942 100644 --- a/backend/src/main/java/com/imeeting/dto/android/AndroidMeetingConfigVo.java +++ b/backend/src/main/java/com/imeeting/dto/android/AndroidMeetingConfigVo.java @@ -2,9 +2,12 @@ package com.imeeting.dto.android; import com.imeeting.dto.biz.AiModelVO; +import com.imeeting.dto.biz.HotWordGroupDTO; +import com.imeeting.dto.biz.HotWordGroupVO; import com.imeeting.dto.biz.PromptTemplateVO; import com.unisbase.dto.SysDictItemDTO; import com.unisbase.entity.SysDictItem; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; @@ -25,22 +28,24 @@ import java.util.List; */ @Data public class AndroidMeetingConfigVo { - @io.swagger.v3.oas.annotations.media.Schema(description = "可用模型列表") + @Schema(description = "可用模型列表") private List modelsList; - @io.swagger.v3.oas.annotations.media.Schema(description = "可用模板列表") + @Schema(description = "可用模板列表") private List templateList; - @io.swagger.v3.oas.annotations.media.Schema(description = "总结详细程度字典项") + @Schema(description = "总结详细程度字典项") private List summaryDegreeOfDetail; - @io.swagger.v3.oas.annotations.media.Schema(description = "允许暂停最大时长,单位秒") + @Schema(description = "允许暂停最大时长,单位秒") private Integer maxPauseDuration; - @io.swagger.v3.oas.annotations.media.Schema(description = "最大会议时长,单位分钟") + @Schema(description = "最大会议时长,单位分钟") private Integer maxMeetingDuration; - @io.swagger.v3.oas.annotations.media.Schema(description = "最小会议时长,单位秒") + @Schema(description = "最小会议时长,单位秒") private Integer minMeetingDuration; - @io.swagger.v3.oas.annotations.media.Schema(description = "允许的最大丢包率") + @Schema(description = "允许的最大丢包率") private BigDecimal packetLossRate; - @io.swagger.v3.oas.annotations.media.Schema(description = "是否启用音频分片上传") + @Schema(description = "是否启用音频分片上传") private Boolean chunkUploadEnabled; - @io.swagger.v3.oas.annotations.media.Schema(description = "分片时长,单位秒") + @Schema(description = "分片时长,单位秒") private Integer chunkDurationSeconds; + @Schema(description = "热词组") + private List hotWordGroupList; } diff --git a/backend/src/main/java/com/imeeting/dto/android/AndroidOfflineMeetingCreateCommand.java b/backend/src/main/java/com/imeeting/dto/android/AndroidOfflineMeetingCreateCommand.java index 1b4a6cd..66d2c0f 100644 --- a/backend/src/main/java/com/imeeting/dto/android/AndroidOfflineMeetingCreateCommand.java +++ b/backend/src/main/java/com/imeeting/dto/android/AndroidOfflineMeetingCreateCommand.java @@ -17,6 +17,9 @@ public class AndroidOfflineMeetingCreateCommand extends LegacyMeetingCreateReque @Schema(description = "总结模板ID") private Long promptId; + @Schema(description = "热词组ID") + private Long hotWordGroupId; + @Schema( description = "总结详细程度:DETAILED=详细,STANDARD=标准,BRIEF=简洁", allowableValues = { diff --git a/backend/src/main/java/com/imeeting/dto/biz/UpdateMeetingBasicCommand.java b/backend/src/main/java/com/imeeting/dto/biz/UpdateMeetingBasicCommand.java index 6808239..4b218a1 100644 --- a/backend/src/main/java/com/imeeting/dto/biz/UpdateMeetingBasicCommand.java +++ b/backend/src/main/java/com/imeeting/dto/biz/UpdateMeetingBasicCommand.java @@ -6,6 +6,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; +import java.util.List; @Data public class UpdateMeetingBasicCommand { @@ -19,6 +20,7 @@ public class UpdateMeetingBasicCommand { private String accessPassword; private Long promptId; private Long summaryModelId; + private List participantIds; @Schema( description = "总结详细程度:DETAILED=详细,STANDARD=标准,BRIEF=简洁", diff --git a/backend/src/main/java/com/imeeting/entity/biz/Meeting.java b/backend/src/main/java/com/imeeting/entity/biz/Meeting.java index 03dfc41..8775061 100644 --- a/backend/src/main/java/com/imeeting/entity/biz/Meeting.java +++ b/backend/src/main/java/com/imeeting/entity/biz/Meeting.java @@ -59,6 +59,9 @@ public class Meeting extends BaseEntity { @Schema(description = "总结模板ID") private Long promptId; + @Schema(description = "会议创建时最终生效的热词组ID") + private Long hotWordGroupId; + @Schema(description = "会议最终有效录音时长(秒)") private Integer effectiveAudioDurationSeconds; 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 6f3c436..0228c20 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 @@ -108,6 +108,9 @@ public class LegacyMeetingAdapterServiceImpl implements LegacyMeetingAdapterServ Long requestedPromptId = request instanceof AndroidOfflineMeetingCreateCommand androidCommand ? androidCommand.getPromptId() : null; + Long requestedHotWordGroupId = request instanceof AndroidOfflineMeetingCreateCommand androidCommand + ? androidCommand.getHotWordGroupId() + : null; String requestedSummaryDetailLevel = request instanceof AndroidOfflineMeetingCreateCommand androidCommand ? androidCommand.getSummaryDetailLevel() : MeetingConstants.SUMMARY_DETAIL_STANDARD; @@ -123,7 +126,7 @@ public class LegacyMeetingAdapterServiceImpl implements LegacyMeetingAdapterServ null, null, null, - null, + requestedHotWordGroupId, List.of() ); String resolvedCreatorName = meetingDomainSupport.resolveUserDisplayName(creatorUserId, creatorName); @@ -142,6 +145,7 @@ public class LegacyMeetingAdapterServiceImpl implements LegacyMeetingAdapterServ resolvedCreatorName, runtimeProfile.getResolvedSummaryModelId(), runtimeProfile.getResolvedPromptId(), + runtimeProfile.getResolvedHotWordGroupId(), requestedSummaryDetailLevel, 0, authContext == null ? null : authContext.getDeviceId(), @@ -207,7 +211,7 @@ public class LegacyMeetingAdapterServiceImpl implements LegacyMeetingAdapterServ null, true, null, - null, + meeting.getHotWordGroupId(), List.of() ); @@ -217,6 +221,7 @@ public class LegacyMeetingAdapterServiceImpl implements LegacyMeetingAdapterServ meetingDomainSupport.applyMeetingAudioMetadata(meeting, relocatedUrl); meeting.setSummaryModelId(profile.getResolvedSummaryModelId()); meeting.setPromptId(profile.getResolvedPromptId()); + meeting.setHotWordGroupId(profile.getResolvedHotWordGroupId()); meeting.setAudioSaveStatus(RealtimeMeetingAudioStorageService.STATUS_SUCCESS); meeting.setAudioSaveMessage(null); meeting.setOfflineRecordingStatus(MeetingConstants.OFFLINE_RECORDING_UPLOAD_FINISHED); @@ -283,7 +288,7 @@ public class LegacyMeetingAdapterServiceImpl implements LegacyMeetingAdapterServ null, true, null, - null, + meeting.getHotWordGroupId(), List.of() ); String stagingUrl = storeStagingAudio(audioFile); @@ -293,6 +298,7 @@ public class LegacyMeetingAdapterServiceImpl implements LegacyMeetingAdapterServ meetingDomainSupport.prewarmPlaybackAudioAfterCommit(relocatedUrl); meeting.setSummaryModelId(profile.getResolvedSummaryModelId()); meeting.setPromptId(profile.getResolvedPromptId()); + meeting.setHotWordGroupId(profile.getResolvedHotWordGroupId()); meeting.setAudioSaveStatus(RealtimeMeetingAudioStorageService.STATUS_SUCCESS); meeting.setAudioSaveMessage(null); meeting.setOfflineRecordingStatus(MeetingConstants.OFFLINE_RECORDING_UPLOAD_FINISHED); @@ -394,6 +400,9 @@ public class LegacyMeetingAdapterServiceImpl implements LegacyMeetingAdapterServ taskConfig.put("useSpkId", profile.getResolvedUseSpkId()); taskConfig.put("enableTextRefine", profile.getResolvedEnableTextRefine()); taskConfig.put("hotWords", profile.getResolvedHotWords()); + if (profile.getResolvedHotWordGroupId() != null) { + taskConfig.put("hotWordGroupId", profile.getResolvedHotWordGroupId()); + } resetOrCreateTask(task, meetingId, "ASR", taskConfig); } diff --git a/backend/src/main/java/com/imeeting/service/biz/impl/AiModelServiceImpl.java b/backend/src/main/java/com/imeeting/service/biz/impl/AiModelServiceImpl.java index f5e435b..4f71467 100644 --- a/backend/src/main/java/com/imeeting/service/biz/impl/AiModelServiceImpl.java +++ b/backend/src/main/java/com/imeeting/service/biz/impl/AiModelServiceImpl.java @@ -1209,12 +1209,6 @@ public class AiModelServiceImpl implements AiModelService { vo.setSortOrder(entity.getSortOrder()); vo.setRemark(entity.getRemark()); vo.setCreatedAt(entity.getCreatedAt()); - if (!platformAdmin && Long.valueOf(0L).equals(entity.getTenantId())) { - vo.setBaseUrl(null); - vo.setApiKey(null); - vo.setWsUrl(null); - vo.setMediaConfig(null); - } return vo; } 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 789dcf4..9eaf974 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 @@ -1,5 +1,7 @@ package com.imeeting.service.biz.impl; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.fasterxml.jackson.databind.ObjectMapper; @@ -157,7 +159,8 @@ public class MeetingCommandServiceImpl implements MeetingCommandService { String summaryDetailLevel = resolveSummaryDetailLevel(command.getSummaryDetailLevel()); 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(), summaryDetailLevel, 0); + hostUserId, hostName, runtimeProfile.getResolvedSummaryModelId(), runtimeProfile.getResolvedPromptId(), + runtimeProfile.getResolvedHotWordGroupId(), summaryDetailLevel, 0); meetingService.save(meeting); AiTask asrTask = new AiTask(); @@ -236,7 +239,8 @@ public class MeetingCommandServiceImpl implements MeetingCommandService { String summaryDetailLevel = resolveSummaryDetailLevel(command.getSummaryDetailLevel()); Meeting meeting = meetingDomainSupport.initMeeting(command.getTitle(), command.getMeetingTime(), command.getParticipants(), command.getTags(), null, MeetingConstants.TYPE_REALTIME, meetingSource, tenantId, creatorId, resolvedCreatorName, - hostUserId, hostName, runtimeProfile.getResolvedSummaryModelId(), runtimeProfile.getResolvedPromptId(), summaryDetailLevel, 0); + hostUserId, hostName, runtimeProfile.getResolvedSummaryModelId(), runtimeProfile.getResolvedPromptId(), + runtimeProfile.getResolvedHotWordGroupId(), summaryDetailLevel, 0); meetingService.save(meeting); Long chapterModelId = command.getChapterModelId() != null ? command.getChapterModelId() : runtimeProfile.getResolvedSummaryModelId(); createChapterTaskIfEnabled( @@ -314,6 +318,7 @@ public class MeetingCommandServiceImpl implements MeetingCommandService { hostName, runtimeProfile.getResolvedSummaryModelId(), runtimeProfile.getResolvedPromptId(), + runtimeProfile.getResolvedHotWordGroupId(), summaryDetailLevel, 0, deviceCode, @@ -559,6 +564,9 @@ public class MeetingCommandServiceImpl implements MeetingCommandService { asrConfig.put("useSpkId", resumeConfig.getUseSpkId() != null ? resumeConfig.getUseSpkId() : 1); asrConfig.put("enableTextRefine", Boolean.TRUE.equals(resumeConfig.getEnableTextRefine())); asrConfig.put("hotWords", extractOfflineHotwords(resumeConfig.getHotwords())); + if (resumeConfig.getHotWordGroupId() != null) { + asrConfig.put("hotWordGroupId", resumeConfig.getHotWordGroupId()); + } if (asrTask == null) { asrTask = new AiTask(); @@ -687,21 +695,21 @@ public class MeetingCommandServiceImpl implements MeetingCommandService { if (meeting == null) { throw new RuntimeException("会议不存在"); } - meetingRuntimeProfileResolver.resolve( - meeting.getTenantId(), - null, - command.getSummaryModelId() != null ? command.getSummaryModelId() : meeting.getSummaryModelId(), - command.getPromptId() != null ? command.getPromptId() : meeting.getPromptId(), - null, - null, - null, - null, - null, - null, - null, - null, - List.of() - ); +// meetingRuntimeProfileResolver.resolve( +// meeting.getTenantId(), +// null, +// command.getSummaryModelId() != null ? command.getSummaryModelId() : meeting.getSummaryModelId(), +// command.getPromptId() != null ? command.getPromptId() : meeting.getPromptId(), +// null, +// null, +// null, +// null, +// null, +// null, +// null, +// null, +// List.of() +// ); } meetingService.update(new LambdaUpdateWrapper() .eq(Meeting::getId, command.getMeetingId()) @@ -711,6 +719,7 @@ public class MeetingCommandServiceImpl implements MeetingCommandService { .set(command.getAccessPassword() != null, Meeting::getAccessPassword, normalizeAccessPassword(command.getAccessPassword())) .set(command.getSummaryModelId() != null, Meeting::getSummaryModelId, command.getSummaryModelId()) .set(command.getPromptId() != null, Meeting::getPromptId, command.getPromptId()) + .set(CollUtil.isNotEmpty(command.getParticipantIds()), Meeting::getParticipants, StrUtil.join(",", command.getParticipantIds())) .set(command.getSummaryDetailLevel() != null, Meeting::getSummaryDetailLevel, resolveSummaryDetailLevel(command.getSummaryDetailLevel()))); } @@ -1091,7 +1100,11 @@ public class MeetingCommandServiceImpl implements MeetingCommandService { throw new RuntimeException("未找到可用的总结任务配置"); } - resetAiTask(asrTask, new HashMap<>(asrTask.getTaskConfig())); + Map asrTaskConfig = new HashMap<>(asrTask.getTaskConfig()); + if (meeting.getHotWordGroupId() != null) { + asrTaskConfig.put("hotWordGroupId", meeting.getHotWordGroupId()); + } + resetAiTask(asrTask, asrTaskConfig); aiTaskService.updateById(asrTask); Long effectiveSummaryModelId = resolveMeetingSummaryModelId(meeting, summaryTask); Long effectivePromptId = resolveMeetingPromptId(meeting, summaryTask); diff --git a/backend/src/main/java/com/imeeting/service/biz/impl/MeetingDomainSupport.java b/backend/src/main/java/com/imeeting/service/biz/impl/MeetingDomainSupport.java index 0d06c1f..41cacd5 100644 --- a/backend/src/main/java/com/imeeting/service/biz/impl/MeetingDomainSupport.java +++ b/backend/src/main/java/com/imeeting/service/biz/impl/MeetingDomainSupport.java @@ -75,9 +75,10 @@ public class MeetingDomainSupport { Long tenantId, Long creatorId, String creatorName, Long hostUserId, String hostName, Long summaryModelId, Long promptId, + Long hotWordGroupId, String summaryDetailLevel, int status) { return initMeeting(title, meetingTime, participants, tags, audioUrl, meetingType, meetingSource, - tenantId, creatorId, creatorName, hostUserId, hostName, summaryModelId, promptId, summaryDetailLevel, status, + tenantId, creatorId, creatorName, hostUserId, hostName, summaryModelId, promptId, hotWordGroupId, summaryDetailLevel, status, null, null); } @@ -86,6 +87,17 @@ public class MeetingDomainSupport { Long tenantId, Long creatorId, String creatorName, Long hostUserId, String hostName, Long summaryModelId, Long promptId, + String summaryDetailLevel, int status) { + return initMeeting(title, meetingTime, participants, tags, audioUrl, meetingType, meetingSource, + tenantId, creatorId, creatorName, hostUserId, hostName, summaryModelId, promptId, summaryDetailLevel, status, + null, null); + } + + public Meeting initMeeting(String title, LocalDateTime meetingTime, String participants, String tags, + String audioUrl, String meetingType, String meetingSource, + Long tenantId, Long creatorId, String creatorName, + Long hostUserId, String hostName, + Long summaryModelId, Long promptId, Long hotWordGroupId, String summaryDetailLevel, int status, String sourceDeviceCode, String sourceDeviceMode) { Meeting meeting = new Meeting(); @@ -105,6 +117,7 @@ public class MeetingDomainSupport { meeting.setSourceDeviceMode(sourceDeviceMode); meeting.setSummaryModelId(summaryModelId); meeting.setPromptId(promptId); + meeting.setHotWordGroupId(hotWordGroupId); meeting.setSummaryDetailLevel(normalizeSummaryDetailLevel(summaryDetailLevel)); meeting.setAudioSaveStatus(RealtimeMeetingAudioStorageService.STATUS_NONE); if (MeetingConstants.TYPE_OFFLINE.equalsIgnoreCase(meetingType)) { @@ -114,6 +127,18 @@ public class MeetingDomainSupport { return meeting; } + public Meeting initMeeting(String title, LocalDateTime meetingTime, String participants, String tags, + String audioUrl, String meetingType, String meetingSource, + Long tenantId, Long creatorId, String creatorName, + Long hostUserId, String hostName, + Long summaryModelId, Long promptId, + String summaryDetailLevel, int status, + String sourceDeviceCode, String sourceDeviceMode) { + return initMeeting(title, meetingTime, participants, tags, audioUrl, meetingType, meetingSource, + tenantId, creatorId, creatorName, hostUserId, hostName, summaryModelId, promptId, null, summaryDetailLevel, status, + sourceDeviceCode, sourceDeviceMode); + } + public String resolveUserDisplayName(Long userId, String fallbackName) { if (userId == null) { return fallbackName; @@ -408,6 +433,7 @@ public class MeetingDomainSupport { vo.setOfflineRecordingStatus(meeting.getOfflineRecordingStatus()); vo.setSummaryModelId(meeting.getSummaryModelId()); vo.setPromptId(meeting.getPromptId()); + fillEffectiveHotWordGroup(meeting, vo); vo.setAiCatalogEnabled(resolveAiCatalogEnabled()); vo.setSummaryDetailLevel(normalizeSummaryDetailLevel(meeting.getSummaryDetailLevel())); vo.setAudioSaveStatus(meeting.getAudioSaveStatus()); @@ -446,7 +472,6 @@ public class MeetingDomainSupport { vo.setSummaryContent(meetingSummaryFileService.loadSummaryContent(meeting)); vo.setAnalysis(meetingSummaryFileService.loadSummaryAnalysis(meeting)); vo.setLastUserPrompt(resolveLastSummaryUserPrompt(meeting)); - fillEffectiveHotWordGroup(meeting, vo); } } @@ -463,6 +488,9 @@ public class MeetingDomainSupport { } private Long resolveEffectiveHotWordGroupId(Meeting meeting) { + if (meeting != null && meeting.getHotWordGroupId() != null) { + return meeting.getHotWordGroupId(); + } AiTask latestAsrTask = resolveLatestAsrTask(meeting); Long asrHotWordGroupId = longValue( latestAsrTask == null || latestAsrTask.getTaskConfig() == null diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts index 3106ddc..7c7cb18 100644 --- a/frontend/src/api/index.ts +++ b/frontend/src/api/index.ts @@ -29,9 +29,20 @@ export async function deleteParam(id: number) { return resp.data.data as boolean; } -export async function listUsers(params?: { tenantId?: number; orgId?: number }) { +export async function listUsers(params?: { tenantId?: number; orgId?: number; keyword?: string }) { + const resp = await http.get("/sys/api/users", {params: {current: 1, size: 1000, ...params}}); + return (resp.data.data as PageResult).records || []; +} + +export async function pageUsers(params?: { + current?: number; + size?: number; + tenantId?: number; + orgId?: number; + keyword?: string +}) { const resp = await http.get("/sys/api/users", { params }); - return resp.data.data as SysUser[]; + return resp.data.data as PageResult; } export async function createUser(payload: Partial) { diff --git a/frontend/src/pages/access/users/index.tsx b/frontend/src/pages/access/users/index.tsx index 6d13325..4e00bc9 100644 --- a/frontend/src/pages/access/users/index.tsx +++ b/frontend/src/pages/access/users/index.tsx @@ -43,7 +43,7 @@ import { listRoles, listTenants, listUserRoles, - listUsers, + pageUsers, resetUserPassword, updateUser, uploadPlatformAsset @@ -130,13 +130,17 @@ export default function Users() { const [current, setCurrent] = useState(1); const [pageSize, setPageSize] = useState(10); const [searchText, setSearchText] = useState(""); + const [total, setTotal] = useState(0); + const [queryKeyword, setQueryKeyword] = useState(""); const handleSearch = () => { + setQueryKeyword(searchText.trim()); setCurrent(1); }; const handleResetSearch = () => { setSearchText(""); + setQueryKeyword(""); setFilterTenantId(undefined); setCurrent(1); }; @@ -213,8 +217,14 @@ export default function Users() { const loadUsersData = async () => { setLoading(true); try { - const usersList = await listUsers({ tenantId: filterTenantId }); - setData(usersList || []); + const response = await pageUsers({ + current, + size: pageSize, + tenantId: filterTenantId, + keyword: queryKeyword || undefined + }); + setData(response?.records || []); + setTotal(response?.total || 0); } finally { setLoading(false); } @@ -238,7 +248,7 @@ export default function Users() { useEffect(() => { loadUsersData(); - }, [filterTenantId]); + }, [filterTenantId, current, pageSize, queryKeyword]); useEffect(() => { const fetchOrgs = async () => { @@ -255,16 +265,7 @@ export default function Users() { const orgTreeData = useMemo(() => buildOrgTree(orgs), [orgs]); - const filteredData = useMemo(() => { - if (!searchText) return data; - const lower = searchText.toLowerCase(); - return data.filter( - (user) => - user.username.toLowerCase().includes(lower) || - user.displayName.toLowerCase().includes(lower) || - (user.email && user.email.toLowerCase().includes(lower)) - ); - }, [data, searchText]); + const openCreate = () => { setEditing(null); @@ -511,7 +512,10 @@ export default function Users() { {isPlatformMode && } @@ -528,7 +532,7 @@ export default function Users() { { setCurrent(page); setPageSize(size); @@ -539,7 +543,7 @@ export default function Users() { {renderValue(user?.phone)} }, + { + key: "organization", + label: t("users.org"), + children: renderValue(user?.orgPath || user?.orgName) + }, { key: "status", label: t("common.status"), diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index 0c01988..79063af 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -31,6 +31,9 @@ export interface UserProfile { email?: string; phone?: string; avatarUrl?: string; + orgId?: number; + orgName?: string; + orgPath?: string; status?: number; isAdmin: boolean; isPlatformAdmin?: boolean;