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 的 服务连接方式以及权限,避免无法连接服务或内核
|
- 改进 Windows 和 Unix 的 服务连接方式以及权限,避免无法连接服务或内核
|
||||||
- 修改内核默认日志级别为 Info
|
- 修改内核默认日志级别为 Info
|
||||||
- 支持通过桌面快捷方式重新打开应用
|
- 支持通过桌面快捷方式重新打开应用
|
||||||
- 主界面“当前节点”卡片新增自动延迟检测开关(默认关闭)
|
|
||||||
- 支持订阅界面输入链接后回车导入
|
- 支持订阅界面输入链接后回车导入
|
||||||
|
- 选择按延迟排序时每次延迟测试自动刷新节点顺序
|
||||||
|
|
||||||
### 🐞 修复问题
|
### 🐞 修复问题
|
||||||
|
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ export const CurrentProxyCard = () => {
|
|||||||
const savedSortType = localStorage.getItem(STORAGE_KEY_SORT_TYPE);
|
const savedSortType = localStorage.getItem(STORAGE_KEY_SORT_TYPE);
|
||||||
return savedSortType ? (Number(savedSortType) as ProxySortType) : 0;
|
return savedSortType ? (Number(savedSortType) as ProxySortType) : 0;
|
||||||
});
|
});
|
||||||
|
const [delaySortRefresh, setDelaySortRefresh] = useState(0);
|
||||||
|
|
||||||
// 定义状态类型
|
// 定义状态类型
|
||||||
type ProxyState = {
|
type ProxyState = {
|
||||||
@@ -443,12 +444,17 @@ export const CurrentProxyCard = () => {
|
|||||||
} finally {
|
} finally {
|
||||||
autoCheckInProgressRef.current = false;
|
autoCheckInProgressRef.current = false;
|
||||||
refreshProxy();
|
refreshProxy();
|
||||||
|
if (sortType === 1) {
|
||||||
|
setDelaySortRefresh((prev) => prev + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
isDirectMode,
|
isDirectMode,
|
||||||
refreshProxy,
|
refreshProxy,
|
||||||
state.selection.group,
|
state.selection.group,
|
||||||
state.selection.proxy,
|
state.selection.proxy,
|
||||||
|
sortType,
|
||||||
|
setDelaySortRefresh,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -487,28 +493,25 @@ export const CurrentProxyCard = () => {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
// 自定义渲染选择框中的值
|
// 自定义渲染选择框中的值
|
||||||
const renderProxyValue = useCallback(
|
const renderProxyValue = (selected: string) => {
|
||||||
(selected: string) => {
|
if (!selected || !state.proxyData.records[selected]) return selected;
|
||||||
if (!selected || !state.proxyData.records[selected]) return selected;
|
|
||||||
|
|
||||||
const delayValue = delayManager.getDelayFix(
|
const delayValue = delayManager.getDelayFix(
|
||||||
state.proxyData.records[selected],
|
state.proxyData.records[selected],
|
||||||
state.selection.group,
|
state.selection.group,
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ display: "flex", justifyContent: "space-between" }}>
|
<Box sx={{ display: "flex", justifyContent: "space-between" }}>
|
||||||
<Typography noWrap>{selected}</Typography>
|
<Typography noWrap>{selected}</Typography>
|
||||||
<Chip
|
<Chip
|
||||||
size="small"
|
size="small"
|
||||||
label={delayManager.formatDelay(delayValue)}
|
label={delayManager.formatDelay(delayValue)}
|
||||||
color={convertDelayColor(delayValue)}
|
color={convertDelayColor(delayValue)}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
},
|
};
|
||||||
[state.proxyData.records, state.selection.group],
|
|
||||||
);
|
|
||||||
|
|
||||||
// 排序类型变更
|
// 排序类型变更
|
||||||
const handleSortTypeChange = useCallback(() => {
|
const handleSortTypeChange = useCallback(() => {
|
||||||
@@ -594,24 +597,28 @@ export const CurrentProxyCard = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
refreshProxy();
|
refreshProxy();
|
||||||
|
if (sortType === 1) {
|
||||||
|
setDelaySortRefresh((prev) => prev + 1);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 排序代理函数(增加非空校验)
|
// 计算要显示的代理选项(增加非空校验)
|
||||||
const sortProxies = useCallback(
|
const proxyOptions = useMemo(() => {
|
||||||
(proxies: ProxyOption[]) => {
|
const sortWithLatency = (proxiesToSort: ProxyOption[]) => {
|
||||||
if (!proxies || sortType === 0) return proxies;
|
if (!proxiesToSort || sortType === 0) return proxiesToSort;
|
||||||
|
|
||||||
// 确保数据存在
|
if (!state.proxyData.records || !state.selection.group) {
|
||||||
if (!state.proxyData.records || !state.selection.group) return proxies;
|
return proxiesToSort;
|
||||||
|
}
|
||||||
|
|
||||||
const list = [...proxies];
|
const list = [...proxiesToSort];
|
||||||
|
|
||||||
if (sortType === 1) {
|
if (sortType === 1) {
|
||||||
|
const refreshTick = delaySortRefresh;
|
||||||
list.sort((a, b) => {
|
list.sort((a, b) => {
|
||||||
const recordA = state.proxyData.records[a.name];
|
const recordA = state.proxyData.records[a.name];
|
||||||
const recordB = state.proxyData.records[b.name];
|
const recordB = state.proxyData.records[b.name];
|
||||||
|
|
||||||
// 处理 record 不存在的情况
|
|
||||||
if (!recordA) return 1;
|
if (!recordA) return 1;
|
||||||
if (!recordB) return -1;
|
if (!recordB) return -1;
|
||||||
|
|
||||||
@@ -621,19 +628,16 @@ export const CurrentProxyCard = () => {
|
|||||||
if (ad === -1 || ad === -2) return 1;
|
if (ad === -1 || ad === -2) return 1;
|
||||||
if (bd === -1 || bd === -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 {
|
} else {
|
||||||
list.sort((a, b) => a.name.localeCompare(b.name));
|
list.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
},
|
};
|
||||||
[sortType, state.proxyData.records, state.selection.group],
|
|
||||||
);
|
|
||||||
|
|
||||||
// 计算要显示的代理选项(增加非空校验)
|
|
||||||
const proxyOptions = useMemo(() => {
|
|
||||||
if (isDirectMode) {
|
if (isDirectMode) {
|
||||||
return [{ name: "DIRECT" }];
|
return [{ name: "DIRECT" }];
|
||||||
}
|
}
|
||||||
@@ -647,7 +651,7 @@ export const CurrentProxyCard = () => {
|
|||||||
name: typeof p === "string" ? p : p.name,
|
name: typeof p === "string" ? p : p.name,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return sortProxies(options);
|
return sortWithLatency(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 规则模式
|
// 规则模式
|
||||||
@@ -657,7 +661,7 @@ export const CurrentProxyCard = () => {
|
|||||||
|
|
||||||
if (group) {
|
if (group) {
|
||||||
const options = group.all.map((name) => ({ name }));
|
const options = group.all.map((name) => ({ name }));
|
||||||
return sortProxies(options);
|
return sortWithLatency(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
@@ -667,7 +671,8 @@ export const CurrentProxyCard = () => {
|
|||||||
proxies,
|
proxies,
|
||||||
state.proxyData,
|
state.proxyData,
|
||||||
state.selection.group,
|
state.selection.group,
|
||||||
sortProxies,
|
sortType,
|
||||||
|
delaySortRefresh,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 获取排序图标
|
// 获取排序图标
|
||||||
|
|||||||
@@ -80,6 +80,16 @@ export const ProxyGroups = (props: Props) => {
|
|||||||
selectedGroup,
|
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({
|
const { handleProxyGroupChange } = useProxySelection({
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
@@ -297,9 +307,13 @@ export const ProxyGroups = (props: Props) => {
|
|||||||
console.log(`[ProxyGroups] 延迟测试完成,组: ${groupName}`);
|
console.log(`[ProxyGroups] 延迟测试完成,组: ${groupName}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`[ProxyGroups] 延迟测试出错,组: ${groupName}`, 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