feat(device): 建立采购员与 Android 手机归属管理前置能力 #329

Open
opened 2026-09-21 09:09:33 +08:00 by ila · 6 comments
Owner

原始需求

多人同时使用系统时,每个采购员账号拥有自己的一个或多个 Android 手机,手机不在采购员之间混用。为支持 #328 的一键关联/一键替换隔离,需要先建立可靠的“采购员 ↔ 手机”归属数据和维护入口。

本单目标

建立设备归属的前置能力,供 #328 消费。交付范围:

  1. 设计并实施最小设备归属数据模型(优先复用现有用户和设备表;如需迁移,明确字段、唯一性、删除/转移行为)。
  2. 管理员维护入口:查看设备、查看当前归属、分配给采购员、变更归属、解除归属;一个采购员可拥有多台手机,一台手机同一时刻最多归属一个采购员。
  3. 明确管理员账号的可见范围和操作权限;普通采购员不维护归属。
  4. 制定并执行存量设备初始化方案:当前生产设备共 8 台,必须在实施前形成逐台归属清单;不得根据设备名称、历史采集记录或浏览器偏好自动推断。未确认归属的设备保持未归属,不作为 #328 候选。
  5. 提供供 #328 使用的服务端查询/校验契约:按当前登录用户查询本人设备;校验指定 deviceId 是否属于当前用户;管理员范围按本单确认规则返回。契约不得允许前端绕过归属校验。

非目标

