diff --git a/web/src/components/playground/ParameterControl.js b/web/src/components/playground/ParameterControl.js index 669b38f9..e499dcfe 100644 --- a/web/src/components/playground/ParameterControl.js +++ b/web/src/components/playground/ParameterControl.js @@ -34,7 +34,7 @@ const ParameterControl = ({ Temperature - + {inputs.temperature} @@ -70,7 +70,7 @@ const ParameterControl = ({ Top P - + {inputs.top_p} @@ -106,7 +106,7 @@ const ParameterControl = ({ Frequency Penalty - + {inputs.frequency_penalty} @@ -142,7 +142,7 @@ const ParameterControl = ({ Presence Penalty - + {inputs.presence_penalty} diff --git a/web/src/components/settings/ChannelSelectorModal.js b/web/src/components/settings/ChannelSelectorModal.js index 72fdb970..4a3a0d18 100644 --- a/web/src/components/settings/ChannelSelectorModal.js +++ b/web/src/components/settings/ChannelSelectorModal.js @@ -118,25 +118,25 @@ const ChannelSelectorModal = forwardRef(({ switch (status) { case 1: return ( - }> + }> {t('已启用')} ); case 2: return ( - }> + }> {t('已禁用')} ); case 3: return ( - }> + }> {t('自动禁用')} ); default: return ( - }> + }> {t('未知状态')} ); diff --git a/web/src/components/table/ChannelsTable.js b/web/src/components/table/ChannelsTable.js index 810993c4..df0838a7 100644 --- a/web/src/components/table/ChannelsTable.js +++ b/web/src/components/table/ChannelsTable.js @@ -63,7 +63,6 @@ const ChannelsTable = () => { } return ( { return ( @@ -90,25 +88,25 @@ const ChannelsTable = () => { switch (status) { case 1: return ( - + {t('已启用')} ); case 2: return ( - + {t('已禁用')} ); case 3: return ( - + {t('自动禁用')} ); default: return ( - + {t('未知状态')} ); @@ -120,31 +118,31 @@ const ChannelsTable = () => { time = time.toFixed(2) + t(' 秒'); if (responseTime === 0) { return ( - + {t('未测试')} ); } else if (responseTime <= 1000) { return ( - + {time} ); } else if (responseTime <= 3000) { return ( - + {time} ); } else if (responseTime <= 5000) { return ( - + {time} ); } else { return ( - + {time} ); @@ -331,7 +329,7 @@ const ChannelsTable = () => {
- + {renderQuota(record.used_quota)} @@ -339,7 +337,6 @@ const ChannelsTable = () => { updateChannelBalance(record)} > @@ -352,7 +349,7 @@ const ChannelsTable = () => { } else { return ( - + {renderQuota(record.used_quota)} @@ -1240,7 +1237,7 @@ const ChannelsTable = () => { tab={ {t('全部')} - + {channelTypeCounts['all'] || 0} @@ -1258,7 +1255,7 @@ const ChannelsTable = () => { {getChannelIcon(option.value)} {option.label} - + {count} @@ -1461,7 +1458,7 @@ const ChannelsTable = () => { const fixChannelsAbilities = async () => { const res = await API.post(`/api/channel/fix`); - const { success, message, data } = res.data; + const { success, message, data } = res.data; if (success) { showSuccess(t('已修复 ${success} 个通道,失败 ${fails} 个通道。').replace('${success}', data.success).replace('${fails}', data.fails)); await refresh(); @@ -2033,7 +2030,7 @@ const ChannelsTable = () => { if (isTesting) { return ( - + {t('测试中')} ); @@ -2041,7 +2038,7 @@ const ChannelsTable = () => { if (!testResult) { return ( - + {t('未开始')} ); @@ -2050,7 +2047,6 @@ const ChannelsTable = () => { return (
diff --git a/web/src/components/table/LogsTable.js b/web/src/components/table/LogsTable.js index cc1d2082..9d1013ae 100644 --- a/web/src/components/table/LogsTable.js +++ b/web/src/components/table/LogsTable.js @@ -78,37 +78,37 @@ const LogsTable = () => { switch (type) { case 1: return ( - + {t('充值')} ); case 2: return ( - + {t('消费')} ); case 3: return ( - + {t('管理')} ); case 4: return ( - + {t('系统')} ); case 5: return ( - + {t('错误')} ); default: return ( - + {t('未知')} ); @@ -118,13 +118,13 @@ const LogsTable = () => { function renderIsStream(bool) { if (bool) { return ( - + {t('流')} ); } else { return ( - + {t('非流')} ); @@ -135,21 +135,21 @@ const LogsTable = () => { const time = parseInt(type); if (time < 101) { return ( - + {' '} {time} s{' '} ); } else if (time < 300) { return ( - + {' '} {time} s{' '} ); } else { return ( - + {' '} {time} s{' '} @@ -162,21 +162,21 @@ const LogsTable = () => { time = time.toFixed(1); if (time < 3) { return ( - + {' '} {time} s{' '} ); } else if (time < 10) { return ( - + {' '} {time} s{' '} ); } else { return ( - + {' '} {time} s{' '} @@ -363,7 +363,6 @@ const LogsTable = () => { {' '} @@ -415,7 +414,6 @@ const LogsTable = () => {
{ //cancel the row click event @@ -567,7 +565,6 @@ const LogsTable = () => { { copyText(event, text); diff --git a/web/src/components/table/MjLogsTable.js b/web/src/components/table/MjLogsTable.js index 66e52dd6..76a235eb 100644 --- a/web/src/components/table/MjLogsTable.js +++ b/web/src/components/table/MjLogsTable.js @@ -185,115 +185,115 @@ const LogsTable = () => { switch (type) { case 'IMAGINE': return ( - }> + }> {t('绘图')} ); case 'UPSCALE': return ( - }> + }> {t('放大')} ); case 'VIDEO': return ( - }> + }> {t('视频')} ); case 'EDITS': return ( - }> + }> {t('编辑')} ); case 'VARIATION': return ( - }> + }> {t('变换')} ); case 'HIGH_VARIATION': return ( - }> + }> {t('强变换')} ); case 'LOW_VARIATION': return ( - }> + }> {t('弱变换')} ); case 'PAN': return ( - }> + }> {t('平移')} ); case 'DESCRIBE': return ( - }> + }> {t('图生文')} ); case 'BLEND': return ( - }> + }> {t('图混合')} ); case 'UPLOAD': return ( - }> + }> 上传文件 ); case 'SHORTEN': return ( - }> + }> {t('缩词')} ); case 'REROLL': return ( - }> + }> {t('重绘')} ); case 'INPAINT': return ( - }> + }> {t('局部重绘-提交')} ); case 'ZOOM': return ( - }> + }> {t('变焦')} ); case 'CUSTOM_ZOOM': return ( - }> + }> {t('自定义变焦-提交')} ); case 'MODAL': return ( - }> + }> {t('窗口处理')} ); case 'SWAP_FACE': return ( - }> + }> {t('换脸')} ); default: return ( - }> + }> {t('未知')} ); @@ -304,31 +304,31 @@ const LogsTable = () => { switch (code) { case 1: return ( - }> + }> {t('已提交')} ); case 21: return ( - }> + }> {t('等待中')} ); case 22: return ( - }> + }> {t('重复提交')} ); case 0: return ( - }> + }> {t('未提交')} ); default: return ( - }> + }> {t('未知')} ); @@ -339,43 +339,43 @@ const LogsTable = () => { switch (type) { case 'SUCCESS': return ( - }> + }> {t('成功')} ); case 'NOT_START': return ( - }> + }> {t('未启动')} ); case 'SUBMITTED': return ( - }> + }> {t('队列中')} ); case 'IN_PROGRESS': return ( - }> + }> {t('执行中')} ); case 'FAILURE': return ( - }> + }> {t('失败')} ); case 'MODAL': return ( - }> + }> {t('窗口等待')} ); default: return ( - }> + }> {t('未知')} ); @@ -405,7 +405,7 @@ const LogsTable = () => { const color = durationSec > 60 ? 'red' : 'green'; return ( - }> + }> {durationSec} {t('秒')} ); @@ -439,7 +439,6 @@ const LogsTable = () => {
} onClick={() => { diff --git a/web/src/components/table/ModelPricing.js b/web/src/components/table/ModelPricing.js index bf9df911..cf498e70 100644 --- a/web/src/components/table/ModelPricing.js +++ b/web/src/components/table/ModelPricing.js @@ -76,13 +76,13 @@ const ModelPricing = () => { switch (type) { case 1: return ( - + {t('按次计费')} ); case 0: return ( - + {t('按量计费')} ); @@ -116,7 +116,6 @@ const ModelPricing = () => { {endpoint} @@ -179,7 +178,7 @@ const ModelPricing = () => { if (usableGroup[group]) { if (group === selectedGroup) { return ( - }> + }> {group} ); @@ -187,7 +186,6 @@ const ModelPricing = () => { return ( { setSelectedGroup(group); @@ -392,7 +390,6 @@ const ModelPricing = () => { {category.label} {modelCount} @@ -436,7 +433,6 @@ const ModelPricing = () => { onCompositionEnd={handleCompositionEnd} onChange={handleChange} showClear - size="large" />
diff --git a/web/src/components/table/RedemptionsTable.js b/web/src/components/table/RedemptionsTable.js index 9bdb603f..2cea3ab9 100644 --- a/web/src/components/table/RedemptionsTable.js +++ b/web/src/components/table/RedemptionsTable.js @@ -53,31 +53,31 @@ const RedemptionsTable = () => { const renderStatus = (status, record) => { if (isExpired(record)) { return ( - {t('已过期')} + {t('已过期')} ); } switch (status) { case 1: return ( - + {t('未使用')} ); case 2: return ( - + {t('已禁用')} ); case 3: return ( - + {t('已使用')} ); default: return ( - + {t('未知状态')} ); @@ -107,7 +107,7 @@ const RedemptionsTable = () => { render: (text, record, index) => { return (
- + {renderQuota(parseInt(text))}
diff --git a/web/src/components/table/TaskLogsTable.js b/web/src/components/table/TaskLogsTable.js index de41478e..c7d1a1fb 100644 --- a/web/src/components/table/TaskLogsTable.js +++ b/web/src/components/table/TaskLogsTable.js @@ -106,7 +106,7 @@ function renderDuration(submit_time, finishTime) { // 返回带有样式的颜色标签 return ( - }> + }> {durationSec} 秒 ); @@ -198,31 +198,31 @@ const LogsTable = () => { switch (type) { case 'MUSIC': return ( - }> + }> {t('生成音乐')} ); case 'LYRICS': return ( - }> + }> {t('生成歌词')} ); case TASK_ACTION_GENERATE: return ( - }> + }> {t('图生视频')} ); case TASK_ACTION_TEXT_GENERATE: return ( - }> + }> {t('文生视频')} ); default: return ( - }> + }> {t('未知')} ); @@ -233,25 +233,25 @@ const LogsTable = () => { switch (platform) { case 'suno': return ( - }> + }> Suno ); case 'kling': return ( - }> + }> Kling ); case 'jimeng': return ( - }> + }> Jimeng ); default: return ( - }> + }> {t('未知')} ); @@ -262,55 +262,55 @@ const LogsTable = () => { switch (type) { case 'SUCCESS': return ( - }> + }> {t('成功')} ); case 'NOT_START': return ( - }> + }> {t('未启动')} ); case 'SUBMITTED': return ( - }> + }> {t('队列中')} ); case 'IN_PROGRESS': return ( - }> + }> {t('执行中')} ); case 'FAILURE': return ( - }> + }> {t('失败')} ); case 'QUEUED': return ( - }> + }> {t('排队中')} ); case 'UNKNOWN': return ( - }> + }> {t('未知')} ); case '': return ( - }> + }> {t('正在提交')} ); default: return ( - }> + }> {t('未知')} ); diff --git a/web/src/components/table/TokensTable.js b/web/src/components/table/TokensTable.js index a6d669a6..50a4dded 100644 --- a/web/src/components/table/TokensTable.js +++ b/web/src/components/table/TokensTable.js @@ -7,7 +7,7 @@ import { timestamp2string, renderGroup, renderQuota, - getQuotaPerUnit + getModelCategories } from '../../helpers'; import { ITEMS_PER_PAGE } from '../../constants'; import { @@ -22,6 +22,12 @@ import { SplitButtonGroup, Table, Tag, + AvatarGroup, + Avatar, + Tooltip, + Progress, + Switch, + Input, Typography } from '@douyinfe/semi-ui'; import { @@ -31,7 +37,10 @@ import { import { IconSearch, IconTreeTriangleDown, - IconMore, + IconCopy, + IconEyeOpened, + IconEyeClosed, + IconBolt, } from '@douyinfe/semi-icons'; import { Key } from 'lucide-react'; import EditToken from '../../pages/Token/EditToken'; @@ -47,49 +56,6 @@ function renderTimestamp(timestamp) { const TokensTable = () => { const { t } = useTranslation(); - const renderStatus = (status, model_limits_enabled = false) => { - switch (status) { - case 1: - if (model_limits_enabled) { - return ( - - {t('已启用:限制模型')} - - ); - } else { - return ( - - {t('已启用')} - - ); - } - case 2: - return ( - - {t('已禁用')} - - ); - case 3: - return ( - - {t('已过期')} - - ); - case 4: - return ( - - {t('已耗尽')} - - ); - default: - return ( - - {t('未知状态')} - - ); - } - }; - const columns = [ { title: t('名称'), @@ -99,66 +65,249 @@ const TokensTable = () => { title: t('状态'), dataIndex: 'status', key: 'status', - render: (text, record, index) => { - return ( -
- - {renderStatus(text, record.model_limits_enabled)} - {renderGroup(record.group)} - -
- ); - }, - }, - { - title: t('已用额度'), - dataIndex: 'used_quota', - render: (text, record, index) => { - return ( -
- - {renderQuota(parseInt(text))} - -
- ); - }, - }, - { - title: t('剩余额度'), - dataIndex: 'remain_quota', - render: (text, record, index) => { - const getQuotaColor = (quotaValue) => { - const quotaPerUnit = getQuotaPerUnit(); - const dollarAmount = quotaValue / quotaPerUnit; - - if (dollarAmount <= 0) { - return 'red'; - } else if (dollarAmount <= 100) { - return 'yellow'; + render: (text, record) => { + const enabled = text === 1; + const handleToggle = (checked) => { + if (checked) { + manageToken(record.id, 'enable', record); } else { - return 'green'; + manageToken(record.id, 'disable', record); } }; + let tagColor = 'black'; + let tagText = t('未知状态'); + if (enabled) { + tagColor = 'green'; + tagText = t('已启用'); + } else if (text === 2) { + tagColor = 'red'; + tagText = t('已禁用'); + } else if (text === 3) { + tagColor = 'yellow'; + tagText = t('已过期'); + } else if (text === 4) { + tagColor = 'grey'; + tagText = t('已耗尽'); + } + return ( -
- {record.unlimited_quota ? ( - - {t('无限制')} - - ) : ( - - {renderQuota(parseInt(text))} - - )} + + } + > + {tagText} + + ); + }, + }, + { + title: t('分组'), + dataIndex: 'group', + key: 'group', + render: (text) => { + if (text === 'auto') { + return ( + + }> {t('智能熔断')} + + ); + } + return renderGroup(text); + }, + }, + { + title: t('密钥'), + key: 'token_key', + render: (text, record) => { + const fullKey = 'sk-' + record.key; + const maskedKey = 'sk-' + record.key.slice(0, 3) + '********' + record.key.slice(-3); + const revealed = !!showKeys[record.id]; + + return ( +
+ +
+ } + />
); }, }, + { + title: t('额度'), + key: 'quota', + render: (text, record) => { + if (record.unlimited_quota) { + return {t('无限制')}; + } + + const used = parseInt(record.used_quota) || 0; + const remain = parseInt(record.remain_quota) || 0; + const total = used + remain; + const percent = total > 0 ? (used / total) * 100 : 0; + + const getProgressColor = (pct) => { + if (pct >= 90) return 'var(--semi-color-danger)'; + if (pct >= 70) return 'var(--semi-color-warning)'; + return undefined; // default color + }; + + return ( + +
{t('已用额度')}: {renderQuota(used)}
+
{t('剩余额度')}: {renderQuota(remain)}
+
{t('总额度')}: {renderQuota(total)}
+
+ } + > +
+ {percent.toFixed(0)}%} + type="circle" + width={30} + /> +
+
+ ); + }, + }, + { + title: t('可用模型'), + dataIndex: 'model_limits', + render: (text, record) => { + if (record.model_limits_enabled && text) { + const models = text.split(',').filter(Boolean); + const categories = getModelCategories(t); + + const vendorAvatars = []; + Object.entries(categories).forEach(([key, category]) => { + if (key === 'all') return; + if (!category.icon || !category.filter) return; + const vendorModels = models.filter((m) => category.filter({ model_name: m })); + if (vendorModels.length > 0) { + vendorAvatars.push( + + + {category.icon} + + + ); + } + }); + + if (vendorAvatars.length === 0) { + vendorAvatars.push( + + + {models[0].slice(0, 2).toUpperCase()} + + + ); + } + + return ( + + {vendorAvatars} + + ); + } else { + return ( + + {t('无限制')} + + ); + } + }, + }, + { + title: t('IP限制'), + dataIndex: 'allow_ips', + render: (text) => { + if (!text || text.trim() === '') { + return ( + + {t('无限制')} + + ); + } + + const ips = text + .split('\n') + .map((ip) => ip.trim()) + .filter(Boolean); + + const displayIps = ips.slice(0, 1); + const extraCount = ips.length - displayIps.length; + + const ipTags = displayIps.map((ip, idx) => ( + + {ip} + + )); + + if (extraCount > 0) { + ipTags.push( + + + {'+' + extraCount} + + + ); + } + + return {ipTags}; + }, + }, { title: t('创建时间'), dataIndex: 'created_time', @@ -211,58 +360,6 @@ const TokensTable = () => { } } - // 创建更多操作的下拉菜单项 - const moreMenuItems = [ - { - node: 'item', - name: t('查看'), - onClick: () => { - Modal.info({ - title: t('令牌详情'), - content: 'sk-' + record.key, - size: 'large', - }); - }, - }, - { - node: 'item', - name: t('删除'), - type: 'danger', - onClick: () => { - Modal.confirm({ - title: t('确定是否要删除此令牌?'), - content: t('此修改将不可逆'), - onOk: () => { - manageToken(record.id, 'delete', record).then(() => { - removeRecord(record.key); - }); - }, - }); - }, - } - ]; - - // 动态添加启用/禁用按钮 - if (record.status === 1) { - moreMenuItems.push({ - node: 'item', - name: t('禁用'), - type: 'warning', - onClick: () => { - manageToken(record.id, 'disable', record); - }, - }); - } else { - moreMenuItems.push({ - node: 'item', - name: t('启用'), - type: 'secondary', - onClick: () => { - manageToken(record.id, 'enable', record); - }, - }); - } - return ( { - - - { + Modal.confirm({ + title: t('确定是否要删除此令牌?'), + content: t('此修改将不可逆'), + onOk: () => { + manageToken(record.id, 'delete', record).then(() => { + removeRecord(record.key); + }); + }, + }); + }} > - ); }, @@ -357,6 +449,7 @@ const TokensTable = () => { id: undefined, }); const [compactMode, setCompactMode] = useTableCompactMode('tokens'); + const [showKeys, setShowKeys] = useState({}); // Form 初始值 const formInitValues = { diff --git a/web/src/components/table/UsersTable.js b/web/src/components/table/UsersTable.js index 02a19b80..891c0585 100644 --- a/web/src/components/table/UsersTable.js +++ b/web/src/components/table/UsersTable.js @@ -54,25 +54,25 @@ const UsersTable = () => { switch (role) { case 1: return ( - }> + }> {t('普通用户')} ); case 10: return ( - }> + }> {t('管理员')} ); case 100: return ( - }> + }> {t('超级管理员')} ); default: return ( - }> + }> {t('未知身份')} ); @@ -82,16 +82,16 @@ const UsersTable = () => { const renderStatus = (status) => { switch (status) { case 1: - return }>{t('已激活')}; + return }>{t('已激活')}; case 2: return ( - }> + }> {t('已封禁')} ); default: return ( - }> + }> {t('未知状态')} ); @@ -117,7 +117,7 @@ const UsersTable = () => { {text} - +
{displayRemark} @@ -142,13 +142,13 @@ const UsersTable = () => { return (
- }> + }> {t('剩余')}: {renderQuota(record.quota)} - }> + }> {t('已用')}: {renderQuota(record.used_quota)} - }> + }> {t('调用')}: {renderNumber(record.request_count)} @@ -163,13 +163,13 @@ const UsersTable = () => { return (
- }> + }> {t('邀请')}: {renderNumber(record.aff_count)} - }> + }> {t('收益')}: {renderQuota(record.aff_history_quota)} - }> + }> {record.inviter_id === 0 ? t('无邀请人') : `邀请人: ${record.inviter_id}`} diff --git a/web/src/helpers/render.js b/web/src/helpers/render.js index 00862b4a..646374d3 100644 --- a/web/src/helpers/render.js +++ b/web/src/helpers/render.js @@ -539,7 +539,7 @@ export function stringToColor(str) { export function renderModelTag(modelName, options = {}) { const { color, - size = 'large', + size = 'default', shape = 'circle', onClick, suffixIcon, @@ -584,7 +584,7 @@ export function renderText(text, limit) { export function renderGroup(group) { if (group === '') { return ( - + {i18next.t('用户分组')} ); @@ -603,7 +603,6 @@ export function renderGroup(group) { {groups.map((group) => ( 路径参数 > 系统默认": "Token latitude controls Midjouney configuration, setting priority: token > path parameter > system default", "启用速率限制": "Enable rate limiting", "复制BaseURL": "Copy BaseURL", diff --git a/web/src/pages/Detail/index.js b/web/src/pages/Detail/index.js index f455abb6..584a0ab2 100644 --- a/web/src/pages/Detail/index.js +++ b/web/src/pages/Detail/index.js @@ -1381,7 +1381,7 @@ const Detail = (props) => {
{t('系统公告')} - + {t('显示最新20条')}
diff --git a/web/src/pages/Setup/index.js b/web/src/pages/Setup/index.js index 23988e7a..c0cf4aaf 100644 --- a/web/src/pages/Setup/index.js +++ b/web/src/pages/Setup/index.js @@ -183,7 +183,7 @@ const Setup = () => { title={
{t('数据库警告')} - + SQLite
@@ -222,7 +222,7 @@ const Setup = () => { title={
{t('数据库信息')} - + MySQL
@@ -256,7 +256,7 @@ const Setup = () => { title={
{t('数据库信息')} - + PostgreSQL
@@ -425,7 +425,7 @@ const Setup = () => {
{t('对外运营模式')}
{t('适用于为多个用户提供服务的场景')}
- + {t('默认模式')}
@@ -443,7 +443,7 @@ const Setup = () => {
{t('自用模式')}
{t('适用于个人使用的场景,不需要设置模型价格')}
- + {t('无需计费')}
@@ -461,7 +461,7 @@ const Setup = () => {
{t('演示站点模式')}
{t('适用于展示系统功能的场景,提供基础功能演示')}
- + {t('演示体验')}
@@ -522,8 +522,8 @@ const Setup = () => {

{t('默认模式,适用于为多个用户提供服务的场景。')}

{t('此模式下,系统将计算每次调用的用量,您需要对每个模型都设置价格,如果没有设置价格,用户将无法使用该模型。')}

- {t('计费模式')} - {t('多用户支持')} + {t('计费模式')} + {t('多用户支持')}
@@ -542,8 +542,8 @@ const Setup = () => {

{t('适用于个人使用的场景。')}

{t('不需要设置模型价格,系统将弱化用量计算,您可专注于使用模型。')}

- {t('无需计费')} - {t('个人使用')} + {t('无需计费')} + {t('个人使用')}
@@ -562,8 +562,8 @@ const Setup = () => {

{t('适用于展示系统功能的场景。')}

{t('提供基础功能演示,方便用户了解系统特性。')}

- {t('功能演示')} - {t('体验试用')} + {t('功能演示')} + {t('体验试用')}