mirror of
https://github.com/linux-do/new-api.git
synced 2025-11-12 17:13:43 +08:00
Merge branch 'main' into refactor-settings-operation
This commit is contained in:
@@ -31,6 +31,7 @@ import {
|
||||
} from '@douyinfe/semi-ui';
|
||||
import EditChannel from '../pages/Channel/EditChannel';
|
||||
import { IconTreeTriangleDown } from '@douyinfe/semi-icons';
|
||||
import { loadChannelModels } from './utils.js';
|
||||
|
||||
function renderTimestamp(timestamp) {
|
||||
return <>{timestamp2string(timestamp)}</>;
|
||||
@@ -354,27 +355,29 @@ const ChannelsTable = () => {
|
||||
};
|
||||
|
||||
const copySelectedChannel = async (id) => {
|
||||
const channelToCopy = channels.find(channel => String(channel.id) === String(id));
|
||||
console.log(channelToCopy)
|
||||
const channelToCopy = channels.find(
|
||||
(channel) => String(channel.id) === String(id),
|
||||
);
|
||||
console.log(channelToCopy);
|
||||
channelToCopy.name += '_复制';
|
||||
channelToCopy.created_time = null;
|
||||
channelToCopy.balance = 0;
|
||||
channelToCopy.used_quota = 0;
|
||||
if (!channelToCopy) {
|
||||
showError("渠道未找到,请刷新页面后重试。");
|
||||
return;
|
||||
showError('渠道未找到,请刷新页面后重试。');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const newChannel = {...channelToCopy, id: undefined};
|
||||
const response = await API.post('/api/channel/', newChannel);
|
||||
if (response.data.success) {
|
||||
showSuccess("渠道复制成功");
|
||||
await refresh();
|
||||
} else {
|
||||
showError(response.data.message);
|
||||
}
|
||||
const newChannel = { ...channelToCopy, id: undefined };
|
||||
const response = await API.post('/api/channel/', newChannel);
|
||||
if (response.data.success) {
|
||||
showSuccess('渠道复制成功');
|
||||
await refresh();
|
||||
} else {
|
||||
showError(response.data.message);
|
||||
}
|
||||
} catch (error) {
|
||||
showError("渠道复制失败: " + error.message);
|
||||
showError('渠道复制失败: ' + error.message);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -395,6 +398,7 @@ const ChannelsTable = () => {
|
||||
showError(reason);
|
||||
});
|
||||
fetchGroups().then();
|
||||
loadChannelModels().then();
|
||||
}, []);
|
||||
|
||||
const manageChannel = async (id, action, record, value) => {
|
||||
|
||||
@@ -19,9 +19,15 @@ import {
|
||||
Spin,
|
||||
Table,
|
||||
Tag,
|
||||
Tooltip,
|
||||
} from '@douyinfe/semi-ui';
|
||||
import { ITEMS_PER_PAGE } from '../constants';
|
||||
import { renderNumber, renderQuota, stringToColor } from '../helpers/render';
|
||||
import {
|
||||
renderModelPrice,
|
||||
renderNumber,
|
||||
renderQuota,
|
||||
stringToColor,
|
||||
} from '../helpers/render';
|
||||
import Paragraph from '@douyinfe/semi-ui/lib/es/typography/paragraph';
|
||||
|
||||
const { Header } = Layout;
|
||||
@@ -292,16 +298,44 @@ const LogsTable = () => {
|
||||
title: '详情',
|
||||
dataIndex: 'content',
|
||||
render: (text, record, index) => {
|
||||
if (record.other === '') {
|
||||
return (
|
||||
<Paragraph
|
||||
ellipsis={{
|
||||
rows: 2,
|
||||
showTooltip: {
|
||||
type: 'popover',
|
||||
opts: { style: { width: 240 } },
|
||||
},
|
||||
}}
|
||||
style={{ maxWidth: 240 }}
|
||||
>
|
||||
{text}
|
||||
</Paragraph>
|
||||
);
|
||||
}
|
||||
let other = JSON.parse(record.other);
|
||||
let content = renderModelPrice(
|
||||
other.model_ratio,
|
||||
other.model_price,
|
||||
other.completion_ratio,
|
||||
other.group_ratio,
|
||||
);
|
||||
return (
|
||||
<Paragraph
|
||||
ellipsis={{
|
||||
rows: 2,
|
||||
showTooltip: { type: 'popover', opts: { style: { width: 240 } } },
|
||||
}}
|
||||
style={{ maxWidth: 240 }}
|
||||
>
|
||||
{text}
|
||||
</Paragraph>
|
||||
<Tooltip content={content}>
|
||||
<Paragraph
|
||||
ellipsis={{
|
||||
rows: 2,
|
||||
showTooltip: {
|
||||
type: 'popover',
|
||||
opts: { style: { width: 240 } },
|
||||
},
|
||||
}}
|
||||
style={{ maxWidth: 240 }}
|
||||
>
|
||||
{text}
|
||||
</Paragraph>
|
||||
</Tooltip>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -236,6 +236,31 @@ const renderTimestamp = (timestampInSeconds) => {
|
||||
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; // 格式化输出
|
||||
};
|
||||
// 修改renderDuration函数以包含颜色逻辑
|
||||
function renderDuration(submit_time, finishTime) {
|
||||
// 确保startTime和finishTime都是有效的时间戳
|
||||
if (!submit_time || !finishTime) return 'N/A';
|
||||
|
||||
// 将时间戳转换为Date对象
|
||||
const start = new Date(submit_time);
|
||||
const finish = new Date(finishTime);
|
||||
|
||||
// 计算时间差(毫秒)
|
||||
const durationMs = finish - start;
|
||||
|
||||
// 将时间差转换为秒,并保留一位小数
|
||||
const durationSec = (durationMs / 1000).toFixed(1);
|
||||
|
||||
// 设置颜色:大于60秒则为红色,小于等于60秒则为绿色
|
||||
const color = durationSec > 60 ? 'red' : 'green';
|
||||
|
||||
// 返回带有样式的颜色标签
|
||||
return (
|
||||
<Tag color={color} size="large">
|
||||
{durationSec} 秒
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
|
||||
const LogsTable = () => {
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
@@ -248,6 +273,15 @@ const LogsTable = () => {
|
||||
return <div>{renderTimestamp(text / 1000)}</div>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '花费时间',
|
||||
dataIndex: 'finish_time', // 以finish_time作为dataIndex
|
||||
key: 'finish_time',
|
||||
render: (finish, record) => {
|
||||
// 假设record.start_time是存在的,并且finish是完成时间的时间戳
|
||||
return renderDuration(record.submit_time, finish);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '渠道',
|
||||
dataIndex: 'channel_id',
|
||||
|
||||
@@ -29,6 +29,7 @@ const OperationSetting = () => {
|
||||
PreConsumedQuota: 0,
|
||||
StreamCacheQueueLength: 0,
|
||||
ModelRatio: '',
|
||||
CompletionRatio: '',
|
||||
ModelPrice: '',
|
||||
GroupRatio: '',
|
||||
TopUpLink: '',
|
||||
@@ -69,6 +70,7 @@ const OperationSetting = () => {
|
||||
if (
|
||||
item.key === 'ModelRatio' ||
|
||||
item.key === 'GroupRatio' ||
|
||||
item.key === 'CompletionRatio' ||
|
||||
item.key === 'ModelPrice'
|
||||
) {
|
||||
item.value = JSON.stringify(JSON.parse(item.value), null, 2);
|
||||
@@ -166,6 +168,13 @@ const OperationSetting = () => {
|
||||
}
|
||||
await updateOption('ModelRatio', inputs.ModelRatio);
|
||||
}
|
||||
if (originInputs['CompletionRatio'] !== inputs.CompletionRatio) {
|
||||
if (!verifyJSON(inputs.CompletionRatio)) {
|
||||
showError('模型补全倍率不是合法的 JSON 字符串');
|
||||
return;
|
||||
}
|
||||
await updateOption('CompletionRatio', inputs.CompletionRatio);
|
||||
}
|
||||
if (originInputs['GroupRatio'] !== inputs.GroupRatio) {
|
||||
if (!verifyJSON(inputs.GroupRatio)) {
|
||||
showError('分组倍率不是合法的 JSON 字符串');
|
||||
@@ -304,6 +313,20 @@ const OperationSetting = () => {
|
||||
placeholder='为一个 JSON 文本,键为模型名称,值为倍率'
|
||||
/>
|
||||
</Form.Group>
|
||||
<Form.Group widths='equal'>
|
||||
<Form.TextArea
|
||||
label='模型补全倍率(仅对自定义模型有效)'
|
||||
name='CompletionRatio'
|
||||
onChange={handleInputChange}
|
||||
style={{
|
||||
minHeight: 250,
|
||||
fontFamily: 'JetBrains Mono, Consolas',
|
||||
}}
|
||||
autoComplete='new-password'
|
||||
value={inputs.CompletionRatio}
|
||||
placeholder='为一个 JSON 文本,键为分组名称,值为倍率'
|
||||
/>
|
||||
</Form.Group>
|
||||
<Form.Group widths='equal'>
|
||||
<Form.TextArea
|
||||
label='分组倍率'
|
||||
|
||||
@@ -18,3 +18,32 @@ export async function onGitHubOAuthClicked(github_client_id) {
|
||||
`https://github.com/login/oauth/authorize?client_id=${github_client_id}&state=${state}&scope=user:email`,
|
||||
);
|
||||
}
|
||||
|
||||
let channelModels = undefined;
|
||||
export async function loadChannelModels() {
|
||||
const res = await API.get('/api/models');
|
||||
const { success, data } = res.data;
|
||||
if (!success) {
|
||||
return;
|
||||
}
|
||||
channelModels = data;
|
||||
localStorage.setItem('channel_models', JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function getChannelModels(type) {
|
||||
if (channelModels !== undefined && type in channelModels) {
|
||||
if (!channelModels[type]) {
|
||||
return [];
|
||||
}
|
||||
return channelModels[type];
|
||||
}
|
||||
let models = localStorage.getItem('channel_models');
|
||||
if (!models) {
|
||||
return [];
|
||||
}
|
||||
channelModels = JSON.parse(models);
|
||||
if (type in channelModels) {
|
||||
return channelModels[type];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user