diff --git a/web/default/src/components/LogsTable.js b/web/default/src/components/LogsTable.js
index 39bafc2e..1f528676 100644
--- a/web/default/src/components/LogsTable.js
+++ b/web/default/src/components/LogsTable.js
@@ -9,13 +9,34 @@ import {
Select,
Table,
} from 'semantic-ui-react';
-import { API, isAdmin, showError, timestamp2string } from '../helpers';
+import {
+ API,
+ copy,
+ isAdmin,
+ showError,
+ showSuccess,
+ showWarning,
+ timestamp2string,
+} from '../helpers';
import { ITEMS_PER_PAGE } from '../constants';
-import { renderQuota } from '../helpers/render';
+import { renderColorLabel, renderQuota } from '../helpers/render';
-function renderTimestamp(timestamp) {
- return <>{timestamp2string(timestamp)}>;
+function renderTimestamp(timestamp, request_id) {
+ return (
+ {
+ if (await copy(request_id)) {
+ showSuccess(`已复制请求 ID:${request_id}`);
+ } else {
+ showWarning(`请求 ID 复制失败:${request_id}`);
+ }
+ }}
+ style={{ cursor: 'pointer' }}
+ >
+ {timestamp2string(timestamp)}
+
+ );
}
const MODE_OPTIONS = [
@@ -103,8 +124,6 @@ function renderDetail(log) {
>
)}
-
- {log.request_id}
>
);
}
@@ -467,7 +486,9 @@ const LogsTable = () => {
if (log.deleted) return <>>;
return (
- {renderTimestamp(log.created_at)}
+
+ {renderTimestamp(log.created_at, log.request_id)}
+
{isAdminUser && (
{log.channel ? : ''}
@@ -475,23 +496,21 @@ const LogsTable = () => {
)}
{isAdminUser && (
- {log.username ? : ''}
+ {log.username ? (
+
+ ) : (
+ ''
+ )}
)}
- {log.token_name ? (
-
- ) : (
- ''
- )}
+ {log.token_name ? renderColorLabel(log.token_name) : ''}
{renderType(log.type)}
- {log.model_name ? (
-
- ) : (
- ''
- )}
+ {log.model_name ? renderColorLabel(log.model_name) : ''}
{log.prompt_tokens ? log.prompt_tokens : ''}
diff --git a/web/default/src/helpers/render.js b/web/default/src/helpers/render.js
index a9c81cc1..b622f8a6 100644
--- a/web/default/src/helpers/render.js
+++ b/web/default/src/helpers/render.js
@@ -13,16 +13,18 @@ export function renderGroup(group) {
}
let groups = group.split(',');
groups.sort();
- return <>
- {groups.map((group) => {
- if (group === 'vip' || group === 'pro') {
- return ;
- } else if (group === 'svip' || group === 'premium') {
- return ;
- }
- return ;
- })}
- >;
+ return (
+ <>
+ {groups.map((group) => {
+ if (group === 'vip' || group === 'pro') {
+ return ;
+ } else if (group === 'svip' || group === 'premium') {
+ return ;
+ }
+ return ;
+ })}
+ >
+ );
}
export function renderNumber(num) {
@@ -55,4 +57,33 @@ export function renderQuotaWithPrompt(quota, digits) {
return `(等价金额:${renderQuota(quota, digits)})`;
}
return '';
-}
\ No newline at end of file
+}
+
+const colors = [
+ 'red',
+ 'orange',
+ 'yellow',
+ 'olive',
+ 'green',
+ 'teal',
+ 'blue',
+ 'violet',
+ 'purple',
+ 'pink',
+ 'brown',
+ 'grey',
+ 'black',
+];
+
+export function renderColorLabel(text) {
+ let hash = 0;
+ for (let i = 0; i < text.length; i++) {
+ hash = text.charCodeAt(i) + ((hash << 5) - hash);
+ }
+ let index = Math.abs(hash % colors.length);
+ return (
+
+ );
+}