首页
/ cc-switch 供应商管理实战:拖拽排序、一键复制与删除确认的完整机制解析

cc-switch 供应商管理实战:拖拽排序、一键复制与删除确认的完整机制解析

2026-09-06 12:32:56作者:郦嵘贵Just

本篇技术文章围绕 cc-switch(一款面向 Claude Code、Codex、OpenCode、OpenClaw、Grok Build 与 Hermes Agent 的跨平台桌面助手)用户手册中的「排序与复制」章节展开,系统讲解供应商(Provider)的拖拽重排、快速复制与删除三大日常操作。读完本文,你不仅能在界面上熟练完成这三类操作,还能结合 cc-switch 的 React 前端与 Rust(Tauri)后端源码,理解排序索引 sort_index 的持久化机制、复制操作如何生成不冲突的供应商标识,以及删除保护与故障转移队列之间的联动关系。

cc-switch 供应商卡片操作区截图

一、拖拽排序:调整供应商的展示与故障转移顺序

cc-switch 允许通过拖拽调整供应商列表的显示顺序,核心交互依赖卡片左侧的拖拽手柄:

  1. 将鼠标移到供应商卡片左侧的 拖拽手柄上;
  2. 按住鼠标左键;
  3. 上下拖拽到目标位置;
  4. 松开鼠标完成重排。

排序主要有两个实际用途:

  • 常用置顶:把高频使用的供应商拖到列表顶部,减少切换时的查找成本;
  • 故障转移顺序:排序结果会影响故障转移队列(failover queue)的默认顺序——在启用自动故障转移的路由类应用中,列表靠前的供应商拥有更高的接管优先级。

源码解析:排序如何持久化

前端排序逻辑集中在 useDragSort Hook 中,可以从中确认几个关键实现细节:

1. 列表顺序的三级判定规则。 sortedProviders 的计算逻辑(见 useDragSort.ts)按以下优先级排序:

// 1) 有 sortIndex 的供应商按 sortIndex 升序;
// 2) 只有 sortIndex 的一方排在前面;
// 3) 都没有 sortIndex 时,按 createdAt 创建时间升序;
// 4) 时间戳相同则按名称 localeCompare(随界面语言切换 zh-CN / zh-TW / en-US)。

也就是说,从未手动拖拽过的供应商按创建时间排列,一旦拖拽过一次,sortIndex 即成为唯一顺序依据。

2. 拖拽事件绑定。 Hook 使用 @dnd-kit/core 同时注册了 PointerSensorKeyboardSensor,其中 PointerSensor 配置了 activationConstraint: { distance: 8 }(见 useDragSort.ts)——鼠标按下后位移超过 8 像素才触发拖拽,避免普通点击被误判为拖拽;同时支持键盘方向键排序(sortableKeyboardCoordinates)。

3. 落点处理与联动刷新。 拖拽结束的 handleDragEnd 处理(见 useDragSort.ts)依次执行:

  • arrayMove 重排数组后,为每一个供应商生成新的 sortIndex(即落点位置),通过 providersApi.updateSortOrder(updates, appId) 一次性批量持久化到后端;
  • 失效 ["providers", appId] 查询缓存,触发列表重渲染;
  • 若当前应用是路由类应用(isProxyAppId(appId)),额外失效 ["failoverQueue", appId] 缓存——源码注释明确写道 “Routing apps derive failover order from sort_index”,这正对应文档中「排序影响故障转移队列默认顺序」的说法;
  • 最后调用 providersApi.updateTrayMenu() 同步刷新系统托盘菜单(托盘更新失败仅记录日志,不影响排序本身的成功)。

4. 后端与队列读取。 排序结果以 sort_index 字段存入 SQLite。数据库查询层直接使用 ORDER BY COALESCE(sort_index, 999999), created_at ASC, id ASC 读取列表(见 providers.rs),而故障转移队列的读取同样按 sort_index 排序(见 failover.rs),两者共用同一顺序源,保证「所见顺序即故障接管顺序」。

二、复制供应商:基于现有配置快速派生新配置

复制功能用于在已有配置基础上快速派生变体,典型场景包括:

  • 基于现有配置创建变体(如不同 API Key、不同接入点);
  • 为当前配置做备份;
  • 建立独立的测试配置,避免污染正式配置。

自 v3.15.0 起,统一供应商(Universal Provider)也提供复制操作(见 v3.15.0-en.md),可以先复制再调整启用的应用与模型。

操作步骤:

  1. 鼠标悬停供应商卡片,显隐动作按钮组;
  2. 点击「复制(Duplicate)」按钮;
  3. 系统自动创建一份带 copy 名称后缀的副本;
  4. 编辑副本,按需修改配置。

