Compare commits
5 Commits
e022bc8036
...
38351e6873
Author | SHA1 | Date | |
---|---|---|---|
38351e6873 | |||
ab9e1b7e10 | |||
1e3f8dc3c6 | |||
07d3bb2bb9 | |||
381e1f16d1 |
@ -22,6 +22,11 @@ npm run build
|
|||||||
|
|
||||||
2、单独域名部署,设置环境变量ONLY_LIVE=yes,使用正常编译即可
|
2、单独域名部署,设置环境变量ONLY_LIVE=yes,使用正常编译即可
|
||||||
|
|
||||||
|
#### 多语言部署
|
||||||
|
应用默认使用简体中文进行编译;如果需要指定其他语言需要设置环境变量:`APP_LANGUAGE`;
|
||||||
|
|
||||||
|
`APP_LANGUAGE`目前支持的值有:`zh-CN`(中文)、`en-US`(英语)。
|
||||||
|
|
||||||
**使用docker**
|
**使用docker**
|
||||||
|
|
||||||
[x] TODO
|
[x] TODO
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
"description": "数字人直播间",
|
"description": "数字人直播间",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --host",
|
"dev": "vite --host",
|
||||||
"dev-test": "vite --host --mode=test",
|
"dev-test": "set APP_LANGUAGE=en-US && vite --host --mode=test",
|
||||||
|
"dev-lang-en": "set APP_LANGUAGE=en-US && vite --host --mode=lang-en",
|
||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
"build-test": "tsc && vite build --mode=test",
|
"build-test": "tsc && vite build --mode=test",
|
||||||
"build-relative": "tsc && vite build --mode=relative",
|
"build-relative": "tsc && vite build --mode=relative",
|
||||||
|
@ -272,9 +272,12 @@
|
|||||||
@apply text-right;
|
@apply text-right;
|
||||||
.btn-to-top {
|
.btn-to-top {
|
||||||
@apply w-[44px] h-[44px] inline-block bg-blue-300 text-center p-0 transition hover:bg-blue-500;
|
@apply w-[44px] h-[44px] inline-block bg-blue-300 text-center p-0 transition hover:bg-blue-500;
|
||||||
min-width: 0;
|
min-width: 0 !important;
|
||||||
border-radius: 50px;
|
border-radius: 50px;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
|
svg{
|
||||||
|
margin-left: 0 !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -454,6 +457,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.lang-en-US{
|
||||||
|
.page-action {
|
||||||
|
button{
|
||||||
|
@apply min-w-[140px];
|
||||||
|
.text{
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
svg{
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 时间选择
|
// 时间选择
|
||||||
.timer-select-container {
|
.timer-select-container {
|
||||||
|
@ -145,7 +145,7 @@ export default function ArticleEditModal(props: Props) {
|
|||||||
onCancel={() => props.onClose?.()}
|
onCancel={() => props.onClose?.()}
|
||||||
okButtonProps={{loading: state.loading}}
|
okButtonProps={{loading: state.loading}}
|
||||||
onOk={handleSave}
|
onOk={handleSave}
|
||||||
okText={props.type == 'news' ? t('confirm') : t('news.edit_generate_video_again')}
|
okText={props.type == 'news' ? t('confirm_text') : t('news.edit_generate_video_again')}
|
||||||
>
|
>
|
||||||
<div className="article-title mt-5">
|
<div className="article-title mt-5">
|
||||||
<input className={'input-box text-lg'} value={title} onChange={e => {
|
<input className={'input-box text-lg'} value={title} onChange={e => {
|
||||||
@ -170,7 +170,7 @@ export default function ArticleEditModal(props: Props) {
|
|||||||
<div className="flex gap-10 ">
|
<div className="flex gap-10 ">
|
||||||
{props.type == 'news' && props.id ? <button className="text-gray-400 hover:text-gray-800" onClick={handlePush2Video}>{t('news.edit_generate_video')}{state.generating?'推送中...':''}</button> : null}
|
{props.type == 'news' && props.id ? <button className="text-gray-400 hover:text-gray-800" onClick={handlePush2Video}>{t('news.edit_generate_video')}{state.generating?'推送中...':''}</button> : null}
|
||||||
<button className="text-gray-400 hover:text-gray-800" onClick={() => props.onClose?.()}>{t('cancel')}</button>
|
<button className="text-gray-400 hover:text-gray-800" onClick={() => props.onClose?.()}>{t('cancel')}</button>
|
||||||
<button onClick={handleSave} className="text-gray-800 hover:text-blue-500">{props.type == 'news' ? t('confirm') : t('news.edit_generate_again')}</button>
|
<button onClick={handleSave} className="text-gray-800 hover:text-blue-500">{props.type == 'news' ? t('confirm_text') : t('news.edit_generate_again')}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Modal>);
|
</Modal>);
|
||||||
|
@ -56,7 +56,7 @@ export default function ButtonBatch(
|
|||||||
if(confirmMessage){
|
if(confirmMessage){
|
||||||
modal.confirm({
|
modal.confirm({
|
||||||
wrapClassName: 'root-modal-confirm',
|
wrapClassName: 'root-modal-confirm',
|
||||||
title: title || t('confirm.title'),
|
title: <span dangerouslySetInnerHTML={{__html:title || t('confirm.title')}}></span>,
|
||||||
centered: true,
|
centered: true,
|
||||||
icon: <span className="anticon anticon-exclamation-circle"><IconWarningCircle/></span>,
|
icon: <span className="anticon anticon-exclamation-circle"><IconWarningCircle/></span>,
|
||||||
content: confirmMessage,
|
content: confirmMessage,
|
||||||
|
@ -9,6 +9,6 @@ export const DocumentTitle: React.FC<DocumentTitleProps> = ({children, title}) =
|
|||||||
if (title || children) {
|
if (title || children) {
|
||||||
document.title = title || children || '';
|
document.title = title || children || '';
|
||||||
}
|
}
|
||||||
}, []);
|
}, [title,children]);
|
||||||
return <></>
|
return <></>
|
||||||
}
|
}
|
@ -122,7 +122,7 @@ const TagSelect = (props: {
|
|||||||
set(!visible)
|
set(!visible)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span>{checkedAll || selectValues.length == 0 ? t('news.news_all_source') : t('news.source')}</span>
|
<span>{(checkedAll || selectValues.length == 0) ? t('news.news_all_source') : t('news.source')}</span>
|
||||||
<CaretUpOutlined className={`ml-2 arrow-icon ${visible ? 'rotate-0' : 'rotate-180'}`}/>
|
<CaretUpOutlined className={`ml-2 arrow-icon ${visible ? 'rotate-0' : 'rotate-180'}`}/>
|
||||||
</div>
|
</div>
|
||||||
<div className={`options-list-container absolute ${visible ? 'block' : 'hidden'}`}>
|
<div className={`options-list-container absolute ${visible ? 'block' : 'hidden'}`}>
|
||||||
@ -131,7 +131,7 @@ const TagSelect = (props: {
|
|||||||
<li className="select-option-item relative">
|
<li className="select-option-item relative">
|
||||||
<div className="option-value whitespace-nowrap flex justify-between">
|
<div className="option-value whitespace-nowrap flex justify-between">
|
||||||
<span className="text-center flex-1"
|
<span className="text-center flex-1"
|
||||||
onClick={() => handleAllChanged(!checkedAll)}>t('news.news_all_source')</span>
|
onClick={() => handleAllChanged(!checkedAll)}>{t('news.news_all_source')}</span>
|
||||||
<Checkbox className="ml-6" checked={checkedAll}
|
<Checkbox className="ml-6" checked={checkedAll}
|
||||||
onChange={e => handleAllChanged(e.target.checked)}/>
|
onChange={e => handleAllChanged(e.target.checked)}/>
|
||||||
</div>
|
</div>
|
||||||
|
13
src/hooks/useGlobalConfig.ts
Normal file
13
src/hooks/useGlobalConfig.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
const globalConfig:{
|
||||||
|
i18n?:I18n
|
||||||
|
} = {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function useGlobalConfig(){
|
||||||
|
return {
|
||||||
|
globalConfig
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useGlobalConfig;
|
@ -3,10 +3,10 @@ import {initReactI18next} from 'react-i18next';
|
|||||||
import LangEN from './translations/en-US.json';
|
import LangEN from './translations/en-US.json';
|
||||||
import LangCN from './translations/zh-CN.json';
|
import LangCN from './translations/zh-CN.json';
|
||||||
|
|
||||||
console.log('AppConfig',AppMode)
|
console.log('AppConfig',AppMode,AppConfig)
|
||||||
i18next.use(initReactI18next).init({
|
i18next.use(initReactI18next).init({
|
||||||
debug: true,
|
debug: true,
|
||||||
lng:'en-US',
|
lng: (AppConfig.APP_LANG || 'zh-CN').trim(),
|
||||||
fallbackLng: 'en-US',
|
fallbackLng: 'en-US',
|
||||||
resources: {
|
resources: {
|
||||||
'en-US': {translation:LangEN},
|
'en-US': {translation:LangEN},
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"AppTitle": "Metahuman Streaming platform",
|
"AppTitle": "AI Livesteam",
|
||||||
"Hello": "Hello",
|
"Hello": "Hello",
|
||||||
"close": "Close",
|
"close": "Close",
|
||||||
"confirm": {
|
"confirm": {
|
||||||
@ -12,21 +12,21 @@
|
|||||||
"delete_success": "Delete success",
|
"delete_success": "Delete success",
|
||||||
"download": "Download",
|
"download": "Download",
|
||||||
"generating": {
|
"generating": {
|
||||||
"title": "Preview - Click video item to play"
|
"title": "Preview - Click the video to play"
|
||||||
},
|
},
|
||||||
"history": {
|
"history": {
|
||||||
"delete_confirm": "Are you sure you want to delete this video?",
|
"delete_confirm": "Are you sure you want to delete this video?",
|
||||||
"push_success": "Streaming success",
|
"push_success": "Streaming success",
|
||||||
"search_key": "Please enter keywords for video title",
|
"search_key": "Please enter title keywords",
|
||||||
"text": "History video"
|
"text": "Video history"
|
||||||
},
|
},
|
||||||
"live": {
|
"live": {
|
||||||
"duration": "Duration",
|
"duration": "Duration",
|
||||||
"edit_locked": "Disable to sort",
|
"edit_locked": "Locked",
|
||||||
"edit_unlock": "Unlock",
|
"edit_unlock": "Unlock",
|
||||||
"play_first": "Play first video",
|
"play_first": "Play first video",
|
||||||
"playlist_count": "Current playlist total has {{count}} items",
|
"playlist_count": "{{count}} videos in total",
|
||||||
"title": "Live"
|
"title": "Livestream"
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"code_sending": "Sending...",
|
"code_sending": "Sending...",
|
||||||
@ -43,27 +43,29 @@
|
|||||||
"editing": "Editing",
|
"editing": "Editing",
|
||||||
"generating": "Generating",
|
"generating": "Generating",
|
||||||
"live": "Streaming",
|
"live": "Streaming",
|
||||||
"materials": "News Materials"
|
"materials": "News"
|
||||||
},
|
},
|
||||||
"news": {
|
"news": {
|
||||||
"delete_confirm": "Are you sure you want to delete this item?",
|
"delete_confirm": "Are you sure you want to delete this item?",
|
||||||
"delete_confirm_count": "Are you sure you want to delete these {{count}} items?",
|
"delete_confirm_count": "Are you sure you want to delete these {{count}} items?",
|
||||||
"delete_description": "This item will be deleted.<br/>It can be recovered from the “news” page. ",
|
"delete_description": "This item will be deleted.<br/>It can be recovered from the \"News\" page. ",
|
||||||
|
"delete_description_count": "These item will be deleted.<br/>It can be recovered from the \"News\" page. ",
|
||||||
"delete_empty": "Please select the items to delete",
|
"delete_empty": "Please select the items to delete",
|
||||||
"download_empty": "Please select the news to download",
|
"download_empty": "Please select the news to download",
|
||||||
"download_failed": "Download failed!",
|
"download_failed": "Download failed!",
|
||||||
"edit_form_search": "Please enter keywords for news title",
|
"edit_form_search": "Please enter title keywords",
|
||||||
"editing": "Editing",
|
"editing": "Editing",
|
||||||
"filter_all": "All",
|
"filter_all": "All",
|
||||||
"filter_source": "News source",
|
"filter_source": "News source",
|
||||||
"generate_video": "Generating",
|
"generate_video": "Generating",
|
||||||
"get_detail": "Get news details",
|
"get_detail": "Get news details",
|
||||||
"get_detail_error": "Get new details failed",
|
"get_detail_error": "Get new details failed",
|
||||||
"image_count": "image",
|
"image_count": "Images",
|
||||||
|
"word_count": "Words",
|
||||||
"materials": {
|
"materials": {
|
||||||
"title": "News Materials"
|
"title": "News Materials"
|
||||||
},
|
},
|
||||||
"news_all_source": "source",
|
"news_all_source": "All",
|
||||||
"push_empty": "please select the news to edit",
|
"push_empty": "please select the news to edit",
|
||||||
"push_failed": "Failed to editing",
|
"push_failed": "Failed to editing",
|
||||||
"push_stream_empty": "please select the news to streaming",
|
"push_stream_empty": "please select the news to streaming",
|
||||||
@ -71,44 +73,40 @@
|
|||||||
"push_streaming": "Pushing...",
|
"push_streaming": "Pushing...",
|
||||||
"push_success": "Push success",
|
"push_success": "Push success",
|
||||||
"push_to_edit": "Editing",
|
"push_to_edit": "Editing",
|
||||||
"pushed": "Pushed",
|
"pushed": "Editing",
|
||||||
"search_key_title": "Please enter keywords",
|
"search_key_title": "Please enter title keywords",
|
||||||
"source": "source",
|
"source": "Source",
|
||||||
"title": "News content",
|
"title": "News content",
|
||||||
"title_image_count": "Number of pictures",
|
"title_image_count": "No. of images",
|
||||||
"title_operate": "Operation",
|
"title_operate": "",
|
||||||
"title_time": "time",
|
"title_time": "Time stamp",
|
||||||
"title_word_count": "Wordcount",
|
"title_word_count": "Word count",
|
||||||
"word_count": "word",
|
"edit_digital_text": "MetaHuman Material",
|
||||||
|
"edit_other_text": "Other media Material",
|
||||||
"edit_digital_text": "MetaHuman materiel",
|
|
||||||
"edit_other_text": "Other media materiel",
|
|
||||||
"edit_generate_video_again": "Regenerate",
|
"edit_generate_video_again": "Regenerate",
|
||||||
"edit_generate_again": "Regenerate",
|
"edit_generate_again": "Regenerate",
|
||||||
"edit_generate_video": "Video generation",
|
"edit_generate_video": "Generating",
|
||||||
"edit_save_failed": "Save failed!",
|
"edit_save_failed": "Save failed!",
|
||||||
|
|
||||||
"edit_notice_keep_1": "Keep at least one content block",
|
"edit_notice_keep_1": "Keep at least one content block",
|
||||||
"edit_notice_enter_text": "Please enter content",
|
"edit_notice_enter_text": "Please enter content",
|
||||||
"edit_notice_enter_article_title": "Please enter title",
|
"edit_notice_enter_article_title": "Please enter title",
|
||||||
"edit_notice_enter_article_title1": "Please enter news title",
|
"edit_notice_enter_article_title1": "Please enter news title",
|
||||||
"edit_notice_enter_article_content": "Please enter content",
|
"edit_notice_enter_article_content": "Please enter content",
|
||||||
|
|
||||||
"edit_add_group": "Add Group",
|
"edit_add_group": "Add Group",
|
||||||
"edit_delete_group": "Delete Group",
|
"edit_delete_group": "Delete Group",
|
||||||
"edit_delete_group_confirm": "Are you sure delete the group?",
|
"edit_delete_group_confirm": "Are you sure you want to delete the group?",
|
||||||
"delete_the_picture": "Are you sure delete the picture?"
|
"delete_the_picture": "Are you sure delete the picture?"
|
||||||
},
|
},
|
||||||
"upload": {
|
"upload": {
|
||||||
"upload_failed": "Upload failed",
|
"upload_failed": "Upload failed",
|
||||||
"delete_confirm": "Are you sure delete the picture?",
|
"delete_confirm": "Are you sure delete the picture?",
|
||||||
"upload_image": "Upload Picture"
|
"upload_image": "Upload Image"
|
||||||
},
|
},
|
||||||
"delete": "Delete",
|
"delete": "Delete",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"confirm": "Confirm",
|
"confirm_text": "Confirm",
|
||||||
"select": {
|
"select": {
|
||||||
"pushed": "Pushed: {{count}}",
|
"pushed": "Pushed: {{count}}",
|
||||||
"select_all": "Select all",
|
"select_all": "Select all",
|
||||||
"selected": "Selected",
|
"selected": "Selected",
|
||||||
"selected_some": "Selected: {{count}}",
|
"selected_some": "Selected: {{count}}",
|
||||||
@ -116,7 +114,7 @@
|
|||||||
"total": "Total: {{count}}"
|
"total": "Total: {{count}}"
|
||||||
},
|
},
|
||||||
"time_filter": {
|
"time_filter": {
|
||||||
"all": "All time",
|
"all": "All",
|
||||||
"last_week": "Last week",
|
"last_week": "Last week",
|
||||||
"past_24_hour": "Past 24 hour",
|
"past_24_hour": "Past 24 hour",
|
||||||
"past_30_min": "Past 30 min",
|
"past_30_min": "Past 30 min",
|
||||||
@ -128,14 +126,16 @@
|
|||||||
},
|
},
|
||||||
"video": {
|
"video": {
|
||||||
"delete_confirm_title": "Are you sure you want to delete this video?",
|
"delete_confirm_title": "Are you sure you want to delete this video?",
|
||||||
"delete_confirm": "These videos will be deleted.<br.>They can be recovered from the “news” page. ",
|
"delete_confirm": "The video will be deleted.<br/> It can be recovered from the \"News\" page. ",
|
||||||
"delete_description": "Are you sure you want to delete these {{count}} videos?",
|
"delete_confirm_count": "These videos will be deleted.<br/> They can be recovered from the \"News\" page. ",
|
||||||
|
"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_empty": "Select the video you want to delete",
|
||||||
"download": "Download",
|
"download": "Download",
|
||||||
"push_confirm": "Are you sure you want to streaming these video?",
|
"push_confirm": "Are you sure you want to streaming these video?",
|
||||||
"push_empty": "Select the video you want to streaming",
|
"push_empty": "Select the video you want to streaming",
|
||||||
"push_failed": "some video streaming failed!",
|
"push_failed": "some video streaming failed!",
|
||||||
"push_success": "Streaming success,please goto Streaming!",
|
"push_success": "Streaming success,please goto \"Streaming\"!",
|
||||||
"push_to_live": "Streaming",
|
"push_to_live": "Streaming",
|
||||||
"sort_modify_confirm": "Are you change video sequence?",
|
"sort_modify_confirm": "Are you change video sequence?",
|
||||||
"sort_modify_failed": "Video sequence change failed",
|
"sort_modify_failed": "Video sequence change failed",
|
||||||
@ -144,9 +144,10 @@
|
|||||||
"sort_modify_success": "Video sequence changed",
|
"sort_modify_success": "Video sequence changed",
|
||||||
"title": "Title",
|
"title": "Title",
|
||||||
"title_generated_time": "Time stamp",
|
"title_generated_time": "Time stamp",
|
||||||
"title_operation": "Operation",
|
"title_operation": "",
|
||||||
"title_thumb": "Cover",
|
"title_thumb": "Cover",
|
||||||
"playing": "Playing",
|
"playing": "Playing",
|
||||||
"generating": "Generating"
|
"generating": "Generating"
|
||||||
}
|
},
|
||||||
}
|
"history.pushed": "Streaming: {{count}}"
|
||||||
|
}
|
||||||
|
@ -49,6 +49,7 @@
|
|||||||
"delete_confirm": "你确定要删除吗?",
|
"delete_confirm": "你确定要删除吗?",
|
||||||
"delete_confirm_count": "你确定要删除选择的 {{count}} 条新闻吗?",
|
"delete_confirm_count": "你确定要删除选择的 {{count}} 条新闻吗?",
|
||||||
"delete_description": "删除后需从新闻素材中重新选择",
|
"delete_description": "删除后需从新闻素材中重新选择",
|
||||||
|
"delete_description_count": "删除后需从新闻素材中重新选择",
|
||||||
"delete_empty": "请选择要删除的新闻",
|
"delete_empty": "请选择要删除的新闻",
|
||||||
"download_empty": "请选择要下载的新闻",
|
"download_empty": "请选择要下载的新闻",
|
||||||
"download_failed": "下载新闻失败,请重试!",
|
"download_failed": "下载新闻失败,请重试!",
|
||||||
@ -80,20 +81,17 @@
|
|||||||
"title_time": "时间",
|
"title_time": "时间",
|
||||||
"title_word_count": "字数",
|
"title_word_count": "字数",
|
||||||
"word_count": "字数",
|
"word_count": "字数",
|
||||||
|
|
||||||
"edit_digital_text": "数字人主播台编辑区",
|
"edit_digital_text": "数字人主播台编辑区",
|
||||||
"edit_other_text": "素材融合呈现编辑区",
|
"edit_other_text": "素材融合呈现编辑区",
|
||||||
"edit_generate_video_again": "重新生成",
|
"edit_generate_video_again": "重新生成",
|
||||||
"edit_generate_again": "重新生成",
|
"edit_generate_again": "重新生成",
|
||||||
"edit_generate_video": "生成视频",
|
"edit_generate_video": "生成视频",
|
||||||
"edit_save_failed": "保存失败,请重试!",
|
"edit_save_failed": "保存失败,请重试!",
|
||||||
|
|
||||||
"edit_notice_keep_1": "至少保留一个内容块",
|
"edit_notice_keep_1": "至少保留一个内容块",
|
||||||
"edit_notice_enter_text": "请先添加内容",
|
"edit_notice_enter_text": "请先添加内容",
|
||||||
"edit_notice_enter_article_title": "请输入文章标题",
|
"edit_notice_enter_article_title": "请输入文章标题",
|
||||||
"edit_notice_enter_article_title1": "请输入标题内容",
|
"edit_notice_enter_article_title1": "请输入标题内容",
|
||||||
"edit_notice_enter_article_content": "请输入正文文本内容",
|
"edit_notice_enter_article_content": "请输入正文文本内容",
|
||||||
|
|
||||||
"edit_add_group": "新增分组",
|
"edit_add_group": "新增分组",
|
||||||
"edit_delete_group": "删除此分组",
|
"edit_delete_group": "删除此分组",
|
||||||
"edit_delete_group_confirm": "请确认删除此分组?",
|
"edit_delete_group_confirm": "请确认删除此分组?",
|
||||||
@ -106,7 +104,7 @@
|
|||||||
},
|
},
|
||||||
"delete": "删除",
|
"delete": "删除",
|
||||||
"cancel": "取消",
|
"cancel": "取消",
|
||||||
"confirm": "确定",
|
"confirm_text": "确定",
|
||||||
"select": {
|
"select": {
|
||||||
"pushed": "已推送: {{count}} 条",
|
"pushed": "已推送: {{count}} 条",
|
||||||
"select_all": "全选",
|
"select_all": "全选",
|
||||||
@ -129,7 +127,9 @@
|
|||||||
"video": {
|
"video": {
|
||||||
"delete_confirm_title": "你确定要删除此视频吗 ",
|
"delete_confirm_title": "你确定要删除此视频吗 ",
|
||||||
"delete_confirm": "删除后需重新生成视频",
|
"delete_confirm": "删除后需重新生成视频",
|
||||||
|
"delete_confirm_count": "删除后需重新生成视频",
|
||||||
"delete_description": "已选择{{count}}条,确定要全部删除吗?",
|
"delete_description": "已选择{{count}}条,确定要全部删除吗?",
|
||||||
|
"delete_description_count": "已选择{{count}}条,确定要全部删除吗?",
|
||||||
"delete_empty": "请选择要删除的视频",
|
"delete_empty": "请选择要删除的视频",
|
||||||
"download": "下载视频",
|
"download": "下载视频",
|
||||||
"push_confirm": "是否确定一键推流选中新闻视频?",
|
"push_confirm": "是否确定一键推流选中新闻视频?",
|
||||||
@ -147,5 +147,6 @@
|
|||||||
"title_operation": "操作",
|
"title_operation": "操作",
|
||||||
"title_thumb": "缩略图",
|
"title_thumb": "缩略图",
|
||||||
"playing": "播放中"
|
"playing": "播放中"
|
||||||
}
|
},
|
||||||
}
|
"history.pushed": "已推送 {{count}} 条"
|
||||||
|
}
|
||||||
|
@ -49,7 +49,7 @@ export default function SearchForm({onSearch}: Props) {
|
|||||||
placeholder={t("history.search_key")}
|
placeholder={t("history.search_key")}
|
||||||
/>
|
/>
|
||||||
<TimeSelect
|
<TimeSelect
|
||||||
className="w-[120px] ml-1"
|
className="w-[140px] ml-1"
|
||||||
value={state.time_flag}
|
value={state.time_flag}
|
||||||
onChange={handleTimeFilter}
|
onChange={handleTimeFilter}
|
||||||
/>
|
/>
|
||||||
|
@ -106,17 +106,17 @@ export default function LibraryIndex() {
|
|||||||
<div className="live-control flex justify-between mb-2">
|
<div className="live-control flex justify-between mb-2">
|
||||||
<div className="pl-[70px]"></div>
|
<div className="pl-[70px]"></div>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<Space className="text-gray-400">
|
<Space className="text-gray-400" size={20}>
|
||||||
<span>{t('select.total',{count:data?.list.length || 0})}</span>
|
<span>{t('select.total',{count:data?.list?.length || 0})}</span>
|
||||||
<span>{t('select.pushed',{count:state.pushedCount})}</span>
|
<span>{t('history.pushed',{count:state.pushedCount})}</span>
|
||||||
<span className={'text-blue-500'}>{t('select.selected_some',{count:checkedIdArray.length})}</span>
|
<span className={'text-blue-500'}>{t('select.selected_some',{count:checkedIdArray.length})}</span>
|
||||||
</Space>
|
</Space>
|
||||||
<button className="hover:text-blue-300 text-gray-400 ml-2"
|
<button className="hover:text-blue-300 text-gray-400 ml-4"
|
||||||
onClick={() => handleAllCheckedChange(checkedIdArray.length != data?.list.length)}>
|
onClick={() => handleAllCheckedChange(checkedIdArray.length != data?.list.length)}>
|
||||||
<span className="text-sm mr-2">{t("select.select_all")}</span>
|
<span className="text-sm mr-2">{t("select.select_all")}</span>
|
||||||
{/*<CheckCircleFilled className={clsx({'text-blue-500': state.checkedAll})}/>*/}
|
{/*<CheckCircleFilled className={clsx({'text-blue-500': state.checkedAll})}/>*/}
|
||||||
</button>
|
</button>
|
||||||
<Checkbox checked={checkedIdArray.length == data?.list.length}
|
<Checkbox checked={checkedIdArray.length == data?.list?.length}
|
||||||
onChange={e => handleAllCheckedChange(e.target.checked)}/>
|
onChange={e => handleAllCheckedChange(e.target.checked)}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -159,9 +159,17 @@ export default function LibraryIndex() {
|
|||||||
onSuccess={refresh}
|
onSuccess={refresh}
|
||||||
className='bg-gray-300 hover:bg-gray-400 text-white'
|
className='bg-gray-300 hover:bg-gray-400 text-white'
|
||||||
icon={<IconDelete className=""/>}
|
icon={<IconDelete className=""/>}
|
||||||
title={t('video.delete_description',{count:checkedIdArray.length})}
|
title={
|
||||||
|
checkedIdArray.length == 1
|
||||||
|
? t('video.delete_description',{count:checkedIdArray.length})
|
||||||
|
: t('video.delete_description_count',{count:checkedIdArray.length})
|
||||||
|
}
|
||||||
emptyMessage={t('video.delete_empty')}
|
emptyMessage={t('video.delete_empty')}
|
||||||
confirmMessage={t('video.delete_confirm')}
|
confirmMessage={<span dangerouslySetInnerHTML={{
|
||||||
|
__html: checkedIdArray.length == 1
|
||||||
|
? t('video.delete_confirm')
|
||||||
|
: t('video.delete_confirm_count',{count:checkedIdArray.length})
|
||||||
|
}}></span>}
|
||||||
onProcess={deleteHistories}
|
onProcess={deleteHistories}
|
||||||
>{t('delete_batch')}</ButtonBatch>}
|
>{t('delete_batch')}</ButtonBatch>}
|
||||||
{checkedIdArray?.length > 0 && <ButtonBatch
|
{checkedIdArray?.length > 0 && <ButtonBatch
|
||||||
|
@ -324,7 +324,10 @@ export default function LiveIndex() {
|
|||||||
className='bg-gray-300 hover:bg-gray-400 text-white'
|
className='bg-gray-300 hover:bg-gray-400 text-white'
|
||||||
selected={checkedIdArray}
|
selected={checkedIdArray}
|
||||||
emptyMessage={t('video.delete_empty')}
|
emptyMessage={t('video.delete_empty')}
|
||||||
confirmMessage={t('video.delete_description',{count:checkedIdArray.length})}
|
confirmMessage={checkedIdArray.length > 1?
|
||||||
|
t('video.delete_description_count',{count:checkedIdArray.length})
|
||||||
|
:
|
||||||
|
t('video.delete_description',{count:checkedIdArray.length})}
|
||||||
onSuccess={loadList}
|
onSuccess={loadList}
|
||||||
onProcess={processDeleteVideo}
|
onProcess={processDeleteVideo}
|
||||||
>
|
>
|
||||||
|
@ -30,8 +30,8 @@ export default function ButtonDeleteBatch(props: { ids: Id[];onSuccess?: () => v
|
|||||||
modal.confirm({
|
modal.confirm({
|
||||||
wrapClassName:'root-modal-confirm',
|
wrapClassName:'root-modal-confirm',
|
||||||
icon: <span className="anticon anticon-exclamation-circle"><IconWarningCircle/></span>,
|
icon: <span className="anticon anticon-exclamation-circle"><IconWarningCircle/></span>,
|
||||||
title: t('news.delete_confirm_count',{count:props.ids.length}),
|
title: t(props.ids.length == 1 ?'news.delete_confirm':'news.delete_confirm_count',{count:props.ids.length}),
|
||||||
content: <span dangerouslySetInnerHTML={{__html:t('news.delete_description')}}></span>,
|
content: <span dangerouslySetInnerHTML={{__html:props.ids.length == 1 ?t('news.delete_description') :t('news.delete_description_count')}}></span>,
|
||||||
onOk: handlePush,
|
onOk: handlePush,
|
||||||
centered: true
|
centered: true
|
||||||
})
|
})
|
||||||
|
@ -171,11 +171,11 @@ export default function VideoIndex() {
|
|||||||
<div className="live-control flex justify-between">
|
<div className="live-control flex justify-between">
|
||||||
<div className="pl-[70px]"></div>
|
<div className="pl-[70px]"></div>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<Space>
|
<Space size={20}>
|
||||||
<span>{t('select.selected_some',{count:videoData.length || 0})}</span>
|
<span>{t('select.total',{count:videoData.length || 0})}</span>
|
||||||
<span className={'text-blue-500'}>{t('select.selected_some',{count:checkedIdArray.length})}</span>
|
<span className={'text-blue-500'}>{t('select.selected_some',{count:checkedIdArray.length})}</span>
|
||||||
</Space>
|
</Space>
|
||||||
<button className="hover:text-blue-300 text-gray-400 ml-2"
|
<button className="hover:text-blue-300 text-gray-400 ml-5"
|
||||||
onClick={handleAllCheckedChange}>
|
onClick={handleAllCheckedChange}>
|
||||||
<span className="text-sm mr-2">{t("select.select_all")}</span>
|
<span className="text-sm mr-2">{t("select.select_all")}</span>
|
||||||
{/*<CheckCircleFilled className={clsx({'text-blue-500': state.checkedAll})}/>*/}
|
{/*<CheckCircleFilled className={clsx({'text-blue-500': state.checkedAll})}/>*/}
|
||||||
@ -261,9 +261,16 @@ export default function VideoIndex() {
|
|||||||
onProcess={deleteFromList}
|
onProcess={deleteFromList}
|
||||||
selected={checkedIdArray}
|
selected={checkedIdArray}
|
||||||
emptyMessage={t('video.delete_empty')}
|
emptyMessage={t('video.delete_empty')}
|
||||||
title={t('video.delete_description',{count:checkedIdArray.length})}
|
title={
|
||||||
|
checkedIdArray.length == 1 ? t('video.delete_description',{count:checkedIdArray.length}):
|
||||||
|
t('video.delete_description_count',{count:checkedIdArray.length})
|
||||||
|
}
|
||||||
className='bg-gray-300 hover:bg-gray-400 text-white'
|
className='bg-gray-300 hover:bg-gray-400 text-white'
|
||||||
confirmMessage={t('video.delete_confirm')}
|
confirmMessage={<span dangerouslySetInnerHTML={{
|
||||||
|
__html:checkedIdArray.length == 1?
|
||||||
|
t('video.delete_confirm',{count:checkedIdArray.length}):
|
||||||
|
t('video.delete_confirm_count',{count:checkedIdArray.length})
|
||||||
|
}}></span>}
|
||||||
onSuccess={() => {
|
onSuccess={() => {
|
||||||
showToast(t('delete_success'), 'success')
|
showToast(t('delete_success'), 'success')
|
||||||
loadList()
|
loadList()
|
||||||
|
@ -11,6 +11,7 @@ import routes from "@/routes/routes.tsx";
|
|||||||
import {DocumentTitle} from "@/components/document.tsx";
|
import {DocumentTitle} from "@/components/document.tsx";
|
||||||
import useConfig from "@/hooks/useConfig.ts";
|
import useConfig from "@/hooks/useConfig.ts";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
|
import useGlobalConfig from "@/hooks/useGlobalConfig.ts";
|
||||||
|
|
||||||
|
|
||||||
const router = createBrowserRouter([
|
const router = createBrowserRouter([
|
||||||
@ -27,21 +28,23 @@ const router = createBrowserRouter([
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const {globalConfig} = useGlobalConfig();
|
||||||
// future={{v7_startTransition: true,v7_relativeSplatPath: true}}
|
// future={{v7_startTransition: true,v7_relativeSplatPath: true}}
|
||||||
const AppRouter = () => {
|
const AppRouter = () => {
|
||||||
const {t,i18n:langConfig} = useTranslation();
|
const {t,i18n} = useTranslation();
|
||||||
const {i18n} = useConfig();
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (i18n && i18n == 'zh-CN') {
|
if (i18n && i18n.language == 'zh-CN') {
|
||||||
dayjs.locale('zh-cn');
|
dayjs.locale('zh-cn');
|
||||||
}else{
|
}else{
|
||||||
dayjs.locale('en')
|
dayjs.locale('en')
|
||||||
}
|
}
|
||||||
langConfig.changeLanguage(i18n).then(()=>console.log('change lang to ',i18n))
|
globalConfig.i18n = i18n.language
|
||||||
|
// i18n.changeLanguage(i18n).then(()=>console.log('change lang to ',i18n))
|
||||||
}, [i18n])
|
}, [i18n])
|
||||||
|
|
||||||
return (<ConfigProvider
|
return (<ConfigProvider
|
||||||
locale={i18n == 'zh-CN' ? zhCN : undefined}
|
locale={i18n?.language?.toString() == 'zh-CN' ? zhCN : undefined}
|
||||||
theme={{
|
theme={{
|
||||||
token: {
|
token: {
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
@ -49,7 +52,7 @@ const AppRouter = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DocumentTitle title={t('AppTitle')}/>
|
<DocumentTitle title={t('AppTitle')}/>
|
||||||
<App>
|
<App className={`lang-${i18n.language}`}>
|
||||||
<Suspense fallback={<Loader/>}>
|
<Suspense fallback={<Loader/>}>
|
||||||
<RouterProvider future={{v7_startTransition: true}} router={router}/>
|
<RouterProvider future={{v7_startTransition: true}} router={router}/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {Outlet, useLocation, useNavigate} from "react-router-dom";
|
import {Outlet, useLocation, useNavigate, useSearchParams} from "react-router-dom";
|
||||||
import {Button, Divider, Dropdown, MenuProps} from "antd";
|
import {Button, Divider, Dropdown, MenuProps} from "antd";
|
||||||
import React, {useEffect} from "react";
|
import React, {useEffect} from "react";
|
||||||
|
|
||||||
@ -77,7 +77,8 @@ const NavigationUserContainer = () => {
|
|||||||
</div>)
|
</div>)
|
||||||
}
|
}
|
||||||
export const BaseLayout: React.FC<LayoutProps> = ({children}) => {
|
export const BaseLayout: React.FC<LayoutProps> = ({children}) => {
|
||||||
const {i18n,onChangeLocalization} = useConfig();
|
const {i18n} = useTranslation();
|
||||||
|
const [params] = useSearchParams();
|
||||||
return (<div className={'dashboard-layout min-h-screen'}>
|
return (<div className={'dashboard-layout min-h-screen'}>
|
||||||
<div className="min-h-screen w-full">
|
<div className="min-h-screen w-full">
|
||||||
<div className="app-header">
|
<div className="app-header">
|
||||||
@ -86,13 +87,15 @@ export const BaseLayout: React.FC<LayoutProps> = ({children}) => {
|
|||||||
</div>
|
</div>
|
||||||
<DashboardNavigation/>
|
<DashboardNavigation/>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
|
{(params.get('lang') == 'yes' || AppConfig.APP_LANG == 'multiple') && <div>
|
||||||
{
|
{
|
||||||
i18n == 'zh-CN'?(
|
i18n.language == 'zh-CN'?(
|
||||||
<Button className="ml-2" onClick={()=>onChangeLocalization('en-US')}>Change To EN</Button>
|
<Button className="ml-2" onClick={()=>i18n.changeLanguage('en-US')}>Change To EN</Button>
|
||||||
):(
|
):(
|
||||||
<Button className="ml-2" onClick={()=>onChangeLocalization('zh-CN')}>显示中文</Button>
|
<Button className="ml-2" onClick={()=>i18n.changeLanguage('zh-CN')}>显示中文</Button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
</div>}
|
||||||
<NavigationUserContainer/>
|
<NavigationUserContainer/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -116,7 +119,7 @@ const DashboardLayout: React.FC<{ children?: React.ReactNode }> = ({children}) =
|
|||||||
}
|
}
|
||||||
},[])
|
},[])
|
||||||
return <AuthGuard>
|
return <AuthGuard>
|
||||||
<div className="fixed">first path:{defaultCache.firstLoadPath}</div>
|
<div className="fixed">{defaultCache.firstLoadPath}</div>
|
||||||
<BaseLayout>
|
<BaseLayout>
|
||||||
{children ? children : <Outlet/>}
|
{children ? children : <Outlet/>}
|
||||||
</BaseLayout>
|
</BaseLayout>
|
||||||
|
@ -2,6 +2,7 @@ import axios from 'axios';
|
|||||||
import {stringify} from 'qs'
|
import {stringify} from 'qs'
|
||||||
import {BizError} from './types';
|
import {BizError} from './types';
|
||||||
import {getAuthToken} from "@/hooks/useAuth.ts";
|
import {getAuthToken} from "@/hooks/useAuth.ts";
|
||||||
|
import useGlobalConfig from '@/hooks/useGlobalConfig';
|
||||||
|
|
||||||
const JSON_FORMAT: string = 'application/json';
|
const JSON_FORMAT: string = 'application/json';
|
||||||
const REQUEST_TIMEOUT = 300000; // 超时时长5min
|
const REQUEST_TIMEOUT = 300000; // 超时时长5min
|
||||||
@ -11,10 +12,19 @@ const Axios = axios.create({
|
|||||||
headers: {'Content-Type': JSON_FORMAT}
|
headers: {'Content-Type': JSON_FORMAT}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const {globalConfig} = useGlobalConfig();
|
||||||
// 请求前拦截
|
// 请求前拦截
|
||||||
Axios.interceptors.request.use(config => {
|
Axios.interceptors.request.use(config => {
|
||||||
const token = getAuthToken();
|
const token = getAuthToken();
|
||||||
|
if (globalConfig.i18n){
|
||||||
|
let url = config.url;
|
||||||
|
if(url){
|
||||||
|
url += (url.indexOf('?') == -1?'?':'&') + `lang=${globalConfig.i18n || ''}`
|
||||||
|
config.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
//config.headers['language'] = globalConfig.i18n;
|
||||||
|
}
|
||||||
if (token) {
|
if (token) {
|
||||||
config.headers['Token'] = `${token}`;
|
config.headers['Token'] = `${token}`;
|
||||||
}
|
}
|
||||||
|
1
src/vite-env.d.ts
vendored
1
src/vite-env.d.ts
vendored
@ -13,6 +13,7 @@ declare const AppConfig: {
|
|||||||
AUTHED_PERSON_DATA_KEY: string;
|
AUTHED_PERSON_DATA_KEY: string;
|
||||||
API_PREFIX: string;
|
API_PREFIX: string;
|
||||||
ONLY_LIVE: string;
|
ONLY_LIVE: string;
|
||||||
|
APP_LANG: string;
|
||||||
};
|
};
|
||||||
declare const AppMode: 'test' | 'production' | 'development';
|
declare const AppMode: 'test' | 'production' | 'development';
|
||||||
|
|
||||||
|
@ -4,9 +4,17 @@ import {resolve} from "path";
|
|||||||
import AppPackage from './package.json'
|
import AppPackage from './package.json'
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
|
const DevServerList:{
|
||||||
|
[key:string]:string
|
||||||
|
} = {
|
||||||
|
'test':'https://fm-admin.starbitech.com',
|
||||||
|
'development':'http://192.168.0.231:9999',
|
||||||
|
'lang-en':'https://mh.starbitech.com'
|
||||||
|
}
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig(({mode}) => {
|
export default defineConfig(({mode}) => {
|
||||||
const devServerHost = mode == 'test' ? 'https://fm-admin.starbitech.com' : 'http://192.168.0.231:9999'
|
const devServerHost = DevServerList[mode] || 'http://192.168.0.231:9999'
|
||||||
const AUTH_TOKEN_KEY = mode == 'production' ? 'digital-person-token' : `digital-person-token_${mode}`
|
const AUTH_TOKEN_KEY = mode == 'production' ? 'digital-person-token' : `digital-person-token_${mode}`
|
||||||
|
|
||||||
if (mode !== 'production') {
|
if (mode !== 'production') {
|
||||||
@ -22,6 +30,7 @@ export default defineConfig(({mode}) => {
|
|||||||
AUTH_TOKEN_KEY: process.env.AUTH_TOKEN_KEY || AUTH_TOKEN_KEY,
|
AUTH_TOKEN_KEY: process.env.AUTH_TOKEN_KEY || AUTH_TOKEN_KEY,
|
||||||
AUTHED_PERSON_DATA_KEY: process.env.AUTHED_PERSON_DATA_KEY || 'digital-person-user-info',
|
AUTHED_PERSON_DATA_KEY: process.env.AUTHED_PERSON_DATA_KEY || 'digital-person-user-info',
|
||||||
ONLY_LIVE: process.env.ONLY_LIVE || 'no',
|
ONLY_LIVE: process.env.ONLY_LIVE || 'no',
|
||||||
|
APP_LANG: process.env.APP_LANGUAGE || 'zh-CN'
|
||||||
}),
|
}),
|
||||||
AppMode: JSON.stringify(mode),
|
AppMode: JSON.stringify(mode),
|
||||||
AppBuildVersion: JSON.stringify(AppPackage.name + '-' + AppPackage.version + '-' + dayjs().format('YYYYMMDDHH_mmss'))
|
AppBuildVersion: JSON.stringify(AppPackage.name + '-' + AppPackage.version + '-' + dayjs().format('YYYYMMDDHH_mmss'))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user