fix: address code review findings

- fix(api): use effectiveTokenId in route channel insert to match duplicate detection logic
- fix(css): rename keyframes to kebab-case (filter-bar-slide-down/up)
- fix(web): wrap "保存中..." text with tr() in ManualRoutePanel
- fix(web): use ref for fresh cache check and add error handling in useRouteChannels
This commit is contained in:
Hureru
2026-03-11 15:51:10 +08:00
parent 8128d6e036
commit f5fcf5d707
4 changed files with 14 additions and 9 deletions
+1 -1
View File
@@ -539,7 +539,7 @@ export async function tokensRoutes(app: FastifyInstance) {
await db.insert(schema.routeChannels).values({
routeId,
accountId: item.accountId,
tokenId: item.tokenId,
tokenId: effectiveTokenId,
sourceModel: sourceModel || null,
priority: 0,
weight: 10,
+4 -4
View File
@@ -4101,19 +4101,19 @@ textarea {
display: flex;
flex-direction: column;
gap: 8px;
animation: filterBarSlideDown 0.22s cubic-bezier(0.22, 1, 0.36, 1);
animation: filter-bar-slide-down 0.22s cubic-bezier(0.22, 1, 0.36, 1);
}
.route-filter-bar-expanded.is-closing {
animation: filterBarSlideUp 0.18s ease forwards;
animation: filter-bar-slide-up 0.18s ease forwards;
}
@keyframes filterBarSlideDown {
@keyframes filter-bar-slide-down {
from { opacity: 0; max-height: 0; transform: translateY(-4px); }
to { opacity: 1; max-height: 600px; transform: translateY(0); }
}
@keyframes filterBarSlideUp {
@keyframes filter-bar-slide-up {
from { opacity: 1; max-height: 600px; }
to { opacity: 0; max-height: 0; overflow: hidden; }
}
@@ -174,7 +174,7 @@ export default function ManualRoutePanel({
className="spinner spinner-sm"
style={{ borderTopColor: 'white', borderColor: 'rgba(255,255,255,0.3)' }}
/>{' '}
保存中...
{tr('保存中...')}
</>
) : (
tr(editingRouteId ? '保存群组' : '创建群组')
@@ -1,4 +1,4 @@
import { useState, useCallback } from 'react';
import { useState, useCallback, useRef } from 'react';
import { api } from '../../api.js';
import { normalizeChannels } from './utils.js';
import type { RouteChannel } from './types.js';
@@ -6,19 +6,24 @@ import type { RouteChannel } from './types.js';
export function useRouteChannels() {
const [channelsByRouteId, setChannelsByRouteId] = useState<Record<number, RouteChannel[]>>({});
const [loadingChannelsByRouteId, setLoadingChannelsByRouteId] = useState<Record<number, boolean>>({});
const channelsByRouteIdRef = useRef(channelsByRouteId);
channelsByRouteIdRef.current = channelsByRouteId;
const loadChannels = useCallback(async (routeId: number, force = false) => {
if (!force && channelsByRouteId[routeId]) return channelsByRouteId[routeId];
if (!force && channelsByRouteIdRef.current[routeId]) return channelsByRouteIdRef.current[routeId];
setLoadingChannelsByRouteId((prev) => ({ ...prev, [routeId]: true }));
try {
const channels = await api.getRouteChannels(routeId);
const sorted = normalizeChannels(channels || []);
setChannelsByRouteId((prev) => ({ ...prev, [routeId]: sorted }));
return sorted;
} catch (error) {
console.error(`Failed to load channels for route ${routeId}:`, error);
throw error;
} finally {
setLoadingChannelsByRouteId((prev) => ({ ...prev, [routeId]: false }));
}
}, [channelsByRouteId]);
}, []);
const invalidateChannels = useCallback((routeId: number) => {
setChannelsByRouteId((prev) => {