diff --git a/backend/src/main/java/com/imeeting/mapper/LicenseMapper.java b/backend/src/main/java/com/imeeting/mapper/LicenseMapper.java index 54e78eb..9788825 100644 --- a/backend/src/main/java/com/imeeting/mapper/LicenseMapper.java +++ b/backend/src/main/java/com/imeeting/mapper/LicenseMapper.java @@ -220,4 +220,14 @@ public interface LicenseMapper extends BaseMapper { AND is_deleted = 0 """) int invalidateById(@Param("id") Long id); + + @InterceptorIgnore(tenantLine = "true") + @Update(""" + UPDATE biz_license + SET is_deleted = 1, + updated_at = CURRENT_TIMESTAMP + WHERE tenant_id = #{tenantId} + AND is_deleted = 0 + """) + int logicalDeleteByTenantId(@Param("tenantId") Long tenantId); } diff --git a/backend/src/main/java/com/imeeting/mapper/biz/MeetingPointsAccountMapper.java b/backend/src/main/java/com/imeeting/mapper/biz/MeetingPointsAccountMapper.java index 99d6050..c981056 100644 --- a/backend/src/main/java/com/imeeting/mapper/biz/MeetingPointsAccountMapper.java +++ b/backend/src/main/java/com/imeeting/mapper/biz/MeetingPointsAccountMapper.java @@ -5,6 +5,7 @@ import com.imeeting.entity.biz.MeetingPointsAccount; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Update; @Mapper public interface MeetingPointsAccountMapper extends BaseMapper { @@ -18,4 +19,13 @@ public interface MeetingPointsAccountMapper extends BaseMapper { + @Update(""" + UPDATE biz_meeting_points_ledgers + SET is_deleted = 1, + updated_at = CURRENT_TIMESTAMP + WHERE tenant_id = #{tenantId} + AND is_deleted = 0 + """) + int logicalDeleteByTenantId(@Param("tenantId") Long tenantId); } diff --git a/backend/src/main/java/com/imeeting/mapper/biz/MeetingSummaryChargeRecordMapper.java b/backend/src/main/java/com/imeeting/mapper/biz/MeetingSummaryChargeRecordMapper.java index 11209dd..ce26f87 100644 --- a/backend/src/main/java/com/imeeting/mapper/biz/MeetingSummaryChargeRecordMapper.java +++ b/backend/src/main/java/com/imeeting/mapper/biz/MeetingSummaryChargeRecordMapper.java @@ -5,6 +5,7 @@ import com.imeeting.entity.biz.MeetingSummaryChargeRecord; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Update; @Mapper public interface MeetingSummaryChargeRecordMapper extends BaseMapper { @@ -17,4 +18,13 @@ public interface MeetingSummaryChargeRecordMapper extends BaseMapper { @@ -17,4 +19,14 @@ public interface TenantMeetingPointsSettingMapper extends BaseMapper> listTenants(Integer current, Integer size, String name, String code) { - if (isSingleTenantMode()) { - SysTenantDTO defaultTenant = sysTenantService.findById(getDefaultTenantId()); - PageResult> result = new PageResult<>(); - result.setRecords(defaultTenant == null ? List.of() : List.of(defaultTenant)); - result.setTotal(defaultTenant == null ? 0 : 1); - return result; - } - return sysTenantService.page(current, size, name, code); + return delegate.listTenants(current, size, name, code); } @Override public SysTenantDTO getTenant(Long tenantId) { - return sysTenantService.findById(tenantId); + return delegate.getTenant(tenantId); } @Override @Transactional(rollbackFor = Exception.class) public Long createTenant(CreateTenantDTO tenant) { - assertTenantLifecycleAllowed(); - Long tenantId = sysTenantService.createTenantWithAdmin(tenant); + Long tenantId = delegate.createTenant(tenant); licenseService.initializeTemporaryLicenses(tenantId); meetingPointsService.initializeTenantPointsAccount(tenantId); tenantMeetingPointsSettingService.initializeTenantSetting(tenantId); @@ -68,55 +75,25 @@ public class TenantManagementServicePrimaryImpl implements TenantManagementServi @Override public boolean updateTenant(Long tenantId, SysTenantDTO tenant) { - assertDefaultTenantCanBeUpdated(tenantId, tenant == null ? null : tenant.getStatus()); - if (tenant == null) { - throw new IllegalArgumentException("租户信息不能为空"); - } - tenant.setId(tenantId); - return sysTenantService.update(tenant); + return delegate.updateTenant(tenantId, tenant); } @Override + @Transactional(rollbackFor = Exception.class) public boolean deleteTenant(Long tenantId) { - assertTenantLifecycleAllowed(); - return sysTenantService.deleteById(tenantId); + boolean deleted = delegate.deleteTenant(tenantId); + if (!deleted || tenantId == null) { + return deleted; + } + logicalDeleteTenantBizData(tenantId); + return true; } - private boolean isSingleTenantMode() { - if (unisBaseProperties == null || unisBaseProperties.getTenant() == null) { - return false; - } - String mode = unisBaseProperties.getTenant().getMode(); - if (mode != null && !mode.isBlank()) { - return "single".equalsIgnoreCase(mode.trim()); - } - return !unisBaseProperties.getTenant().isEnabled(); - } - - private Long getDefaultTenantId() { - if (unisBaseProperties == null || unisBaseProperties.getTenant() == null) { - return DEFAULT_TENANT_ID; - } - Long configured = unisBaseProperties.getTenant().getDefaultTenantId(); - return configured == null || configured <= 0 ? DEFAULT_TENANT_ID : configured; - } - - private void assertTenantLifecycleAllowed() { - if (isSingleTenantMode()) { - throw new IllegalArgumentException("当前为单租户模式,不支持租户生命周期操作"); - } - } - - private void assertDefaultTenantCanBeUpdated(Long tenantId, Integer status) { - if (!isSingleTenantMode()) { - return; - } - Long defaultTenantId = getDefaultTenantId(); - if (!defaultTenantId.equals(tenantId)) { - throw new IllegalArgumentException("当前为单租户模式,只允许维护默认租户"); - } - if (status != null && status != 1) { - throw new IllegalArgumentException("当前为单租户模式,不允许禁用默认租户"); - } + private void logicalDeleteTenantBizData(Long tenantId) { + tenantMeetingPointsSettingMapper.logicalDeleteByTenantId(tenantId); + meetingPointsLedgerMapper.logicalDeleteByTenantId(tenantId); + meetingSummaryChargeRecordMapper.logicalDeleteByTenantId(tenantId); + meetingPointsAccountMapper.logicalDeleteByTenantId(tenantId); + licenseMapper.logicalDeleteByTenantId(tenantId); } } diff --git a/frontend/src/pages/business/Meetings.tsx b/frontend/src/pages/business/Meetings.tsx index 53f1eb5..9eac195 100644 --- a/frontend/src/pages/business/Meetings.tsx +++ b/frontend/src/pages/business/Meetings.tsx @@ -115,7 +115,18 @@ const shouldTrackGenerationProgress = (item: MeetingVO) => !hasLatestGenerationFailure(item) && (item.status === 0 || item.status === 1 || item.status === 2); const isTerminalMeetingProgress = (progress?: MeetingProgress | null) => - !!progress && (progress.percent === 100 || progress.percent < 0); + !!progress && ( + progress.percent === 100 + || progress.percent < 0 + || progress.unifiedStatus?.statusCode === "COMPLETED" + || progress.unifiedStatus?.statusCode?.startsWith("FAILED_") + ); + +const isUnifiedTerminalProgress = (progress?: MeetingProgress | null) => + !!progress && ( + progress.unifiedStatus?.statusCode === "COMPLETED" + || progress.unifiedStatus?.statusCode?.startsWith("FAILED_") + ); const shouldPollMeetingCard = (item: MeetingVO) => shouldTrackGenerationProgress(item) @@ -212,7 +223,7 @@ const IntegratedStatusTag: React.FC<{ meeting: MeetingVO; progress: MeetingProgr const displayConfig = progress?.unifiedStatus?.statusText ? { ...config, text: progress.unifiedStatus.statusText } : config; - const isProcessing = shouldTrackGenerationProgress(meeting); + const isProcessing = shouldTrackGenerationProgress(meeting) && !isUnifiedTerminalProgress(progress); const percent = isProcessing ? progress?.percent || 0 : 0; return (