diff --git a/config/routes.ts b/config/routes.ts index 6d1305c..03eb6e3 100644 --- a/config/routes.ts +++ b/config/routes.ts @@ -52,7 +52,7 @@ export const roleRoutes = [ meta: { permissions: ['rule:list'], }, - wrappers: ['@/wrappers/noBindDataSource'], + wrappers: ['@/wrappers/CompanyExpire', '@/wrappers/noBindDataSource'], component: './rules', routes: [ { @@ -166,6 +166,7 @@ export const roleRoutes = [ meta: { permissions: ['data-source:list'], }, + wrappers: ['@/wrappers/CompanyExpire'], component: './data-source/index', }, { diff --git a/src/app.tsx b/src/app.tsx index 7786dad..15380ea 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -18,6 +18,7 @@ import { errorConfig } from './requestErrorConfig'; import { getDeviceId } from './utils/fp'; import './utils/sentry'; import CompanyExpireGuard from './components/CompanyExpireGuard'; +import CompanyExpireWarning from './components/CompanyExpireWarning'; import GlobalErrorBoundary from './components/GlobalErrorBoundary'; import PermissionGuard from './components/PermissionGuard'; import SSEController from './components/SSEController'; @@ -140,6 +141,7 @@ export const layout: RunTimeLayoutConfig = ({ initialState }) => { }, actionsRender: (_layoutProps) => { return [ + , , needChangePass && , // { +const fullscreenClass = + 'fixed-all-center flex align-center justify-center bg-white'; +const CompanyExpireGuard: React.FC<{ fullscreen?: boolean }> = ({ + fullscreen = true, +}) => { const { userInfo } = useUserInfo(); const isExpired = userInfo?.company?.validityStatus === 2; if (!isExpired) return null; return ( -
+
{ + const { isGlobalCompany } = useAccess(); + const { userInfo } = useUserInfo(); + const screens = useBreakpoint(); + const { validityEndTime, validityStatus } = userInfo?.company || {}; + if (isGlobalCompany) { + return null; + } + + const expireInDays = dayjs(`${validityEndTime}T23:59:59`).diff( + dayjs().utc(), + 'day', + ); + console.log( + expireInDays, + validityEndTime, + dayjs().utc().format('YYYY-MM-DD HH:mm:ss'), + ); + + const tipsNode = ( + + ); + return ( + umiHistory.push('/profile')}> + {['xs', 'sm'].includes(screens || '') ? ( + + + + ) : ( + tipsNode + )} + + ); +}; +export default CompanyExpireWarning; diff --git a/src/components/VoiceCheck/index.tsx b/src/components/VoiceCheck/index.tsx index 5c57bc5..350797f 100644 --- a/src/components/VoiceCheck/index.tsx +++ b/src/components/VoiceCheck/index.tsx @@ -1,6 +1,17 @@ import { ChromeOutlined, SoundOutlined } from '@ant-design/icons'; +import { useBreakpoint } from '@ant-design/pro-components'; import { getLocale, Icon } from '@umijs/max'; -import { Alert, Divider, Image, Modal, Space, Tabs, Typography } from 'antd'; +import { + Alert, + Divider, + Flex, + Image, + Modal, + Popover, + Space, + Tabs, + Typography, +} from 'antd'; import { useCallback, useEffect, useState } from 'react'; import useRichI18n from '@/hooks/useRichI18n'; import { checkAudioPermission } from '@/utils'; @@ -8,9 +19,9 @@ import bus from '@/utils/eventBus'; import { $t } from '@/utils/i18n'; const { Paragraph } = Typography; -const ChangePassTips: React.FC = () => { +const VoiceCheck: React.FC = () => { const { richFormat } = useRichI18n(); - + const screens = useBreakpoint(); const [visible, setVisible] = useState(false); const [hasAudioPermission, setHasAudioPermission] = useState(true); @@ -69,25 +80,46 @@ const ChangePassTips: React.FC = () => { ), }, ]; - + const tipsNode = ( + <> + + + ); return ( <> - setVisible(true)}> - {!hasAudioPermission && ( - <> - - - - )} + setVisible(true)}> + {!hasAudioPermission && + (['xs', 'sm'].includes(screens || '') ? ( + + + + ) : ( + <> + {tipsNode} + + + ))} {/* {hasAudioPermission ? ( { className="flex align-center" /> )} */} - + { ); }; -export default ChangePassTips; +export default VoiceCheck; diff --git a/src/global.less b/src/global.less index 6cb8bb5..971e335 100644 --- a/src/global.less +++ b/src/global.less @@ -135,6 +135,16 @@ ol { padding-inline: 15px; } +.fixed-all-center { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 9999; + background-color: #fff; +} + @media (max-width: 768px) { .ant-table { width: 100%; diff --git a/src/locales/en_US/pages.ts b/src/locales/en_US/pages.ts index 076002c..e9ed0aa 100644 --- a/src/locales/en_US/pages.ts +++ b/src/locales/en_US/pages.ts @@ -95,7 +95,7 @@ export default { '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.company.expireToday': 'Subscription expiring soon; it expires today.', 'pages.totalDataSourceCount': 'Total Data Sources', 'pages.activeDataSourceCount': 'Active Data Sources', 'pages.mt4DataSourceCount': 'MT4 Data Sources', diff --git a/src/locales/zh_CN/pages.ts b/src/locales/zh_CN/pages.ts index af72acb..dd90000 100644 --- a/src/locales/zh_CN/pages.ts +++ b/src/locales/zh_CN/pages.ts @@ -95,7 +95,7 @@ export default { 'pages.company.expireSubTitle': '您的公司在该系统的使用授权已到期,各项功能已暂时锁定。请联系商务代表进行续费操作以恢复访问。', 'pages.company.expireInDays': '订阅即将到期,剩余 {days}天', - 'pages.company.expireToday': '今天到期', + 'pages.company.expireToday': '订阅即将到期,今天到期', 'pages.totalDataSourceCount': '数据源总数', 'pages.activeDataSourceCount': '活跃数据源', 'pages.mt4DataSourceCount': 'MT4 数据源', diff --git a/src/pages/profile/index.tsx b/src/pages/profile/index.tsx index e642600..3a8dc74 100644 --- a/src/pages/profile/index.tsx +++ b/src/pages/profile/index.tsx @@ -14,6 +14,7 @@ import { Row, Space, Tag, + Typography, } from 'antd'; import React, { useEffect } from 'react'; import { clearAccessToken } from '@/access'; @@ -22,6 +23,8 @@ import useUserInfo from '@/hooks/useUserInfo'; import { changeUserPass } from '@/services/api'; import { $t } from '@/utils/i18n'; +const { Text } = Typography; + const Profile: React.FC = () => { const { userInfo, setUserInfo } = useUserInfo(); const { isGlobalCompany } = useAccess(); @@ -77,13 +80,20 @@ const Profile: React.FC = () => { items.push({ key: '6', span: 'filled', - label: $t('pages.company.permanent'), - children: userCompany?.validityEndTime - ? userCompany.validityEndTime - : $t('pages.company.permanent'), + label: $t('table.validityEndTime'), + children: userCompany?.validityEndTime ? ( + + {userCompany.validityEndTime} + + {$t('pages.company.expired')} + + + ) : ( + $t('pages.company.permanent') + ), }); } - }, [userInfo]); + }, [userCompany, isGlobalCompany]); const changePasswordSuccessHadle = async () => { let countdown = 5; diff --git a/src/pages/rules/index.tsx b/src/pages/rules/index.tsx index b986537..df201b0 100644 --- a/src/pages/rules/index.tsx +++ b/src/pages/rules/index.tsx @@ -253,62 +253,64 @@ const RuleCommon: React.FC = () => {
- {!isGlobalCompany && hasPerms('rule:edit') && ( - <> - - - - - - - - - - - )} + onClick={() => handleToggleStatus(rule)} + > + {rule.status === 1 + ? $t('pages.rules.disable') + : $t('pages.rules.enable')} + + + + + + + + )} ); @@ -438,34 +440,36 @@ const RuleCommon: React.FC = () => { icon={} onClick={() => refreshRules(1)} /> - {!isGlobalCompany && hasPerms('rule:edit') && ( - <> - - - - )} + {!isGlobalCompany && + hasPerms('rule:edit') && + companyInfo?.validityStatus !== 2 && ( + <> + + + + )} diff --git a/src/wrappers/CompanyExpire.tsx b/src/wrappers/CompanyExpire.tsx new file mode 100644 index 0000000..46efce7 --- /dev/null +++ b/src/wrappers/CompanyExpire.tsx @@ -0,0 +1,13 @@ +import { Outlet, useAccess } from '@umijs/max'; +import CompanyExpireGuard from '@/components/CompanyExpireGuard'; +import useUserInfo from '@/hooks/useUserInfo'; + +export default () => { + const { isGlobalCompany } = useAccess(); + const { userInfo } = useUserInfo(); + const { company } = userInfo || {}; + if (!isGlobalCompany && company?.validityStatus === 2) { + return ; + } + return ; +};