diff --git a/src/assets/core.scss b/src/assets/core.scss
index e80fafa..8d2cea6 100644
--- a/src/assets/core.scss
+++ b/src/assets/core.scss
@@ -362,11 +362,13 @@
.icon-warning{
@apply text-red-500;
font-size: 20px;
- transform: translateY(5px);
+ //transform: translateY(5px);
margin-right: 20px;
}
.ant-modal-confirm-title{
- font-size: 20px;
+ font-size: 1rem;
+ line-height: 1.5rem;
+ font-weight: 400;
}
.ant-modal-confirm-content{
margin-top: 10px;
@@ -456,7 +458,20 @@
border-radius: 8px;
}
}
-
+.icon-language{
+ @apply relative text-gray-500 p-1.5 hover:bg-[#e3eeff] hover:text-gray-600 rounded cursor-pointer text-xl;
+}
+@keyframes animation_loading {
+ 0% {
+ transform: rotate(0deg);
+ }
+ 100% {
+ transform: rotate(360deg);
+ }
+}
+.icon-generating{
+ animation: animation_loading 6s linear infinite;
+}
// 全局按钮
.page-action {
@apply fixed right-10 bottom-10 flex flex-col gap-4 z-10;
@@ -466,6 +481,7 @@
flex: 1;
text-align: left;
padding-left: 15px;
+ margin-right: 10px;
}
&:disabled {
diff --git a/src/components/icons/index.tsx b/src/components/icons/index.tsx
index 1303332..283e5ae 100644
--- a/src/components/icons/index.tsx
+++ b/src/components/icons/index.tsx
@@ -208,26 +208,26 @@ export const IconUnlock = ({style, className}: IconProps) => (
)
export const IconPlaying = ({style, className}: IconProps) => (
-
)
export const IconGenerating = ({style, className}: IconProps) => (
-
)
export const IconGenerateFailed = ({style, className}: IconProps) => (
-
)
export const IconRegenerate = ({style, className}: IconProps) => (
-
diff --git a/src/components/icons/language-switcher.tsx b/src/components/icons/language-switcher.tsx
new file mode 100644
index 0000000..c72c0f7
--- /dev/null
+++ b/src/components/icons/language-switcher.tsx
@@ -0,0 +1,32 @@
+import useGlobalConfig from "@/hooks/useGlobalConfig.ts";
+import {useTranslation} from "react-i18next";
+import React from "react";
+import {useSearchParams} from "react-router-dom";
+
+function LanguageSwitcher() {
+ const {i18n} = useTranslation();
+ const [params] = useSearchParams();
+ const {globalConfig} = useGlobalConfig()
+ const handleChangeLang = async () => {
+ const key = i18n.language == 'zh-CN' ? 'en-US' : 'zh-CN'
+ await i18n.changeLanguage(key)
+ globalConfig.i18n = key
+ localStorage.setItem('ai-human-lang',key)
+ }
+ return (
+ (params.get('lang') == 'yes' || AppConfig.APP_LANG == 'multiple') ?
+
: null
+ )
+}
+
+export default LanguageSwitcher
\ No newline at end of file
diff --git a/src/contexts/auth/index.tsx b/src/contexts/auth/index.tsx
index f7fcbd5..d0dedbd 100644
--- a/src/contexts/auth/index.tsx
+++ b/src/contexts/auth/index.tsx
@@ -5,6 +5,10 @@ import {getAuthToken, setAuthToken} from "@/hooks/useAuth.ts";
import {auth} from "@/service/api/user.ts";
import {getAllCategory} from "@/service/api/article.ts";
import {BizError} from "@/service/types.ts";
+import {getRemainingDuration} from "@/service/api/order.ts";
+import {Modal} from "antd";
+import ModalWarning from "@/components/icons/ModalWarning.tsx";
+import {useTranslation} from "react-i18next";
const UserRoleStorageKey = 'user-current-role';
@@ -54,9 +58,9 @@ export const AuthProvider = ({children}: { children: React.ReactNode }) => {
token
}
})
- }catch (e){
+ } catch (e) {
const err = e as BizError;
- if(err.code == 1001){
+ if (err.code == 1001) {
// token失效
setAuthToken(null)
dispatch({
diff --git a/src/i18n/translations/en-US.json b/src/i18n/translations/en-US.json
index 9baeef3..4e91cd7 100644
--- a/src/i18n/translations/en-US.json
+++ b/src/i18n/translations/en-US.json
@@ -4,6 +4,7 @@
"cancel": "Cancel",
"close": "Close",
"confirm": {
+ "ok": "Confirm",
"push_title": "Push Notice",
"push_video": "Are you sure editing selected news?",
"title": "Notice"
@@ -145,6 +146,7 @@
"order_time": "Time stamp",
"title": "Title"
},
+ "remaining_duration_warning": "Unable to generate videos due to insufficient remaining time?",
"text": "Orders"
},
"recycle": {
@@ -185,6 +187,8 @@
"delete_description": "Are you sure you want to delete the video?",
"delete_description_count": "Are you sure you want to delete these {{count}} videos?",
"delete_empty": "Select the video you want to delete",
+ "delete_forever_confirm": "Do you want to permutely delete it?",
+ "delete_forever_confirm_count": "Do you want to permutely delete these videos?",
"download": "Download",
"generate_failed": "Generate Failed",
"generating": "Generating",
@@ -195,6 +199,8 @@
"push_failed": "some video streaming failed!",
"push_success": "Streaming success,please goto \"Streaming\"!",
"push_to_live": "Streaming",
+ "restore_confirm": "Do you want to restore it to the generating page?",
+ "restore_confirm_count": "Do you want to restore these videos to the generating page?",
"rollback_confirm_title": "Are you sure you want to revert this video?",
"sort_modify_confirm": "Are you change video sequence?",
"sort_modify_failed": "Video sequence change failed",
diff --git a/src/i18n/translations/zh-CN.json b/src/i18n/translations/zh-CN.json
index 6ab835b..bc6a2f9 100644
--- a/src/i18n/translations/zh-CN.json
+++ b/src/i18n/translations/zh-CN.json
@@ -4,6 +4,7 @@
"cancel": "取消",
"close": "关闭",
"confirm": {
+ "ok": "确定",
"push_title": "推流提示",
"push_video": "是否确定一键推流选中新闻视频?",
"title": "提示"
@@ -145,6 +146,7 @@
"order_time": "下单时间",
"title": "标题"
},
+ "remaining_duration_warning": "视频生成剩余时长为零,将无法生成视频,请尽快充值额度。",
"text": "订单记录"
},
"recycle": {
@@ -185,6 +187,8 @@
"delete_description": "已选择{{count}}条,确定要全部删除吗?",
"delete_description_count": "已选择{{count}}条,确定要全部删除吗?",
"delete_empty": "请选择要删除的视频",
+ "delete_forever_confirm": "是否彻底删除选中的视频?
这些视频将无法找回",
+ "delete_forever_confirm_count": "是否彻底删除选中的视频?
这些视频将无法找回!",
"download": "下载视频",
"generate_failed": "生成失败",
"generating": "生成中",
@@ -195,6 +199,8 @@
"push_failed": "选择视频中有部分视频还在生成中无法推送,推流成功视频前往数字人直播间页面查看!",
"push_success": "一键推流成功,已推流至数字人直播间,请前往数字人直播间页面查看!",
"push_to_live": "一键推流",
+ "restore_confirm": "是否将选中视频,还原到视频生成页?",
+ "restore_confirm_count": "是否将选中视频,还原到视频生成页",
"rollback_confirm_title": "您确定要回退此视频吗?",
"sort_modify_confirm": "是否采纳移动视频位置操作?",
"sort_modify_failed": "调整视频顺序失败,请重试!",
diff --git a/src/pages/recycle/index.tsx b/src/pages/recycle/index.tsx
index 7d370c5..4ee15f1 100644
--- a/src/pages/recycle/index.tsx
+++ b/src/pages/recycle/index.tsx
@@ -177,8 +177,8 @@ export default function RecycleIndex() {
emptyMessage={t('video.delete_empty')}
confirmMessage={}
onProcess={remove}
>{t('recycle.remove_forever')}}
@@ -188,6 +188,11 @@ export default function RecycleIndex() {
className='bg-[#4096ff] hover:bg-blue-600 text-white'
icon={}
onProcess={restore}
+ confirmMessage={}
emptyMessage={t('video.push_empty')}
onError={e => {
showToast(String((e as BizError).data || e.message), 'error')
diff --git a/src/pages/video/components/button-push2room.tsx b/src/pages/video/components/button-push2room.tsx
index 3bf973c..bf21931 100644
--- a/src/pages/video/components/button-push2room.tsx
+++ b/src/pages/video/components/button-push2room.tsx
@@ -32,6 +32,7 @@ export default function ButtonPush2Room(props: { ids: Id[]; list: VideoInfo[]; o
return
}
Modal.confirm({
+ wrapClassName:'root-modal-confirm',
title: ,
icon: ,
content: t("video.push_confirm"),
diff --git a/src/routes/index.tsx b/src/routes/index.tsx
index bd63e34..06fd65f 100644
--- a/src/routes/index.tsx
+++ b/src/routes/index.tsx
@@ -1,6 +1,6 @@
import {createBrowserRouter, RouterProvider,} from "react-router-dom";
-import {Suspense, useEffect,} from "react";
-import {ConfigProvider, App} from "antd";
+import React, {Suspense, useEffect,} from "react";
+import {ConfigProvider, App, Modal} from "antd";
import zhCN from 'antd/locale/zh_CN';
// for date-picker i18n
import dayjs from "dayjs";
@@ -11,6 +11,8 @@ import routes from "@/routes/routes.tsx";
import {DocumentTitle} from "@/components/document.tsx";
import {useTranslation} from "react-i18next";
import useGlobalConfig from "@/hooks/useGlobalConfig.ts";
+import {getRemainingDuration} from "@/service/api/order.ts";
+import ModalWarning from "@/components/icons/ModalWarning.tsx";
const router = createBrowserRouter([
@@ -31,16 +33,39 @@ const router = createBrowserRouter([
const AppRouter = () => {
const {globalConfig} = useGlobalConfig();
const {t,i18n} = useTranslation();
-
+
+ const initRemainingDuration = () => {
+ getRemainingDuration().then(remain => {
+ if(remain > 0){
+ Modal.warning({
+ wrapClassName:'root-modal-confirm',
+ title: t('confirm.title'),
+ icon: ,
+ content: t("order.remaining_duration_warning"),
+ okText: t('confirm.ok'),
+ centered: true
+ })
+ }
+ console.log('remain', remain)
+ })
+ }
useEffect(() => {
+ if(i18n.language){
+ if(i18n.language == 'multiple'){
+ const lang = localStorage.getItem('ai-human-lang') || (navigator.language.toLocaleLowerCase().indexOf('cn') != -1 ? 'zh-CN' : 'en-US')
+ i18n.changeLanguage(lang).catch(console.log)
+ return;
+ }
+ }
if (i18n && i18n.language == 'zh-CN') {
dayjs.locale('zh-cn');
}else{
dayjs.locale('en')
}
+ initRemainingDuration()
globalConfig.i18n = i18n.language
// i18n.changeLanguage(i18n).then(()=>console.log('change lang to ',i18n))
- }, [i18n])
+ }, [i18n.language])
return ( {
)
}
export const BaseLayout: React.FC = ({children}) => {
- const {i18n} = useTranslation();
- const [params] = useSearchParams();
+
return (
@@ -93,15 +94,7 @@ export const BaseLayout: React.FC = ({children}) => {
- {(params.get('lang') == 'yes' || AppConfig.APP_LANG == 'multiple') &&
- {
- i18n.language == 'zh-CN' ? (
-
- ) : (
-
- )
- }
-
}
+
diff --git a/src/service/api/order.ts b/src/service/api/order.ts
index 4b0a328..bba99d6 100644
--- a/src/service/api/order.ts
+++ b/src/service/api/order.ts
@@ -1,11 +1,18 @@
import {post} from "@/service/request.ts";
+type OrderInfoData = DataList
& {
+ remaining_duration: string | number;
+}
+
export function getList(params: OrderSearchParam) {
- return post<{
- list: OrderInfo[];
- remaining_duration: string | number;
- }>('/order/list', {
+ return post('/order/list', {
page_num: params.pagination.page || 1,
page_size: params.pagination.limit || 10,
})
+}
+
+
+export async function getRemainingDuration() {
+ const result = await getList({pagination: {page: 1, limit: 1}})
+ return Number(result.remaining_duration)
}
\ No newline at end of file
diff --git a/src/service/request.ts b/src/service/request.ts
index e7eeaef..6f3c397 100644
--- a/src/service/request.ts
+++ b/src/service/request.ts
@@ -12,6 +12,7 @@ const Axios = axios.create({
headers: {'Content-Type': JSON_FORMAT}
})
+// eslint-disable-next-line react-hooks/rules-of-hooks
const {globalConfig} = useGlobalConfig();
// 请求前拦截
Axios.interceptors.request.use(config => {