Commit Graph

241 Commits

Author SHA1 Message Date
huangzd1997 24c5a09c7f feat(任务派发): 客户端兜底拉取页面未推送成功的任务 + 修店铺匹配定时任务误杀
问题:任务派发链路的"推送"只存在于页面里(Java 解析落库 PENDING → activate →
pywebview 桥 enqueue_json 推本机队列)。只解析没点启动、推送前关页面、在纯浏览器
打开,任务都会停在 PENDING,2 小时后被 StaleTaskRepairService 标失败
(「任务长期未被领取,已自动失败」,09-11 生产清理过 263 条同画像)。

- 服务端新增 GET /api/tasks/pull-pending(TaskClientPullController,身份从 JWT 取,
  不接受 user_id 参数):只挑创建超 5 分钟仍 PENDING 的本用户任务,逐条条件更新认领
  (PENDING→RUNNING + 接管 owner_instance_id)——与页面 activate 同一谓词,天然互斥,
  不会重复执行;认领后组装不出载荷则标 FAILED,不留 RUNNING 孤儿
- payload 由各业务模块实现 ClientTaskPullSpi 组装(task 侧不 import 业务模块,同 G5):
  首批 SIMILAR_ASIN / COLLECT_DATA / APPEARANCE_PATENT——这三个 Python 消费端会自行
  回拉明细,故载荷极简、客户端零模块知识;开关 aiimage.client-task-pull.enabled 默认 false
- 防双执行:三处 activate 由「非终态即可」收紧为只认 PENDING,未命中抛
  「任务已在执行中(可能已由客户端自动接管),无需重复启动」(顺带堵住整行 updateById
  把认领写入的 owner 覆盖回去的竞态);两个前端页 activate 失败即提示并停止入队
- 客户端:amazon/main.py 新增 pending_task_pull_worker,启动点挂在 app_client/main.py
  的 start_task_monitor(独立入口的 worker 线上并不生效);开关 pending_pull_enabled 用
  getattr 读取,避免 test/ 下的旧 config 缺键导致整包导入失败
- 同批修:StaleTaskRepairService 的 SCHEDULED 分支改按 scheduled_at + 120min 判死
  (原按 updated_at 会必杀排期 >2h 的店铺匹配定时任务,而 activate 又被 scheduledAt-90s 挡住)
- 测试:TaskClientPullServiceTest / StaleTaskRepairServiceTest / CollectDataTaskPullSpiImplTest /
  CollectDataActivateGuardTest 共 20 例;客户端 pending_task_pull_worker 7 例并更新启动顺序契约测试
2026-09-14 16:23:34 +08:00
huangzd1997 8cab9d4bad fix(密钥配置): 保存沿用刚检测过的输入值结果,消除「三项检测通过却提示未检测」死循环
- 服务端:对「输入值(未保存)」的检测结果按 uid+模块+值指纹暂存 Redis(TTL 30min,
  Redis 异常降级为需重新检测,不阻断保存);保存同一个值时落库该结果
  (passed/failed/error 一并沿用),改过值或从未检测则维持未检测
- 前端:保存后清理本地「输入值(未保存)」绿字,展示统一走服务端快照,避免展示与门禁矛盾;
  门禁提示改列「模块名(掩码):未检测 / 检测失败:原因 / 未配置」,同名掩码也能分辨模块
- 测试:UserApiSecretServiceTest 补沿用 / 值不一致 / Redis 降级用例;
  新增前后端一致性守卫测试(保存后必须清检测结果、提示必须带模块名)
2026-09-14 13:49:25 +08:00
huangzd1997 5ea52e5291 perf(F5+): 行数据按需拉取(结果行版本信号)+ 修复 progress/light 恒判 missing
行数据按需拉取(审查 F5 后续):
- V125 给 biz_file_result 补 updated_at(DEFAULT/ON UPDATE 由数据库维护,
  实体标注 insertStrategy/updateStrategy=NEVER —— 否则 selectById→updateById 的
  写回会把旧值写回去、ON UPDATE 不触发,版本信号静默冻结)
- 装配器回传 rowsVersion=「最后变更时间毫秒#行数」,5 个品牌工具页版本未变即跳过
  带行明细的重型 batch;前端变更信号为 rowsVersion + status/fileStatus/fileReady 复合
  (任务收尾常见「行早写完、之后才置成功」,只看行版本会把界面卡在旧状态)

修复线上缺陷(同一功能验证时暴露):
- TaskProgressLightAssembler 列裁剪漏选 module_type 却用它做模块过滤 →
  getModuleType() 恒为 null → light 恒把任务判成 missing;第七批把 light 接进
  跟价/定时匹配/商品风险的轮询后,消费方会把运行中任务判为 FAILED
- 补选中列 + 守卫用例 taskQueryMustSelectModuleType(已反向验证:去掉修复即红)
- 前端 lightClaimsAllTasksMissing:整体性 missing 结论用重型端点复核后再采信