复制了哪些内容

复制会创建一份完整拷贝,具体覆盖范围如下:

内容 是否复制
名称 是(追加 copy 后缀)
配置(settingsConfig) 完整深拷贝
备注(Notes)
网站链接(Website Link)
图标(Icon / iconColor)
端点列表(Endpoint List,配置的一部分)
排序位置 插入在原供应商正下方

源码解析:副本的生成细节

普通供应商的复制入口是 ProviderActions 中的复制图标按钮(onDuplicate 回调存在时才渲染),实际逻辑在 App.tsx 的 handleDuplicateProvider

const duplicatedProvider = {
  name: `${provider.name} copy`,
  settingsConfig: deepClone(provider.settingsConfig), // 深拷贝,避免共享引用
  websiteUrl: provider.websiteUrl,
  category: provider.category,
  sortIndex: provider.sortIndex + 1,   // 副本插入原供应商正下方
  meta: provider.meta ? deepClone(provider.meta) : undefined,
  icon: provider.icon,
  iconColor: provider.iconColor,
};

可以看到:

  • 配置采用 deepClone 深拷贝,后续修改副本不会反向影响原配置;
  • sortIndex 取原值加 1,并在持久化前把原供应商之后所有供应商的 sortIndex 各加 1(批量调用 providersApi.updateSortOrder),确保副本严格落在原供应商正下方,与上表「插入在原供应商下方」一致;
  • 若排序调整失败,函数会直接中止添加流程(return),保证列表顺序与数据落库的一致性。

针对 OpenCode、OpenClaw、Hermes、Pi 这几类会向目标应用原生配置写入供应商的应用,复制逻辑还额外做了标识去重generateUniqueProviderCopyKey(见 App.tsx)会基于原供应商 ID 生成 <原id>-copy 形式的 providerKey,并与现有供应商 ID、原生配置中已启用的 live provider ID 做并集去重;若冲突则依次尝试 -copy-2-copy-3……同时设置 addToLive = false,即副本默认不会立即写入目标应用的原生配置,避免复制动作直接改动正在使用的配置。

统一供应商的复制实现更轻量,位于 UniversalProviderPaneldeepClone 原对象后更换新的 idcrypto.randomUUID())、名称加 copy 后缀、刷新 createdAt,随后依次执行 upsert 落库与 sync 同步到已启用的应用。

复制之后通常要改什么

复制完成后,建议至少检查三处:

  1. 名称:改成有业务含义的名字,避免多个 copy 后缀造成混淆;
  2. API Key:如果副本要指向另一个账户,务必替换密钥;
  3. 接入端点(Endpoint):如果副本要指向另一家服务,替换 Base URL。

三、删除供应商:确认对话框与删除限制

删除步骤:

  1. 悬停供应商卡片,显隐动作按钮;
  2. 点击「删除」按钮;
  3. 在确认对话框中确认删除。

确认对话框会显示:

  • 待删除供应商的名称;
  • 「删除不可撤销」的警示。

删除的限制与注意点:

  • 当前激活供应商:可以被删除,但推荐先切换到其他供应商再删除,避免当前应用的配置出现空档;
  • 统一供应商:删除时会一并移除其已关联到各应用的原生配置。

后端删除入口是 Tauri 命令 delete_provider,它按 app_type 定位应用类型后委托 ProviderService::delete 完成数据库记录与相关状态清理;对于 OpenCode、OpenClaw 这类累加型应用,另有 remove_provider_from_live_config 命令只把供应商从原生配置中摘除而保留数据库记录,两者语义不同,删除操作按应用场景走对应路径。

前端对删除按钮本身也有保护逻辑:ProviderActions 中的 canDelete 判定会禁用只读供应商(例如由 Hermes 管理、需在 Hermes Web UI 中编辑的条目)的删除按钮,并通过 title 提示禁用原因,防止误删托管配置。

四、小结

供应商列表的排序、复制、删除三者共同构成 cc-switch 日常配置管理的基础操作:

  • 拖拽排序以 sort_index 为持久化依据,同时驱动列表展示、故障转移队列顺序与托盘菜单,一次操作三处生效;
  • 复制操作对配置做深拷贝并自动完成排序插入与标识去重,副本默认不侵入目标应用的原生配置,适合快速搭建多变体方案;
  • 删除操作以确认对话框兜底,并结合应用类型区分「彻底删除」与「从原生配置移除」两种语义。

如需进一步了解供应商的创建与编辑流程,可继续阅读 添加供应商编辑供应商 两篇手册章节;排序与故障转移的联动细节也可结合 proxy-guide 深入理解。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391