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
1b9246f7
authored
Mar 08, 2025
by
Calcium-Ion
Committed by
GitHub
Mar 08, 2025
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #828 from Calcium-Ion/ui
feat: Add column visibility settings for Channels and Logs tables
parents
47a92439
f8a8dbec
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
368 additions
and
19 deletions
+368
-19
controller/channel-test.go
+4
-1
web/src/components/ChannelsTable.js
+175
-13
web/src/components/LogsTable.js
+189
-5
No files found.
controller/channel-test.go
View file @
1b9246f7
...
@@ -83,6 +83,8 @@ func testChannel(channel *model.Channel, testModel string) (err error, openAIErr
...
@@ -83,6 +83,8 @@ func testChannel(channel *model.Channel, testModel string) (err error, openAIErr
c
.
Request
.
Header
.
Set
(
"Content-Type"
,
"application/json"
)
c
.
Request
.
Header
.
Set
(
"Content-Type"
,
"application/json"
)
c
.
Set
(
"channel"
,
channel
.
Type
)
c
.
Set
(
"channel"
,
channel
.
Type
)
c
.
Set
(
"base_url"
,
channel
.
GetBaseURL
())
c
.
Set
(
"base_url"
,
channel
.
GetBaseURL
())
group
,
_
:=
model
.
GetUserGroup
(
1
,
false
)
c
.
Set
(
"group"
,
group
)
middleware
.
SetupContextForSelectedChannel
(
c
,
channel
,
testModel
)
middleware
.
SetupContextForSelectedChannel
(
c
,
channel
,
testModel
)
...
@@ -158,7 +160,8 @@ func testChannel(channel *model.Channel, testModel string) (err error, openAIErr
...
@@ -158,7 +160,8 @@ func testChannel(channel *model.Channel, testModel string) (err error, openAIErr
tok
:=
time
.
Now
()
tok
:=
time
.
Now
()
milliseconds
:=
tok
.
Sub
(
tik
)
.
Milliseconds
()
milliseconds
:=
tok
.
Sub
(
tik
)
.
Milliseconds
()
consumedTime
:=
float64
(
milliseconds
)
/
1000.0
consumedTime
:=
float64
(
milliseconds
)
/
1000.0
other
:=
service
.
GenerateTextOtherInfo
(
c
,
info
,
priceData
.
ModelRatio
,
priceData
.
GroupRatio
,
priceData
.
CompletionRatio
,
0
,
0.0
,
priceData
.
ModelPrice
)
other
:=
service
.
GenerateTextOtherInfo
(
c
,
info
,
priceData
.
ModelRatio
,
priceData
.
GroupRatio
,
priceData
.
CompletionRatio
,
usage
.
PromptTokensDetails
.
CachedTokens
,
priceData
.
CacheRatio
,
priceData
.
ModelPrice
)
model
.
RecordConsumeLog
(
c
,
1
,
channel
.
Id
,
usage
.
PromptTokens
,
usage
.
CompletionTokens
,
info
.
OriginModelName
,
"模型测试"
,
model
.
RecordConsumeLog
(
c
,
1
,
channel
.
Id
,
usage
.
PromptTokens
,
usage
.
CompletionTokens
,
info
.
OriginModelName
,
"模型测试"
,
quota
,
"模型测试"
,
0
,
quota
,
int
(
consumedTime
),
false
,
info
.
Group
,
other
)
quota
,
"模型测试"
,
0
,
quota
,
int
(
consumedTime
),
false
,
info
.
Group
,
other
)
common
.
SysLog
(
fmt
.
Sprintf
(
"testing channel #%d, response:
\n
%s"
,
channel
.
Id
,
string
(
respBody
)))
common
.
SysLog
(
fmt
.
Sprintf
(
"testing channel #%d, response:
\n
%s"
,
channel
.
Id
,
string
(
respBody
)))
...
...
web/src/components/ChannelsTable.js
View file @
1b9246f7
...
@@ -29,10 +29,12 @@ import {
...
@@ -29,10 +29,12 @@ import {
Table
,
Table
,
Tag
,
Tag
,
Tooltip
,
Tooltip
,
Typography
Typography
,
Checkbox
,
Layout
}
from
'@douyinfe/semi-ui'
;
}
from
'@douyinfe/semi-ui'
;
import
EditChannel
from
'../pages/Channel/EditChannel'
;
import
EditChannel
from
'../pages/Channel/EditChannel'
;
import
{
IconList
,
IconTreeTriangleDown
}
from
'@douyinfe/semi-icons'
;
import
{
IconList
,
IconTreeTriangleDown
,
IconClose
,
IconFilter
,
IconPlus
,
IconRefresh
,
IconSetting
}
from
'@douyinfe/semi-icons'
;
import
{
loadChannelModels
}
from
'./utils.js'
;
import
{
loadChannelModels
}
from
'./utils.js'
;
import
EditTagModal
from
'../pages/Channel/EditTagModal.js'
;
import
EditTagModal
from
'../pages/Channel/EditTagModal.js'
;
import
TextNumberInput
from
'./custom/TextNumberInput.js'
;
import
TextNumberInput
from
'./custom/TextNumberInput.js'
;
...
@@ -141,21 +143,105 @@ const ChannelsTable = () => {
...
@@ -141,21 +143,105 @@ const ChannelsTable = () => {
}
}
};
};
const
columns
=
[
// Define column keys for selection
// {
const
COLUMN_KEYS
=
{
// title: '',
ID
:
'id'
,
// dataIndex: 'checkbox',
NAME
:
'name'
,
// className: 'checkbox',
GROUP
:
'group'
,
// },
TYPE
:
'type'
,
STATUS
:
'status'
,
RESPONSE_TIME
:
'response_time'
,
BALANCE
:
'balance'
,
PRIORITY
:
'priority'
,
WEIGHT
:
'weight'
,
OPERATE
:
'operate'
};
// State for column visibility
const
[
visibleColumns
,
setVisibleColumns
]
=
useState
({});
const
[
showColumnSelector
,
setShowColumnSelector
]
=
useState
(
false
);
// Load saved column preferences from localStorage
useEffect
(()
=>
{
const
savedColumns
=
localStorage
.
getItem
(
'channels-table-columns'
);
if
(
savedColumns
)
{
try
{
const
parsed
=
JSON
.
parse
(
savedColumns
);
// Make sure all columns are accounted for
const
defaults
=
getDefaultColumnVisibility
();
const
merged
=
{
...
defaults
,
...
parsed
};
setVisibleColumns
(
merged
);
}
catch
(
e
)
{
console
.
error
(
'Failed to parse saved column preferences'
,
e
);
initDefaultColumns
();
}
}
else
{
initDefaultColumns
();
}
},
[]);
// Update table when column visibility changes
useEffect
(()
=>
{
if
(
Object
.
keys
(
visibleColumns
).
length
>
0
)
{
// Save to localStorage
localStorage
.
setItem
(
'channels-table-columns'
,
JSON
.
stringify
(
visibleColumns
));
}
},
[
visibleColumns
]);
// Get default column visibility
const
getDefaultColumnVisibility
=
()
=>
{
return
{
[
COLUMN_KEYS
.
ID
]:
true
,
[
COLUMN_KEYS
.
NAME
]:
true
,
[
COLUMN_KEYS
.
GROUP
]:
true
,
[
COLUMN_KEYS
.
TYPE
]:
true
,
[
COLUMN_KEYS
.
STATUS
]:
true
,
[
COLUMN_KEYS
.
RESPONSE_TIME
]:
true
,
[
COLUMN_KEYS
.
BALANCE
]:
true
,
[
COLUMN_KEYS
.
PRIORITY
]:
true
,
[
COLUMN_KEYS
.
WEIGHT
]:
true
,
[
COLUMN_KEYS
.
OPERATE
]:
true
};
};
// Initialize default column visibility
const
initDefaultColumns
=
()
=>
{
const
defaults
=
getDefaultColumnVisibility
();
setVisibleColumns
(
defaults
);
};
// Handle column visibility change
const
handleColumnVisibilityChange
=
(
columnKey
,
checked
)
=>
{
const
updatedColumns
=
{
...
visibleColumns
,
[
columnKey
]:
checked
};
setVisibleColumns
(
updatedColumns
);
};
// Handle "Select All" checkbox
const
handleSelectAll
=
(
checked
)
=>
{
const
allKeys
=
Object
.
keys
(
COLUMN_KEYS
).
map
(
key
=>
COLUMN_KEYS
[
key
]);
const
updatedColumns
=
{};
allKeys
.
forEach
(
key
=>
{
updatedColumns
[
key
]
=
checked
;
});
setVisibleColumns
(
updatedColumns
);
};
// Define all columns with keys
const
allColumns
=
[
{
{
key
:
COLUMN_KEYS
.
ID
,
title
:
t
(
'ID'
),
title
:
t
(
'ID'
),
dataIndex
:
'id'
dataIndex
:
'id'
},
},
{
{
key
:
COLUMN_KEYS
.
NAME
,
title
:
t
(
'名称'
),
title
:
t
(
'名称'
),
dataIndex
:
'name'
dataIndex
:
'name'
},
},
{
{
key
:
COLUMN_KEYS
.
GROUP
,
title
:
t
(
'分组'
),
title
:
t
(
'分组'
),
dataIndex
:
'group'
,
dataIndex
:
'group'
,
render
:
(
text
,
record
,
index
)
=>
{
render
:
(
text
,
record
,
index
)
=>
{
...
@@ -177,6 +263,7 @@ const ChannelsTable = () => {
...
@@ -177,6 +263,7 @@ const ChannelsTable = () => {
}
}
},
},
{
{
key
:
COLUMN_KEYS
.
TYPE
,
title
:
t
(
'类型'
),
title
:
t
(
'类型'
),
dataIndex
:
'type'
,
dataIndex
:
'type'
,
render
:
(
text
,
record
,
index
)
=>
{
render
:
(
text
,
record
,
index
)
=>
{
...
@@ -188,6 +275,7 @@ const ChannelsTable = () => {
...
@@ -188,6 +275,7 @@ const ChannelsTable = () => {
}
}
},
},
{
{
key
:
COLUMN_KEYS
.
STATUS
,
title
:
t
(
'状态'
),
title
:
t
(
'状态'
),
dataIndex
:
'status'
,
dataIndex
:
'status'
,
render
:
(
text
,
record
,
index
)
=>
{
render
:
(
text
,
record
,
index
)
=>
{
...
@@ -211,6 +299,7 @@ const ChannelsTable = () => {
...
@@ -211,6 +299,7 @@ const ChannelsTable = () => {
}
}
},
},
{
{
key
:
COLUMN_KEYS
.
RESPONSE_TIME
,
title
:
t
(
'响应时间'
),
title
:
t
(
'响应时间'
),
dataIndex
:
'response_time'
,
dataIndex
:
'response_time'
,
render
:
(
text
,
record
,
index
)
=>
{
render
:
(
text
,
record
,
index
)
=>
{
...
@@ -218,6 +307,7 @@ const ChannelsTable = () => {
...
@@ -218,6 +307,7 @@ const ChannelsTable = () => {
}
}
},
},
{
{
key
:
COLUMN_KEYS
.
BALANCE
,
title
:
t
(
'已用/剩余'
),
title
:
t
(
'已用/剩余'
),
dataIndex
:
'expired_time'
,
dataIndex
:
'expired_time'
,
render
:
(
text
,
record
,
index
)
=>
{
render
:
(
text
,
record
,
index
)
=>
{
...
@@ -255,6 +345,7 @@ const ChannelsTable = () => {
...
@@ -255,6 +345,7 @@ const ChannelsTable = () => {
}
}
},
},
{
{
key
:
COLUMN_KEYS
.
PRIORITY
,
title
:
t
(
'优先级'
),
title
:
t
(
'优先级'
),
dataIndex
:
'priority'
,
dataIndex
:
'priority'
,
render
:
(
text
,
record
,
index
)
=>
{
render
:
(
text
,
record
,
index
)
=>
{
...
@@ -304,6 +395,7 @@ const ChannelsTable = () => {
...
@@ -304,6 +395,7 @@ const ChannelsTable = () => {
}
}
},
},
{
{
key
:
COLUMN_KEYS
.
WEIGHT
,
title
:
t
(
'权重'
),
title
:
t
(
'权重'
),
dataIndex
:
'weight'
,
dataIndex
:
'weight'
,
render
:
(
text
,
record
,
index
)
=>
{
render
:
(
text
,
record
,
index
)
=>
{
...
@@ -353,6 +445,7 @@ const ChannelsTable = () => {
...
@@ -353,6 +445,7 @@ const ChannelsTable = () => {
}
}
},
},
{
{
key
:
COLUMN_KEYS
.
OPERATE
,
title
:
''
,
title
:
''
,
dataIndex
:
'operate'
,
dataIndex
:
'operate'
,
render
:
(
text
,
record
,
index
)
=>
{
render
:
(
text
,
record
,
index
)
=>
{
...
@@ -493,6 +586,68 @@ const ChannelsTable = () => {
...
@@ -493,6 +586,68 @@ const ChannelsTable = () => {
}
}
];
];
// Filter columns based on visibility settings
const
getVisibleColumns
=
()
=>
{
return
allColumns
.
filter
(
column
=>
visibleColumns
[
column
.
key
]);
};
// Column selector modal
const
renderColumnSelector
=
()
=>
{
return
(
<
Modal
title
=
{
t
(
'列设置'
)}
visible
=
{
showColumnSelector
}
onCancel
=
{()
=>
setShowColumnSelector
(
false
)}
footer
=
{
<>
<
Button
onClick
=
{()
=>
initDefaultColumns
()}
>
{
t
(
'重置'
)}
<
/Button
>
<
Button
onClick
=
{()
=>
setShowColumnSelector
(
false
)}
>
{
t
(
'取消'
)}
<
/Button
>
<
Button
type
=
"primary"
onClick
=
{()
=>
setShowColumnSelector
(
false
)}
>
{
t
(
'确定'
)}
<
/Button
>
<
/
>
}
style
=
{{
width
:
500
}}
bodyStyle
=
{{
padding
:
'24px'
}}
>
<
div
style
=
{{
marginBottom
:
20
}}
>
<
Checkbox
checked
=
{
Object
.
values
(
visibleColumns
).
every
(
v
=>
v
===
true
)}
indeterminate
=
{
Object
.
values
(
visibleColumns
).
some
(
v
=>
v
===
true
)
&&
!
Object
.
values
(
visibleColumns
).
every
(
v
=>
v
===
true
)}
onChange
=
{
e
=>
handleSelectAll
(
e
.
target
.
checked
)}
>
{
t
(
'全选'
)}
<
/Checkbox
>
<
/div
>
<
div
style
=
{{
display
:
'flex'
,
flexWrap
:
'wrap'
,
maxHeight
:
'400px'
,
overflowY
:
'auto'
,
border
:
'1px solid var(--semi-color-border)'
,
borderRadius
:
'6px'
,
padding
:
'16px'
}}
>
{
allColumns
.
map
(
column
=>
{
// Skip columns without title
if
(
!
column
.
title
)
{
return
null
;
}
return
(
<
div
key
=
{
column
.
key
}
style
=
{{
width
:
'50%'
,
marginBottom
:
16
,
paddingRight
:
8
}}
>
<
Checkbox
checked
=
{
!!
visibleColumns
[
column
.
key
]}
onChange
=
{
e
=>
handleColumnVisibilityChange
(
column
.
key
,
e
.
target
.
checked
)}
>
{
column
.
title
}
<
/Checkbox
>
<
/div
>
);
})}
<
/div
>
<
/Modal
>
);
};
const
[
channels
,
setChannels
]
=
useState
([]);
const
[
channels
,
setChannels
]
=
useState
([]);
const
[
loading
,
setLoading
]
=
useState
(
true
);
const
[
loading
,
setLoading
]
=
useState
(
true
);
const
[
activePage
,
setActivePage
]
=
useState
(
1
);
const
[
activePage
,
setActivePage
]
=
useState
(
1
);
...
@@ -1032,6 +1187,7 @@ const ChannelsTable = () => {
...
@@ -1032,6 +1187,7 @@ const ChannelsTable = () => {
return
(
return
(
<>
<>
{
renderColumnSelector
()}
<
EditTagModal
<
EditTagModal
visible
=
{
showEditTag
}
visible
=
{
showEditTag
}
tag
=
{
editingTag
}
tag
=
{
editingTag
}
...
@@ -1238,15 +1394,22 @@ const ChannelsTable = () => {
...
@@ -1238,15 +1394,22 @@ const ChannelsTable = () => {
>
>
{
t
(
'批量设置标签'
)}
{
t
(
'批量设置标签'
)}
<
/Button
>
<
/Button
>
<
Button
theme
=
"light"
type
=
"tertiary"
icon
=
{
<
IconSetting
/>
}
onClick
=
{()
=>
setShowColumnSelector
(
true
)}
style
=
{{
marginRight
:
8
}}
>
{
t
(
'列设置'
)}
<
/Button
>
<
/Space
>
<
/Space
>
<
/div
>
<
/div
>
<
Table
<
Table
className
=
{
'channel-table'
}
loading
=
{
loading
}
style
=
{{
marginTop
:
15
}}
columns
=
{
getVisibleColumns
()}
columns
=
{
columns
}
dataSource
=
{
pageData
}
dataSource
=
{
pageData
}
pagination
=
{{
pagination
=
{{
currentPage
:
activePage
,
currentPage
:
activePage
,
...
@@ -1260,7 +1423,6 @@ const ChannelsTable = () => {
...
@@ -1260,7 +1423,6 @@ const ChannelsTable = () => {
},
},
onPageChange
:
handlePageChange
onPageChange
:
handlePageChange
}}
}}
loading
=
{
loading
}
onRow
=
{
handleRow
}
onRow
=
{
handleRow
}
rowSelection
=
{
rowSelection
=
{
enableBatchDelete
enableBatchDelete
...
...
web/src/components/LogsTable.js
View file @
1b9246f7
...
@@ -21,7 +21,8 @@ import {
...
@@ -21,7 +21,8 @@ import {
Spin
,
Spin
,
Table
,
Table
,
Tag
,
Tag
,
Tooltip
Tooltip
,
Checkbox
}
from
'@douyinfe/semi-ui'
;
}
from
'@douyinfe/semi-ui'
;
import
{
ITEMS_PER_PAGE
}
from
'../constants'
;
import
{
ITEMS_PER_PAGE
}
from
'../constants'
;
import
{
import
{
...
@@ -34,7 +35,7 @@ import {
...
@@ -34,7 +35,7 @@ import {
import
Paragraph
from
'@douyinfe/semi-ui/lib/es/typography/paragraph'
;
import
Paragraph
from
'@douyinfe/semi-ui/lib/es/typography/paragraph'
;
import
{
getLogOther
}
from
'../helpers/other.js'
;
import
{
getLogOther
}
from
'../helpers/other.js'
;
import
{
StyleContext
}
from
'../context/Style/index.js'
;
import
{
StyleContext
}
from
'../context/Style/index.js'
;
import
{
IconInherit
,
IconRefresh
}
from
'@douyinfe/semi-icons'
;
import
{
IconInherit
,
IconRefresh
,
IconSetting
}
from
'@douyinfe/semi-icons'
;
const
{
Header
}
=
Layout
;
const
{
Header
}
=
Layout
;
...
@@ -215,12 +216,104 @@ const LogsTable = () => {
...
@@ -215,12 +216,104 @@ const LogsTable = () => {
}
}
const
columns
=
[
// Define column keys for selection
const
COLUMN_KEYS
=
{
TIME
:
'time'
,
CHANNEL
:
'channel'
,
USERNAME
:
'username'
,
TOKEN
:
'token'
,
GROUP
:
'group'
,
TYPE
:
'type'
,
MODEL
:
'model'
,
USE_TIME
:
'use_time'
,
PROMPT
:
'prompt'
,
COMPLETION
:
'completion'
,
COST
:
'cost'
,
RETRY
:
'retry'
,
DETAILS
:
'details'
};
// State for column visibility
const
[
visibleColumns
,
setVisibleColumns
]
=
useState
({});
const
[
showColumnSelector
,
setShowColumnSelector
]
=
useState
(
false
);
// Load saved column preferences from localStorage
useEffect
(()
=>
{
const
savedColumns
=
localStorage
.
getItem
(
'logs-table-columns'
);
if
(
savedColumns
)
{
try
{
const
parsed
=
JSON
.
parse
(
savedColumns
);
// Make sure all columns are accounted for
const
defaults
=
getDefaultColumnVisibility
();
const
merged
=
{
...
defaults
,
...
parsed
};
setVisibleColumns
(
merged
);
}
catch
(
e
)
{
console
.
error
(
'Failed to parse saved column preferences'
,
e
);
initDefaultColumns
();
}
}
else
{
initDefaultColumns
();
}
},
[]);
// Get default column visibility based on user role
const
getDefaultColumnVisibility
=
()
=>
{
return
{
[
COLUMN_KEYS
.
TIME
]:
true
,
[
COLUMN_KEYS
.
CHANNEL
]:
isAdminUser
,
[
COLUMN_KEYS
.
USERNAME
]:
isAdminUser
,
[
COLUMN_KEYS
.
TOKEN
]:
true
,
[
COLUMN_KEYS
.
GROUP
]:
true
,
[
COLUMN_KEYS
.
TYPE
]:
true
,
[
COLUMN_KEYS
.
MODEL
]:
true
,
[
COLUMN_KEYS
.
USE_TIME
]:
true
,
[
COLUMN_KEYS
.
PROMPT
]:
true
,
[
COLUMN_KEYS
.
COMPLETION
]:
true
,
[
COLUMN_KEYS
.
COST
]:
true
,
[
COLUMN_KEYS
.
RETRY
]:
isAdminUser
,
[
COLUMN_KEYS
.
DETAILS
]:
true
};
};
// Initialize default column visibility
const
initDefaultColumns
=
()
=>
{
const
defaults
=
getDefaultColumnVisibility
();
setVisibleColumns
(
defaults
);
localStorage
.
setItem
(
'logs-table-columns'
,
JSON
.
stringify
(
defaults
));
};
// Handle column visibility change
const
handleColumnVisibilityChange
=
(
columnKey
,
checked
)
=>
{
const
updatedColumns
=
{
...
visibleColumns
,
[
columnKey
]:
checked
};
setVisibleColumns
(
updatedColumns
);
};
// Handle "Select All" checkbox
const
handleSelectAll
=
(
checked
)
=>
{
const
allKeys
=
Object
.
keys
(
COLUMN_KEYS
).
map
(
key
=>
COLUMN_KEYS
[
key
]);
const
updatedColumns
=
{};
allKeys
.
forEach
(
key
=>
{
// For admin-only columns, only enable them if user is admin
if
((
key
===
COLUMN_KEYS
.
CHANNEL
||
key
===
COLUMN_KEYS
.
USERNAME
||
key
===
COLUMN_KEYS
.
RETRY
)
&&
!
isAdminUser
)
{
updatedColumns
[
key
]
=
false
;
}
else
{
updatedColumns
[
key
]
=
checked
;
}
});
setVisibleColumns
(
updatedColumns
);
};
// Define all columns
const
allColumns
=
[
{
{
key
:
COLUMN_KEYS
.
TIME
,
title
:
t
(
'时间'
),
title
:
t
(
'时间'
),
dataIndex
:
'timestamp2string'
,
dataIndex
:
'timestamp2string'
,
},
},
{
{
key
:
COLUMN_KEYS
.
CHANNEL
,
title
:
t
(
'渠道'
),
title
:
t
(
'渠道'
),
dataIndex
:
'channel'
,
dataIndex
:
'channel'
,
className
:
isAdmin
()
?
'tableShow'
:
'tableHiddle'
,
className
:
isAdmin
()
?
'tableShow'
:
'tableHiddle'
,
...
@@ -249,6 +342,7 @@ const LogsTable = () => {
...
@@ -249,6 +342,7 @@ const LogsTable = () => {
},
},
},
},
{
{
key
:
COLUMN_KEYS
.
USERNAME
,
title
:
t
(
'用户'
),
title
:
t
(
'用户'
),
dataIndex
:
'username'
,
dataIndex
:
'username'
,
className
:
isAdmin
()
?
'tableShow'
:
'tableHiddle'
,
className
:
isAdmin
()
?
'tableShow'
:
'tableHiddle'
,
...
@@ -274,6 +368,7 @@ const LogsTable = () => {
...
@@ -274,6 +368,7 @@ const LogsTable = () => {
},
},
},
},
{
{
key
:
COLUMN_KEYS
.
TOKEN
,
title
:
t
(
'令牌'
),
title
:
t
(
'令牌'
),
dataIndex
:
'token_name'
,
dataIndex
:
'token_name'
,
render
:
(
text
,
record
,
index
)
=>
{
render
:
(
text
,
record
,
index
)
=>
{
...
@@ -297,6 +392,7 @@ const LogsTable = () => {
...
@@ -297,6 +392,7 @@ const LogsTable = () => {
},
},
},
},
{
{
key
:
COLUMN_KEYS
.
GROUP
,
title
:
t
(
'分组'
),
title
:
t
(
'分组'
),
dataIndex
:
'group'
,
dataIndex
:
'group'
,
render
:
(
text
,
record
,
index
)
=>
{
render
:
(
text
,
record
,
index
)
=>
{
...
@@ -333,6 +429,7 @@ const LogsTable = () => {
...
@@ -333,6 +429,7 @@ const LogsTable = () => {
},
},
},
},
{
{
key
:
COLUMN_KEYS
.
TYPE
,
title
:
t
(
'类型'
),
title
:
t
(
'类型'
),
dataIndex
:
'type'
,
dataIndex
:
'type'
,
render
:
(
text
,
record
,
index
)
=>
{
render
:
(
text
,
record
,
index
)
=>
{
...
@@ -340,6 +437,7 @@ const LogsTable = () => {
...
@@ -340,6 +437,7 @@ const LogsTable = () => {
},
},
},
},
{
{
key
:
COLUMN_KEYS
.
MODEL
,
title
:
t
(
'模型'
),
title
:
t
(
'模型'
),
dataIndex
:
'model_name'
,
dataIndex
:
'model_name'
,
render
:
(
text
,
record
,
index
)
=>
{
render
:
(
text
,
record
,
index
)
=>
{
...
@@ -351,6 +449,7 @@ const LogsTable = () => {
...
@@ -351,6 +449,7 @@ const LogsTable = () => {
},
},
},
},
{
{
key
:
COLUMN_KEYS
.
USE_TIME
,
title
:
t
(
'用时/首字'
),
title
:
t
(
'用时/首字'
),
dataIndex
:
'use_time'
,
dataIndex
:
'use_time'
,
render
:
(
text
,
record
,
index
)
=>
{
render
:
(
text
,
record
,
index
)
=>
{
...
@@ -378,6 +477,7 @@ const LogsTable = () => {
...
@@ -378,6 +477,7 @@ const LogsTable = () => {
},
},
},
},
{
{
key
:
COLUMN_KEYS
.
PROMPT
,
title
:
t
(
'提示'
),
title
:
t
(
'提示'
),
dataIndex
:
'prompt_tokens'
,
dataIndex
:
'prompt_tokens'
,
render
:
(
text
,
record
,
index
)
=>
{
render
:
(
text
,
record
,
index
)
=>
{
...
@@ -389,6 +489,7 @@ const LogsTable = () => {
...
@@ -389,6 +489,7 @@ const LogsTable = () => {
},
},
},
},
{
{
key
:
COLUMN_KEYS
.
COMPLETION
,
title
:
t
(
'补全'
),
title
:
t
(
'补全'
),
dataIndex
:
'completion_tokens'
,
dataIndex
:
'completion_tokens'
,
render
:
(
text
,
record
,
index
)
=>
{
render
:
(
text
,
record
,
index
)
=>
{
...
@@ -401,6 +502,7 @@ const LogsTable = () => {
...
@@ -401,6 +502,7 @@ const LogsTable = () => {
},
},
},
},
{
{
key
:
COLUMN_KEYS
.
COST
,
title
:
t
(
'花费'
),
title
:
t
(
'花费'
),
dataIndex
:
'quota'
,
dataIndex
:
'quota'
,
render
:
(
text
,
record
,
index
)
=>
{
render
:
(
text
,
record
,
index
)
=>
{
...
@@ -412,6 +514,7 @@ const LogsTable = () => {
...
@@ -412,6 +514,7 @@ const LogsTable = () => {
},
},
},
},
{
{
key
:
COLUMN_KEYS
.
RETRY
,
title
:
t
(
'重试'
),
title
:
t
(
'重试'
),
dataIndex
:
'retry'
,
dataIndex
:
'retry'
,
className
:
isAdmin
()
?
'tableShow'
:
'tableHiddle'
,
className
:
isAdmin
()
?
'tableShow'
:
'tableHiddle'
,
...
@@ -439,6 +542,7 @@ const LogsTable = () => {
...
@@ -439,6 +542,7 @@ const LogsTable = () => {
},
},
},
},
{
{
key
:
COLUMN_KEYS
.
DETAILS
,
title
:
t
(
'详情'
),
title
:
t
(
'详情'
),
dataIndex
:
'content'
,
dataIndex
:
'content'
,
render
:
(
text
,
record
,
index
)
=>
{
render
:
(
text
,
record
,
index
)
=>
{
...
@@ -481,6 +585,76 @@ const LogsTable = () => {
...
@@ -481,6 +585,76 @@ const LogsTable = () => {
},
},
];
];
// Update table when column visibility changes
useEffect
(()
=>
{
if
(
Object
.
keys
(
visibleColumns
).
length
>
0
)
{
// Save to localStorage
localStorage
.
setItem
(
'logs-table-columns'
,
JSON
.
stringify
(
visibleColumns
));
}
},
[
visibleColumns
]);
// Filter columns based on visibility settings
const
getVisibleColumns
=
()
=>
{
return
allColumns
.
filter
(
column
=>
visibleColumns
[
column
.
key
]);
};
// Column selector modal
const
renderColumnSelector
=
()
=>
{
return
(
<
Modal
title
=
{
t
(
'列设置'
)}
visible
=
{
showColumnSelector
}
onCancel
=
{()
=>
setShowColumnSelector
(
false
)}
footer
=
{
<>
<
Button
onClick
=
{()
=>
initDefaultColumns
()}
>
{
t
(
'重置'
)}
<
/Button
>
<
Button
onClick
=
{()
=>
setShowColumnSelector
(
false
)}
>
{
t
(
'取消'
)}
<
/Button
>
<
Button
type
=
"primary"
onClick
=
{()
=>
setShowColumnSelector
(
false
)}
>
{
t
(
'确定'
)}
<
/Button
>
<
/
>
}
>
<
div
style
=
{{
marginBottom
:
20
}}
>
<
Checkbox
checked
=
{
Object
.
values
(
visibleColumns
).
every
(
v
=>
v
===
true
)}
indeterminate
=
{
Object
.
values
(
visibleColumns
).
some
(
v
=>
v
===
true
)
&&
!
Object
.
values
(
visibleColumns
).
every
(
v
=>
v
===
true
)}
onChange
=
{
e
=>
handleSelectAll
(
e
.
target
.
checked
)}
>
{
t
(
'全选'
)}
<
/Checkbox
>
<
/div
>
<
div
style
=
{{
display
:
'flex'
,
flexWrap
:
'wrap'
,
maxHeight
:
'400px'
,
overflowY
:
'auto'
,
border
:
'1px solid var(--semi-color-border)'
,
borderRadius
:
'6px'
,
padding
:
'16px'
}}
>
{
allColumns
.
map
(
column
=>
{
// Skip admin-only columns for non-admin users
if
(
!
isAdminUser
&&
(
column
.
key
===
COLUMN_KEYS
.
CHANNEL
||
column
.
key
===
COLUMN_KEYS
.
USERNAME
||
column
.
key
===
COLUMN_KEYS
.
RETRY
))
{
return
null
;
}
return
(
<
div
key
=
{
column
.
key
}
style
=
{{
width
:
'50%'
,
marginBottom
:
16
,
paddingRight
:
8
}}
>
<
Checkbox
checked
=
{
!!
visibleColumns
[
column
.
key
]}
onChange
=
{
e
=>
handleColumnVisibilityChange
(
column
.
key
,
e
.
target
.
checked
)}
>
{
column
.
title
}
<
/Checkbox
>
<
/div
>
);
})}
<
/div
>
<
/Modal
>
);
};
const
[
styleState
,
styleDispatch
]
=
useContext
(
StyleContext
);
const
[
styleState
,
styleDispatch
]
=
useContext
(
StyleContext
);
const
[
logs
,
setLogs
]
=
useState
([]);
const
[
logs
,
setLogs
]
=
useState
([]);
const
[
expandData
,
setExpandData
]
=
useState
({});
const
[
expandData
,
setExpandData
]
=
useState
({});
...
@@ -782,8 +956,9 @@ const LogsTable = () => {
...
@@ -782,8 +956,9 @@ const LogsTable = () => {
return
(
return
(
<>
<>
{
renderColumnSelector
()}
<
Layout
>
<
Layout
>
<
Header
>
<
Header
style
=
{{
backgroundColor
:
'var(--semi-color-bg-1)'
}}
>
<
Spin
spinning
=
{
loadingStat
}
>
<
Spin
spinning
=
{
loadingStat
}
>
<
Space
>
<
Space
>
<
Tag
color
=
'green'
size
=
'large'
style
=
{{
padding
:
15
}}
>
<
Tag
color
=
'green'
size
=
'large'
style
=
{{
padding
:
15
}}
>
...
@@ -917,10 +1092,19 @@ const LogsTable = () => {
...
@@ -917,10 +1092,19 @@ const LogsTable = () => {
<
Select
.
Option
value
=
'3'
>
{
t
(
'管理'
)}
<
/Select.Option
>
<
Select
.
Option
value
=
'3'
>
{
t
(
'管理'
)}
<
/Select.Option
>
<
Select
.
Option
value
=
'4'
>
{
t
(
'系统'
)}
<
/Select.Option
>
<
Select
.
Option
value
=
'4'
>
{
t
(
'系统'
)}
<
/Select.Option
>
<
/Select
>
<
/Select
>
<
Button
theme
=
'light'
type
=
'tertiary'
icon
=
{
<
IconSetting
/>
}
onClick
=
{()
=>
setShowColumnSelector
(
true
)}
style
=
{{
marginLeft
:
8
}}
>
{
t
(
'列设置'
)}
<
/Button
>
<
/div
>
<
/div
>
<
Table
<
Table
style
=
{{
marginTop
:
5
}}
style
=
{{
marginTop
:
5
}}
columns
=
{
columns
}
columns
=
{
getVisibleColumns
()
}
expandedRowRender
=
{
expandRowRender
}
expandedRowRender
=
{
expandRowRender
}
expandRowByClick
=
{
true
}
expandRowByClick
=
{
true
}
dataSource
=
{
logs
}
dataSource
=
{
logs
}
...
...
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