契约与文档:light 白名单补 rowsVersion(Java 契约测试 / spec 06 §2 / 12 个端点描述)
测试:mvn test 2901 全绿;前端 npm test 765 全绿
2026-09-14 12:08:25 +08:00
huangzd1997 1360a44e01 fix(web): 货源查询/外观专利入队不再把 api_key 当必填
密钥已服务端化,本机无明文属正常状态,Java 侧 readApiKey 会按 uid 从用户密钥表兜底;
列成必填会把未在本机手输密钥的用户全部挡在启动之前。
2026-09-14 11:21:09 +08:00
huangzd1997 86c05e71a2 fix(web): 补齐命令式调用的 EP 按需样式,修拦截弹窗贴到文档左上角
Element Plus 走按需引入,只有模板里用到的组件才会注入样式;ElMessage /
ElMessageBox 都是 import 后函数式调用,构建产物里一条 .el-message-box 规则都没有,
弹窗因此没有定位与遮罩,渲染成普通块元素压在页头文字上(ElMessage 提示条同样受影响)。
入口显式引入两个样式模块,并加测试钉住「显式 import 的 EP 组件必须有样式引入」。
2026-09-14 11:21:08 +08:00
huangzd1997 fae26aa460 style(version): 指定版本下拉只显示版本号,去掉发布日期 2026-09-14 11:08:07 +08:00
huangzd1997 8803e22f39 feat(version): 桌面端更新面板支持指定版本安装
- 新增公开接口 GET /api/version/list(最近 50 条,字段口径同管理端列表),
  桌面端下拉不再拼 OSS 地址(版本包被删后拼地址会 404)
- 更新面板(登录页 + 首页)加「指定版本更新」选择器:默认选中最新版,
  可选全部已发布版本(含回退),回退/同版给出明确文案与二次确认
- 客户端无需发版:do_update_app(file_url) 本就接受任意版本包直链
2026-09-14 11:05:30 +08:00
huangzd1997 c55c4a140b feat(A1/A3+C8): 客户端令牌链路打通(按人鉴权就绪)+ 快照 JSON 写入节流
A1/A3 客户端令牌链路(服务端守卫已能按 JWT 鉴权,缺口在客户端不带身份)
- 前端:新增 user-token-bridge(纯逻辑,值变化才推送)+ user-token-sync(启动安装,
  pywebviewready/storage/60s 轮询补推),main.ts 接入;桥接口补 set_user_token
- 客户端:新增 crawler_core/user_token.py(持有 + 对自家 Java 端点注入
  Authorization: Bearer <jwt>,Session.request 包装,第三方域名不注入、已有头不覆盖、
  登出清空、SHUFUAI_DISABLE_USER_TOKEN_HOOK 可关);main.py 暴露桥方法并在启动安装钩子
- 服务端:守卫契约测试补 5 个用户态前缀用例(开关关闭放行 / 打开后匿名 401 /
  用户令牌通过 / 内部令牌仍放行 / /api/ziniao 第二层)
- 翻开关的前置条件(客户端铺开后置 aiimage.security.user-tool-guard-enabled=true)写入报告

C8 快照 JSON 写入节流
- 读端改以 biz_task_result_item 行为准、JSON 仅兜底(历史任务 JSON 仍是唯一副本时可用)
- 整档 JSON 改 30s 节流写,终态路径 force 立即写;新增 2 个契约测试钉住语义

验证:mvn test 2888 全绿;npm test 741 全绿;user_token 钩子自测(注入/归一/第三方跳过/不覆盖/登出)通过
2026-09-14 10:20:15 +08:00
huangzd1997 ef3a2c9bd6 docs(更新日志): 追加客户端 4.0.13 条目 2026-09-14 07:08:39 +08:00
huangzd1997 67223f8950 perf(frontend): 工具页分页/历史截断/轻量轮询/共享纯逻辑(审查 F5/F6/F9/F12/G3)
- F9 新增 useTablePaging composable 并接入 7 个工具页"匹配结果"表(只切渲染窗口,
  不加选择语义;每页 100 条)+ 深色分页样式
- F6 历史任务抽屉渲染截断(默认 50 条 + "显示全部/收起"),全选口径改为当前可见条目
- F5 新增 task-progress-polling 适配器:等待任务终态的紧循环走 /tasks/progress/light,
  异常或空响应回退重型 batch;已接入跟价/定时匹配的 waitForTaskTerminal
- F12 背景图 bg.jpg 251KB → 166KB(1920 宽 + quality 80,image-set 仍优先 webp)
- G3 抽出共享纯逻辑 task-queue-state(开始时间表序列化校验 + 记录缺失错误判定),
  5 个工具页删除逐字重复实现
