feat: 添加平台管理员权限和优化会议状态处理逻辑
- 在 `usePermission` 钩子中添加 `isPlatformAdmin` 权限检查 - 在 `TenantMeetingPointsSettings` 页面中根据权限控制按钮显示 - 优化 `MeetingCommandServiceImpl` 和 `MeetingUnifiedStatusServiceImpl` 中的会议状态处理逻辑 - 更新 `Meetings.tsx` 中的会议状态判断逻辑 - 在 `AiTaskServiceImpl` 中添加 `AndroidMeetingPushService` 依赖,并在任务完成或失败时推送会议状态变化dev_na
parent
4572d15bea
commit
3c299aaf3b
|
|
@ -10,6 +10,7 @@ import com.imeeting.common.MeetingProgressStage;
|
||||||
import com.imeeting.dto.biz.AiModelVO;
|
import com.imeeting.dto.biz.AiModelVO;
|
||||||
import com.imeeting.dto.biz.MeetingSummarySource;
|
import com.imeeting.dto.biz.MeetingSummarySource;
|
||||||
import com.imeeting.dto.biz.MeetingTranscriptSourceVO;
|
import com.imeeting.dto.biz.MeetingTranscriptSourceVO;
|
||||||
|
import com.imeeting.dto.biz.UnifiedMeetingStatusStage;
|
||||||
import com.imeeting.entity.biz.AiTask;
|
import com.imeeting.entity.biz.AiTask;
|
||||||
import com.imeeting.entity.biz.HotWord;
|
import com.imeeting.entity.biz.HotWord;
|
||||||
import com.imeeting.entity.biz.Meeting;
|
import com.imeeting.entity.biz.Meeting;
|
||||||
|
|
@ -18,6 +19,7 @@ import com.imeeting.enums.MeetingStatusEnum;
|
||||||
import com.imeeting.mapper.biz.AiTaskMapper;
|
import com.imeeting.mapper.biz.AiTaskMapper;
|
||||||
import com.imeeting.mapper.biz.MeetingMapper;
|
import com.imeeting.mapper.biz.MeetingMapper;
|
||||||
import com.imeeting.mapper.biz.MeetingTranscriptMapper;
|
import com.imeeting.mapper.biz.MeetingTranscriptMapper;
|
||||||
|
import com.imeeting.service.android.AndroidMeetingPushService;
|
||||||
import com.imeeting.support.TaskSecurityContextRunner;
|
import com.imeeting.support.TaskSecurityContextRunner;
|
||||||
import com.imeeting.service.biz.AiModelService;
|
import com.imeeting.service.biz.AiModelService;
|
||||||
import com.imeeting.service.biz.AiTaskService;
|
import com.imeeting.service.biz.AiTaskService;
|
||||||
|
|
@ -107,6 +109,8 @@ public class AiTaskServiceImpl extends ServiceImpl<AiTaskMapper, AiTask> impleme
|
||||||
.connectTimeout(Duration.ofSeconds(300))
|
.connectTimeout(Duration.ofSeconds(300))
|
||||||
.version(HttpClient.Version.HTTP_1_1)
|
.version(HttpClient.Version.HTTP_1_1)
|
||||||
.build();
|
.build();
|
||||||
|
@Autowired
|
||||||
|
private AndroidMeetingPushService androidMeetingPushService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public AiTaskServiceImpl(MeetingMapper meetingMapper,
|
public AiTaskServiceImpl(MeetingMapper meetingMapper,
|
||||||
|
|
@ -323,10 +327,12 @@ public class AiTaskServiceImpl extends ServiceImpl<AiTaskMapper, AiTask> impleme
|
||||||
chapterTask == null ? null : chapterTask.getId(),
|
chapterTask == null ? null : chapterTask.getId(),
|
||||||
chapterTask == null ? null : chapterTask.getStatus());
|
chapterTask == null ? null : chapterTask.getStatus());
|
||||||
reconcileMeetingStatus(meetingId);
|
reconcileMeetingStatus(meetingId);
|
||||||
|
androidMeetingPushService.pushMeetingStatusChanged(meetingId, UnifiedMeetingStatusStage.FAILED_SUMMARIZING.getCode());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
executeChapterFlow(meeting, chapterTask);
|
executeChapterFlow(meeting, chapterTask);
|
||||||
reconcileMeetingStatus(meetingId);
|
reconcileMeetingStatus(meetingId);
|
||||||
|
androidMeetingPushService.pushMeetingStatusChanged(meetingId, UnifiedMeetingStatusStage.COMPLETED.getCode());
|
||||||
log.info("[CHAPTER-FLOW] 章节任务流程结束: meetingId={}, chapterTaskId={}, costMs={}",
|
log.info("[CHAPTER-FLOW] 章节任务流程结束: meetingId={}, chapterTaskId={}, costMs={}",
|
||||||
meetingId, chapterTask.getId(), System.currentTimeMillis() - startMillis);
|
meetingId, chapterTask.getId(), System.currentTimeMillis() - startMillis);
|
||||||
}
|
}
|
||||||
|
|
@ -365,11 +371,13 @@ public class AiTaskServiceImpl extends ServiceImpl<AiTaskMapper, AiTask> impleme
|
||||||
sumTask == null ? null : sumTask.getStatus());
|
sumTask == null ? null : sumTask.getStatus());
|
||||||
}
|
}
|
||||||
reconcileMeetingStatus(meetingId);
|
reconcileMeetingStatus(meetingId);
|
||||||
|
androidMeetingPushService.pushMeetingStatusChanged(meetingId, UnifiedMeetingStatusStage.COMPLETED.getCode());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("[SUMMARY-FLOW] 总结任务执行异常: meetingId={}, sumTaskId={}",
|
log.error("[SUMMARY-FLOW] 总结任务执行异常: meetingId={}, sumTaskId={}",
|
||||||
meetingId, sumTask == null ? null : sumTask.getId(), e);
|
meetingId, sumTask == null ? null : sumTask.getId(), e);
|
||||||
failPendingSummaryTask(sumTask, e.getMessage());
|
failPendingSummaryTask(sumTask, e.getMessage());
|
||||||
reconcileMeetingStatus(meetingId);
|
reconcileMeetingStatus(meetingId);
|
||||||
|
androidMeetingPushService.pushMeetingStatusChanged(meetingId, UnifiedMeetingStatusStage.FAILED_SUMMARIZING.getCode());
|
||||||
} finally {
|
} finally {
|
||||||
log.info("[SUMMARY-FLOW] 总结任务流程结束: meetingId={}, costMs={}",
|
log.info("[SUMMARY-FLOW] 总结任务流程结束: meetingId={}, costMs={}",
|
||||||
meetingId, System.currentTimeMillis() - startMillis);
|
meetingId, System.currentTimeMillis() - startMillis);
|
||||||
|
|
|
||||||
|
|
@ -1047,7 +1047,7 @@ public class MeetingCommandServiceImpl implements MeetingCommandService {
|
||||||
if (effectivePromptId == null) {
|
if (effectivePromptId == null) {
|
||||||
throw new RuntimeException("缺少 promptId,无法创建总结任务");
|
throw new RuntimeException("缺少 promptId,无法创建总结任务");
|
||||||
}
|
}
|
||||||
meetingDomainSupport.createSummaryTask(
|
AiTask summaryTask = meetingDomainSupport.createSummaryTask(
|
||||||
meetingId,
|
meetingId,
|
||||||
effectiveSummaryModelId,
|
effectiveSummaryModelId,
|
||||||
effectiveChapterModelId,
|
effectiveChapterModelId,
|
||||||
|
|
@ -1060,11 +1060,12 @@ public class MeetingCommandServiceImpl implements MeetingCommandService {
|
||||||
meeting.setPromptId(effectivePromptId);
|
meeting.setPromptId(effectivePromptId);
|
||||||
meeting.setSummaryDetailLevel(effectiveSummaryDetailLevel);
|
meeting.setSummaryDetailLevel(effectiveSummaryDetailLevel);
|
||||||
meeting.setStatus(MeetingStatusEnum.SUMMARIZING.getCode());
|
meeting.setStatus(MeetingStatusEnum.SUMMARIZING.getCode());
|
||||||
|
meeting.setLatestSummaryTaskId(summaryTask.getId());
|
||||||
meetingService.updateById(meeting);
|
meetingService.updateById(meeting);
|
||||||
if ("EXTERNAL_N8N".equalsIgnoreCase(summaryOrchestrationMode)) {
|
if ("EXTERNAL_N8N".equalsIgnoreCase(summaryOrchestrationMode)) {
|
||||||
updateMeetingProgress(meetingId, 95, "等待外部总结编排...", 0);
|
updateMeetingProgress(meetingId, summaryTask, 95, "等待外部总结编排...", 0);
|
||||||
} else {
|
} else {
|
||||||
updateMeetingProgress(meetingId, 90, "重新总结已提交,正在生成总结...", 0);
|
updateMeetingProgress(meetingId, summaryTask, 90, "重新总结已提交,正在生成总结...", 0);
|
||||||
}
|
}
|
||||||
dispatchSummaryTaskAfterCommit(meetingId, meeting.getTenantId(), meeting.getCreatorId());
|
dispatchSummaryTaskAfterCommit(meetingId, meeting.getTenantId(), meeting.getCreatorId());
|
||||||
}
|
}
|
||||||
|
|
@ -1457,6 +1458,10 @@ public class MeetingCommandServiceImpl implements MeetingCommandService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateMeetingProgress(Long meetingId, int percent, String message, int eta) {
|
private void updateMeetingProgress(Long meetingId, int percent, String message, int eta) {
|
||||||
|
updateMeetingProgress(meetingId, null, percent, message, eta);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateMeetingProgress(Long meetingId, AiTask task, int percent, String message, int eta) {
|
||||||
com.imeeting.common.MeetingProgressStage stage;
|
com.imeeting.common.MeetingProgressStage stage;
|
||||||
int meetingStatus;
|
int meetingStatus;
|
||||||
if (percent < 0) {
|
if (percent < 0) {
|
||||||
|
|
@ -1478,7 +1483,7 @@ public class MeetingCommandServiceImpl implements MeetingCommandService {
|
||||||
stage = com.imeeting.common.MeetingProgressStage.QUEUED;
|
stage = com.imeeting.common.MeetingProgressStage.QUEUED;
|
||||||
meetingStatus = MeetingStatusEnum.TRANSCRIBING.getCode();
|
meetingStatus = MeetingStatusEnum.TRANSCRIBING.getCode();
|
||||||
}
|
}
|
||||||
meetingProgressService.markStageAfterCommitOrNow(meetingId, null, meetingStatus, stage, percent, message, eta);
|
meetingProgressService.markStageAfterCommitOrNow(meetingId, task, meetingStatus, stage, percent, message, eta);
|
||||||
}
|
}
|
||||||
|
|
||||||
private RealtimeMeetingResumeConfig buildRealtimeResumeConfig(CreateRealtimeMeetingCommand command,
|
private RealtimeMeetingResumeConfig buildRealtimeResumeConfig(CreateRealtimeMeetingCommand command,
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,9 @@ public class MeetingUnifiedStatusServiceImpl implements MeetingUnifiedStatusServ
|
||||||
if (isTaskFailed(chapterTask)) {
|
if (isTaskFailed(chapterTask)) {
|
||||||
return UnifiedMeetingStatusStage.FAILED_SUMMARIZING;
|
return UnifiedMeetingStatusStage.FAILED_SUMMARIZING;
|
||||||
}
|
}
|
||||||
|
if (isTaskCompleted(asrTask) || hasTranscript(meeting.getId()) || summaryTask != null || chapterTask != null) {
|
||||||
|
return UnifiedMeetingStatusStage.FAILED_SUMMARIZING;
|
||||||
|
}
|
||||||
|
|
||||||
return UnifiedMeetingStatusStage.FAILED_INITIALIZING;
|
return UnifiedMeetingStatusStage.FAILED_INITIALIZING;
|
||||||
}
|
}
|
||||||
|
|
@ -210,6 +213,10 @@ public class MeetingUnifiedStatusServiceImpl implements MeetingUnifiedStatusServ
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean canViewTranscript(Long meetingId) {
|
private boolean canViewTranscript(Long meetingId) {
|
||||||
|
return hasTranscript(meetingId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasTranscript(Long meetingId) {
|
||||||
return meetingId != null && meetingTranscriptMapper.selectCount(new LambdaQueryWrapper<MeetingTranscript>()
|
return meetingId != null && meetingTranscriptMapper.selectCount(new LambdaQueryWrapper<MeetingTranscript>()
|
||||||
.eq(MeetingTranscript::getMeetingId, meetingId)) > 0;
|
.eq(MeetingTranscript::getMeetingId, meetingId)) > 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,10 @@ const PROFILE_KEY = "userProfile";
|
||||||
interface PermissionState {
|
interface PermissionState {
|
||||||
codes: string[];
|
codes: string[];
|
||||||
isAdmin: boolean;
|
isAdmin: boolean;
|
||||||
|
isPlatformAdmin: boolean;
|
||||||
setCodes: (codes: string[]) => void;
|
setCodes: (codes: string[]) => void;
|
||||||
setIsAdmin: (isAdmin: boolean) => void;
|
setIsAdmin: (isAdmin: boolean) => void;
|
||||||
|
setIsPlatformAdmin: (isAdmin: boolean) => void;
|
||||||
load: () => Promise<void>;
|
load: () => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -32,6 +34,16 @@ export const usePermissionStore = create<PermissionState>((set) => ({
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
})(),
|
})(),
|
||||||
|
isPlatformAdmin: (() => {
|
||||||
|
try {
|
||||||
|
const raw = sessionStorage.getItem(PROFILE_KEY);
|
||||||
|
if (!raw) return false;
|
||||||
|
const parsed = JSON.parse(raw);
|
||||||
|
return !!parsed.isPlatformAdmin;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
})(),
|
||||||
setCodes: (codes) => {
|
setCodes: (codes) => {
|
||||||
set({ codes });
|
set({ codes });
|
||||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(codes));
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(codes));
|
||||||
|
|
@ -39,20 +51,27 @@ export const usePermissionStore = create<PermissionState>((set) => ({
|
||||||
setIsAdmin: (isAdmin) => {
|
setIsAdmin: (isAdmin) => {
|
||||||
set({ isAdmin });
|
set({ isAdmin });
|
||||||
},
|
},
|
||||||
|
setIsPlatformAdmin: (isPlatformAdmin) => {
|
||||||
|
set({isPlatformAdmin});
|
||||||
|
},
|
||||||
load: async () => {
|
load: async () => {
|
||||||
try {
|
try {
|
||||||
let isAdmin = false;
|
let isAdmin = false;
|
||||||
|
let isPlatformAdmin = false;
|
||||||
const cachedProfile = sessionStorage.getItem(PROFILE_KEY);
|
const cachedProfile = sessionStorage.getItem(PROFILE_KEY);
|
||||||
if (cachedProfile) {
|
if (cachedProfile) {
|
||||||
const parsed = JSON.parse(cachedProfile);
|
const parsed = JSON.parse(cachedProfile);
|
||||||
isAdmin = !!parsed.isAdmin;
|
isAdmin = !!parsed.isAdmin;
|
||||||
|
isPlatformAdmin = !!parsed.isPlatformAdmin;
|
||||||
} else {
|
} else {
|
||||||
const profile = await getCurrentUser();
|
const profile = await getCurrentUser();
|
||||||
isAdmin = !!profile.isAdmin;
|
isAdmin = !!profile.isAdmin;
|
||||||
|
isPlatformAdmin = !!profile.isPlatformAdmin;
|
||||||
sessionStorage.setItem(PROFILE_KEY, JSON.stringify(profile));
|
sessionStorage.setItem(PROFILE_KEY, JSON.stringify(profile));
|
||||||
}
|
}
|
||||||
|
set({isPlatformAdmin});
|
||||||
set({ isAdmin });
|
set({ isAdmin });
|
||||||
if (isAdmin) {
|
if (isPlatformAdmin) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const perms = await listMyPermissions();
|
const perms = await listMyPermissions();
|
||||||
|
|
@ -66,27 +85,23 @@ export const usePermissionStore = create<PermissionState>((set) => ({
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export function usePermission() {
|
export function usePermission() {
|
||||||
const { codes, load, isAdmin } = usePermissionStore();
|
const {codes, load, isAdmin, isPlatformAdmin} = usePermissionStore();
|
||||||
|
|
||||||
const can = (perm?: string) => {
|
const can = (perm?: string) => {
|
||||||
if (!perm) return true;
|
if (!perm) return true;
|
||||||
|
|
||||||
if (isAdmin) return true;
|
if (isPlatformAdmin) return true;
|
||||||
|
|
||||||
if (!codes || codes.length === 0) {
|
if (!codes || codes.length === 0) {
|
||||||
return true;
|
return perm.startsWith("menu:");
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasMenuCodes = codes.some((c) => c.startsWith("menu:"));
|
const hasMenuCodes = codes.some((c) => c.startsWith("menu:"));
|
||||||
const hasButtonCodes = codes.some((c) => !c.startsWith("menu:") && c.includes(":"));
|
|
||||||
|
|
||||||
let result = false;
|
|
||||||
if (perm.startsWith("menu:")) {
|
if (perm.startsWith("menu:")) {
|
||||||
result = !hasMenuCodes || codes.includes(perm);
|
return !hasMenuCodes || codes.includes(perm);
|
||||||
} else {
|
|
||||||
result = !hasButtonCodes || codes.includes(perm);
|
|
||||||
}
|
}
|
||||||
return result;
|
return codes.includes(perm);
|
||||||
};
|
};
|
||||||
|
|
||||||
return { codes, load, can, isAdmin };
|
return { codes, load, can, isAdmin };
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ const hasLatestGenerationFailure = (item: MeetingVO) =>
|
||||||
item.latestChapterAttemptStatus === 3 || item.latestSummaryAttemptStatus === 3;
|
item.latestChapterAttemptStatus === 3 || item.latestSummaryAttemptStatus === 3;
|
||||||
|
|
||||||
const shouldTrackGenerationProgress = (item: MeetingVO) =>
|
const shouldTrackGenerationProgress = (item: MeetingVO) =>
|
||||||
!hasLatestGenerationFailure(item) && (item.status === 0 || item.status === 1 || item.status === 2);
|
item.status === 0 || item.status === 1 || item.status === 2;
|
||||||
|
|
||||||
const isTerminalMeetingProgress = (progress?: MeetingProgress | null) =>
|
const isTerminalMeetingProgress = (progress?: MeetingProgress | null) =>
|
||||||
!!progress && (
|
!!progress && (
|
||||||
|
|
@ -156,14 +156,17 @@ const getEffectiveStatus = (item: MeetingVO, progress: MeetingProgress | null) =
|
||||||
if (unifiedStatusCode?.startsWith("FAILED_")) {
|
if (unifiedStatusCode?.startsWith("FAILED_")) {
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
if (hasLatestGenerationFailure(item)) {
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
const status = item.displayStatus ?? item.status;
|
const status = item.displayStatus ?? item.status;
|
||||||
// 如果处于初始化中但已经有进度,则视为转译音频中
|
// 如果处于初始化中但已经有进度,则视为转译音频中
|
||||||
if (status === 0 && progress && progress.percent > 0) {
|
if (status === 0 && progress && progress.percent > 0) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
if (status === 0 || status === 1 || status === 2) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
if (hasLatestGenerationFailure(item)) {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
return status;
|
return status;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { getCurrentUser } from "@/api";
|
||||||
import AppPagination from "@/components/shared/AppPagination";
|
import AppPagination from "@/components/shared/AppPagination";
|
||||||
import ListTable from "@/components/shared/ListTable/ListTable";
|
import ListTable from "@/components/shared/ListTable/ListTable";
|
||||||
import PageContainer from "@/components/shared/PageContainer";
|
import PageContainer from "@/components/shared/PageContainer";
|
||||||
|
import {usePermission} from "@/hooks/usePermission";
|
||||||
import {
|
import {
|
||||||
getCurrentTenantMeetingPointsSetting,
|
getCurrentTenantMeetingPointsSetting,
|
||||||
pageTenantMeetingPointsSettings,
|
pageTenantMeetingPointsSettings,
|
||||||
|
|
@ -14,6 +15,7 @@ import { Button, Card, Input, message, Modal, Select, Space, Statistic, Tag, Typ
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
const BALANCE_CHECK_UPDATE_PERMISSION = "biz:tenant-meeting-points:balance-check:update";
|
||||||
|
|
||||||
function formatDateTime(value?: string) {
|
function formatDateTime(value?: string) {
|
||||||
return value ? value.replace("T", " ").substring(0, 19) : "-";
|
return value ? value.replace("T", " ").substring(0, 19) : "-";
|
||||||
|
|
@ -26,6 +28,7 @@ function renderStatusTag(enabled?: boolean) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function TenantMeetingPointsSettings() {
|
export default function TenantMeetingPointsSettings() {
|
||||||
|
const {can} = usePermission();
|
||||||
const [profile, setProfile] = useState<UserProfile | null>(null);
|
const [profile, setProfile] = useState<UserProfile | null>(null);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [switchingTenantId, setSwitchingTenantId] = useState<number | null>(null);
|
const [switchingTenantId, setSwitchingTenantId] = useState<number | null>(null);
|
||||||
|
|
@ -42,6 +45,7 @@ export default function TenantMeetingPointsSettings() {
|
||||||
|
|
||||||
const isPlatformAdmin = Boolean(profile?.isPlatformAdmin);
|
const isPlatformAdmin = Boolean(profile?.isPlatformAdmin);
|
||||||
const isTenantAdmin = Boolean(profile?.isTenantAdmin);
|
const isTenantAdmin = Boolean(profile?.isTenantAdmin);
|
||||||
|
const canUpdateBalanceCheck = isPlatformAdmin || (isTenantAdmin && can(BALANCE_CHECK_UPDATE_PERMISSION));
|
||||||
|
|
||||||
const loadPlatformPage = async (nextParams = params) => {
|
const loadPlatformPage = async (nextParams = params) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
@ -179,7 +183,11 @@ export default function TenantMeetingPointsSettings() {
|
||||||
key: "action",
|
key: "action",
|
||||||
width: 140,
|
width: 140,
|
||||||
fixed: "right" as const,
|
fixed: "right" as const,
|
||||||
render: (_: unknown, record: TenantMeetingPointsSettingVO) => (
|
render: (_: unknown, record: TenantMeetingPointsSettingVO) => {
|
||||||
|
if (!canUpdateBalanceCheck) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
loading={switchingTenantId === record.tenantId}
|
loading={switchingTenantId === record.tenantId}
|
||||||
|
|
@ -187,7 +195,8 @@ export default function TenantMeetingPointsSettings() {
|
||||||
>
|
>
|
||||||
{record.balanceCheckEnabled ? "切换为无限余额" : "开启余额校验"}
|
{record.balanceCheckEnabled ? "切换为无限余额" : "开启余额校验"}
|
||||||
</Button>
|
</Button>
|
||||||
),
|
);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -231,6 +240,7 @@ export default function TenantMeetingPointsSettings() {
|
||||||
</Space>
|
</Space>
|
||||||
|
|
||||||
<Space>
|
<Space>
|
||||||
|
{canUpdateBalanceCheck ? (
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
loading={switchingTenantId === currentTenantSetting.tenantId}
|
loading={switchingTenantId === currentTenantSetting.tenantId}
|
||||||
|
|
@ -238,6 +248,7 @@ export default function TenantMeetingPointsSettings() {
|
||||||
>
|
>
|
||||||
{currentTenantSetting.balanceCheckEnabled ? "切换为无限余额" : "开启余额校验"}
|
{currentTenantSetting.balanceCheckEnabled ? "切换为无限余额" : "开启余额校验"}
|
||||||
</Button>
|
</Button>
|
||||||
|
) : null}
|
||||||
<Button icon={<ReloadOutlined />} onClick={() => void handleRefresh()}>
|
<Button icon={<ReloadOutlined />} onClick={() => void handleRefresh()}>
|
||||||
刷新
|
刷新
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue