/** * 桌面客户端更新日志(面向用户的通俗说明,桌面端更新面板展示)。 * * 数据来源:app_client 仓库 git 历史——以各版本发版提交 * (chore(release): 版本号 x.y.z …)为界,取该窗口内的 feat/fix 提交, * 自动整理成"用户能看懂的一句话"后追加到本文件(新版本放最前)。 * 取某版本区间的原始提交: * git -C app_client log --oneline <上一版提交>..<本版提交> * * 注意:version 必须与 web_config 发布记录 / /api/version/latest 的版本号 * 完全一致(不带 v 前缀),否则按本机版本筛选时匹配不到条目。 */ import { compareVersions, normVersion } from './utils/version-compare.ts' export interface ClientChangelogEntry { /** 客户端版本号,与线上发布记录一致 */ version: string /** 发布日期 yyyy-MM-dd */ date: string /** 面向用户的更新说明,一条一行,不用技术术语 */ items: string[] } /** 更新日志数据(新版本在前;发版时在数组最前追加一条) */ export const CLIENT_CHANGELOG: ClientChangelogEntry[] = [ { version: '4.0.18', date: '2026-09-15', items: [ '数据采集:价格固定当地币种(英国英镑、欧洲欧元),不再错显成人民币', '数据采集:采集前自动设置当地配送地址,价格与配送信息更准确', '跟价:兼容亚马逊新版页面,当前价格读取更稳定', '修复:启动时不再误关闭你手动打开的紫鸟浏览器', ], }, { version: '4.0.17', date: '2026-09-15', items: [ '跟价修复:购物车归属判断不出来时不再改价,避免价格被改错方向', '跟价结果里「购物车店铺名」不再因个别字段缺失而整列丢失', '跟价失败会显示真实原因(例如代理余额不足),不用再反复重试等待', '代理欠费或套餐到期时不再重复派发任务,并提示检查代理设置', ], }, { version: '4.0.16', date: '2026-09-14', items: [ '品牌检测更省代理:线路被限流时不再反复更换,减少不必要的消耗', '代理线路在有效期内被更充分地复用,减少重复提取次数', ], }, { version: '4.0.15', date: '2026-09-14', items: [ '任务卡住时自动识别并收尾,已采集到的数据可以正常下载', '网络不稳定时自动更换线路重试,采集成功率更高', '跟价修复:购物车归属判断更准确,避免误改商品价格', '页面没推送成功的任务会自动接管执行,不再一直停在等待中', '品牌检测更稳定:遇到限流会自动等待后重试', ], }, { version: '4.0.14', date: '2026-09-14', items: [ '登录后任务会带上你的账号身份,服务端校验更严格', ], }, { version: '4.0.13', date: '2026-09-14', items: [ '图片生成的历史记录写入失败时会正常释放连接,长时间使用不会拖慢客户端', '运行过的任务记录会自动收敛,长时间挂机不再持续占用内存', ], }, { version: '4.0.12', date: '2026-09-14', items: [ '启动采集/跟价时不再关闭你自己打开的 Chrome 浏览器', '密码检测不再打断其它正在运行的任务', '任务失败或被停止后会正常结束,不会一直卡在"处理中"', '长时间挂机不再持续占用磁盘空间(缓存会自动清理)', '多个品牌检测任务同时提交时会排队执行,代理额度不会互相错记', '日志和配置目录更稳定,升级后设置不会"找不到"', ], }, { version: '4.0.11', date: '2026-09-13', items: [ '代理失效会自动切换并暂停购买,减少花冤枉钱', '风险审批结果自动保存,网络波动也不白干(断开后自动补交)', '品牌检测连续失败时自动停止,不再反复无效尝试', ], }, { version: '4.0.10', date: '2026-09-13', items: [ '修复切换国家时页面断开后一直卡住不动的问题', '修复产品风险审批"批准"数量一直不减(处理了却没算数)的问题', ], }, { version: '4.0.9', date: '2026-09-13', items: [ '修复长时间使用后电脑越来越卡的问题(浏览器进程不再越积越多)', '修复窗口最大化、还原时客户端偶尔没反应的问题', ], }, { version: '4.0.7', date: '2026-09-13', items: [ '跟价、风险审批的"旧版/新版"选项恢复真实生效(选哪个就走哪个)', '店铺界面已是新版时选"旧版"会明确提示,不再假装处理成功', ], }, { version: '4.0.6', date: '2026-09-13', items: ['跟价指定 ASIN 时严格按指定范围执行,未指定 ASIN 的国家不再全量改价'], }, { version: '4.0.5', date: '2026-09-13', items: [ '重做产品风险审批的保存流程:保存结果如实反馈,不再"显示成功其实没保存"', '修复风险审批多条待处理记录只处理第一条的问题', ], }, { version: '4.0.4', date: '2026-09-13', items: [ '修复风险审批新界面里"提交"按钮从未被点击、选了记录也不保存的问题', '修复跟价提示改价成功、实际没改价的问题;未设置最低价时不再漏处理商品', ], }, { version: '4.0.3', date: '2026-09-12', items: [ '货源查询改用真实浏览器采集,结果更准确', '修复跟价把购物车里已加购的商品误判为"没有卖家"的问题', '修复部分电脑提示"更新程序缺失"无法自动更新;更新显示真实下载进度', ], }, { version: '4.0.2', date: '2026-09-12', items: ['修复跟价等任务只处理第一页商品、其余被跳过的问题'], }, { version: '4.0.1', date: '2026-09-12', items: ['修复货源查询结果中"阿里巴巴"商品图片整列空白的问题'], }, { version: '4.0.0', date: '2026-09-11', items: [ '修复产品风险审批新界面频繁提示"处理失败"的问题', '修复商品翻页加载慢时只处理第一页的问题', ], }, { version: '3.0.73', date: '2026-09-11', items: ['修复集采数据、跟价等功能因接口鉴权失败无法使用的问题'], }, { version: '3.0.71', date: '2026-09-11', items: ['升级支持断点续传,并显示真实的下载进度'], }, ] /** 数据文件里最新的版本号(无数据时空串)。 */ export function newestChangelogVersion(entries: ClientChangelogEntry[] = CLIENT_CHANGELOG): string { return entries.length ? normVersion(entries[0].version) : '' } /** * 挑选本次要展示的更新日志:本机版本之后、最新版本(含)之间的条目,新的在前。 * * - latestVersion 为空(检测未完成/失败)时按数据文件里最新版本兜底; * - currentVersion 为空(旧客户端无版本桥)时只给最新版本一条,不把整段历史倒给用户; * - 本机版本已高于线上(灰度/回滚)时返回空数组,由调用方隐藏该区块。 */ export function selectChangelogEntries(options: { currentVersion?: string latestVersion?: string entries?: ClientChangelogEntry[] } = {}): ClientChangelogEntry[] { const entries = options.entries ?? CLIENT_CHANGELOG if (!entries.length) return [] const current = normVersion(options.currentVersion) const upper = normVersion(options.latestVersion) || newestChangelogVersion(entries) const inRange = entries.filter((entry) => compareVersions(entry.version, upper) <= 0) if (!inRange.length) return [] if (!current) { const newest = inRange.find((entry) => compareVersions(entry.version, upper) === 0) return [newest ?? inRange[0]] } return inRange.filter((entry) => compareVersions(entry.version, current) > 0) }