- 新增 4 个单测文件(分页切片/历史截断/轻量轮询归一/任务队列纯逻辑)
2026-09-14 06:23:46 +08:00
huangzd1997 4daf235385 docs(更新日志): 追加客户端 4.0.12 条目 2026-09-14 04:36:35 +08:00
huangzd1997 6d46506726 fix: 全维度审查修复(安全/正确性/性能/稳定性/客户端/前端)
安全
- /api/ziniao/** 五个匿名接口加管理员鉴权(此前可匿名换取任意员工店铺登录令牌)
- 删除 Flask 遗留后门:默认密码建超管 + 每次启动写生产 users 表(服务端与客户端各一份)
- 进度/详情接口归属过滤:新增 TaskProgressOwnershipSupport,11 模块 progress/light 与
  /tasks/batch 接入,DTO 补 userId,前端 13 个查询封装补传(未传时后端不过滤,兼容旧端)
- 代理提取链接(含账密)不再明文入日志(新增 common/util/SecretMasking)
- 全局异常兜底不再回传原始异常信息;内部令牌比较改常量时间
- 登录加失败计数与锁定(10 次锁 15 分钟);品牌源文件下载加 SSRF 防护
- AdminApiGuardFilter 覆盖前缀从 2 扩到 15(开关默认 false,行为不变,为收紧做准备)
- 生产关闭 springdoc/knife4j(/doc.html 匿名可读全部接口定义)

正确性
- 40901/40902 拆分:锁竞争不再被伪装成 success=true(此前客户端停止重试、分片静默丢失)
- 假成功收敛:集采明细批量写失败改为抛出、去重 worker 异常标失败、4 个 worker 改判
  success 字段、publish 空 ASIN 行参与批次 flush、巡店删除全失败带 error 上报
- 客户端心跳 discard 移入 finally(7 模块,失败路径不再留僵尸 RUNNING 任务)
- 状态机条件更新:跟价停止循环、集采 activate/fail、imagevideo 归档回填、店铺匹配提交

性能
- 前端入口包 JS 1.05MB→204KB、CSS 355KB→10.7KB(Element Plus 改按需 + el-config-provider)
- 载荷引用计数按指针里的 taskId 收敛(原 JSON 列 IN 全表扫且逐行调用)
- 店铺明细多值批量 INSERT;快照 upsert 预载缓存;结果文件列改单条 UPDATE
- 新增迁移 V120(补 3 个缺失索引)/V121(删 4 个被覆盖的冗余索引)/V122(URL 前缀索引)

稳定性
- 新增 common/util/ThreadPools 有界线程池替换 5 处无界队列(防堆积 OOM)
- Redis 锁释放改 Lua 原子校验(原裸 delete 会误删他人已过期的锁)
- imagevideo 加死节点接管;锁续期失败重试;调度池 4→16;openStream 全部加超时
- 事务内远程对象删除移到提交后;启动恢复锁按实例命名

客户端
- 不再 taskkill /f /im chrome.exe(改为按调试端口精准回收,不杀用户自己的浏览器)
- 密码检测不再无条件杀紫鸟进程;品牌检测加全局互斥(代理池不再互相覆盖)
- base_dir 统一到 exe 目录(原被 os.getcwd() 覆盖,日志/缓存会分裂两个目录)
- 缓存加定时清理;图片下载加超时;mkstemp 句柄托管

测试
- 同步更新受影响的契约测试(构造器签名/条件更新/方法改名/新增接口方法等)
- 修复 FaultInjectionTest 等 3 处 mock 未 stub 流式 read 导致的读循环 OOM
- mvn test 2795 个测试全绿
2026-09-14 04:15:36 +08:00
huangzd1997 864c22ffc7 fix(密钥检测): 直连失败重试一次,超时/网络提示中文化
上游 ai.t8star.org 实测约 1/8 单请求完全不应答(主机 A 上 JDK 客户端
HTTP/1.1 与 HTTP/2 均复现),检测只有一次机会时用户会看到
「网络不可达:HttpTimeoutException: request timed out」。

- 传输层失败(超时/网络不可达)对直连最后一跳重试一次(800ms 间隔);
  代理模块不重试——jikip 按提取次数计费,重试会多扣一次
- 失败文案中文化(新增 CODE_TIMEOUT),英文异常串只进服务端日志
- 探测提问改「你好」(最简一次调用)
- 检测面板标明检测对象(配置密钥 sk-**** / 输入值(未保存)),
  检测接口超时单独放宽(客户端 60s / 后台 180s),避免重试期间前端先超时
2026-09-14 00:28:35 +08:00
huangzd1997 ff1ffbbfa3 feat(站内通知): 铃铛面板支持时间/内容搜索、按天分组与分页
- 列表接口加 keyword(标题/内容模糊)与 startDate/endDate(年月日闭区间)参数,
  两端控制器透传,服务端补筛选日志
- 两端铃铛面板:搜索框(防抖 300ms)+ 日期区间 + 按年月日分组 + 翻页,
  面板改 Teleport 到 body(挂在顶栏时会被页面 el-select 压住,提 z-index 无效)
- 固化可见范围回归测试:超管全量/管理员只看本组/普通用户只看自己,
  含读写两侧的 user_id+audience 裁剪断言与两端控制器身份来源断言
2026-09-13 23:59:06 +08:00
huangzd1997 9ffd68bae5 feat(教程管理): 后台可上传教程包,工具台按最新上传下载
- admin-vue 新增「记录与版本 → 教程管理」页(menuKey admin_tutorial):
  zip 浏览器直传 MinIO(presign → PUT 带进度 → confirm 落库)+ 列表/下载/删除,
  最新一条标「当前生效」;补操作指引与 align-tutorial 守卫测试。
- frontend-vue 工具台「立即下载教程」进页面取 /api/tutorial/latest(最新上传优先),
  接口异常或无记录回退历史固定直链,按钮不失效。
- Java 侧 tutorial 模块与 V119 迁移已在 dc6e8924 提交并上线(2026-09-13)。

vue-tsc + 两端单测(工具台 695 / 后台 1617)通过;生产已实测
presign→PUT→confirm→latest 切换→删除回落全链路。
2026-09-13 23:48:24 +08:00
huangzd1997 14a723ab1c refactor(品牌工具页): 历史批量删除抽为 runBatchDelete
16 个品牌页逐字相同的 batchDeleteHistory 循环(逐条删除 + 容忍个别失败计数)
收敛为 shared/utils/batch-delete.ts 的 runBatchDelete;各页仅保留自己的删除调用
与提示文案。补单测 4 例(空列表 / 全成功 / 部分失败继续 / 非 Error 异常)。

净减约 120 行;vue-tsc 构建与 699 个前端单测通过。
2026-09-13 23:32:27 +08:00
huangzd1997 dc6e8924a9 refactor(品牌工具页): 历史轮询抽为 useHistoryPolling
QueryAsin / Withdraw / PatrolDelete 三页逐字相同的 startHistoryPolling /
stopHistoryPolling 收敛为 shared/composables/useHistoryPolling:定时器走各页
categorized-timers(category 固定 history-poll),间隔默认主轮询的 2 倍。
categorized-timers 补 CategorizedTimers 类型导出;补注入式假定时器单测 5 例。

净减约 40 行;vue-tsc 构建与 695 个前端单测通过。
2026-09-13 23:22:49 +08:00
huangzd1997 882ccdac12 refactor(品牌工具页): 抽取 formatDateTime 与 uploadPathsToJava 公共工具
- 新增 shared/utils/datetime.ts:13 个品牌页逐字重复的 formatDateTime 收敛为一处;
  语义不同的 3 个变体(toLocaleString / 字符串切片 / 支持时间戳)保留不动
- 新增 shared/utils/upload-to-java.ts:10 个品牌页的上传循环收敛,api 依赖注入便于单测;
  保留 uploadOss(品牌Tab)与 returnEmptyWhenUnavailable(跟价)两处行为差异
- 补 datetime / upload-to-java 单测 10 例

净减约 327 行;vue-tsc 构建与 690 个前端单测全通过
2026-09-13 23:16:59 +08:00
huangzd1997 b70557a077 feat(认证/通知): 单设备登录互踢 + 站内通知铃铛系统
- 单设备登录:登录成功即 last-login-wins 绑定 users.machine;非超管旧 token
  在下一次受保护请求抛 4011 下线,超管豁免;仅认 token 内签名 deviceId,不用请求头。
  前端两端接入踢下线跳转(?kicked=1 提示),V118 清空历史 machine
- 站内通知:新增 notification 模块(任务失败扫描 / 密钥欠费 / 下游服务探测三类来源),
  前后台铃铛组件 + 轮询;后台列表按主管数据范围(UserDataScopeSupport)过滤;V116 建表

均已于 2026-09-13 部署上线,此次补提交源码(此前仅存在于已部署 JAR/构建产物中)
2026-09-13 23:08:22 +08:00
huangzd1997 05ae0c62d6 feat(密钥管理): 后台分组过滤+欠费状态识别
- 后台密钥列表:主管只看本组子账户(created_by_id=自己),超管全量可按创建人筛选;行 VO 新增 createdById/createdByUsername
- 代理提取接口欠费(message=余额不足)识别为 insufficient_balance,不再静默回退直连
- 上游 LLM 网关欠费(code=insufficient_user_quota/预扣费额度失败)同样归为欠费并透传额度明细
- 前端:桌面设置面板显示"欠费",admin 后台单格药丸显示"欠费"、新增所属管理员列与超管筛选
2026-09-13 13:22:14 +08:00
huangzd1997 2a766efb83 feat(客户端密钥面板): 代理设置支持连通性检测与状态展示
- 代理卡片新增检测按钮:地址有改动时检测输入值(不落库),否则检测/落库已存值
- 状态行展示检测结果(连通正常/失败原因/耗时),颜色区分通过/失败/警示
- 余量无数据时显示"余额查询暂不可用"占位
2026-09-13 12:14:41 +08:00
huangzd1997 c81ebb7053 fix(前端测试): 修复 npm test 卡死——定时器泄漏 + 去套娃 + 强制退出/超时
- 根因:polling-backoff-recovery 测试断言失败后跳过 loop.dispose(),残留自续期定时器导致 node --test 子进程永不退出
- dead-code-cleanup:移除套娃用例 test_full_vitest_green(再跑一遍全量套件,放大问题),execSync 加 300s 超时;其余静态断言保留
- package.json:node --test --test-force-exit --test-timeout=180000
- CI workflow 前端测试步骤改为 npm test(与 package.json 单一来源)
- 修正 3 处过时期望值(轮询退避/品牌 files+taskType/巡店 delete_conditions)
- 验证:本地 666 用例全过,19-24s,无残留进程
2026-09-13 10:51:19 +08:00
huangzd1997 b7d4d325e0 feat(密钥管理): 列表按用户聚合三字段列 + 代理配置服务端上报
- Java:后台列表一行一用户(货源查询密钥/外观专利密钥/代理设置),行级状态三项全通过才算通过;检测/清空改为按用户;搜索仅按用户名(去 UID);新增代理检测(经用户代理请求自家域名)与代理掩码(隐去账密)
- 后台前端:三字段列改版 + 行级状态筛选 + 用户名筛选
- 桌面前端:登录加载密钥时补报本地代理(只填空缺不覆盖)、保存/清空代理实时上报
2026-09-13 10:47:19 +08:00
huangzd1997 82a782550e feat(密钥): 用户 API 密钥服务端化——V115 按账号绑定存储 + 后台密钥管理页 + 桌面端全站拦截与配置引导
- 新增 usersecret 模块:外观专利/货源查询密钥从本地 localStorage 迁移至 biz_user_api_secret(AES 加密、按 uid 绑定)
- 后台「密钥管理」页:脱敏展示、立即检测、清空;每日 04:30 分布式锁定时巡检
- 桌面端:密钥设置面板走服务端、未配齐引导 /setup-secrets、代理余量展示
- 删除专利汇令牌全链路与密钥保留时长选择器
2026-09-13 10:03:59 +08:00
huangzd1997 d1b56918fa fix(跟价): 指定ASIN文件提交改 fileKey + 服务端三形态解析兼容
- 前端 resolveAsinRequestPaths 改发上传返回的 fileKey(与去重/转换/采集一致),
  修复安全加固后服务端按拼接解析绝对路径失败导致"ASIN 文件不存在或不可读"
- Java parseAsinRowsByCountry 三种形态解析:绝对路径直读 → tempRoot 拼接 → fileKey 反查,
  均过 isInsideTempDir 穿越校验,不放开临时目录外读取
2026-09-13 03:01:56 +08:00
huangzd1997 e6021593ea fix(安全/健壮性): 全工作区审查修复——鉴权兜底扩展+路径穿越+忙等+泄漏
- AdminApiGuardFilter 兜底扩展到 /api/collect-data、/api/price-track:无需鉴权的
  工具接口纳入 JWT/内部令牌校验(原匿名可达即越权读写他人数据)
- pricetrack asinFiles 改为仅允许上传临时目录内文件(canonical 前缀校验),
  修复请求路径直接 new File 可读服务器任意 csv/xlsx 的穿越
- dedupe 删除导入逐行 REQUIRES_NEW 事务改 500 条一批 IN 删除,50 万行导入
  由 50 万个事务收敛为千级
- 前端记住密码 XOR 硬编码密钥改 WebCrypto AES-GCM(密钥随机生成独立存储),
  登录流程接口改 async 并保证自动登录恢复时序
- 任务进度轮询失败按指数退避(原固定 5s 无限撞);下载进度终态条目 2 分钟
  自动清理(原永久堆积);AmazonConsolePage statusTimer 卸载清理
2026-09-11 17:11:43 +08:00
huangzd1997 30d31fb318 feat(代理): 代理配置按登录用户隔离——桌面端 current_uid 登录同步 + brand 页 proxy_users[uid] 读写,各用户各自代理池各自计费复用(未登录回退全局 proxy_url 兼容旧配置) 2026-09-11 16:09:56 +08:00
huangzd1997 bb52574767 fix(更新检测): 版本比较改真实比大小——线上版本不高于本机一律不提示更新;本机高于线上时明确提示无需更新(灰度/回滚/漏发版场景不再被引导降级) 2026-09-11 16:09:53 +08:00
huangzd1997 32985c78f3 feat(下载): 工具页统一下载进度条——AmazonToolPageShell 挂载 DownloadProgressPanel
进度条组件原先只挂在 ImageVideoPage 内的 BrandTopBar,而所有工具页(货源查询/去重/拆分/
转换/删除品牌/外观专利/跟价/商品风险/巡店删除/取款/查询ASIN/匹配店铺/采集数据等)都经
AmazonToolPageShell 渲染,导致这些页面下载结果时没有任何进度展示。

在外壳挂载后一次覆盖全部工具页:面板 position:fixed 且数据来自全局 store,跨页面切换不会
丢进度;桌面客户端下载走 pywebview 进度事件,浏览器 Web 版本就无下载能力。
2026-09-11 15:43:58 +08:00
huangzd1997 94a0c287e0 feat(客户端更新): 登录页/首页更新面板显示更新包下载进度条
- 新增 shared/utils/update-progress.ts:进度事件解析/百分比钳制/文案格式化(纯函数)
- 新增 shared/components/UpdateProgressBar.vue:两页共用,失败态琥珀色并停在断点
  百分比、总大小未知走不确定态
- useVersionUpdate:先挂监听再发桥调用(避免丢首帧),监听 pywebview-update-progress
  (Python 侧 evaluate_js 推送,同 pywebview-download-progress 约定);失败保留上次进度
- 测试:tests/update-progress.test.ts(8 用例)

兼容:老客户端没有该事件源,进度条不出现,其余行为不变(优雅降级)。
注:本仓库 modules-withdraw / modules-image-video 有 3 个既存失败用例(隔离复现),
与本次改动无关;全仓库仅新增测试引用本次新增模块。
2026-09-11 01:59:42 +08:00
huangzd1997 dd45ffe34c chore(清理): 删除死代码与过期文件——7个无引用DTO+图片工作台整棵子树(16文件)+冗余副本+一次性脚本+可再生审计快照
每项删除前均做过全仓库引用核对(含 tests/、两个前端、Python 侧):
- Java 7 个 DTO:BrandTaskRunRequest、LegacyBrandTaskCreateVo、Ziniao{SwitchShopRequest,CurrentShopVo,LoginUrlVo,SwitchShopVo}、
  AppearancePatentParsedGroupManifestDto —— 全仓库仅命中声明行本身
- frontend-vue 整棵 src/pages/image/(16 文件):9a487ae9 起首页一级入口已删("图片已并入视频页"),
  该子树完全自闭环;同步移除 /image 路由与 ImageVideoPage 的图片入口
- frontend-vue 两个孤儿组件 AiModuleSwitch/AiWorkflowShell:无引用,且位于 src/shared/components
  而非 unplugin-vue-components 默认扫描的 src/components,不存在自动注册
- backend/tool/devices.py + .device_id:app_client/tool/devices.py 的冗余副本(活的是 app_client 那份),
  app.py 只注册 version_bp,无任何引用
- admin-frontend-vue 的一次性 Playwright 调试脚本 rescan.tmp.mjs / diag-role-price.mjs
- backend-java/scripts/*_report.json ×4:可由 n1_scan.py 等重跑的审计快照
- frontend-vue/DESIGN.md:Last refreshed 2026-06-09,仍是 MPA 时代内容
- backend/requirement.txt:pip freeze 63 条裁剪为实际 import 的 5 条;run.sh 硬依赖该文件存在,故保留文件本身

验证:mvn compile 通过、vue-tsc --noEmit 通过、残留引用 grep 零命中。
注:仓库既有的 4 个失败测试类(FlywayMigration*DocTest、MigrationInventoryTest、HttpClientTimeoutEffectiveTest)
经 stash 对照实验确认与本次改动无关(相同 Failures/Errors 计数)。
2026-09-11 01:33:54 +08:00
huangzd1997 48ee76d60d fix(patrol-delete): 任务跑完不出现「下载结果」按钮——轮询在任务终态即停,而结果 Excel 由 Java 侧 MQ 异步生成,两者时间窗内前端本地的 fileReady 永远停在 false
现象:任务 27547(用户 996)15:06:31 创建、15:12:20 完成,结果文件 15:12:20 已生成并上传 OSS
(result/patrol_delete/.../巡店删除-27547.xlsx,4033 字节,直链与 /results/{id}/download 均 200),
但页面上始终没有下载入口,用户只能靠刷新页面才刷出来。

排查(生产日志时间线):结果文件任务 15:12:10 入队(MQ)、15:12:20 完成;前端最后一次拉取
history/progress 是 15:12:12,之后客户端再无任何请求——即前端是在 fileReady 尚为 false 时停的轮询。

根因:waitForTaskTerminal 只认 taskStatus(SUCCESS/FAILED)就 return,随后 clearActiveQueueTask()
令 hasQueueWork=false、stopHistoryPolling() 停掉历史轮询,refreshTaskViews() 也只跑这一轮。
taskStatus 是 Python 端回传完毕的信号,而 Excel 是 Java 收尾后(finalizeTaskWorkbook →
enqueueAssembleResult)异步生成的,中间有数秒到数十秒间隔;错过就再也不会刷新,本地 fileReady
永远为 false,canDownload() 恒假 → 历史记录里不渲染「下载结果」按钮。

修复:
① 新增 isResultFilePending():判定「确实有文件任务在生成」(fileJobId 存在或
   fileStatus=PENDING/RUNNING),文件已就绪(fileReady/downloadUrl)或已终态
   (SUCCESS/FAILED)则不再等待;全部店铺失败的任务本就不生成文件(fileStatus 为空),不会被误等。
② waitForTaskTerminal 在任务终态后继续轮询至文件就绪,上限 MAX_FILE_WAIT_ROUNDS=12(≈2 分钟),
   期间 queuePushResult 提示「正在生成结果文件(n/12)」,超时打 warn 后按终态返回,不阻塞队列。
③ 新增 settlePendingResultFiles():页面加载时若历史里存在「任务已完成、文件仍在生成」的记录
   (在生成窗口内刷新页面/重开客户端的场景),继续轮询收敛,避免同一个坑的另一个入口。
   仅在无未完成任务时执行,避免与 processQueue 重复轮询。

与同类页面对齐:BrandAppearancePatentTab 早已用 pendingFileTaskIds 等文件就绪再停轮询,
巡店删除页缺这一环。日志按规范用中文,关键分支(等待/超时/收敛完成)均有输出便于线上排查。
2026-09-10 15:26:59 +08:00
huangzd1997 6fe67b648f feat(patrol-delete): 删除条件改为添加式交互——输入后回车/点添加逐个加入chips列表(可单项移除),去掉原'保存到条件库+勾选'两步式与已知状态下拉,启动时随任务携带条件 2026-09-09 19:06:27 +08:00
huangzd1997 96e93944d9 fix(patrol-delete): 删除条件为空的任务四层拦截——①前端启动前拦截(不再先创建后失败,避免任务残留执行中)并创建时上传delete_conditions ②Java服务端校验删除条件非空(旧版本/直调兜底) ③Python端空条件直接按失败上报,不再逐店空转 2026-09-09 18:59:45 +08:00
huangzd1997 0cf20527a4 fix(frontend): 菜单点击偶发无响应三处根因——①路由懒加载chunk失败被静默吞掉(新增onError自动整页重载+保险丝防循环) ②首页入口被权限接口阻塞(改乐观显示+缓存TTL10分钟+超时30s→8s) ③菜单hover预取目标页chunk(工具卡片/工作流步骤/顶部导航) 2026-09-09 18:53:34 +08:00
huangzd1997 83cb3ff84e style(frontend): 全站背景图 webp 化(bg.jpg 4MB→251KB 压缩 + bg.webp)+品牌工具页默认策略调优(品牌检测默认改精确匹配 Simple、Terms 后置)+任务面板/登录页/亚马逊控制台观感微调 2026-09-09 18:32:56 +08:00
huangzd1997 9a487ae9a7 feat(frontend): 桌面端首页删除一级「图片」入口——图片已并入视频页(/image-video)二级菜单,首页仅保留 亚马逊/视频,权限计算同步清理 image 分支 2026-09-09 18:32:48 +08:00
huangzd1997 ffd8c718dd feat(web): 记住密码/自动登录与版本更新放开到网页形态
- 登录页与首页移除 isDesktopRuntime 门控,网页浏览器同样显示记住密码/自动登录与更新版本入口
- 记住密码由 base64 明文改为 XOR+位移可逆加密存储(v1. 前缀),兼容解密历史值
- 网页形态进入登录页即回填凭据并尝试自动登录(登出/切号导航仍豁免)
- 版本更新在无桌面桥时降级为 OSS 直链下载安装包,桌面端维持自动安装
2026-09-09 00:13:13 +08:00
huangzd1997 5fad0ae027 feat(brand): 品牌检测任务统一轮询驱动并展示行级实时进度
任务面板状态改为独立轮询(getTaskPollIntervalMs 节奏),刷新/提交/取消/删除后
按是否有运行中任务自动续轮询或停表;运行中任务通过详情接口拉取 Redis 行级进度,
进度按"已处理品牌行/总行(含查询失败)"推进并展示 crawling/assembling/uploading 阶段文案
2026-09-08 22:52:49 +08:00
huangzd1997 3f599547e6 fix(auth): 登录页守卫对登出/切号导航放行判断改读 to.query
window.location.search 在守卫执行时仍是旧地址,会漏判 /home 点击"退出"的
router-link 导致登出无效果;改为判断路由目标 query 的 logout/switch 参数。
2026-09-08 22:30:54 +08:00
huangzd1997 7c1c13526e feat(web): 桌面登录页记住密码/自动登录与版本更新,首页版本更新入口与背景修复
- 登录页(仅桌面端)新增"记住密码/自动登录"勾选与"更新版本"按钮:登录成功持久化凭据
  (base64 存桌面 localStorage),打开登录页恢复勾选并静默登录;显式登出/切号后关闭自动登录
- 新增 shared/composables/useVersionUpdate 统一版本检测:/api/version/latest 与本机版本比较,
  通过 pywebview 桥 get_app_version 读本地 exe 版本,缺桥时降级为可手动更新
- 首页保留 ↻ 图标并加显式"更新版本"按钮,接入新检测逻辑
- 首页背景改画到 .home-root,避免被 SPA 全局样式时序覆盖导致图不显示
2026-09-08 22:30:50 +08:00
huangzd1997 15222be2b5 fix(login): 退出登录/切号彻底清除 uid 与 username 登录态
logout=1 仅清 token,uid 残留会被 main.ts 守卫当已登录自动带回首页,导致退出无效
2026-09-08 21:54:05 +08:00
huangzd1997 3cc5a64609 fix(brand): 品牌检测提交统一立即执行,去掉无人消费的"添加到队列"模式
queue 模式只建 pending 无后台消费者,任务会永久停在排队中;统一走 /api/brand/run 立即执行(与历史链路一致)
2026-09-08 21:54:02 +08:00
huangzd1997 ba581ed095 fix(brand): 品牌检测源文件改走 OSS URL(服务端化跨节点组装可用)
前端上传桥与降级桥透传 uploadOss;品牌页提交时 fileUrl 优先取上传响应的 OSS url,localPath 仅作旧桌面桥兜底。
2026-09-08 15:19:21 +08:00
huangzd1997 4ac8f8b472 fix(pricetrack): ASIN文件路径防本地路径误提交+fileKey兜底反查 2026-09-08 13:34:08 +08:00
huangzd1997 7b6f62f1bc fix(brand): 品牌检测补上传链+新增 /api/brand/run 端点+文件夹展开桥
- BrandBrandTab 对齐其它工具页:选文件/文件夹后先 upload_file_to_java 再提交(服务器可读路径),修复本地路径直传导致的「请先上传待处理文件/没有有效的xlsx文件路径」
- runBrandNow/createBrandTask 改为 files 契约(fileUrl=临时路径 localPath)+ 传 userId
- Java 新增 POST /api/brand/run(等价 /tasks 并返回待爬取数据),修复前端「立即运行」No static resource
- 选择文件夹改走新版桌面客户端桥 expand_brand_folder(本机展开);旧客户端提示改用文件多选
- 生产 .env 已另配 AIIMAGE_BRAND_CHECK_TOKEN(上游 16890 鉴权),非代码变更
2026-09-08 13:18:58 +08:00
huangzd1997 d9e3f34d37 chore: 移除项目内无用代码(28 文件)
- 清理任务面板/SPA 化改造遗留的未使用变量与函数(模板管理配套 6 函数、
  payloadForDisplay/showTip/hasRunning/schedulePoll/removeMatchedRowLocally 等 30+ 处)
- 清理未使用 import(getBrandTemplateXlsxUrl/uploadTempFileToJava/getProductRiskTasksBatch 等)
- useTaskProgressLoop 改为仅类型导入;progress/task-request 缓存未用参数精简
- DeleteBrandRunService 删除永不执行的 taskItems 死分支
- 全量 vue-tsc(含 --noUnusedLocals/--noUnusedParameters)0 错误;648 测试全过
2026-09-08 10:20:30 +08:00
huangzd1997 e248b6e43a feat(web): 前端 SPA 化 + 工具页任务面板统一与历史批量删除
- SPA 化:22 个 MPA html 入口与 *-main.ts 合并为 index.html + vue-router(URL 无 .html 后缀),
  页面跳转全部 router-link,/new_web_source/xxx.html 旧路径归一为 /xxx
- 任务面板统一:共享 TaskCenterPanel/TaskItemCard/TaskStatCards/HistoryTaskLayer,
  16 个工具页右侧统一为统计卡 + 当前任务 + 历史任务弹层(任务ID/开始/结束/状态必展示)
- 历史记录支持单条删除 + 批量勾选删除(确认框/全选/失败提示)
- Java 7 模块(dedupe/convert/split/productrisk/shopmatch/pricetrack/deletebrand)
  history 接口补齐任务时间字段(VO+Service,复用 biz_file_task 列)
- 图片工作台/API 层(brand/permission/user)既有未提交改动一并提交
2026-09-08 10:02:55 +08:00
huangzd1997 c086d402a7 feat(web): 品牌检测/图片生成服务端化——URL 统一 https+域名,入口文件带 hash 防长缓存失效
- brand/image 本地执行 API 服务端化(主机A shufu-web-api:15126,nginx 转发 /api/brand/* 等)
- 前端撤销本地回连逻辑(local-http 删除,http.ts/brand.ts 还原为域名相对路径)
- 版本更新改桌面桥 do_update_app(原 Flask /api/update/do 桥化,Web 无更新入口)
- 品牌检测页 Web 可用(hasBridge 恢复 blanket 判定:文件选择走浏览器降级、任务/SSE 走域名)
- vite 入口文件带内容 hash(/assets 配了 immutable 长缓存,无 hash 入口导致更新永不生效)
- public/logo.jpg:Web 版 /logo.jpg 素材(原 app_client/logo.jpg 随桌面瘦身移除)
2026-09-07 17:11:33 +08:00
huangzd1997 30b8c910e8 feat(web): 桌面端前端 Web 独立部署适配——浏览器降级桥+登录态引导+页面动态修正
- 新增 web-fallback.ts:无 pywebview 时以浏览器能力降级(文件选择/上传/模板下载/配置),
  其余桌面能力(enqueue_json/vc_*/folder 选择等)保持 undefined 交由页面既有请在本地客户端中打开提示
- 新增 ensure-auth.ts:无 uid 时经 /newApi/check_login 恢复登录态,无 token/失效跳登录页;
  21 个入口 main.ts 挂载前先引导(桌面端已注入 uid 时零开销)
- pywebview.ts:getPywebviewApi() 在纯浏览器环境返回降级桥;新增 isDesktopRuntime 标志
  (首页更新面板/退出链接据此区分桌面与 Web);hasPywebview 语义修正为真实桥判定
- 登录页跳转、首页登出链接、品牌检测页 hasBridge 判定(select_brand_folder 存在性)适配 Web
2026-09-07 16:35:19 +08:00