diff --git a/config/proxy.ts b/config/proxy.ts
index 5bfce15..ba63b71 100644
--- a/config/proxy.ts
+++ b/config/proxy.ts
@@ -15,7 +15,8 @@ export default {
'/api': {
// The address to proxy
// target: 'http://2333z061l7.51mypc.cn',
- target: 'http://172.20.177.121:8080',
+ // target: 'http://172.20.177.121:8080',
+ target: 'http://172.20.177.121:8082',
changeOrigin: true,
pathRewrite: {
'^/api': '',
diff --git a/src/app.tsx b/src/app.tsx
index 20dd5b6..7786dad 100644
--- a/src/app.tsx
+++ b/src/app.tsx
@@ -17,6 +17,7 @@ import ServerErrorPage from './pages/500';
import { errorConfig } from './requestErrorConfig';
import { getDeviceId } from './utils/fp';
import './utils/sentry';
+import CompanyExpireGuard from './components/CompanyExpireGuard';
import GlobalErrorBoundary from './components/GlobalErrorBoundary';
import PermissionGuard from './components/PermissionGuard';
import SSEController from './components/SSEController';
@@ -197,6 +198,12 @@ export const layout: RunTimeLayoutConfig = ({ initialState }) => {
// Add a loading state
childrenRender: (children) => {
if (initialState?.loading) return ;
+
+ const { company } = currentUser ?? {};
+
+ if (company?.special !== 0 && company?.validityStatus === 2) {
+ return ;
+ }
return (
<>
{currentUser && (
diff --git a/src/components/CompanyExpireGuard/index.tsx b/src/components/CompanyExpireGuard/index.tsx
new file mode 100644
index 0000000..d399b26
--- /dev/null
+++ b/src/components/CompanyExpireGuard/index.tsx
@@ -0,0 +1,50 @@
+import { Button, Result, Space } from 'antd';
+import { logoutAndToLoginPage } from '@/access';
+import useUserInfo from '@/hooks/useUserInfo';
+import { $t } from '@/utils/i18n';
+
+const CompanyExpireGuard: React.FC = () => {
+ const { userInfo } = useUserInfo();
+ const isExpired = userInfo?.company?.validityStatus === 2;
+
+ if (!isExpired) return null;
+
+ return (
+
+
+
+
+
+ }
+ />
+
+ );
+};
+
+export default CompanyExpireGuard;
diff --git a/src/locales/en_US/pages.ts b/src/locales/en_US/pages.ts
index d87314e..076002c 100644
--- a/src/locales/en_US/pages.ts
+++ b/src/locales/en_US/pages.ts
@@ -46,6 +46,8 @@ export default {
'table.contactEmail': 'Contact Email',
'table.dataSourceCount': 'Data Sources',
'table.userCount': 'Users',
+ 'table.validityEndTime': 'Expire At (UTC+0)',
+ 'table.validityEndTime.tips': 'Company subscription expiry date ',
'table.createTime': 'Create Time',
'table.name': 'Name',
'table.ipAddress': 'IP Address',
@@ -87,6 +89,13 @@ export default {
'pages.totalAlertCount': 'Total Alerts',
'pages.totalCompanyCount': 'Total Companies',
'pages.activeCompanyCount': 'Active Companies',
+ 'pages.company.expired': 'Expired',
+ 'pages.company.permanent': 'Permanent',
+ 'pages.company.expireTitle': 'Company Subscription Expired',
+ 'pages.company.expireSubTitle':
+ "Your company's license has expired. All features are temporarily locked. Please contact your sales representative to renew.",
+ 'pages.company.expireInDays': 'Subscription expires in {days} days',
+ 'pages.company.expireToday': 'Expires Today',
'pages.totalDataSourceCount': 'Total Data Sources',
'pages.activeDataSourceCount': 'Active Data Sources',
'pages.mt4DataSourceCount': 'MT4 Data Sources',
@@ -329,6 +338,9 @@ export default {
'form.role.placeholder2': 'System roles cannot modify permission levels',
'form.role.badgeColor': 'Badge Color',
'form.role.menuIds': 'Bound Permissions (Menus)',
+ 'form.company.validityEndTime': 'Expiry At (UTC+0)',
+ 'form.company.validityEndTime.placeholder': 'Select expiry date',
+ 'form.company.validityEndTime.tips': 'Blank for Permanent',
'form.role.permissionGuide': 'Permission Guide',
'form.role.otherPermissions': 'Other Menu Permissions',
diff --git a/src/locales/zh_CN/pages.ts b/src/locales/zh_CN/pages.ts
index 7f1c0b8..af72acb 100644
--- a/src/locales/zh_CN/pages.ts
+++ b/src/locales/zh_CN/pages.ts
@@ -46,6 +46,8 @@ export default {
'table.contactEmail': '联系邮箱',
'table.dataSourceCount': '数据源',
'table.userCount': '用户数',
+ 'table.validityEndTime': '订阅到期时间(UTC+0)',
+ 'table.validityEndTime.tips': '公司订阅服务到期时间',
'table.createTime': '创建时间',
'table.name': '名称',
'table.ipAddress': 'IP地址',
@@ -87,6 +89,13 @@ export default {
'pages.totalAlertCount': '总告警数',
'pages.totalCompanyCount': '总公司数',
'pages.activeCompanyCount': '活跃公司数',
+ 'pages.company.expired': '已过期',
+ 'pages.company.permanent': '永久有效',
+ 'pages.company.expireTitle': '公司订阅已过期',
+ 'pages.company.expireSubTitle':
+ '您的公司在该系统的使用授权已到期,各项功能已暂时锁定。请联系商务代表进行续费操作以恢复访问。',
+ 'pages.company.expireInDays': '订阅即将到期,剩余 {days}天',
+ 'pages.company.expireToday': '今天到期',
'pages.totalDataSourceCount': '数据源总数',
'pages.activeDataSourceCount': '活跃数据源',
'pages.mt4DataSourceCount': 'MT4 数据源',
@@ -321,6 +330,9 @@ export default {
'form.role.placeholder2': '系统角色权限级别不可修改',
'form.role.badgeColor': '徽章颜色',
'form.role.menuIds': '绑定权限(菜单)',
+ 'form.company.validityEndTime': '到期时间(UTC+0)',
+ 'form.company.validityEndTime.placeholder': '请选择到期时间',
+ 'form.company.validityEndTime.tips': '留空为永久有效',
'form.role.permissionGuide': '权限怎么选',
'form.role.otherPermissions': '其他菜单权限',
diff --git a/src/pages/company/Popup.tsx b/src/pages/company/Popup.tsx
index 8c7dc45..24359ab 100644
--- a/src/pages/company/Popup.tsx
+++ b/src/pages/company/Popup.tsx
@@ -1,5 +1,6 @@
import {
ModalForm,
+ ProFormDatePicker,
ProFormDependency,
type ProFormInstance,
ProFormSelect,
@@ -8,6 +9,7 @@ import {
} from '@ant-design/pro-components';
import { useAccess } from '@umijs/max';
import { Divider, Space, Typography } from 'antd';
+import type { Dayjs } from 'dayjs';
import { useRef } from 'react';
import useUserInfo from '@/hooks/useUserInfo';
import {
@@ -16,6 +18,7 @@ import {
getEmailConfigList,
} from '@/services/api';
import { $t } from '@/utils/i18n';
+import { utcInstance as dayjs } from '@/utils/timeFormat';
const { Text } = Typography;
type CompanyListItem = Partial;
@@ -25,7 +28,7 @@ export default (props: {
onSubmit: (values: CompanyListItem) => void;
onDone: () => void;
}) => {
- const { isGlobalCompany } = useAccess();
+ const { isGlobalCompany, isSuperAdmin } = useAccess();
const { userInfo } = useUserInfo();
const { modalVisit, formValues, onSubmit, onDone } = props;
@@ -43,6 +46,13 @@ export default (props: {
if (!isGlobalCompany) {
values.companyId = userInfo?.companyId;
}
+
+ if (isSuperAdmin) {
+ values.validityEndTime = values.validityEndTime
+ ? dayjs(values.validityEndTime).endOf('day').format('YYYY-MM-DD')
+ : '';
+ values.validityStartTime = values.validityEndTime ? '2026-01-01' : '';
+ }
return onSubmit(values);
}}
modalProps={{
@@ -70,6 +80,7 @@ export default (props: {
return {
...values,
...companyMailHostConfig,
+ validityEndTime: values.validityEndTime || undefined,
};
}
return values || {};
@@ -106,6 +117,23 @@ export default (props: {
},
]}
/>
+ {isSuperAdmin && (
+
+ value ? value : undefined
+ }
+ fieldProps={{
+ style: { width: '100%' },
+ disabledDate: (current: Dayjs) =>
+ current?.isBefore(dayjs().startOf('day')),
+ }}
+ // extra={{$t('pages.company.expired')}}
+ />
+ )}
{formValues?.id !== void 0 && (
<>
diff --git a/src/pages/company/index.tsx b/src/pages/company/index.tsx
index 2ef314d..135262d 100644
--- a/src/pages/company/index.tsx
+++ b/src/pages/company/index.tsx
@@ -5,7 +5,8 @@ import {
type ProColumns,
ProTable,
} from '@ant-design/pro-components';
-import { Badge, Button, Col, Row } from 'antd';
+import { useAccess } from '@umijs/max';
+import { Badge, Button, Col, Row, Space, Typography } from 'antd';
import React, { useRef, useState } from 'react';
import HeadStatisticCard, {
type CardInfo,
@@ -13,9 +14,13 @@ import HeadStatisticCard, {
import MyTag from '@/components/MyTag';
import { companyHandle, getCompanyPages } from '@/services/api';
import { $t } from '@/utils/i18n';
+import { utcInstance as dayjs } from '@/utils/timeFormat';
import PopUp from './Popup';
+const { Text } = Typography;
+
const Company: React.FC = () => {
+ const { isSuperAdmin } = useAccess();
const [modalVisit, setModalVisit] = useState(false);
const [cardInfo, setCardInfo] = useState({
@@ -92,6 +97,28 @@ const Company: React.FC = () => {
);
},
},
+ {
+ title: $t('table.validityEndTime'),
+ dataIndex: 'validityEndTime',
+ tooltip: $t('table.validityEndTime.tips'),
+ hideInTable: !isSuperAdmin,
+ render: (_, { validityEndTime, validityStatus }) => {
+ return (
+
+ {!validityEndTime ? (
+ {$t('pages.company.permanent')}
+ ) : (
+ {dayjs(validityEndTime).format('YYYY-MM-DD')}
+ )}
+ {validityStatus === 2 && (
+
+ {$t('pages.company.expired')}
+
+ )}
+
+ );
+ },
+ },
{
title: $t('table.createTime'),
dataIndex: 'createTime',
@@ -122,7 +149,10 @@ const Company: React.FC = () => {
size="small"
key="edit"
onClick={() => {
- setFormValues(item);
+ setFormValues({
+ ...item,
+ validityEndTime: item.validityEndTime || undefined,
+ });
setModalVisit(true);
}}
>
diff --git a/src/pages/profile/index.tsx b/src/pages/profile/index.tsx
index 9a47081..e642600 100644
--- a/src/pages/profile/index.tsx
+++ b/src/pages/profile/index.tsx
@@ -3,7 +3,7 @@ import {
ProForm,
ProFormText,
} from '@ant-design/pro-components';
-import { history } from '@umijs/max';
+import { history, useAccess } from '@umijs/max';
import {
App,
Button,
@@ -15,7 +15,7 @@ import {
Space,
Tag,
} from 'antd';
-import React from 'react';
+import React, { useEffect } from 'react';
import { clearAccessToken } from '@/access';
import PasswordLevel from '@/components/PasswordLevel';
import useUserInfo from '@/hooks/useUserInfo';
@@ -24,6 +24,7 @@ import { $t } from '@/utils/i18n';
const Profile: React.FC = () => {
const { userInfo, setUserInfo } = useUserInfo();
+ const { isGlobalCompany } = useAccess();
const userCompany = userInfo?.company;
const { message: antdMessage, modal } = App.useApp();
@@ -71,6 +72,19 @@ const Profile: React.FC = () => {
},
];
+ useEffect(() => {
+ if (!isGlobalCompany) {
+ items.push({
+ key: '6',
+ span: 'filled',
+ label: $t('pages.company.permanent'),
+ children: userCompany?.validityEndTime
+ ? userCompany.validityEndTime
+ : $t('pages.company.permanent'),
+ });
+ }
+ }, [userInfo]);
+
const changePasswordSuccessHadle = async () => {
let countdown = 5;
let timer: NodeJS.Timeout | null = null;
diff --git a/src/services/api/api.ts b/src/services/api/api.ts
index acc4cc7..96236b5 100644
--- a/src/services/api/api.ts
+++ b/src/services/api/api.ts
@@ -83,6 +83,8 @@ export async function companyHandle(
name?: string;
email?: string;
status?: number;
+ validityStartTime?: string | null;
+ validityEndTime?: string | null;
},
options?: ObjType,
) {
diff --git a/src/services/typings.d.ts b/src/services/typings.d.ts
index b4f7866..73cc381 100644
--- a/src/services/typings.d.ts
+++ b/src/services/typings.d.ts
@@ -113,6 +113,9 @@ declare namespace API {
fromName: string | null;
mailHostConfigId: number | string | null;
mailStatus: number | null;
+ validityStartTime?: string | null;
+ validityEndTime?: string | null;
+ validityStatus?: number | null;
};
// "DataSource" Type