不实现一键关联/替换候选过滤(由 #328 实施);不改 Android Agent、采集流程、采购流程、付款/下单、全局菜单权限或历史任务;不自动迁移设备归属;不执行真实采购。

设计门禁

这是新的设备管理界面和权限/数据功能,实施前必须先制作可访问的 QuantUX 或低保真原型并由用户确认。原型至少覆盖:正常列表、空状态、加载、无归属、分配/变更确认、解除归属确认、失败/冲突、无权限状态。原型确认前不得编写生产 UI。

安全与风险

设备归属、权限和数据库迁移属于高风险修改,实施前需明确授权。服务端必须最终校验归属,不能只信任前端。归属变更应记录操作者、时间和前后归属;并发分配冲突不得静默覆盖。解除归属后设备不再出现在采购员候选中,但不删除设备或历史任务。

验收标准

  • 数据模型可表示未归属、一对多(用户到设备)和设备唯一归属。
  • 管理员可完成查看、分配、变更、解除,并有明确成功/失败/冲突反馈。
  • 普通采购员不能进行归属维护。
  • 8 台存量设备均有明确初始化结果(归属或确认未归属),迁移可重复执行且不覆盖已有明确归属。
  • 服务端契约能按用户过滤和拒绝越权 deviceId,并有契约/权限/并发测试。
  • 原型、实现、测试、迁移和文档影响均回写本单;未授权前不发布、不重启。

依赖关系

完成并验收本单后,#328 才可解除阻塞并实施。#328 不得在本单完成前自行创建归属字段或临时绕过归属校验。

当前状态

本单仅创建需求记录,保持待实施。Gitea MCP 未暴露,使用项目安全配置 API 回退创建。

## 原始需求 多人同时使用系统时,每个采购员账号拥有自己的一个或多个 Android 手机,手机不在采购员之间混用。为支持 #328 的一键关联/一键替换隔离,需要先建立可靠的“采购员 ↔ 手机”归属数据和维护入口。 ## 本单目标 建立设备归属的前置能力,供 #328 消费。交付范围: 1. 设计并实施最小设备归属数据模型(优先复用现有用户和设备表;如需迁移,明确字段、唯一性、删除/转移行为)。 2. 管理员维护入口:查看设备、查看当前归属、分配给采购员、变更归属、解除归属;一个采购员可拥有多台手机,一台手机同一时刻最多归属一个采购员。 3. 明确管理员账号的可见范围和操作权限;普通采购员不维护归属。 4. 制定并执行存量设备初始化方案:当前生产设备共 8 台,必须在实施前形成逐台归属清单;不得根据设备名称、历史采集记录或浏览器偏好自动推断。未确认归属的设备保持未归属,不作为 #328 候选。 5. 提供供 #328 使用的服务端查询/校验契约:按当前登录用户查询本人设备;校验指定 deviceId 是否属于当前用户;管理员范围按本单确认规则返回。契约不得允许前端绕过归属校验。 ## 非目标 不实现一键关联/替换候选过滤(由 #328 实施);不改 Android Agent、采集流程、采购流程、付款/下单、全局菜单权限或历史任务;不自动迁移设备归属;不执行真实采购。 ## 设计门禁 这是新的设备管理界面和权限/数据功能,实施前必须先制作可访问的 QuantUX 或低保真原型并由用户确认。原型至少覆盖:正常列表、空状态、加载、无归属、分配/变更确认、解除归属确认、失败/冲突、无权限状态。原型确认前不得编写生产 UI。 ## 安全与风险 设备归属、权限和数据库迁移属于高风险修改,实施前需明确授权。服务端必须最终校验归属,不能只信任前端。归属变更应记录操作者、时间和前后归属;并发分配冲突不得静默覆盖。解除归属后设备不再出现在采购员候选中,但不删除设备或历史任务。 ## 验收标准 - 数据模型可表示未归属、一对多(用户到设备)和设备唯一归属。 - 管理员可完成查看、分配、变更、解除,并有明确成功/失败/冲突反馈。 - 普通采购员不能进行归属维护。 - 8 台存量设备均有明确初始化结果(归属或确认未归属),迁移可重复执行且不覆盖已有明确归属。 - 服务端契约能按用户过滤和拒绝越权 deviceId,并有契约/权限/并发测试。 - 原型、实现、测试、迁移和文档影响均回写本单;未授权前不发布、不重启。 ## 依赖关系 完成并验收本单后,#328 才可解除阻塞并实施。#328 不得在本单完成前自行创建归属字段或临时绕过归属校验。 ## 当前状态 本单仅创建需求记录,保持待实施。Gitea MCP 未暴露,使用项目安全配置 API 回退创建。
Author
Owner

v1 低保真原型已创建,待审核

  • QuantUX App ID:6ab086dd191a826306a7fed7
  • 预览链接:https://qux.ilapage.cn/#/apps/6ab086dd191a826306a7fed7.html
  • 覆盖:设备归属列表、分配手机、归属冲突刷新、无权限/无设备提示、在线/离线/未归属、分配/变更/解除操作位置。
  • QuantUX 导出一致性验证:PASS;4 个页面、31 个控件,无运行时错误。
  • 本次只创建原型和补充工单证据,尚未修改代码、数据库、权限或设备归属数据。

请先审核并确认该 v1 原型;确认后再授权实施数据库迁移、权限写入和管理员维护界面。

## v1 低保真原型已创建,待审核 - QuantUX App ID:`6ab086dd191a826306a7fed7` - 预览链接:https://qux.ilapage.cn/#/apps/6ab086dd191a826306a7fed7.html - 覆盖:设备归属列表、分配手机、归属冲突刷新、无权限/无设备提示、在线/离线/未归属、分配/变更/解除操作位置。 - QuantUX 导出一致性验证:PASS;4 个页面、31 个控件,无运行时错误。 - 本次只创建原型和补充工单证据,尚未修改代码、数据库、权限或设备归属数据。 请先审核并确认该 v1 原型;确认后再授权实施数据库迁移、权限写入和管理员维护界面。
Author
Owner

原型显示问题已修正(2026-09-21)

核对确认:QuantUX 的 Label/Button 渲染使用 props.label;原型控件创建时只写入了 props.text,因此预览/导出可能出现空白。该判断正确。

已对 App 6ab086dd191a826306a7fed7 的全部 Label/Button 补齐对应 props.label,保留原 props.text 作为兼容字段。重新执行 QuantUX 导出一致性验证:PASS,4 个页面、31 个控件、无运行时错误。

更新后的预览链接不变:
https://qux.ilapage.cn/#/apps/6ab086dd191a826306a7fed7.html

仍未修改生产代码、数据库、权限或设备归属数据;请按修正后的原型审核。

## 原型显示问题已修正(2026-09-21) 核对确认:QuantUX 的 Label/Button 渲染使用 `props.label`;原型控件创建时只写入了 `props.text`,因此预览/导出可能出现空白。该判断正确。 已对 App `6ab086dd191a826306a7fed7` 的全部 Label/Button 补齐对应 `props.label`,保留原 `props.text` 作为兼容字段。重新执行 QuantUX 导出一致性验证:PASS,4 个页面、31 个控件、无运行时错误。 更新后的预览链接不变: https://qux.ilapage.cn/#/apps/6ab086dd191a826306a7fed7.html 仍未修改生产代码、数据库、权限或设备归属数据;请按修正后的原型审核。
Author
Owner

方案补充与范围收敛(2026-09-21)

按确认方案,本单不再新增独立设备管理页面,也不改变采集/采购流程。

最终范围

  • 在现有设备列表/设备编辑能力中增加“所属采购员”字段。
  • 一个采购员可绑定多台手机;一台手机同一时刻最多绑定一个采购员;允许未归属。
  • 管理员维护归属;普通采购员不能维护。
  • 现存设备由管理员明确分配或保持未归属,不根据设备名称、历史采集记录或浏览器偏好推断。
  • #328 使用该归属数据:一键关联/替换只展示当前账号拥有的手机;多台时沿用现有小下拉选择并记忆。实际候选取所选手机的最新可用临时采集,不取账号所有手机的全局最新记录。
  • 选定后冻结 taskId/deviceId/PDD 商品和规格上下文,避免新采集导致漂移。

原型门禁调整

不新增独立管理页面;复用现有设备列表/编辑交互。原型仅作为现有列表新增归属字段和编辑状态的设计证据,已修正 QuantUX props.label 显示问题:
https://qux.ilapage.cn/#/apps/6ab086dd191a826306a7fed7.html

实施顺序

  1. 核对现有设备模型、设备列表接口和管理员权限,优先最小字段/接口改动。
  2. 如无可复用字段,增加最小数据库迁移和服务端归属校验。
  3. 更新现有设备列表编辑交互及测试。
  4. 完成后再解除 #328 的阻塞并实施候选过滤。

本评论是范围更新和实施起点;不新增菜单权限,不执行真实采购/下单。数据库迁移、权限写入、发布/重启仍按项目高风险规则在对应动作前确认授权。

## 方案补充与范围收敛(2026-09-21) 按确认方案,本单不再新增独立设备管理页面,也不改变采集/采购流程。 ### 最终范围 - 在现有设备列表/设备编辑能力中增加“所属采购员”字段。 - 一个采购员可绑定多台手机;一台手机同一时刻最多绑定一个采购员;允许未归属。 - 管理员维护归属;普通采购员不能维护。 - 现存设备由管理员明确分配或保持未归属,不根据设备名称、历史采集记录或浏览器偏好推断。 - #328 使用该归属数据:一键关联/替换只展示当前账号拥有的手机;多台时沿用现有小下拉选择并记忆。实际候选取所选手机的最新可用临时采集,不取账号所有手机的全局最新记录。 - 选定后冻结 taskId/deviceId/PDD 商品和规格上下文,避免新采集导致漂移。 ### 原型门禁调整 不新增独立管理页面;复用现有设备列表/编辑交互。原型仅作为现有列表新增归属字段和编辑状态的设计证据,已修正 QuantUX props.label 显示问题: https://qux.ilapage.cn/#/apps/6ab086dd191a826306a7fed7.html ### 实施顺序 1. 核对现有设备模型、设备列表接口和管理员权限,优先最小字段/接口改动。 2. 如无可复用字段,增加最小数据库迁移和服务端归属校验。 3. 更新现有设备列表编辑交互及测试。 4. 完成后再解除 #328 的阻塞并实施候选过滤。 本评论是范围更新和实施起点;不新增菜单权限,不执行真实采购/下单。数据库迁移、权限写入、发布/重启仍按项目高风险规则在对应动作前确认授权。
Author
Owner

实施完成,待验收(2026-09-21)

提交:bb1a410(已推送 main)。

已实现

  • agent_device.owner_user_id 可空字段及索引;未归属设备保持可表示。
  • 现有设备列表返回所属采购员 ID;管理员可在现有列表中打开“归属”对话框,分配、变更或解除采购员归属。
  • 新增管理员接口:
    • GET /api/admin/v1/devices/owners
    • PATCH /api/admin/v1/devices/:deviceId/owner
  • 服务端仅允许分配有效的非管理员用户;设备归属变更不删除设备或历史任务。
  • 新增版本迁移 1789800300000_device_owner.go,复用 GoAuto 迁移集合创建字段。
  • 未修改 Android、采集流程、采购流程和 #328 候选过滤逻辑。

验证

  • Server 定向测试通过:go test ./app/goauto/device ./app/goauto/migrations ./cmd/migrate/migration/...
  • GoAuto 受影响包测试通过;全量 GoAuto 测试仍有既有 sybimport/sybspec 失败,与本单无关,未将其宣称为通过。
  • Web npm run build:prod 通过(保留既有 Vite CSS/大包警告)。
  • Web 全量 lint 存在既有错误;本单新增 devices.js 的错误已修正,设备页面仅有一条既有格式警告。
  • 未执行线上迁移、生产权限写入、设备归属初始化、发布或重启。

待验收/待后续

  • 请在迁移前确认 8 台存量设备逐台归属或保持未归属。
  • 本单验收后,再实施 #328 的按登录账号/选定设备过滤和服务端越权校验。
  • 生产迁移和发布仍需单独授权。
## 实施完成,待验收(2026-09-21) 提交:`bb1a410`(已推送 main)。 ### 已实现 - `agent_device.owner_user_id` 可空字段及索引;未归属设备保持可表示。 - 现有设备列表返回所属采购员 ID;管理员可在现有列表中打开“归属”对话框,分配、变更或解除采购员归属。 - 新增管理员接口: - `GET /api/admin/v1/devices/owners` - `PATCH /api/admin/v1/devices/:deviceId/owner` - 服务端仅允许分配有效的非管理员用户;设备归属变更不删除设备或历史任务。 - 新增版本迁移 `1789800300000_device_owner.go`,复用 GoAuto 迁移集合创建字段。 - 未修改 Android、采集流程、采购流程和 #328 候选过滤逻辑。 ### 验证 - Server 定向测试通过:`go test ./app/goauto/device ./app/goauto/migrations ./cmd/migrate/migration/...` - GoAuto 受影响包测试通过;全量 GoAuto 测试仍有既有 sybimport/sybspec 失败,与本单无关,未将其宣称为通过。 - Web `npm run build:prod` 通过(保留既有 Vite CSS/大包警告)。 - Web 全量 lint 存在既有错误;本单新增 devices.js 的错误已修正,设备页面仅有一条既有格式警告。 - 未执行线上迁移、生产权限写入、设备归属初始化、发布或重启。 ### 待验收/待后续 - 请在迁移前确认 8 台存量设备逐台归属或保持未归属。 - 本单验收后,再实施 #328 的按登录账号/选定设备过滤和服务端越权校验。 - 生产迁移和发布仍需单独授权。
Author
Owner

本地迁移完成(2026-09-21)

已按授权使用本地 D:\OPC\goauto\config.yaml 执行迁移,连接本机 MySQL(未触碰线上)。

结果:

  • agent_device.owner_user_id 已存在。
  • sys_migration 已记录 1789800300000。
  • 重复执行验证:新执行 0 个,跳过 54 个。
  • 修正迁移提交:beec630(记录迁移版本),已推送 main。

当前仍需在本地 Admin 设备列表给手机分配采购员,之后采购员才能在 #328 一键关联/替换中看到自己的设备。

## 本地迁移完成(2026-09-21) 已按授权使用本地 `D:\OPC\goauto\config.yaml` 执行迁移,连接本机 MySQL(未触碰线上)。 结果: - `agent_device.owner_user_id` 已存在。 - `sys_migration` 已记录 `1789800300000`。 - 重复执行验证:新执行 0 个,跳过 54 个。 - 修正迁移提交:`beec630`(记录迁移版本),已推送 main。 当前仍需在本地 Admin 设备列表给手机分配采购员,之后采购员才能在 #328 一键关联/替换中看到自己的设备。
Author
Owner

线上发布完成(2026-09-22)

已按授权发布 main 提交 5e0a9d1,发布标识 20260922-5e0a9d1-328-330。

  • Server/Web 已构建并上传;线上 /home/goauto/current 已原子切换到该 release。
  • 执行线上幂等迁移:新增执行 1 个(设备归属 1789800300000),其余 53 个已应用;未修改定时任务启停状态。
  • goauto.service 状态为 active,Nginx reload 成功。
  • 本机 API 健康检查和公网 Admin 首页 HTTP 200;线上二进制 SHA-256:4a6806759108901808acaf162959909ece6c46d5dab02acdd56df30bccd315e8。
  • 未执行真实采购、下单或付款;未初始化生产设备归属,存量设备仍需管理员明确分配后才会进入采购员候选范围。

状态:待线上功能验收。

## 线上发布完成(2026-09-22) 已按授权发布 main 提交 `5e0a9d1`,发布标识 `20260922-5e0a9d1-328-330`。 - Server/Web 已构建并上传;线上 `/home/goauto/current` 已原子切换到该 release。 - 执行线上幂等迁移:新增执行 1 个(设备归属 `1789800300000`),其余 53 个已应用;未修改定时任务启停状态。 - `goauto.service` 状态为 active,Nginx reload 成功。 - 本机 API 健康检查和公网 Admin 首页 HTTP 200;线上二进制 SHA-256:`4a6806759108901808acaf162959909ece6c46d5dab02acdd56df30bccd315e8`。 - 未执行真实采购、下单或付款;未初始化生产设备归属,存量设备仍需管理员明确分配后才会进入采购员候选范围。 状态:待线上功能验收。
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OPC/goauto#329