feat(proxy-groups, current-proxy-card): auto-refresh delay sorting
- proxy-groups: recalculate active group head and reapply delay sort after tests so list reorders automatically when "按延迟排序" is active. - current-proxy-card: add delaySortRefresh trigger after auto/manual latency checks to immediately refresh selector and proxy list ordering. - current-proxy-card: listen for delaySortRefresh to keep displayed delay chips and option ordering aligned with latest measurements.
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
- 主界面“当前节点”卡片新增“延迟测试”按钮
|
||||
- 新增批量选择配置文件功能
|
||||
- 新增本地备份功能
|
||||
- 主界面“当前节点”卡片新增自动延迟检测开关(默认关闭)
|
||||
|
||||
### 🚀 优化改进
|
||||
|
||||
@@ -28,8 +29,8 @@
|
||||
- 改进 Windows 和 Unix 的 服务连接方式以及权限,避免无法连接服务或内核
|
||||
- 修改内核默认日志级别为 Info
|
||||
- 支持通过桌面快捷方式重新打开应用
|
||||
- 主界面“当前节点”卡片新增自动延迟检测开关(默认关闭)
|
||||
- 支持订阅界面输入链接后回车导入
|
||||
- 选择按延迟排序时每次延迟测试自动刷新节点顺序
|
||||
|
||||
### 🐞 修复问题
|
||||
|
||||
|
||||
@@ -124,6 +124,7 @@ export const CurrentProxyCard = () => {
|
||||
const savedSortType = localStorage.getItem(STORAGE_KEY_SORT_TYPE);
|
||||
return savedSortType ? (Number(savedSortType) as ProxySortType) : 0;
|
||||
});
|
||||
const [delaySortRefresh, setDelaySortRefresh] = useState(0);
|
||||
|
||||
// 定义状态类型
|
||||
type ProxyState = {
|
||||
@@ -443,12 +444,17 @@ export const CurrentProxyCard = () => {
|
||||
} finally {
|
||||
autoCheckInProgressRef.current = false;
|
||||
refreshProxy();
|
||||
if (sortType === 1) {
|
||||
setDelaySortRefresh((prev) => prev + 1);
|
||||
}
|
||||
}
|
||||
}, [
|
||||
isDirectMode,
|
||||
refreshProxy,
|
||||
state.selection.group,
|
||||
state.selection.proxy,
|
||||
sortType,
|
||||
setDelaySortRefresh,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -487,28 +493,25 @@ export const CurrentProxyCard = () => {
|
||||
]);
|
||||
|
||||
// 自定义渲染选择框中的值
|
||||
const renderProxyValue = useCallback(
|
||||
(selected: string) => {
|
||||
if (!selected || !state.proxyData.records[selected]) return selected;
|
||||
const renderProxyValue = (selected: string) => {
|
||||
if (!selected || !state.proxyData.records[selected]) return selected;
|
||||
|
||||
const delayValue = delayManager.getDelayFix(
|
||||
state.proxyData.records[selected],
|
||||
state.selection.group,
|
||||
);
|
||||
const delayValue = delayManager.getDelayFix(
|
||||
state.proxyData.records[selected],
|
||||
state.selection.group,
|
||||
);
|
||||
|
||||
return (
|
||||
<Box sx={{ display: "flex", justifyContent: "space-between" }}>
|
||||
<Typography noWrap>{selected}</Typography>
|
||||
<Chip
|
||||
size="small"
|
||||
label={delayManager.formatDelay(delayValue)}
|
||||
color={convertDelayColor(delayValue)}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
},
|
||||
[state.proxyData.records, state.selection.group],
|
||||
);
|
||||
return (
|
||||
<Box sx={{ display: "flex", justifyContent: "space-between" }}>
|
||||
<Typography noWrap>{selected}</Typography>
|
||||
<Chip
|
||||
size="small"
|
||||
label={delayManager.formatDelay(delayValue)}
|
||||
color={convertDelayColor(delayValue)}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
// 排序类型变更
|
||||
const handleSortTypeChange = useCallback(() => {
|
||||
@@ -594,24 +597,28 @@ export const CurrentProxyCard = () => {
|
||||
}
|
||||
|
||||
refreshProxy();
|
||||
if (sortType === 1) {
|
||||
setDelaySortRefresh((prev) => prev + 1);
|
||||
}
|
||||
});
|
||||
|
||||
// 排序代理函数(增加非空校验)
|
||||
const sortProxies = useCallback(
|
||||
(proxies: ProxyOption[]) => {
|
||||
if (!proxies || sortType === 0) return proxies;
|
||||
// 计算要显示的代理选项(增加非空校验)
|
||||
const proxyOptions = useMemo(() => {
|
||||
const sortWithLatency = (proxiesToSort: ProxyOption[]) => {
|
||||
if (!proxiesToSort || sortType === 0) return proxiesToSort;
|
||||
|
||||
// 确保数据存在
|
||||
if (!state.proxyData.records || !state.selection.group) return proxies;
|
||||
if (!state.proxyData.records || !state.selection.group) {
|
||||
return proxiesToSort;
|
||||
}
|
||||
|
||||
const list = [...proxies];
|
||||
const list = [...proxiesToSort];
|
||||
|
||||
if (sortType === 1) {
|
||||
const refreshTick = delaySortRefresh;
|
||||
list.sort((a, b) => {
|
||||
const recordA = state.proxyData.records[a.name];
|
||||
const recordB = state.proxyData.records[b.name];
|
||||
|
||||
// 处理 record 不存在的情况
|
||||
if (!recordA) return 1;
|
||||
if (!recordB) return -1;
|
||||
|
||||
@@ -621,19 +628,16 @@ export const CurrentProxyCard = () => {
|
||||
if (ad === -1 || ad === -2) return 1;
|
||||
if (bd === -1 || bd === -2) return -1;
|
||||
|
||||
return ad - bd;
|
||||
if (ad !== bd) return ad - bd;
|
||||
return refreshTick >= 0 ? a.name.localeCompare(b.name) : 0;
|
||||
});
|
||||
} else {
|
||||
list.sort((a, b) => a.name.localeCompare(b.name));
|
||||
}
|
||||
|
||||
return list;
|
||||
},
|
||||
[sortType, state.proxyData.records, state.selection.group],
|
||||
);
|
||||
};
|
||||
|
||||
// 计算要显示的代理选项(增加非空校验)
|
||||
const proxyOptions = useMemo(() => {
|
||||
if (isDirectMode) {
|
||||
return [{ name: "DIRECT" }];
|
||||
}
|
||||
@@ -647,7 +651,7 @@ export const CurrentProxyCard = () => {
|
||||
name: typeof p === "string" ? p : p.name,
|
||||
}));
|
||||
|
||||
return sortProxies(options);
|
||||
return sortWithLatency(options);
|
||||
}
|
||||
|
||||
// 规则模式
|
||||
@@ -657,7 +661,7 @@ export const CurrentProxyCard = () => {
|
||||
|
||||
if (group) {
|
||||
const options = group.all.map((name) => ({ name }));
|
||||
return sortProxies(options);
|
||||
return sortWithLatency(options);
|
||||
}
|
||||
|
||||
return [];
|
||||
@@ -667,7 +671,8 @@ export const CurrentProxyCard = () => {
|
||||
proxies,
|
||||
state.proxyData,
|
||||
state.selection.group,
|
||||
sortProxies,
|
||||
sortType,
|
||||
delaySortRefresh,
|
||||
]);
|
||||
|
||||
// 获取排序图标
|
||||
|
||||
@@ -80,6 +80,16 @@ export const ProxyGroups = (props: Props) => {
|
||||
selectedGroup,
|
||||
);
|
||||
|
||||
const getGroupHeadState = useCallback(
|
||||
(groupName: string) => {
|
||||
const headItem = renderList.find(
|
||||
(item) => item.type === 1 && item.group?.name === groupName,
|
||||
);
|
||||
return headItem?.headState;
|
||||
},
|
||||
[renderList],
|
||||
);
|
||||
|
||||
// 统代理选择
|
||||
const { handleProxyGroupChange } = useProxySelection({
|
||||
onSuccess: () => {
|
||||
@@ -297,9 +307,13 @@ export const ProxyGroups = (props: Props) => {
|
||||
console.log(`[ProxyGroups] 延迟测试完成,组: ${groupName}`);
|
||||
} catch (error) {
|
||||
console.error(`[ProxyGroups] 延迟测试出错,组: ${groupName}`, error);
|
||||
} finally {
|
||||
const headState = getGroupHeadState(groupName);
|
||||
if (headState?.sortType === 1) {
|
||||
onHeadState(groupName, { sortType: headState.sortType });
|
||||
}
|
||||
onProxies();
|
||||
}
|
||||
|
||||
onProxies();
|
||||
});
|
||||
|
||||
// 滚到对应的节点
|
||||
|
||||
Reference in New Issue
Block a user