Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
07d87d60
authored
May 23, 2025
by
Apple\Apple
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
♻
️Refactor: TaskLogs Page
parent
17c42cc0
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
452 additions
and
222 deletions
+452
-222
web/src/components/TaskLogsTable.js
+448
-221
web/src/i18n/locales/en.json
+4
-1
No files found.
web/src/components/TaskLogsTable.js
View file @
07d87d60
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
{
Label
}
from
'semantic-ui-reac
t'
;
import
{
useTranslation
}
from
'react-i18nex
t'
;
import
{
import
{
API
,
API
,
copy
,
copy
,
...
@@ -10,17 +10,28 @@ import {
...
@@ -10,17 +10,28 @@ import {
}
from
'../helpers'
;
}
from
'../helpers'
;
import
{
import
{
Table
,
Tag
,
Form
,
Button
,
Button
,
Card
,
Checkbox
,
DatePicker
,
Divider
,
Input
,
Layout
,
Layout
,
Modal
,
Modal
,
Typography
,
Progress
,
Progress
,
Card
,
Skeleton
,
Table
,
Tag
,
Typography
,
}
from
'@douyinfe/semi-ui'
;
}
from
'@douyinfe/semi-ui'
;
import
{
ITEMS_PER_PAGE
}
from
'../constants'
;
import
{
ITEMS_PER_PAGE
}
from
'../constants'
;
import
{
IconEyeOpened
,
IconSearch
,
IconSetting
,
}
from
'@douyinfe/semi-icons'
;
const
{
Text
}
=
Typography
;
const
colors
=
[
const
colors
=
[
'amber'
,
'amber'
,
...
@@ -40,6 +51,20 @@ const colors = [
...
@@ -40,6 +51,20 @@ const colors = [
'yellow'
,
'yellow'
,
];
];
// 定义列键值常量
const
COLUMN_KEYS
=
{
SUBMIT_TIME
:
'submit_time'
,
FINISH_TIME
:
'finish_time'
,
DURATION
:
'duration'
,
CHANNEL
:
'channel'
,
PLATFORM
:
'platform'
,
TYPE
:
'type'
,
TASK_ID
:
'task_id'
,
TASK_STATUS
:
'task_status'
,
PROGRESS
:
'progress'
,
FAIL_REASON
:
'fail_reason'
,
};
const
renderTimestamp
=
(
timestampInSeconds
)
=>
{
const
renderTimestamp
=
(
timestampInSeconds
)
=>
{
const
date
=
new
Date
(
timestampInSeconds
*
1000
);
// 从秒转换为毫秒
const
date
=
new
Date
(
timestampInSeconds
*
1000
);
// 从秒转换为毫秒
...
@@ -79,101 +104,259 @@ function renderDuration(submit_time, finishTime) {
...
@@ -79,101 +104,259 @@ function renderDuration(submit_time, finishTime) {
}
}
const
LogsTable
=
()
=>
{
const
LogsTable
=
()
=>
{
const
{
t
}
=
useTranslation
();
const
[
isModalOpen
,
setIsModalOpen
]
=
useState
(
false
);
const
[
isModalOpen
,
setIsModalOpen
]
=
useState
(
false
);
const
[
modalContent
,
setModalContent
]
=
useState
(
''
);
const
[
modalContent
,
setModalContent
]
=
useState
(
''
);
// 列可见性状态
const
[
visibleColumns
,
setVisibleColumns
]
=
useState
({});
const
[
showColumnSelector
,
setShowColumnSelector
]
=
useState
(
false
);
const
isAdminUser
=
isAdmin
();
const
isAdminUser
=
isAdmin
();
const
columns
=
[
const
[
pageSize
,
setPageSize
]
=
useState
(
ITEMS_PER_PAGE
);
// 加载保存的列偏好设置
useEffect
(()
=>
{
const
savedColumns
=
localStorage
.
getItem
(
'task-logs-table-columns'
);
if
(
savedColumns
)
{
try
{
const
parsed
=
JSON
.
parse
(
savedColumns
);
const
defaults
=
getDefaultColumnVisibility
();
const
merged
=
{
...
defaults
,
...
parsed
};
setVisibleColumns
(
merged
);
}
catch
(
e
)
{
console
.
error
(
'Failed to parse saved column preferences'
,
e
);
initDefaultColumns
();
}
}
else
{
initDefaultColumns
();
}
},
[]);
// 获取默认列可见性
const
getDefaultColumnVisibility
=
()
=>
{
return
{
[
COLUMN_KEYS
.
SUBMIT_TIME
]:
true
,
[
COLUMN_KEYS
.
FINISH_TIME
]:
true
,
[
COLUMN_KEYS
.
DURATION
]:
true
,
[
COLUMN_KEYS
.
CHANNEL
]:
isAdminUser
,
[
COLUMN_KEYS
.
PLATFORM
]:
true
,
[
COLUMN_KEYS
.
TYPE
]:
true
,
[
COLUMN_KEYS
.
TASK_ID
]:
true
,
[
COLUMN_KEYS
.
TASK_STATUS
]:
true
,
[
COLUMN_KEYS
.
PROGRESS
]:
true
,
[
COLUMN_KEYS
.
FAIL_REASON
]:
true
,
};
};
// 初始化默认列可见性
const
initDefaultColumns
=
()
=>
{
const
defaults
=
getDefaultColumnVisibility
();
setVisibleColumns
(
defaults
);
localStorage
.
setItem
(
'task-logs-table-columns'
,
JSON
.
stringify
(
defaults
));
};
// 处理列可见性变化
const
handleColumnVisibilityChange
=
(
columnKey
,
checked
)
=>
{
const
updatedColumns
=
{
...
visibleColumns
,
[
columnKey
]:
checked
};
setVisibleColumns
(
updatedColumns
);
};
// 处理全选
const
handleSelectAll
=
(
checked
)
=>
{
const
allKeys
=
Object
.
keys
(
COLUMN_KEYS
).
map
((
key
)
=>
COLUMN_KEYS
[
key
]);
const
updatedColumns
=
{};
allKeys
.
forEach
((
key
)
=>
{
if
(
key
===
COLUMN_KEYS
.
CHANNEL
&&
!
isAdminUser
)
{
updatedColumns
[
key
]
=
false
;
}
else
{
updatedColumns
[
key
]
=
checked
;
}
});
setVisibleColumns
(
updatedColumns
);
};
// 更新表格时保存列可见性
useEffect
(()
=>
{
if
(
Object
.
keys
(
visibleColumns
).
length
>
0
)
{
localStorage
.
setItem
(
'task-logs-table-columns'
,
JSON
.
stringify
(
visibleColumns
));
}
},
[
visibleColumns
]);
const
renderType
=
(
type
)
=>
{
switch
(
type
)
{
case
'MUSIC'
:
return
(
<
Tag
color
=
'grey'
size
=
'large'
shape
=
'circle'
>
{
t
(
'生成音乐'
)}
<
/Tag
>
);
case
'LYRICS'
:
return
(
<
Tag
color
=
'pink'
size
=
'large'
shape
=
'circle'
>
{
t
(
'生成歌词'
)}
<
/Tag
>
);
default
:
return
(
<
Tag
color
=
'white'
size
=
'large'
shape
=
'circle'
>
{
t
(
'未知'
)}
<
/Tag
>
);
}
};
const
renderPlatform
=
(
type
)
=>
{
switch
(
type
)
{
case
'suno'
:
return
(
<
Tag
color
=
'green'
size
=
'large'
shape
=
'circle'
>
Suno
<
/Tag
>
);
default
:
return
(
<
Tag
color
=
'white'
size
=
'large'
shape
=
'circle'
>
{
t
(
'未知'
)}
<
/Tag
>
);
}
};
const
renderStatus
=
(
type
)
=>
{
switch
(
type
)
{
case
'SUCCESS'
:
return
(
<
Tag
color
=
'green'
size
=
'large'
shape
=
'circle'
>
{
t
(
'成功'
)}
<
/Tag
>
);
case
'NOT_START'
:
return
(
<
Tag
color
=
'grey'
size
=
'large'
shape
=
'circle'
>
{
t
(
'未启动'
)}
<
/Tag
>
);
case
'SUBMITTED'
:
return
(
<
Tag
color
=
'yellow'
size
=
'large'
shape
=
'circle'
>
{
t
(
'队列中'
)}
<
/Tag
>
);
case
'IN_PROGRESS'
:
return
(
<
Tag
color
=
'blue'
size
=
'large'
shape
=
'circle'
>
{
t
(
'执行中'
)}
<
/Tag
>
);
case
'FAILURE'
:
return
(
<
Tag
color
=
'red'
size
=
'large'
shape
=
'circle'
>
{
t
(
'失败'
)}
<
/Tag
>
);
case
'QUEUED'
:
return
(
<
Tag
color
=
'orange'
size
=
'large'
shape
=
'circle'
>
{
t
(
'排队中'
)}
<
/Tag
>
);
case
'UNKNOWN'
:
return
(
<
Tag
color
=
'white'
size
=
'large'
shape
=
'circle'
>
{
t
(
'未知'
)}
<
/Tag
>
);
case
''
:
return
(
<
Tag
color
=
'grey'
size
=
'large'
shape
=
'circle'
>
{
t
(
'正在提交'
)}
<
/Tag
>
);
default
:
return
(
<
Tag
color
=
'white'
size
=
'large'
shape
=
'circle'
>
{
t
(
'未知'
)}
<
/Tag
>
);
}
};
// 定义所有列
const
allColumns
=
[
{
{
title
:
'提交时间'
,
key
:
COLUMN_KEYS
.
SUBMIT_TIME
,
title
:
t
(
'提交时间'
),
dataIndex
:
'submit_time'
,
dataIndex
:
'submit_time'
,
render
:
(
text
,
record
,
index
)
=>
{
render
:
(
text
,
record
,
index
)
=>
{
return
<
div
>
{
text
?
renderTimestamp
(
text
)
:
'-'
}
<
/div>
;
return
<
div
>
{
text
?
renderTimestamp
(
text
)
:
'-'
}
<
/div>
;
},
},
},
},
{
{
title
:
'结束时间'
,
key
:
COLUMN_KEYS
.
FINISH_TIME
,
title
:
t
(
'结束时间'
),
dataIndex
:
'finish_time'
,
dataIndex
:
'finish_time'
,
render
:
(
text
,
record
,
index
)
=>
{
render
:
(
text
,
record
,
index
)
=>
{
return
<
div
>
{
text
?
renderTimestamp
(
text
)
:
'-'
}
<
/div>
;
return
<
div
>
{
text
?
renderTimestamp
(
text
)
:
'-'
}
<
/div>
;
},
},
},
},
{
{
title
:
'进度'
,
key
:
COLUMN_KEYS
.
DURATION
,
dataIndex
:
'progress'
,
title
:
t
(
'花费时间'
),
width
:
50
,
dataIndex
:
'finish_time'
,
render
:
(
text
,
record
,
index
)
=>
{
return
(
<
div
>
{
// 转换例如100%为数字100,如果text未定义,返回0
isNaN
(
text
.
replace
(
'%'
,
''
))
?
(
text
)
:
(
<
Progress
width
=
{
42
}
type
=
'circle'
showInfo
=
{
true
}
percent
=
{
Number
(
text
.
replace
(
'%'
,
''
)
||
0
)}
aria
-
label
=
'drawing progress'
/>
)
}
<
/div
>
);
},
},
{
title
:
'花费时间'
,
dataIndex
:
'finish_time'
,
// 以finish_time作为dataIndex
key
:
'finish_time'
,
render
:
(
finish
,
record
)
=>
{
render
:
(
finish
,
record
)
=>
{
// 假设record.start_time是存在的,并且finish是完成时间的时间戳
return
<>
{
finish
?
renderDuration
(
record
.
submit_time
,
finish
)
:
'-'
}
<
/>
;
return
<>
{
finish
?
renderDuration
(
record
.
submit_time
,
finish
)
:
'-'
}
<
/>
;
},
},
},
},
{
{
title
:
'渠道'
,
key
:
COLUMN_KEYS
.
CHANNEL
,
title
:
t
(
'渠道'
),
dataIndex
:
'channel_id'
,
dataIndex
:
'channel_id'
,
className
:
isAdminUser
?
'tableShow'
:
'tableHiddle'
,
className
:
isAdminUser
?
'tableShow'
:
'tableHiddle'
,
render
:
(
text
,
record
,
index
)
=>
{
render
:
(
text
,
record
,
index
)
=>
{
return
(
return
isAdminUser
?
(
<
div
>
<
div
>
<
Tag
<
Tag
color
=
{
colors
[
parseInt
(
text
)
%
colors
.
length
]}
color
=
{
colors
[
parseInt
(
text
)
%
colors
.
length
]}
size
=
'large'
size
=
'large'
shape
=
'circle'
onClick
=
{()
=>
{
onClick
=
{()
=>
{
copyText
(
text
);
// 假设copyText是用于文本复制的函数
copyText
(
text
);
}}
}}
>
>
{
' '
}
{
text
}
{
text
}{
' '
}
<
/Tag
>
<
/Tag
>
<
/div
>
<
/div
>
)
:
(
<><
/
>
);
);
},
},
},
},
{
{
title
:
'平台'
,
key
:
COLUMN_KEYS
.
PLATFORM
,
title
:
t
(
'平台'
),
dataIndex
:
'platform'
,
dataIndex
:
'platform'
,
render
:
(
text
,
record
,
index
)
=>
{
render
:
(
text
,
record
,
index
)
=>
{
return
<
div
>
{
renderPlatform
(
text
)}
<
/div>
;
return
<
div
>
{
renderPlatform
(
text
)}
<
/div>
;
},
},
},
},
{
{
title
:
'类型'
,
key
:
COLUMN_KEYS
.
TYPE
,
title
:
t
(
'类型'
),
dataIndex
:
'action'
,
dataIndex
:
'action'
,
render
:
(
text
,
record
,
index
)
=>
{
render
:
(
text
,
record
,
index
)
=>
{
return
<
div
>
{
renderType
(
text
)}
<
/div>
;
return
<
div
>
{
renderType
(
text
)}
<
/div>
;
},
},
},
},
{
{
title
:
'任务ID(点击查看详情)'
,
key
:
COLUMN_KEYS
.
TASK_ID
,
title
:
t
(
'任务ID'
),
dataIndex
:
'task_id'
,
dataIndex
:
'task_id'
,
render
:
(
text
,
record
,
index
)
=>
{
render
:
(
text
,
record
,
index
)
=>
{
return
(
return
(
<
Typography
.
Text
<
Typography
.
Text
ellipsis
=
{{
showTooltip
:
true
}}
ellipsis
=
{{
showTooltip
:
true
}}
//style={{width: 100}}
onClick
=
{()
=>
{
onClick
=
{()
=>
{
setModalContent
(
JSON
.
stringify
(
record
,
null
,
2
));
setModalContent
(
JSON
.
stringify
(
record
,
null
,
2
));
setIsModalOpen
(
true
);
setIsModalOpen
(
true
);
...
@@ -185,22 +368,48 @@ const LogsTable = () => {
...
@@ -185,22 +368,48 @@ const LogsTable = () => {
},
},
},
},
{
{
title
:
'任务状态'
,
key
:
COLUMN_KEYS
.
TASK_STATUS
,
title
:
t
(
'任务状态'
),
dataIndex
:
'status'
,
dataIndex
:
'status'
,
render
:
(
text
,
record
,
index
)
=>
{
render
:
(
text
,
record
,
index
)
=>
{
return
<
div
>
{
renderStatus
(
text
)}
<
/div>
;
return
<
div
>
{
renderStatus
(
text
)}
<
/div>
;
},
},
},
},
{
{
title
:
'失败原因'
,
key
:
COLUMN_KEYS
.
PROGRESS
,
title
:
t
(
'进度'
),
dataIndex
:
'progress'
,
render
:
(
text
,
record
,
index
)
=>
{
return
(
<
div
>
{
isNaN
(
text
?.
replace
(
'%'
,
''
))
?
(
text
||
'-'
)
:
(
<
Progress
stroke
=
{
record
.
status
===
'FAILURE'
?
'var(--semi-color-warning)'
:
null
}
percent
=
{
text
?
parseInt
(
text
.
replace
(
'%'
,
''
))
:
0
}
showInfo
=
{
true
}
aria
-
label
=
'task progress'
/>
)
}
<
/div
>
);
},
},
{
key
:
COLUMN_KEYS
.
FAIL_REASON
,
title
:
t
(
'失败原因'
),
dataIndex
:
'fail_reason'
,
dataIndex
:
'fail_reason'
,
render
:
(
text
,
record
,
index
)
=>
{
render
:
(
text
,
record
,
index
)
=>
{
// 如果text未定义,返回替代文本,例如空字符串''或其他
if
(
!
text
)
{
if
(
!
text
)
{
return
'无'
;
return
t
(
'无'
)
;
}
}
return
(
return
(
<
Typography
.
Text
<
Typography
.
Text
ellipsis
=
{{
showTooltip
:
true
}}
ellipsis
=
{{
showTooltip
:
true
}}
...
@@ -217,6 +426,11 @@ const LogsTable = () => {
...
@@ -217,6 +426,11 @@ const LogsTable = () => {
},
},
];
];
// 根据可见性设置过滤列
const
getVisibleColumns
=
()
=>
{
return
allColumns
.
filter
((
column
)
=>
visibleColumns
[
column
.
key
]);
};
const
[
logs
,
setLogs
]
=
useState
([]);
const
[
logs
,
setLogs
]
=
useState
([]);
const
[
loading
,
setLoading
]
=
useState
(
true
);
const
[
loading
,
setLoading
]
=
useState
(
true
);
const
[
activePage
,
setActivePage
]
=
useState
(
1
);
const
[
activePage
,
setActivePage
]
=
useState
(
1
);
...
@@ -249,16 +463,16 @@ const LogsTable = () => {
...
@@ -249,16 +463,16 @@ const LogsTable = () => {
// console.log(logCount);
// console.log(logCount);
};
};
const
loadLogs
=
async
(
startIdx
)
=>
{
const
loadLogs
=
async
(
startIdx
,
pageSize
=
ITEMS_PER_PAGE
)
=>
{
setLoading
(
true
);
setLoading
(
true
);
let
url
=
''
;
let
url
=
''
;
let
localStartTimestamp
=
parseInt
(
Date
.
parse
(
start_timestamp
)
/
1000
);
let
localStartTimestamp
=
parseInt
(
Date
.
parse
(
start_timestamp
)
/
1000
);
let
localEndTimestamp
=
parseInt
(
Date
.
parse
(
end_timestamp
)
/
1000
);
let
localEndTimestamp
=
parseInt
(
Date
.
parse
(
end_timestamp
)
/
1000
);
if
(
isAdminUser
)
{
if
(
isAdminUser
)
{
url
=
`/api/task/?p=
${
startIdx
}
&channel_id=
${
channel_id
}
&task_id=
${
task_id
}
&start_timestamp=
${
localStartTimestamp
}
&end_timestamp=
${
localEndTimestamp
}
`
;
url
=
`/api/task/?p=
${
startIdx
}
&
page_size=
${
pageSize
}
&
channel_id=
${
channel_id
}
&task_id=
${
task_id
}
&start_timestamp=
${
localStartTimestamp
}
&end_timestamp=
${
localEndTimestamp
}
`
;
}
else
{
}
else
{
url
=
`/api/task/self?p=
${
startIdx
}
&task_id=
${
task_id
}
&start_timestamp=
${
localStartTimestamp
}
&end_timestamp=
${
localEndTimestamp
}
`
;
url
=
`/api/task/self?p=
${
startIdx
}
&
page_size=
${
pageSize
}
&
task_id=
${
task_id
}
&start_timestamp=
${
localStartTimestamp
}
&end_timestamp=
${
localEndTimestamp
}
`
;
}
}
const
res
=
await
API
.
get
(
url
);
const
res
=
await
API
.
get
(
url
);
let
{
success
,
message
,
data
}
=
res
.
data
;
let
{
success
,
message
,
data
}
=
res
.
data
;
...
@@ -267,7 +481,7 @@ const LogsTable = () => {
...
@@ -267,7 +481,7 @@ const LogsTable = () => {
setLogsFormat
(
data
);
setLogsFormat
(
data
);
}
else
{
}
else
{
let
newLogs
=
[...
logs
];
let
newLogs
=
[...
logs
];
newLogs
.
splice
(
startIdx
*
ITEMS_PER_PAGE
,
data
.
length
,
...
data
);
newLogs
.
splice
(
startIdx
*
pageSize
,
data
.
length
,
...
data
);
setLogsFormat
(
newLogs
);
setLogsFormat
(
newLogs
);
}
}
}
else
{
}
else
{
...
@@ -277,223 +491,236 @@ const LogsTable = () => {
...
@@ -277,223 +491,236 @@ const LogsTable = () => {
};
};
const
pageData
=
logs
.
slice
(
const
pageData
=
logs
.
slice
(
(
activePage
-
1
)
*
ITEMS_PER_PAGE
,
(
activePage
-
1
)
*
pageSize
,
activePage
*
ITEMS_PER_PAGE
,
activePage
*
pageSize
,
);
);
const
handlePageChange
=
(
page
)
=>
{
const
handlePageChange
=
(
page
)
=>
{
setActivePage
(
page
);
setActivePage
(
page
);
if
(
page
===
Math
.
ceil
(
logs
.
length
/
ITEMS_PER_PAGE
)
+
1
)
{
if
(
page
===
Math
.
ceil
(
logs
.
length
/
pageSize
)
+
1
)
{
// In this case we have to load more data and then append them.
loadLogs
(
page
-
1
,
pageSize
).
then
((
r
)
=>
{
});
loadLogs
(
page
-
1
).
then
((
r
)
=>
{});
}
}
};
};
const
handlePageSizeChange
=
async
(
size
)
=>
{
localStorage
.
setItem
(
'task-page-size'
,
size
+
''
);
setPageSize
(
size
);
setActivePage
(
1
);
await
loadLogs
(
0
,
size
);
};
const
refresh
=
async
()
=>
{
const
refresh
=
async
()
=>
{
// setLoading(true);
setActivePage
(
1
);
setActivePage
(
1
);
await
loadLogs
(
0
);
await
loadLogs
(
0
,
pageSize
);
};
};
const
copyText
=
async
(
text
)
=>
{
const
copyText
=
async
(
text
)
=>
{
if
(
await
copy
(
text
))
{
if
(
await
copy
(
text
))
{
showSuccess
(
'已复制:'
+
text
);
showSuccess
(
t
(
'已复制:'
)
+
text
);
}
else
{
}
else
{
// setSearchKeyword(text);
Modal
.
error
({
title
:
t
(
'无法复制到剪贴板,请手动复制'
),
content
:
text
});
Modal
.
error
({
title
:
'无法复制到剪贴板,请手动复制'
,
content
:
text
});
}
}
};
};
useEffect
(()
=>
{
useEffect
(()
=>
{
refresh
().
then
();
const
localPageSize
=
parseInt
(
localStorage
.
getItem
(
'task-page-size'
))
||
ITEMS_PER_PAGE
;
setPageSize
(
localPageSize
);
loadLogs
(
0
,
localPageSize
).
then
();
},
[
logType
]);
},
[
logType
]);
const
renderType
=
(
type
)
=>
{
// 列选择器模态框
switch
(
type
)
{
const
renderColumnSelector
=
()
=>
{
case
'MUSIC'
:
return
(
<
Label
basic
color
=
'grey'
>
{
' '
}
生成音乐
{
' '
}
<
/Label
>
);
case
'LYRICS'
:
return
(
<
Label
basic
color
=
'pink'
>
{
' '
}
生成歌词
{
' '
}
<
/Label
>
);
default
:
return
(
return
(
<
Label
basic
color
=
'black'
>
<
Modal
{
' '
}
title
=
{
t
(
'列设置'
)}
未知
{
' '
}
visible
=
{
showColumnSelector
}
<
/Label
>
onCancel
=
{()
=>
setShowColumnSelector
(
false
)}
);
footer
=
{
<
div
className
=
"flex justify-end"
>
<
Button
theme
=
"light"
onClick
=
{()
=>
initDefaultColumns
()}
className
=
"!rounded-full"
>
{
t
(
'重置'
)}
<
/Button
>
<
Button
theme
=
"light"
onClick
=
{()
=>
setShowColumnSelector
(
false
)}
className
=
"!rounded-full"
>
{
t
(
'取消'
)}
<
/Button
>
<
Button
type
=
'primary'
onClick
=
{()
=>
setShowColumnSelector
(
false
)}
className
=
"!rounded-full"
>
{
t
(
'确定'
)}
<
/Button
>
<
/div
>
}
}
};
>
<
div
style
=
{{
marginBottom
:
20
}}
>
const
renderPlatform
=
(
type
)
=>
{
<
Checkbox
switch
(
type
)
{
checked
=
{
Object
.
values
(
visibleColumns
).
every
((
v
)
=>
v
===
true
)}
case
'suno'
:
indeterminate
=
{
return
(
Object
.
values
(
visibleColumns
).
some
((
v
)
=>
v
===
true
)
&&
<
Label
basic
color
=
'green'
>
!
Object
.
values
(
visibleColumns
).
every
((
v
)
=>
v
===
true
)
{
' '
}
}
Suno
{
' '
}
onChange
=
{(
e
)
=>
handleSelectAll
(
e
.
target
.
checked
)
}
<
/Label
>
>
);
{
t
(
'全选'
)}
default
:
<
/Checkbox
>
return
(
<
/div
>
<
Label
basic
color
=
'black'
>
<
div
className
=
"flex flex-wrap max-h-96 overflow-y-auto rounded-lg p-4"
>
{
' '
}
{
allColumns
.
map
((
column
)
=>
{
未知
{
' '
}
// 为非管理员用户跳过管理员专用列
<
/Label
>
if
(
!
isAdminUser
&&
column
.
key
===
COLUMN_KEYS
.
CHANNEL
)
{
)
;
return
null
;
}
}
};
const
renderStatus
=
(
type
)
=>
{
switch
(
type
)
{
case
'SUCCESS'
:
return
(
<
Label
basic
color
=
'green'
>
{
' '
}
成功
{
' '
}
<
/Label
>
);
case
'NOT_START'
:
return
(
<
Label
basic
color
=
'black'
>
{
' '
}
未启动
{
' '
}
<
/Label
>
);
case
'SUBMITTED'
:
return
(
<
Label
basic
color
=
'yellow'
>
{
' '
}
队列中
{
' '
}
<
/Label
>
);
case
'IN_PROGRESS'
:
return
(
<
Label
basic
color
=
'blue'
>
{
' '
}
执行中
{
' '
}
<
/Label
>
);
case
'FAILURE'
:
return
(
<
Label
basic
color
=
'red'
>
{
' '
}
失败
{
' '
}
<
/Label
>
);
case
'QUEUED'
:
return
(
<
Label
basic
color
=
'red'
>
{
' '
}
排队中
{
' '
}
<
/Label
>
);
case
'UNKNOWN'
:
return
(
return
(
<
Label
basic
color
=
'red'
>
<
div
key
=
{
column
.
key
}
className
=
"w-1/2 mb-4 pr-2"
>
{
' '
}
<
Checkbox
未知
{
' '
}
checked
=
{
!!
visibleColumns
[
column
.
key
]}
<
/Label
>
onChange
=
{(
e
)
=>
);
handleColumnVisibilityChange
(
column
.
key
,
e
.
target
.
checked
)
case
''
:
}
return
(
>
<
Label
basic
color
=
'black'
>
{
column
.
title
}
{
' '
}
<
/Checkbox
>
正在提交
{
' '
}
<
/div
>
<
/Label
>
);
);
default
:
})}
return
(
<
/div
>
<
Label
basic
color
=
'black'
>
<
/Modal
>
{
' '
}
未知
{
' '
}
<
/Label
>
);
);
}
};
};
return
(
return
(
<>
<>
{
renderColumnSelector
()}
<
Layout
>
<
Layout
>
<
Form
layout
=
'horizontal'
labelPosition
=
'inset'
>
<
Card
<>
className
=
"!rounded-2xl overflow-hidden mb-4"
{
isAdminUser
&&
(
title
=
{
<
Form
.
Input
<
div
className
=
"flex flex-col w-full"
>
field
=
'channel_id'
<
div
className
=
"flex flex-col md:flex-row justify-between items-center"
>
label
=
'渠道 ID'
<
div
className
=
"flex items-center text-orange-500 mb-2 md:mb-0"
>
style
=
{{
width
:
'236px'
,
marginBottom
:
'10px'
}}
<
IconEyeOpened
className
=
"mr-2"
/>
value
=
{
channel_id
}
{
loading
?
(
placeholder
=
{
'可选值'
}
<
Skeleton
.
Title
name
=
'channel_id'
style
=
{{
onChange
=
{(
value
)
=>
handleInputChange
(
value
,
'channel_id'
)}
width
:
300
,
marginBottom
:
0
,
marginTop
:
0
}}
/
>
/
>
)
:
(
<
Text
>
{
t
(
'任务记录'
)}
<
/Text
>
)}
)}
<
Form
.
Input
<
/div
>
field
=
'task_id'
<
/div
>
label
=
{
'任务 ID'
}
style
=
{{
width
:
'236px'
,
marginBottom
:
'10px'
}}
<
Divider
margin
=
"12px"
/>
{
/* 搜索表单区域 */
}
<
div
className
=
"flex flex-col gap-4"
>
<
div
className
=
"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4"
>
{
/* 时间选择器 */
}
<
div
className
=
"col-span-1 lg:col-span-2"
>
<
DatePicker
className
=
"w-full"
value
=
{[
start_timestamp
,
end_timestamp
]}
type
=
'dateTimeRange'
onChange
=
{(
value
)
=>
{
if
(
Array
.
isArray
(
value
)
&&
value
.
length
===
2
)
{
handleInputChange
(
value
[
0
],
'start_timestamp'
);
handleInputChange
(
value
[
1
],
'end_timestamp'
);
}
}}
/
>
<
/div
>
{
/* 任务 ID */
}
<
Input
prefix
=
{
<
IconSearch
/>
}
placeholder
=
{
t
(
'任务 ID'
)}
value
=
{
task_id
}
value
=
{
task_id
}
placeholder
=
{
'可选值'
}
name
=
'task_id'
onChange
=
{(
value
)
=>
handleInputChange
(
value
,
'task_id'
)}
onChange
=
{(
value
)
=>
handleInputChange
(
value
,
'task_id'
)}
className
=
"!rounded-full"
showClear
/>
/>
<
Form
.
DatePicker
{
/* 渠道 ID - 仅管理员可见 */
}
field
=
'start_timestamp'
{
isAdminUser
&&
(
label
=
{
'起始时间'
}
<
Input
style
=
{{
width
:
'236px'
,
marginBottom
:
'10px'
}}
prefix
=
{
<
IconSearch
/>
}
initValue
=
{
start_timestamp
}
placeholder
=
{
t
(
'渠道 ID'
)}
value
=
{
start_timestamp
}
value
=
{
channel_id
}
type
=
'dateTime'
onChange
=
{(
value
)
=>
handleInputChange
(
value
,
'channel_id'
)}
name
=
'start_timestamp'
className
=
"!rounded-full"
onChange
=
{(
value
)
=>
handleInputChange
(
value
,
'start_timestamp'
)}
showClear
/
>
<
Form
.
DatePicker
field
=
'end_timestamp'
fluid
label
=
{
'结束时间'
}
style
=
{{
width
:
'236px'
,
marginBottom
:
'10px'
}}
initValue
=
{
end_timestamp
}
value
=
{
end_timestamp
}
type
=
'dateTime'
name
=
'end_timestamp'
onChange
=
{(
value
)
=>
handleInputChange
(
value
,
'end_timestamp'
)}
/>
/>
)}
<
/div
>
{
/* 操作按钮区域 */
}
<
div
className
=
"flex justify-between items-center pt-2"
>
<
div
><
/div
>
<
div
className
=
"flex gap-2"
>
<
Button
<
Button
label
=
{
'查询'
}
type
=
'primary'
type
=
'primary'
htmlType
=
'submit'
className
=
'btn-margin-right'
onClick
=
{
refresh
}
onClick
=
{
refresh
}
loading
=
{
loading
}
className
=
"!rounded-full"
>
>
查询
{
t
(
'查询'
)}
<
/Button
>
<
/Button
>
<
/
>
<
Button
<
/Form
>
theme
=
'light'
<
Card
>
type
=
'tertiary'
icon
=
{
<
IconSetting
/>
}
onClick
=
{()
=>
setShowColumnSelector
(
true
)}
className
=
"!rounded-full"
>
{
t
(
'列设置'
)}
<
/Button
>
<
/div
>
<
/div
>
<
/div
>
<
/div
>
}
shadows
=
'hover'
>
<
Table
<
Table
columns
=
{
columns
}
columns
=
{
getVisibleColumns
()
}
dataSource
=
{
pageData
}
dataSource
=
{
pageData
}
rowKey
=
'key'
loading
=
{
loading
}
className
=
"rounded-xl overflow-hidden"
size
=
"middle"
pagination
=
{{
pagination
=
{{
formatPageText
:
(
page
)
=>
t
(
'第 {{start}} - {{end}} 条,共 {{total}} 条'
,
{
start
:
page
.
currentStart
,
end
:
page
.
currentEnd
,
total
:
logCount
,
}),
currentPage
:
activePage
,
currentPage
:
activePage
,
pageSize
:
ITEMS_PER_PAGE
,
pageSize
:
pageSize
,
total
:
logCount
,
total
:
logCount
,
pageSizeOpts
:
[
10
,
20
,
50
,
100
],
pageSizeOptions
:
[
10
,
20
,
50
,
100
],
showSizeChanger
:
true
,
onPageSizeChange
:
(
size
)
=>
{
handlePageSizeChange
(
size
);
},
onPageChange
:
handlePageChange
,
onPageChange
:
handlePageChange
,
}}
}}
loading
=
{
loading
}
/
>
/
>
<
/Card
>
<
/Card
>
<
Modal
<
Modal
visible
=
{
isModalOpen
}
visible
=
{
isModalOpen
}
onOk
=
{()
=>
setIsModalOpen
(
false
)}
onOk
=
{()
=>
setIsModalOpen
(
false
)}
...
...
web/src/i18n/locales/en.json
View file @
07d87d60
...
@@ -512,6 +512,7 @@
...
@@ -512,6 +512,7 @@
"模型映射必须是合法的 JSON 格式!"
:
"Model mapping must be in valid JSON format!"
,
"模型映射必须是合法的 JSON 格式!"
:
"Model mapping must be in valid JSON format!"
,
"取消无限额度"
:
"Cancel unlimited quota"
,
"取消无限额度"
:
"Cancel unlimited quota"
,
"取消"
:
"Cancel"
,
"取消"
:
"Cancel"
,
"重置"
:
"Reset"
,
"请输入新的剩余额度"
:
"Please enter the new remaining quota"
,
"请输入新的剩余额度"
:
"Please enter the new remaining quota"
,
"请输入单个兑换码中包含的额度"
:
"Please enter the quota included in a single redemption code"
,
"请输入单个兑换码中包含的额度"
:
"Please enter the quota included in a single redemption code"
,
"请输入用户名"
:
"Please enter username"
,
"请输入用户名"
:
"Please enter username"
,
...
@@ -1430,5 +1431,6 @@
...
@@ -1430,5 +1431,6 @@
"20个"
:
"20 items"
,
"20个"
:
"20 items"
,
"30个"
:
"30 items"
,
"30个"
:
"30 items"
,
"100个"
:
"100 items"
,
"100个"
:
"100 items"
,
"Midjourney 任务记录"
:
"Midjourney Task Records"
"Midjourney 任务记录"
:
"Midjourney Task Records"
,
"任务记录"
:
"Task Records"
}
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment