fixed: 订单效果

This commit is contained in:
LittleBoy 2025-04-15 15:03:08 +08:00
parent 1be407d34e
commit cbd476d1e2
10 changed files with 95 additions and 38 deletions

View File

@ -0,0 +1,4 @@
<svg class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3726" width="256" height="256">
<path d="M896 213.333333v281.173334l-97.706667-98.133334c-16.64-16.64-43.946667-16.64-60.586666 0L597.333333 537.173333 456.96 396.8a42.496 42.496 0 0 0-60.16 0L256 537.173333 128 408.746667V213.333333c0-46.933333 38.4-85.333333 85.333333-85.333333h597.333334c46.933333 0 85.333333 38.4 85.333333 85.333333z m-128 273.92l128 128.426667V810.666667c0 46.933333-38.4 85.333333-85.333333 85.333333H213.333333c-46.933333 0-85.333333-38.4-85.333333-85.333333v-280.746667l97.706667 97.706667c16.64 16.64 43.52 16.64 60.16 0l140.8-140.8 140.373333 140.373333c16.64 16.64 43.52 16.64 60.16 0l140.8-139.946667z"
fill="#e6e6e6" />
</svg>

After

Width:  |  Height:  |  Size: 770 B

View File

@ -8,6 +8,7 @@ import ImageList from "@/components/article/list.tsx";
import { BlockText} from "./item.tsx";
import styles from './article.module.scss'
import {useTranslation} from "react-i18next";
import ModalWarning from "@/components/icons/ModalWarning.tsx";
type Props = {
children?: React.ReactNode;
@ -86,8 +87,9 @@ export default function ArticleBlock(
rootClassName={'popconfirm-main'}
placement={'left'}
arrow={false}
icon={<IconWarningCircle/>}
title={<div style={{minWidth: 150}}><span>{t('news.edit_delete_group_confirm')}</span></div>}
icon={<ModalWarning.Icon />}
title={<ModalWarning.Title />}
description={<div style={{minWidth: 150}}><span>{t('news.edit_delete_group_confirm')}</span></div>}
onConfirm={onRemove}
okText={t('delete')}
cancelText={t('cancel')}

View File

@ -17,6 +17,7 @@ import {formatTime} from "@/util/strings.ts";
import {useTranslation} from "react-i18next";
import {saveAs} from "file-saver";
import {DeleteItemPopoverConfirm} from "@/components/message/confirm.tsx";
import {showLoading, showToast} from "@/components/message.ts";
type Props = {
video: VideoInfo | LiveVideoInfo,
@ -54,7 +55,7 @@ export const VideoListItem = (
setNodeRef, transform
} = useSortable({resizeObserverConfig: {}, id})
const {t} = useTranslation()
const {t,i18n} = useTranslation()
const [state, setState] = useSetState<{ checked?: boolean }>({})
useEffect(() => {
setState({checked})
@ -65,7 +66,14 @@ export const VideoListItem = (
const handleDownloadVideo = () => {
if (downloadUrl && video.status == VideoStatus.Generated) {
const ext = downloadUrl.substring(downloadUrl.lastIndexOf('.'))
saveAs(downloadUrl, `${video.title || video.video_title}${ext}`)
const loading = showLoading(t('downloading'))
try{
saveAs(downloadUrl, `${video.title || video.video_title}${ext}`)
loading.close()
}catch (e){
loading.update(t('download_failed'),'error')
}
}
}
return <div
@ -129,13 +137,13 @@ export const VideoListItem = (
{/* <button className="hover:text-blue-500 cursor-move">*/}
{/* <MenuOutlined/>*/}
{/* </button> : <button disabled className="cursor-not-allowed"><MenuOutlined/></button>)}*/}
<div className={"flex items-center justify-start gap-6"}>
<div className={"flex items-center justify-center gap-6"}>
{downloadUrl && video.status == VideoStatus.Generated &&
<button className="hover:text-blue-500" onClick={e => {
e.preventDefault()
e.stopPropagation()
handleDownloadVideo?.()
}} style={{fontSize: '1.1em'}}>
}} style={{fontSize: '1.1em'}} title={i18n.language == 'zh-CN'?'下载':'Download'}>
<IconDownloadOutline/>
</button>}
{additionOperationBefore}
@ -145,7 +153,7 @@ export const VideoListItem = (
e.preventDefault()
e.stopPropagation()
onEdit?.()
}} style={{fontSize: '1.1em'}}>
}} style={{fontSize: '1.1em'}} title={i18n.language == 'zh-CN'?'修改':'Modify'}>
<IconEdit/>
</button>}
{onRegenerate && <button
@ -153,22 +161,24 @@ export const VideoListItem = (
e.preventDefault()
e.stopPropagation()
onRegenerate?.()
}} style={{fontSize: '1.1em'}}>
}} style={{fontSize: '1.1em'}} title={i18n.language == 'zh-CN'?'重新生成':'Regenerate'}>
<IconRegenerate/>
</button>}
{onRemove && <DeleteItemPopoverConfirm
{onRemove && !failed && <DeleteItemPopoverConfirm
description={failed ? t('video.rollback_confirm_title') : undefined}
onConfirm={() => onRemove(failed ? 'rollback' : 'delete')}>
<span className="icon-btn">
<button className="hover:text-blue-500">
<button className="hover:text-blue-500" title={
i18n.language == 'zh-CN'?'重新生成':'Regenerate'
}>
{removeIcon ? removeIcon : (failed ?
<IconRollbackCircle/> :
<IconDelete/>)}
</button>
</span>
</DeleteItemPopoverConfirm>}
{hideCheckBox ? <span className={"inline-block w-[18px] h-1"}></span> :
{hideCheckBox ? <></> :
<Checkbox checked={state.checked} onChange={() => {
if (onCheckedChange) {
onCheckedChange(!state.checked)

View File

@ -15,6 +15,8 @@
"delete_failed": "Delete failed",
"delete_success": "Delete success",
"download": "Download",
"downloading": "Downloading...",
"download_fail": "Download Failed",
"error_401": "You do not have permission to access this page",
"error_403": "You do not have permission to access this page",
"error_404": "Page not found",

View File

@ -15,6 +15,8 @@
"delete_failed": "删除失败",
"delete_success": "删除成功",
"download": "下载",
"downloading": "下载中...",
"download_fail": "下载失败",
"error_401": "您没有权限访问本页面",
"error_403": "您没有权限访问本页面",
"error_404": "访问的页面不存在",

View File

@ -55,6 +55,9 @@
left:0;
}
}
.cover{
@apply pl-2;
}
.title{
@apply flex-1 pl-0;
&:after{
@ -100,13 +103,23 @@
.orderDataList{
:global {
.title{
justify-content: left;
}
.id{
@apply pl-0;
width: 120px;
width: 130px;
line-height: 1.2em;
&:after{
display: none;
}
}
.cover{
img{
width: 120px;
max-height: 50px;
}
}
.title {
@apply flex-1 pl-4;
min-width: 100px;

View File

@ -1,19 +1,19 @@
import SearchPanel from "@/pages/news/components/search-panel.tsx";
import React, {useState} from "react";
import {useTranslation} from "react-i18next";
import styles from "@/pages/news/components/style.module.scss";
import {Empty, Image, Pagination} from "antd";
import {useRequest} from "ahooks";
import SearchPanel from "@/pages/news/components/search-panel.tsx";
import styles from "@/pages/news/components/style.module.scss";
import {formatDurationToTime, formatTime} from "@/util/strings.ts";
import {IconDelete, IconEdit, IconWarningCircle} from "@/components/icons";
import {Empty, Pagination, PaginationProps, Popconfirm} from "antd";
import {useRequest, useSetState} from "ahooks";
import {getList} from "@/service/api/order.ts";
import ImageErr from "@/assets/images/error/error_img.svg"
function OrderIndex() {
const {t} = useTranslation()
const [params, setParams] = useState<ApiArticleSearchParams>({
pagination: {page: 1, limit: 12},
pagination: {page: 1, limit: 10},
time_flag: 0,
})
const {data} = useRequest(() => getList(params), {
@ -33,10 +33,10 @@ function OrderIndex() {
<div className={`${styles.newListTable} ${styles.orderDataList} `}>
<div className="header row flex">
<div className="col id w-[160px]">{t('order.list.id')}</div>
<div className="col w-[180px]">{t('order.list.cover')}</div>
<div className="col cover">{t('order.list.cover')}</div>
<div className="col title w-min-60px">{t('order.list.title')}</div>
<div className="col w-[180px]">{t('order.list.order_time')}</div>
<div className="col w-[180px]">{t('order.list.consume_time')}</div>
<div className="col w-[120px]">{t('order.list.consume_time')}</div>
<div className="col w-[180px]">{t('order.list.operator')}</div>
</div>
<div >
@ -47,21 +47,24 @@ function OrderIndex() {
return <div key={i} className="row flex">
<div className="col id w-[160px] text-center">
<div className="flex-1">
<div className="text-base">{item.order_id}</div>
<div className="break-all">{item.order_id}</div>
</div>
</div>
<div className="col w-[180px]">
<img src={item.img_url} className="rounded w-[140px] h-[60px]" alt=""/>
<div className="col cover">
<Image
src={item.img_url} preview={false} className="rounded object-cover"
fallback={ImageErr}
/>
</div>
<div className="col flex-1 w-min-60px">
<div className="text-sm line-clamp-2">{item.title}</div>
<div className="col title order-title flex-1 w-min-60px">
<div className="line-clamp-2 ">{item.title}</div>
</div>
<div className="col w-[180px]">
<div className="text-sm">{formatTime(item.order_time, 'YYYY-MM-DD HH:mm')}</div>
</div>
<div className="col w-[180px]">
<div className="col w-[120px]">
<div
className="text-sm">{formatTime(item.consumption_duration, 'YYYY-MM-DD HH:mm')}</div>
className="text-sm">{formatDurationToTime(item.consumption_duration)}</div>
</div>
<div className="col w-[180px]">
<div className="text-sm">{item.operator}</div>
@ -71,6 +74,12 @@ function OrderIndex() {
<div className="footer flex justify-end mt-10">
<Pagination
onChange={(page, limit) => {
setParams({
...params,
pagination: {page, limit}
})
}}
total={data?.pagination.total || 0}
showTotal={(total) => <div>{t('page.total_item', {total})}</div>}
showSizeChanger={{

View File

@ -1,5 +1,5 @@
import React, {useEffect, useRef, useState} from "react";
import {Checkbox, Modal, Space} from "antd";
import {Checkbox, Empty, Modal, Space} from "antd";
import {useRequest, useSetState} from "ahooks";
import {useTranslation} from "react-i18next";
@ -78,7 +78,7 @@ export default function RecycleIndex() {
autoPlay: boolean
}>()
const handleAllCheckedChange = (checked: boolean) => {
if (!data) return;
if (!data || data.pagination.total == 0) return;
setCheckedIdArray(checked ? data.list.map(v => v.id) : [])
setState({
checkedAll: !state.checkedAll
@ -107,7 +107,12 @@ export default function RecycleIndex() {
{contextHolder}
<div className="search-form-container">
<SearchForm
onSearch={setParams}
onSearch={(params) => {
setParams({
...params,
pagination: {...DEFAULT_PAGE_LIMIT}
})
}}
onBtnStartClick={handleLive}
loading={loading}
/>
@ -126,8 +131,10 @@ export default function RecycleIndex() {
<span className="text-sm mr-2">{t("select.select_all")}</span>
{/*<CheckCircleFilled className={clsx({'text-blue-500': state.checkedAll})}/>*/}
</button>
<Checkbox checked={checkedIdArray.length == data?.list?.length}
onChange={e => handleAllCheckedChange(e.target.checked)}/>
<Checkbox
disabled={data?.pagination.total == 0 || data?.list?.length == 0}
checked={checkedIdArray.length == data?.list?.length}
onChange={e => handleAllCheckedChange(e.target.checked)}/>
</div>
</div>
<InfiniteScroller
@ -139,6 +146,9 @@ export default function RecycleIndex() {
}))
}} onScroll={(top) => setState({showToTop: top > 30})}
>
{data?.pagination.total == 0 && !loading && <div className="mt-20">
<Empty/>
</div>}
<div className={'video-list-container grid gap-4 grid-cols-3 xl:grid-cols-4'}>
{data?.list?.map((it, idx) => (
<VideoItem
@ -189,10 +199,10 @@ export default function RecycleIndex() {
icon={<IconArrowRight className={'text-white'}/>}
onProcess={restore}
confirmMessage={<span dangerouslySetInnerHTML={{
__html: checkedIdArray.length == 1
? t('video.restore_confirm')
: t('video.restore_confirm_count', {count: checkedIdArray.length})
}}></span>}
__html: checkedIdArray.length == 1
? t('video.restore_confirm')
: t('video.restore_confirm_count', {count: checkedIdArray.length})
}}></span>}
emptyMessage={t('video.push_empty')}
onError={e => {
showToast(String((e as BizError).data || e.message), 'error')

View File

@ -306,6 +306,11 @@ export default function VideoIndex() {
<ButtonPush2Room ids={checkedIdArray} list={videoData} onSuccess={loadList}/>
</div>
</div>
<ArticleEditModal type={'video'} id={editId} onClose={() => setEditId(-1)}/>
<ArticleEditModal type={'video'} id={editId} onClose={(saved) =>{
setEditId(-1)
if(saved) {
loadList()
}
}}/>
</div>)
}

View File

@ -30,7 +30,7 @@ export default defineConfig(({mode}) => {
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',
ONLY_LIVE: process.env.ONLY_LIVE || 'no',
APP_LANG: process.env.APP_LANGUAGE || 'multiple'
APP_LANG: process.env.APP_LANGUAGE
}),
AppMode: JSON.stringify(mode),
AppBuildVersion: JSON.stringify(AppPackage.name + '-' + AppPackage.version + '-' + dayjs().format('YYYYMMDDHH_mmss'))