fix: harden tenant auth and quality gates

This commit is contained in:
hectorzhao
2026-08-28 11:44:16 +08:00
parent c3bf8af3e6
commit 2744690f9f
51 changed files with 1750 additions and 466 deletions
+75 -59
View File
@@ -1,69 +1,83 @@
import { lazy, Suspense, type ComponentType, type LazyExoticComponent } from 'react';
import { Navigate, Route, Routes } from 'react-router-dom';
import { AdminAnalyticsPage } from '@/apps/admin/AdminAnalyticsPage';
import { AdminChannelGroupFormPage } from '@/apps/admin/AdminChannelGroupFormPage';
import { AdminChannelGroupsPage } from '@/apps/admin/AdminChannelGroupsPage';
import { AdminChannelsPage } from '@/apps/admin/AdminChannelsPage';
import { AdminChannelReportPage } from '@/apps/admin/AdminChannelReportPage';
import { AdminCustomerDetailPage } from '@/apps/admin/AdminCustomerDetailPage';
import { AdminCustomerFormPage } from '@/apps/admin/AdminCustomerFormPage';
import { AdminCustomersPage } from '@/apps/admin/AdminCustomersPage';
import { AdminDrainageFieldsPage } from '@/apps/admin/AdminDrainageFieldsPage';
import { AdminDrainageDetectionRulesPage } from '@/apps/admin/AdminDrainageDetectionRulesPage';
import { AdminDownstreamDeliveriesPage } from '@/apps/admin/AdminDownstreamDeliveriesPage';
import { AdminDownstreamRecoveryStatusesPage } from '@/apps/admin/AdminDownstreamRecoveryStatusesPage';
import { AdminEnterpriseApplicationsPage } from '@/apps/admin/AdminEnterpriseApplicationsPage';
import { AdminEnterpriseBlacklistPage } from '@/apps/admin/AdminEnterpriseBlacklistPage';
import { AdminEnterpriseSignaturesPage } from '@/apps/admin/AdminEnterpriseSignaturesPage';
import { AdminEnterpriseTemplatesPage } from '@/apps/admin/AdminEnterpriseTemplatesPage';
import { AdminGlobalBlacklistPage } from '@/apps/admin/AdminGlobalBlacklistPage';
import { AdminGatewaySubmitExceptionsPage } from '@/apps/admin/AdminGatewaySubmitExceptionsPage';
import { AdminHome } from '@/apps/admin/AdminHome';
import { AdminMonitorPage } from '@/apps/admin/AdminMonitorPage';
import { AdminPhoneSegmentsPage } from '@/apps/admin/AdminPhoneSegmentsPage';
import { AdminRechargeRecordsPage } from '@/apps/admin/AdminRechargeRecordsPage';
import { AdminReconciliationReportsPage } from '@/apps/admin/AdminReconciliationReportsPage';
import { AdminProfitReportsPage } from '@/apps/admin/AdminProfitReportsPage';
import { AdminQualityReportsPage } from '@/apps/admin/AdminQualityReportsPage';
import { AdminReportRecordsPage } from '@/apps/admin/AdminReportRecordsPage';
import { AdminReportTasksPage } from '@/apps/admin/AdminReportTasksPage';
import { AdminReportMaterialsPage } from '@/apps/admin/AdminReportMaterialsPage';
import { AdminSensitiveWordsPage } from '@/apps/admin/AdminSensitiveWordsPage';
import { AdminSmsAuditPage } from '@/apps/admin/AdminSmsAuditPage';
import { AdminRiskRulesPage } from '@/apps/admin/AdminRiskRulesPage';
import { AdminSmsApplicationFormPage } from '@/apps/admin/AdminSmsApplicationFormPage';
import { AdminSmsRecordsPage } from '@/apps/admin/AdminSmsRecordsPage';
import { AdminSmsTaskProgressPage } from '@/apps/admin/AdminSmsTaskProgressPage';
import { AdminSmsUplinkRecordsPage } from '@/apps/admin/AdminSmsUplinkRecordsPage';
import { AdminSignatureAuditPage } from '@/apps/admin/AdminSignatureAuditPage';
import { AdminSignatureRetirementPage } from '@/apps/admin/AdminSignatureRetirementPage';
import { AdminDrainageAuditPage } from '@/apps/admin/AdminDrainageAuditPage';
import { AdminSystemLogsPage } from '@/apps/admin/AdminSystemLogsPage';
import { AdminSystemMonitoringPage } from '@/apps/admin/system-monitoring/AdminSystemMonitoringPage';
import { AdminSecurityDetectionPage } from '@/apps/admin/security-detection/AdminSecurityDetectionPage';
import { AdminTemplateAuditPage } from '@/apps/admin/AdminTemplateAuditPage';
import { AdminUsersPage } from '@/apps/admin/AdminUsersPage';
import { AdminEnterpriseAuditPage } from '@/apps/admin/AdminEnterpriseAuditPage';
import { ClientApplicationsPage } from '@/apps/client/ClientApplicationsPage';
import { ClientBatchTasksPage } from '@/apps/client/ClientBatchTasksPage';
import { ClientBillingPage } from '@/apps/client/ClientBillingPage';
import { ClientEnterpriseAuthPage } from '@/apps/client/ClientEnterpriseAuthPage';
import { ClientHome } from '@/apps/client/ClientHome';
import { ClientHttpApiPage } from '@/apps/client/ClientHttpApiPage';
import { ClientSendDetailPage } from '@/apps/client/ClientSendDetailPage';
import { ClientSendPage } from '@/apps/client/ClientSendPage';
import { ClientSignaturesPage } from '@/apps/client/ClientSignaturesPage';
import { ClientSystemLogsPage } from '@/apps/client/ClientSystemLogsPage';
import { ClientTemplatesPage } from '@/apps/client/ClientTemplatesPage';
import { ClientUplinkMessagesPage } from '@/apps/client/ClientUplinkMessagesPage';
import { ClientUsersPage } from '@/apps/client/ClientUsersPage';
import { LoginPage } from '@/apps/LoginPage';
import { PagePlaceholder } from '@/components/PagePlaceholder';
import { AdminLayout } from '@/layouts/AdminLayout';
import { ClientLayout } from '@/layouts/ClientLayout';
import { RouteLoadBoundary } from './RouteLoadBoundary';
function lazyNamed(loader: () => Promise<unknown>, exportName: string): LazyExoticComponent<ComponentType<any>> {
return lazy(async () => {
const loaded = await loader() as Record<string, ComponentType>;
const component = loaded[exportName];
if (!component) throw new Error(`Lazy route export ${exportName} was not found`);
return { default: component };
});
}
const AdminAnalyticsPage = lazyNamed(() => import('@/apps/admin/AdminAnalyticsPage'), 'AdminAnalyticsPage');
const AdminChannelGroupFormPage = lazyNamed(() => import('@/apps/admin/AdminChannelGroupFormPage'), 'AdminChannelGroupFormPage');
const AdminChannelGroupsPage = lazyNamed(() => import('@/apps/admin/AdminChannelGroupsPage'), 'AdminChannelGroupsPage');
const AdminChannelsPage = lazyNamed(() => import('@/apps/admin/AdminChannelsPage'), 'AdminChannelsPage');
const AdminChannelReportPage = lazyNamed(() => import('@/apps/admin/AdminChannelReportPage'), 'AdminChannelReportPage');
const AdminCustomerDetailPage = lazyNamed(() => import('@/apps/admin/AdminCustomerDetailPage'), 'AdminCustomerDetailPage');
const AdminCustomerFormPage = lazyNamed(() => import('@/apps/admin/AdminCustomerFormPage'), 'AdminCustomerFormPage');
const AdminCustomersPage = lazyNamed(() => import('@/apps/admin/AdminCustomersPage'), 'AdminCustomersPage');
const AdminDrainageFieldsPage = lazyNamed(() => import('@/apps/admin/AdminDrainageFieldsPage'), 'AdminDrainageFieldsPage');
const AdminDrainageDetectionRulesPage = lazyNamed(() => import('@/apps/admin/AdminDrainageDetectionRulesPage'), 'AdminDrainageDetectionRulesPage');
const AdminDownstreamDeliveriesPage = lazyNamed(() => import('@/apps/admin/AdminDownstreamDeliveriesPage'), 'AdminDownstreamDeliveriesPage');
const AdminDownstreamRecoveryStatusesPage = lazyNamed(() => import('@/apps/admin/AdminDownstreamRecoveryStatusesPage'), 'AdminDownstreamRecoveryStatusesPage');
const AdminEnterpriseApplicationsPage = lazyNamed(() => import('@/apps/admin/AdminEnterpriseApplicationsPage'), 'AdminEnterpriseApplicationsPage');
const AdminEnterpriseBlacklistPage = lazyNamed(() => import('@/apps/admin/AdminEnterpriseBlacklistPage'), 'AdminEnterpriseBlacklistPage');
const AdminEnterpriseSignaturesPage = lazyNamed(() => import('@/apps/admin/AdminEnterpriseSignaturesPage'), 'AdminEnterpriseSignaturesPage');
const AdminEnterpriseTemplatesPage = lazyNamed(() => import('@/apps/admin/AdminEnterpriseTemplatesPage'), 'AdminEnterpriseTemplatesPage');
const AdminGlobalBlacklistPage = lazyNamed(() => import('@/apps/admin/AdminGlobalBlacklistPage'), 'AdminGlobalBlacklistPage');
const AdminGatewaySubmitExceptionsPage = lazyNamed(() => import('@/apps/admin/AdminGatewaySubmitExceptionsPage'), 'AdminGatewaySubmitExceptionsPage');
const AdminHome = lazyNamed(() => import('@/apps/admin/AdminHome'), 'AdminHome');
const AdminMonitorPage = lazyNamed(() => import('@/apps/admin/AdminMonitorPage'), 'AdminMonitorPage');
const AdminPhoneSegmentsPage = lazyNamed(() => import('@/apps/admin/AdminPhoneSegmentsPage'), 'AdminPhoneSegmentsPage');
const AdminRechargeRecordsPage = lazyNamed(() => import('@/apps/admin/AdminRechargeRecordsPage'), 'AdminRechargeRecordsPage');
const AdminReconciliationReportsPage = lazyNamed(() => import('@/apps/admin/AdminReconciliationReportsPage'), 'AdminReconciliationReportsPage');
const AdminProfitReportsPage = lazyNamed(() => import('@/apps/admin/AdminProfitReportsPage'), 'AdminProfitReportsPage');
const AdminQualityReportsPage = lazyNamed(() => import('@/apps/admin/AdminQualityReportsPage'), 'AdminQualityReportsPage');
const AdminReportRecordsPage = lazyNamed(() => import('@/apps/admin/AdminReportRecordsPage'), 'AdminReportRecordsPage');
const AdminReportTasksPage = lazyNamed(() => import('@/apps/admin/AdminReportTasksPage'), 'AdminReportTasksPage');
const AdminReportMaterialsPage = lazyNamed(() => import('@/apps/admin/AdminReportMaterialsPage'), 'AdminReportMaterialsPage');
const AdminSensitiveWordsPage = lazyNamed(() => import('@/apps/admin/AdminSensitiveWordsPage'), 'AdminSensitiveWordsPage');
const AdminSmsAuditPage = lazyNamed(() => import('@/apps/admin/AdminSmsAuditPage'), 'AdminSmsAuditPage');
const AdminRiskRulesPage = lazyNamed(() => import('@/apps/admin/AdminRiskRulesPage'), 'AdminRiskRulesPage');
const AdminSmsApplicationFormPage = lazyNamed(() => import('@/apps/admin/AdminSmsApplicationFormPage'), 'AdminSmsApplicationFormPage');
const AdminSmsRecordsPage = lazyNamed(() => import('@/apps/admin/AdminSmsRecordsPage'), 'AdminSmsRecordsPage');
const AdminSmsTaskProgressPage = lazyNamed(() => import('@/apps/admin/AdminSmsTaskProgressPage'), 'AdminSmsTaskProgressPage');
const AdminSmsUplinkRecordsPage = lazyNamed(() => import('@/apps/admin/AdminSmsUplinkRecordsPage'), 'AdminSmsUplinkRecordsPage');
const AdminSignatureAuditPage = lazyNamed(() => import('@/apps/admin/AdminSignatureAuditPage'), 'AdminSignatureAuditPage');
const AdminSignatureRetirementPage = lazyNamed(() => import('@/apps/admin/AdminSignatureRetirementPage'), 'AdminSignatureRetirementPage');
const AdminDrainageAuditPage = lazyNamed(() => import('@/apps/admin/AdminDrainageAuditPage'), 'AdminDrainageAuditPage');
const AdminSystemLogsPage = lazyNamed(() => import('@/apps/admin/AdminSystemLogsPage'), 'AdminSystemLogsPage');
const AdminSystemMonitoringPage = lazyNamed(() => import('@/apps/admin/system-monitoring/AdminSystemMonitoringPage'), 'AdminSystemMonitoringPage');
const AdminSecurityDetectionPage = lazyNamed(() => import('@/apps/admin/security-detection/AdminSecurityDetectionPage'), 'AdminSecurityDetectionPage');
const AdminTemplateAuditPage = lazyNamed(() => import('@/apps/admin/AdminTemplateAuditPage'), 'AdminTemplateAuditPage');
const AdminUsersPage = lazyNamed(() => import('@/apps/admin/AdminUsersPage'), 'AdminUsersPage');
const AdminEnterpriseAuditPage = lazyNamed(() => import('@/apps/admin/AdminEnterpriseAuditPage'), 'AdminEnterpriseAuditPage');
const ClientApplicationsPage = lazyNamed(() => import('@/apps/client/ClientApplicationsPage'), 'ClientApplicationsPage');
const ClientBatchTasksPage = lazyNamed(() => import('@/apps/client/ClientBatchTasksPage'), 'ClientBatchTasksPage');
const ClientBillingPage = lazyNamed(() => import('@/apps/client/ClientBillingPage'), 'ClientBillingPage');
const ClientEnterpriseAuthPage = lazyNamed(() => import('@/apps/client/ClientEnterpriseAuthPage'), 'ClientEnterpriseAuthPage');
const ClientHome = lazyNamed(() => import('@/apps/client/ClientHome'), 'ClientHome');
const ClientHttpApiPage = lazyNamed(() => import('@/apps/client/ClientHttpApiPage'), 'ClientHttpApiPage');
const ClientSendDetailPage = lazyNamed(() => import('@/apps/client/ClientSendDetailPage'), 'ClientSendDetailPage');
const ClientSendPage = lazyNamed(() => import('@/apps/client/ClientSendPage'), 'ClientSendPage');
const ClientSignaturesPage = lazyNamed(() => import('@/apps/client/ClientSignaturesPage'), 'ClientSignaturesPage');
const ClientSystemLogsPage = lazyNamed(() => import('@/apps/client/ClientSystemLogsPage'), 'ClientSystemLogsPage');
const ClientTemplatesPage = lazyNamed(() => import('@/apps/client/ClientTemplatesPage'), 'ClientTemplatesPage');
const ClientUplinkMessagesPage = lazyNamed(() => import('@/apps/client/ClientUplinkMessagesPage'), 'ClientUplinkMessagesPage');
const ClientUsersPage = lazyNamed(() => import('@/apps/client/ClientUsersPage'), 'ClientUsersPage');
export function AppRoutes() {
return (
<Routes>
<RouteLoadBoundary>
<Suspense fallback={<div className="page-stack"><div className="surface ui-table__empty">...</div></div>}>
<Routes>
<Route path="/" element={<Navigate to="/client" replace />} />
<Route path="/client/login" element={<LoginPage portal="client" />} />
<Route path="/admin/login" element={<LoginPage portal="admin" />} />
@@ -148,6 +162,8 @@ export function AppRoutes() {
<Route path="security-detection" element={<AdminSecurityDetectionPage />} />
<Route path="*" element={<PagePlaceholder />} />
</Route>
</Routes>
</Routes>
</Suspense>
</RouteLoadBoundary>
);
}
+30
View File
@@ -0,0 +1,30 @@
import { Component, type ErrorInfo, type ReactNode } from 'react';
type Props = { children: ReactNode };
type State = { error?: Error };
export class RouteLoadBoundary extends Component<Props, State> {
state: State = {};
static getDerivedStateFromError(error: Error): State {
return { error };
}
componentDidCatch(error: Error, info: ErrorInfo) {
console.error('Route chunk failed to load', error, info.componentStack);
}
render() {
if (!this.state.error) return this.props.children;
return (
<div className="page-stack">
<div className="surface ui-table__empty" role="alert">
<p></p>
<button className="ui-button ui-button--primary" type="button" onClick={() => window.location.reload()}>
</button>
</div>
</div>
);
}
}