Files
CloudHome-Ops/CHANGELOG.md

67 KiB
Raw Blame History

云定制主页管理 (ops-console) — 变更清单

包名:com.ainetv.aishicloud · version:1.0.0+1 标记说明:✅ 已实现 / 已修复 | ⏳ 待后端 / 待验收 | ❌ 已知问题 所有 release APK 均通过 flutter analyze --no-fatal-infos(0 error)


v6-fix68(2026-08-29)

修复两个功能性 Bug:① 设备列表「删除」按钮点击后返回「删除失败:未知异常,请联系管理员」;② 设备详情页修改房号后不生效,页面仍显示 Web 端原有房号。

根因(通过静态分析 Web 前端 JS 逆向真实后端契约得出):

  1. 删除失败:后端 POST /device/info/delete 接收的是裸 JSON 数组 [id](Web 端 Ao(t) → $.adornData(t,!1) → JSON.stringify([id,...]))。旧实现误传 {'ids':[id]}(对象),后端无法解析请求体 → 抛出「未知异常」。
  2. 房号不保存:后端设备表房号字段名为 roomId(Web 端设备编辑表单 prop:'roomId'、列表列 prop:'roomId' 标签「房间号」)。旧实现发送 roomNo,后端忽略该未知字段 → 更新“成功”但房号未变,刷新后回显旧值。

改动:

  1. lib/services/device_service.dart:
    • deleteDevice(id):body 由 {'ids':[id]} 改为裸数组 [id],并在 id 可转为数字时按数字发送(复刻 Web 端 Yo() 的 Number(id) 行为),兼容数字/字符串两种主键;
    • activateDeviceByScan:扫码激活的房号字段 roomNo → roomId(update 与 save 两条路径)。
  2. lib/screens/home/device_detail_page.dart:DeviceGroupRoomSheet 提交时房号字段 roomNo → roomId。
  3. lib/models/device.dart:toJson 房号输出键 roomNo → roomId(fromJson 读取别名列表保留 roomNo/roomId 等,确保后端返回 roomId 时正确回显)。
  4. 版本号 v6-fix67 → v6-fix68。
类型 模块 内容
✅ 已修复 设备服务 deleteDevice(id):删除 body 由 {'ids':[id]} 改为裸数组 [id],对齐 Web 端契约
✅ 已修复 设备/扫码 房号字段统一为后端 roomId(update/save/详情编辑/toJson)
✅ 已更新 版本号 登录页版本号 v6-fix67 → v6-fix68

v6-fix67(2026-08-31)

设备列表页「向左滑动显示删除按钮」手势。

用户需求:在「设备 MAC 排序」列表中,为每个 MAC 项增加向左滑动手势,滑动后露出删除按钮(位于行右侧);点击删除按钮才弹出确认对话框,确认后执行删除、取消则保留。

实现选择:原先用 Dismissible 会在滑动过阈值松手时自动弹确认框(红色背景仅为装饰、不可点击),不满足「先露按钮再点击」的交互。故改用 flutter_slidable(新增依赖 flutter_slidable: ^3.1.0):向左滑揭示一个可点击的红色「删除」动作(位于行右侧),点击动作才触发确认框。

改动:

  1. pubspec.yaml:新增 flutter_slidable: ^3.1.0(flutter pub get 已解析)。
  2. lib/services/device_service.dart:新增 deleteDevice(String id)——POST /device/info/delete,body 为 {ids: [id]},与分组/用户等模块的删除接口约定保持一致。
  3. lib/screens/home/device_list_page.dart:
    • 列表 itemBuilder 每行用 Slidable(endActionPane + ScrollMotion)包裹,向左滑动揭示右侧红色 SlidableAction(删除图标 + t.delete 文案);dismissible: null 表示不自动滑出删除,仅作按钮;
    • SlidableAction.onPressed 调用 _confirmDeleteDevice(device):弹出 AlertDialog(标题 确认删除 / 内容 是否确认删除该设备(设备名/MAC)?,取消/删除按钮);
      • 取消 → 返回 false,行回弹保留;
      • 确认 → 先入 _pendingDeleteIds 本地隐藏该行(避免抖动),再调 deleteDevice,成功 ref.invalidate(devicesByStoreProvider) + SnackBar 已删除,真正由列表刷新移除;异常则移出 _pendingDeleteIds 恢复显示并 SnackBar 删除失败:{原因};
    • 新增 _rowKey(Device):${id 或空}__${mac} 作为行唯一键,避免 device.id 为空时 ValueKey('') 重复触发 Flutter 断言崩溃;_filter 与 _pendingDeleteIds 均改用该键。
类型 模块 内容
✅ 新增 依赖 pubspec.yaml:flutter_slidable: ^3.1.0
✅ 新增 设备服务 lib/services/device_service.dart:deleteDevice(id) 调 POST /device/info/delete,body {ids:[id]}
✅ 新增 设备列表 lib/screens/home/device_list_page.dart:每行 Slidable(startToEnd)露可点击红色「删除」按钮,点击才弹确认框;确认删除、取消保留;删除中本地隐藏防抖、失败回滚并提示;_rowKey 防空 id 重复键
✅ 已更新 版本号 登录页底部版本号 v6-fix66 → v6-fix67

v6-fix66(2026-08-31)

修复 Web 端删除设备后,手机端设备列表仍显示已删除设备的问题。

用户反馈:在 Web 后台删除设备后,手机端设备列表未同步,仍显示该设备 MAC(如截图中 08:C3:ED:64:16:72)。

根因:设备列表页使用 devicesByStoreProvider(Riverpod FutureProvider.family)做缓存,但只在「下拉刷新」「切换门店筛选」「扫码成功」三种场景下刷新;日常从 Web 端删除设备后,手机端没有自动刷新机制,因此一直展示旧缓存。

改动:

  1. lib/screens/home/device_list_page.dart:
    • _DeviceListPageState 混入 WidgetsBindingObserver,在 initState/dispose 中注册/注销生命周期监听;
    • 新增 didChangeAppLifecycleState 处理:应用从后台切回前台(AppLifecycleState.resumed)且跳过首次启动事件后,调用 ref.invalidate(devicesByStoreProvider) 失效所有门店筛选参数下的设备列表缓存,并静默刷新门店列表,使手机端与 Web 端数据同步;
    • 合并原有的 dispose 方法,确保 removeObserver 与控制器释放同时执行。
  2. lib/screens/device/device_scan_page.dart:
    • 将扫码查询命中后端设备、扫码绑定/激活成功后的 ref.invalidate(devicesProvider) 改为 ref.invalidate(devicesByStoreProvider),失效门店筛选 Provider 族(而不是只失效无参数的 devicesProvider),确保返回列表页时看到最新数据。
类型 模块 内容
✅ 已修复 设备列表 lib/screens/home/device_list_page.dart:App 切回前台自动刷新设备/门店列表,同步 Web 端变更
✅ 已修复 扫码页 lib/screens/device/device_scan_page.dart:扫码成功后失效 devicesByStoreProvider 全族,而非仅 devicesProvider
✅ 已更新 版本号 登录页底部版本号 v6-fix65 → v6-fix66

v6-fix65(2026-08-31)

扫码绑定流程改造:扫码成功后改为页面内表单(门店分组下拉 + 房号输入),替代原先分步弹窗。

新增需求:扫码成功后,在页面上直接提供「门店分组」选择控件(从分组列表选取)与「房号」输入框,并明确两者的校验规则,保证移动端布局清晰、操作便捷。

改动:lib/screens/device/device_scan_page.dart

  1. 移除原 _confirmBind / _pickGroup / _pickStore 三步弹窗流程。
  2. 新增 _enterBindForm:扫码识别 MAC 后进入表单态,停止相机预览;
    • 激活模式(无预填门店):加载门店下拉,选择门店后级联加载其分组;
    • 绑定模式(路由已预填门店):门店固定展示,直接加载分组。
  3. 新增 _buildBindForm(SingleChildScrollView + Card):已识别设备 MAC 卡片、门店分组 DropdownButtonFormField、房号 TextFormField、提交/重新扫码按钮;分组加载中显示进度。
  4. 校验规则(_validateForm):
    • 门店:仅激活模式必填(未选门店 → 请先选择门店);
    • 门店分组:必填(未选 → 请选择门店分组;门店无分组 → 该门店暂无设备分组…);
    • 房号:必填且格式校验(非空、长度 1~20、仅含中英文/数字/连字符/斜杠,否则 房号格式不正确…);错误信息以输入框 errorText 实时回显。
  5. _submitBind 校验通过调 DeviceService().activateDeviceByScan(mac, storeId, groupId, roomNo)(后端 roomNo 字段已支持),写本地绑定缓存并 ref.invalidate(devicesProvider),成功 SnackBar 后 context.pop();登录失效仍兜底跳 /login。
  6. i18n(lib/utils/i10n.dart)新增 scanGroupLabel / scanStoreRequired / scanGroupRequired / scanRoomRequired / scanRoomInvalid / scanRoomHint / scanRescan / scanFormInvalid / scanFormDeviceTitle。
类型 模块 内容
✅ 新增 扫码页 页面内绑定表单:门店分组下拉 + 房号输入 + 实时校验 + 提交/重扫
✅ 已删除 扫码页 移除 _confirmBind / _pickGroup / _pickStore 分步弹窗
✅ 新增 i18n 表单相关中文/英文文案
✅ 已更新 版本号 登录页底部版本号 v6-fix64 → v6-fix65

v6-fix60(2026-08-31)

修复设备详情页在线状态与 Web 端不一致的问题。

用户截图:手机端设备详情页状态显示「离线」,但 Web 端同一设备显示「在线」。根因:移动端详情接口 /device/info/info/{id} 返回的 status/lastSyncTime 滞后于列表接口 /device/info/list;Web 端设备列表正是走列表接口并显示最新在线状态。修复后详情页先用 ID 取详情,再用设备 MAC 从列表接口拉一次最新状态并合并,保证手机端详情与 Web 端列表/心跳一致。

类型 模块 内容
✅ 已修复 设备模型 lib/models/device.dart:新增 copyWith 方法;lastSyncTime 解析兼容 heartbeatTime / heartbeat_time / lastHeartbeat / last_heartbeat 等 Web 端心跳命名字段
✅ 已修复 设备服务 lib/services/device_service.dart:fetchDeviceById 在拿到详情后调用 _mergeWithFreshListStatus:用 detail.mac 调 /device/info/list?mac=...&limit=1 取最新状态,合并 status 与 lastSyncTime;列表接口失败时不阻断详情展示
✅ 已更新 版本号 登录页底部版本号 v6-fix59 → v6-fix60

v6-fix61(2026-08-31)

修复「设备列表页扫码时弹出『查询失败:登录已过期,请重新登录』」的体验问题。

用户操作:设备列表页右上角二维码(mode=query 扫码查设备,注意:真正「激活」是底部 + 按钮 mode=bind&activate=1)→ 触发 _queryDevice 读取 devicesProvider.future(GET /device/info/list)。当 token 过期:拦截器 ApiInterceptor.onResponse 识别到 code==401 或「token失效/登录」类文案 → 调 _refreshAndRetry 自动刷新令牌并重试一次;若刷新令牌也失败(refreshToken 失效),则 _notifyUnauthorized() 清空令牌并触发 authProvider.onUnauthorized 回调 → 路由 redirect 自动跳 /login。问题是拦截器最终 handler.reject(ApiException(401,'登录已过期,请重新登录')),该异常冒泡到扫码页 catch,被 formatApiError 取出后以「查询失败:登录已过期,请重新登录」SnackBar 暴露给用户,与登录页跳转形成竞态/困惑。

修复:新增 isUnauthorizedError() 统一识别登录失效异常;扫码页 4 个 catch(查设备 / 激活绑定 / 加载门店 / 加载分组)在捕获到登录失效时不再展示底层错误,直接 context.go('/login') 兜底跳转(与拦截器已触发的路由重定向一致)。自动刷新令牌能力保持不变(首次 401 静默重试成功则用户无感)。

类型 模块 内容
✅ 已修复 网络层 lib/services/api_client.dart:新增顶层 isUnauthorizedError(Object?),识别 ApiException(401) 或含「登录已过期」文案的登录失效异常,供 UI 层复用
✅ 已修复 扫码页 lib/screens/device/device_scan_page.dart:_queryDevice / _confirmBind / _pickGroup / _pickStore 四处 catch 增加登录失效判断——命中时跳过错误 SnackBar、改为 context.go('/login') 引导重新登录
✅ 已更新 版本号 登录页底部版本号 v6-fix60 → v6-fix61

v6-fix64(2026-08-31)

设备列表页登录过期错误提示与扫码页保持一致。

之前设备列表页加载失败时,若遇登录过期,会整屏显示「设备列表加载失败:登录已过期,请重新登录」+ 重试按钮(仍用 error.toString() 暴露底层异常)。拦截器已通过 _notifyUnauthorized 清空令牌并触发路由 redirect 跳 /login,此处应与之对齐——不再展示底层错误。

改动:lib/screens/home/device_list_page.dart 的 devicesAsync.when(error:) 分支:

  • 命中登录失效(isUnauthorizedError)时不再展示错误文案与重试按钮,改为显示加载占位(路由重定向会接管跳登录页);
  • 其他错误改用 formatApiError(error) 输出友好文案(不再直接 error.toString())。
类型 模块 内容
✅ 已修复 设备列表 lib/screens/home/device_list_page.dart:error 分支登录失效走加载占位、其余错误用 formatApiError;补充 api_client.dart 导入
✅ 已更新 版本号 登录页底部版本号 v6-fix63 → v6-fix64

v6-fix63(2026-08-31)

精简设置页与设备列表页:移除运行环境切换、显示运行指标开关及设备列表右上角二维码按钮。

用户反馈(截图):设置页中「运行环境」与「显示运行指标」两项不需要继续展示,要求直接删掉;设备列表页右上角二维码按钮也直接删掉。

改动:

  1. lib/screens/profile/settings_page.dart:
    • 移除「运行环境」_AppSettingsTile(含测试/预发切换、AppConfig.switchEnvironment、ApiClient.instance.reconfigure 等逻辑)。
    • 移除「显示运行指标」SwitchListTile 及其对应的 showRuntimeMetricsProvider watch。
    • 删除不再使用的导入:metrics_visibility_provider、app_config、environment、staging_config、test_config;删除不再使用的 _envLabel 私有方法。
  2. lib/screens/home/device_list_page.dart:移除 AppBar actions 中的二维码 IconButton(mode=query 扫码入口)。底部的「扫码激活」浮动按钮(mode=bind&activate=1)保留。
类型 模块 内容
✅ 已删除 设置页 lib/screens/profile/settings_page.dart:删除运行环境切换与显示运行指标开关
✅ 已删除 设备列表 lib/screens/home/device_list_page.dart:删除 AppBar 右上角二维码按钮
✅ 已更新 版本号 登录页底部版本号 v6-fix62 → v6-fix63

v6-fix62(2026-08-31)

修复扫码查询「未找到设备。请确认二维码内容」且无法识别/连接设备的问题,并优化错误提示。

用户反馈:设备列表页右上角扫码后弹「未找到设备。请确认二维码内容」,未能跳转到对应设备。

根因:device_scan_page.dart 的 _queryDevice(query 模式)把扫码 原始字符串 直接与 device.mac/deviceSn/id 做小写等值比较,但 bind 模式会用 _extractMacFromPayload 解析 JSON({"mac":"..."})或归一化 MAC。因此当二维码是 {"mac":"..."} JSON,或 MAC 分隔符/大小写与设备记录不一致时,query 模式永远匹配不到 → 误报「未找到设备」。此外原提示「请确认二维码内容」过于笼统,对「二维码有效但设备尚未联网/同步」的场景没有引导。

修复:

  1. query 模式新增 _parseScanPayload:解析纯 MAC(兼容 :/-/无分隔)与 JSON(mac/id/sn/deviceUid 等字段),并用 _normalizeMac 归一化比较,忽略分隔符与大小写差异。
  2. 本地列表未命中时,按 MAC/SN 调后端 /device/info/list 兜底查询,覆盖「设备已激活但本地缓存尚未刷新」的场景,命中即刷新列表并跳转详情。
  3. 错误提示分级:二维码无法识别(非 MAC 也非含标识的 JSON)→ 「无法识别该二维码,请扫描设备二维码或确认二维码内容」;二维码有效但设备暂未就绪 → 「未找到对应设备(MAC)。设备可能尚未联网或同步,请确认设备已开机联网、已激活并归属当前账号后重试」。
  4. 登录失效(401)仍按既有逻辑兜底跳登录页。
类型 模块 内容
✅ 已修复 扫码页 lib/screens/device/device_scan_page.dart:_queryDevice 改为先解析 payload(MAC/JSON)、归一化 MAC 比较;本地未命中时按 MAC/SN 后端兜底查询并跳转详情
✅ 已修复 扫码页 新增静态 _parseScanPayload(兼容纯 MAC 与 JSON)与 _normalizeMac(去分隔符转大写)
✅ 已优化 文案 lib/utils/i10n.dart:新增 scanPayloadUnrecognized(无法识别二维码)、scanDeviceNotReady(identifier)(设备暂未就绪引导);原 scanDeviceNotFound 不再使用
✅ 已更新 版本号 登录页底部版本号 v6-fix61 → v6-fix62

v6-fix59(2026-08-28)

修复环境切换后再操作导致的 LateInitializationError。

用户截图显示报错:LateInitializationError: Field '_dio' has already been initialized.,调用栈指向 ApiClient.reconfigure → SettingsPage 的环境切换 SegmentedButton。根因:ApiClient._dio 声明为 late final,reconfigure() 重复调用时会二次赋值,触发 LateInitializationError。修复后支持重复重建,并在环境/语言切换入口增加 try-catch,避免崩溃。

类型 模块 内容
✅ 已修复 网络层 lib/services/api_client.dart:ApiClient._dio 由 late final 改为 late,reconfigure() 改为返回 ({bool success, String? error}),允许安全重复调用,内部捕获异常避免抛崩溃
✅ 已修复 设置页 lib/screens/profile/settings_page.dart:环境切换 closure 加 try-catch,先切换环境、重建 Dio、提示「环境已切换,请重新登录」、再 logout;失败时 SnackBar 提示错误。语言切换也加 try-catch 防御
✅ 已更新 版本号 登录页底部版本号 v6-fix58 → v6-fix59

v6-fix58(2026-08-28)

移除登录页副标题「设备与系统运维监控」。

用户截图显示登录页标题「云定制主页管理」下方仍显示「设备与系统运维监控」一行副标题文字,需移除该文本及相关 UI 元素,保持页面其余布局与功能不受影响。

类型 模块 内容
✅ 已移除 登录页 lib/screens/login/login_page.dart 删除副标题 Text('设备与系统运维监控') 及其上方的 SizedBox(height: 8),登录页不再展示该文字
✅ 已更新 版本号 登录页底部版本号 v6-fix57 → v6-fix58

v6-fix57(2026-08-28)

优化 App「用户管理-新增用户」交互(依据 MuMu 录屏 云定制主页管理(5).mp4)。

打开新增/编辑用户弹窗时,系统默认先弹出「所属组织」选择界面,打断了先填表单(用户名/账号/密码等)的正常流程。调整为:组织选择置于表单填写完成之后,仅用户主动点击「所属组织」字段才展开。

类型 模块 内容
✅ 已修复 用户管理-新增/编辑用户 lib/screens/admin/sys/user_page.dart 的 _UserForm 中 OrgPickerFormField 显式设置 autoOpen: false,打开用户表单不再自动弹出组织选择器,需先填完必填信息、再主动点击字段触发
✅ 已更新 版本号 登录页底部版本号 v6-fix56 → v6-fix57

v6-fix56(2026-08-28)

修复 App 组织选择器交互问题(依据 MuMu 录屏 云定制主页管理(2)(3)(4).mp4)。

视频2/3:门店管理 → 点击编辑门店时,「所属组织」选择器在表单打开后自动弹出,影响操作流程。视频4:用户管理 → 编辑用户 → 点击「所属组织」选择器后,列表未将当前已选组织置顶,导致需滑动查找。

类型 模块 内容
✅ 已修复 门店编辑页 lib/screens/store/store_list_page.dart 中 _StoreFormSheet 的 OrgPickerFormField 显式设置 autoOpen: false,进入编辑/新增表单时不再自动弹出组织选择器,仅用户主动点击字段时才展开
✅ 已修复 组织选择器 lib/widgets/org_picker_sheet.dart 中 OrgPickerSheet 在过滤后把当前 _selectedId 对应的选项置顶到列表最前面,保持其他项原有层级顺序;搜索关键字为空时当前选择一目了然,搜索时仍按名称过滤
✅ 已更新 版本号 登录页底部版本号 v6-fix55 → v6-fix56

v6-fix55(2026-08-27)

用户纠正:v6-fix54 后加的"服务器地址"自由输入设置实为一条可切生产的入口(可手填生产 IP 58.220.83.58),违反"仅测试环境"要求。本版本移除该入口,改为"强制防生产切换"机制:默认锁定测试环境,永不可进入生产模式。

类型 模块 内容
✅ 已重构 环境配置 新增 lib/config/ 模块:AppEnvironment 枚举(仅 test / staging,刻意不含 production)、TestConfig / StagingConfig(测试/预发敏感配置分文件独立管理,禁止交叉引用生产)、AppConfig(按当前环境解析 origin/前缀/验证码开关,默认 test)、ProductionGuard(启动期强制守卫)
✅ 已移除 可切生产入口 删除 lib/utils/server_config.dart 及设置页"服务器地址"自由输入对话框(原可手填任意 URL 含生产 IP);所有网络层(api_client / auth_service / marquee_web_source)改为读 AppConfig 当前环境地址
✅ 已新增 启动守卫 main.dart 启动即调用 ProductionGuard.enforce():① 编译期 assert(!kAllowProduction)(kAllowProduction 恒 false);② 运行期解析当前后端 host,若命中生产拒绝名单(58.220.83.58 / api.ainetv.com / ainetv.com 或含 prod)则 print 清晰报错并 exit(1) 阻断启动,确保系统无法进入生产模式
✅ 已新增 环境切换函数 AppConfig.switchEnvironment(AppEnvironment) 仅接受预定义 test / staging 枚举值,显式排除 production,禁止解析/接收任何生产标识字符串;设置页仅提供 TEST/预发 分段切换(无生产按钮)
✅ 已清理 常量 AppConstants 移除 apiBaseUrl / apiFullBaseUrl / enableCaptcha(原注释含生产 IP 兜底),仅保留 apiPrefix;默认配置不再含任何生产默认值/兜底/隐式生产配置
✅ 已更新 版本号 登录页底部版本号 v6-fix54 → v6-fix55
✅ 已验证 构建 flutter analyze 0 error;release APK ops-console-release-v6-fix55.apk(33.9MB)验鲜:v6-fix55=1、ProductionGuard=1、默认 origin=ips-test.ainetv.com(测试);prod-ip 仅出现在守卫拒绝名单中,非活动端点

v6-fix54(2026-08-27)

类型 模块 内容
✅ 已修复 Web-公司介绍内容展示 修复 Web 端「公司介绍」选中大类后右侧小类列表偶发"暂无数据"的问题:parseIntroSubcategoryList / parseIntroDetailList 现在兼容后端 {data: [...]} 与 {data: {list, totalCount}} 两种返回;loadChildren 始终以当前 treeData 重新定位节点,避免 selectedNode 引用过期,并在 API 解析为空时使用树节点已携带的完整小类数据兜底展示
✅ 已优化 App-公司介绍数据加载 门店内容页加载大类由 getIntroCategoryAll() + 客户端过滤改为 getIntroCategoryList(page, limit, orgId) 服务端过滤,与 Web 端 store-company-intro.vue 的查询方式完全一致,避免门店权限/分页差异导致数据不一致
✅ 已优化 App-公司介绍保存字段 小类表单的 categoryType 预填父大类值;保存时若为空则不下发,与 Web 端保存行为对齐,避免空字符串覆盖后端默认值
✅ 已调整 文案 移除代码注释中的"门店维度"表述;管理首页入口、页面标题继续使用 companyIntro/introCategoryTitle(即"公司介绍")
✅ 已更新 版本号 登录页底部版本号 v6-fix53 → v6-fix54

v6-fix53(2026-08-27)

类型 模块 内容
✅ 已重构 公司介绍-门店维度 将公司介绍入口从「大类→小类→详情」三级结构改为「门店维度」展示:新增 IntroStoreListPage 门店列表页(参考门店管理页布局,支持关键字搜索门店),点击进入 IntroStoreContentPage 门店介绍内容页
✅ 已新增 公司介绍-门店介绍内容页 按门店加载其下所有公司介绍大类,并按 categoryType 内容类型分组呈现;每个分类可展开查看小类,每个小类可展开查看详情内容;数据层级:门店 → 内容类型 → 分类 → 小类 → 详情
✅ 已保留 公司介绍-原管理入口 原 /admin/intro/category 三级管理页保留,可作为后台管理备用入口;管理首页公司介绍入口改为 /admin/intro/store-list
✅ 已新增 公司介绍-快捷操作 门店内容页支持直接在分类/小类/详情层级新增、编辑、删除;新增分类时自动带入当前门店 orgId
✅ 已更新 版本号 登录页底部版本号 v6-fix52 → v6-fix53

v6-fix52(2026-08-27)

类型 模块 内容
✅ 已修复 公司介绍-小类/详情图片上传 根因:原 UploadService.uploadImage 走 POST /sys/upload 通用本地上传,与公司介绍模块(Web 端 company-intro-subcategory-form.vue)使用的腾讯云 COS STS 直传通道不一致,导致上传失败、无法保存。现改为对齐 Web 流程:计算文件 MD5 → GET /theme/resource/check-md5 秒传判断 → GET /theme/upload/credential 取 STS 临时凭证(bucket/region/key)→ 用临时密钥直传 COS(putObject,原生 q-sign-algorithm=sha1 签名)→ POST /theme/resource/register 注册 tv_resource → 返回 https://ipscdn.ainetv.cn/{key} 访问地址
✅ 已新增 依赖 新增 crypto(文件 MD5);腾讯云 COS 直传客户端 vendoring 到 lib/services/cos/cos_client.dart(基于 flutter_cos_client MIT 实现,修复签名有效期硬性 now+3600 与后端 STS ExpiredTime 冲突导致的 403,去掉未维护 0.0.1 包依赖与 mime 依赖)
✅ 已完善 错误提示 上传各阶段(凭证不完整 / 云存储失败 / 资源注册失败)统一抛出 ApiException,message 为可展示中文;前端 catch 已能显示 e.message,便于定位失败原因
✅ 已更新 版本号 登录页底部版本号 v6-fix51 → v6-fix52

v6-fix51(2026-08-26)

类型 模块 内容
✅ 已修复 公司介绍-新增/修改 修复「保存失败」提示不展示后端真实原因的问题:拦截器返回的是 DioException(其 .error 才是 ApiException),原代码 e is ApiException ? e.message : t.saveFailed 永远走兜底,导致只能看到「保存失败」。三个表单(大类/小类/详情)的保存与删除异常提示统一改为 formatApiError(e),可正确显示后端 msg
✅ 已修复 公司介绍-新增大类 与 Web 前端字段对齐:saveIntroCategory 请求体移除后端未使用的 orgName;orgId 在发送前 int.tryParse 转为数字,与 Web 一致
✅ 已新增 公司介绍-表单校验 新增大类/小类/详情保存前进行客户端校验:名称/标题/类型编码/媒体地址非空;类型编码禁止中文。减少无效请求,错误反馈更即时
✅ 已更新 版本号 登录页底部版本号 v6-fix50 → v6-fix51

v6-fix50(2026-08-26)

类型 模块 内容
✅ 已修复 网络层(写操作失败) api_client.dart 的 ApiInterceptor.onRequest 不再给 POST/PUT 等业务 body 注入防缓存字段 t:此前该字段会作为未知列进入后端 insert,导致「列表能读、新增/修改 500 失败」。防缓存 t 仅在 GET 的 query 上保留;写入请求 body 保持纯净
✅ 已更新 版本号 登录页底部版本号 v6-fix49 → v6-fix50

v6-fix49(2026-08-26)

类型 模块 内容
✅ 已更新 后端环境切换 constants.dart 的 apiBaseUrl 由生产环境 http://58.220.83.58 切回测试环境 https://ips-test.ainetv.com(HTTPS);生产地址保留为注释便于后续切回
✅ 已恢复 登录验证码 enableCaptcha 由 false 恢复为 true:测试环境 ips-test.ainetv.com 提供 /api/captcha.jpg(HTTP 200),登录页重新显示验证码输入与刷新
✅ 已更新 版本号 登录页底部版本号 v6-fix48 → v6-fix49

v6-fix48(2026-08-26)

类型 模块 内容
✅ 已更新 桌面/启动图标 将 com_ainetv_ainetvcloud_xxxhdpi_640dpi_云管理.png 生成并覆盖 Android 5 个密度(mdpi/hdpi/xhdpi/xxhdpi/xxxhdpi)的 mipmap-*/ic_launcher.png
✅ 已更新 登录页 logo 登录页继续使用 assets/images/logo.png,已同步替换为同一源图
✅ 已更新 应用内图标 设置页「关于」弹窗新增 applicationIcon,统一使用 assets/images/logo.png(64×64 显示)
✅ 已更新 版本号 登录页底部版本号 v6-fix47 → v6-fix48

v6-fix47(2026-08-26)

类型 模块 内容
✅ 已修复 登录页 logo 将顶部蓝色 Icons.monitor_heart 图标替换为橙色云朵 logo 图片(assets/images/logo.png,文字已改为「云管理」,保留底部「ainetv」)
✅ 已修复 验证码加载失败 新增 AppConstants.enableCaptcha 开关(默认 false):关闭时隐藏验证码输入区与刷新按钮,登录时 captcha/uuid 传空串,避免生产环境 58.220.83.58 未暴露 /api/captcha.jpg 导致登录页报错
✅ 已更新 版本号 登录页底部版本号 v6-fix46 → v6-fix47

v6-fix46(2026-08-26)

类型 模块 内容
✅ 已更新 后端环境切换 constants.dart 的 apiBaseUrl 由测试环境 https://ips-test.ainetv.com 切换为生产环境 http://58.220.83.58(明文 HTTP,Android 已开启 usesCleartextTraffic);测试地址保留为注释便于回退
✅ 已更新 版本号 登录页底部版本号 v6-fix45 → v6-fix46

v6-fix45(2026-08-26)

类型 模块 内容
✅ 已修复 手机端全屏显示 修复应用在手机上未全屏、四周出现黑边的问题:main.dart 启动时设置 SystemUiMode.edgeToEdge + 透明状态栏/导航栏;styles.xml / styles-night.xml 的 NormalTheme 启用 windowDrawsSystemBarBackgrounds 并将状态栏/导航栏颜色设为透明
✅ 已更新 版本号 登录页底部版本号 v6-fix44 → v6-fix45

v6-fix44(2026-08-26)

类型 模块 内容
✅ 已移除 公司介绍门店筛选 移除大类列表顶部「筛选门店」FilterChip 区域(含「全部门店」多选),保留大类/小类/详情三级列表、表单、树形组织选择器、图片/视频上传等其余所有功能与布局
✅ 已清理 冗余代码 移除 _stores、_selectedOrgIds、_loadStores、_applyOrgFilter、_buildOrgFilter 及 StoreInfo import;_storeName 改为仅从组织树回查;initState 改调用 _loadOrgNodes() 以支持列表门店名称回显
✅ 已更新 版本号 登录页底部版本号 v6-fix43 → v6-fix44

v6-fix43(2026-08-26)

类型 模块 内容
✅ 已调整 公司介绍门店选择器节点规则 树形组织选择器仅展示渠道(type=1)、代理商(type=2)与门店(type=3);渠道与代理商节点 selectable=false(禁用、灰色、不可点击);门店节点保持可选;平台(type=0)与设备分组(type=4)不展示
✅ 已新增 节点选择工具方法 新增 _isOrgVisible、_isOrgSelectable,统一控制选择器内组织节点的展示与可选状态
✅ 已更新 版本号 登录页底部版本号 v6-fix42 → v6-fix43

v6-fix42(2026-08-26)

类型 模块 内容
✅ 已改造 公司介绍大类门店选择器 「所属门店」从 DropdownButtonFormField 改为与用户管理一致的树形组织选择器:底部弹窗、实时搜索组织名称、按组织层级缩进展示;复用 OrgPickerSheet/OrgPickerFormField 组件,数据走 OrgService.getOrgTree()(组织树 / flatList / select 三阶回退)
✅ 已实现 编辑态自动高亮当前节点 编辑大类时 OrgPickerFormField 自动展开选择器,并默认选中高亮当前 orgId 对应的门店组织节点;若当前 category 所属组织不在用户可见树中,自动补入选项保证可展示
✅ 已新增 组织树工具方法 intro_category_page 新增 _loadOrgNodes、_buildOrgPickerOptions、_buildHierarchicalOptions、_buildHierarchyFromFlatList、_findOrgByName、_findOrgById,与用户管理 _UserForm 对齐
✅ 已更新 版本号 登录页底部版本号 v6-fix41 → v6-fix42

v6-fix41(2026-08-26)

类型 模块 内容
✅ 已修复 公司介绍大类门店选择 修复新增/编辑大类时「所属门店」下拉为空、无法选择门店的问题:intro_category_page._loadStores 改用 OrgService.getMyStores()(组织树 / myStores / listByLoginOrg 三阶回退),覆盖当前用户可见的所有门店;表单打开前强制重新加载门店;编辑时若当前 category 所属门店不在返回列表中,自动补入下拉项;空字符串 orgId 统一视为未选择,避免收起态显示空白
✅ 已新增 国际化 i10n.dart 新增 introStoreLoadFailed(门店列表加载失败提示)中英 key
✅ 已更新 版本号 登录页底部版本号 v6-fix40 → v6-fix41

v6-fix38(2026-08-25)

类型 模块 内容
✅ 已实现 公司介绍多门店筛选 大类列表页门店筛选由单选下拉改为 FilterChip 多选,空选表示「全部门店」,数据按所选门店列表实时过滤
✅ 已实现 公司介绍图片上传 新增 UploadService,小类/详情表单支持从相册选择图片、本地即时预览、Dio FormData 上传至 /sys/upload,成功后自动回填 mediaUrl 并切换为网络预览;保留手动输入 mediaUrl 兜底
✅ 已对齐 大类表单 新增「所属门店」必填下拉(orgId/orgName 联动);移除 Web 后台不存在的 status 字段,保存字段与 Web 端一致
✅ 已对齐 小类/详情表单 新增「排序号」字段;status 语义与 Web 后台统一为 1=启用/0=禁用;小类新增可选「类型编码」字段(默认预填父大类编码)
✅ 已改造 保存接口分流 IntroService 三个 save* 方法按 id 是否存在分流到 /save(新增)或 /update(编辑),与 Web 端 companyIntro.ts 保持一致
✅ 已修正 状态语义 IntroCategory/IntroSubcategory/IntroDetail 的 _parseStatus 改为后端原值映射(1=启用,0=禁用),列表 Chip 文案同步改为「启用/禁用」
✅ 已新增 国际化 i10n.dart 补充 introFilterStores、introSelectStoresHint、introCategoryStore、introStoreRequired、introSortOrder、introEnabled、introDisabled、introUploadImage、introPickImage、introImagePreview、introUploading、introUploadFailed、introInsertImage 中英 key
✅ 已更新 版本号 登录页底部版本号 v6-fix37 → v6-fix38

v6-fix40(2026-08-26)

类型 模块 内容
✅ 已实现 滚动字幕速度档位化 数字速度输入改为 5 档下拉选择(慢/较慢/中/较快/快),新增 MarqueeConfig/MarqueeSpeed 配置结构,提供 setSpeed/setGrade/copyWith 接口与 speedFromValue/gradeFromValue 历史值吸附;落库仍为 Web 端原值(200/100/50/30/10),卡片与表单直观显示当前生效档位
✅ 已实现 滚动字幕级别选择 新增 3 级「级别」下拉(危险/紧急/普通),落库原值(50/40/20),与 Web 端 scrolling-text.data.ts 一致;列表与表单显示当前生效级别
✅ 已实现 滚动字幕字体颜色色板 「字体颜色 / 背景颜色」由手动输入 #HEX 改为对齐 Web 端 el-color-picker 的色板弹窗:饱和度/明度 2D 选择区 + 色相条 + HEX 输入框 + 实时预览 + 取消/确定,回填 #RRGGBB
✅ 已修复 公司介绍大类门店名称 新增/编辑大类「所属门店」选中后正确展示门店组织名称:下拉增加 selectedItemBuilder 确保收起态渲染所选名称;列表卡片在接口未返回 orgName 时按 orgId 从本地门店列表回查名称
✅ 已对齐 公司介绍小类图片上传 小类素材固定为图片(与 Web 端一致,Web 端无媒体类型选择、始终 mediaType=image);新增图片类型(jpg/png/gif/webp)与大小(≤300KB,建议 1920×1080)校验,超限给出提示;上传仍走后端 /sys/upload,返回 URL 存入 mediaUrl
✅ 已对齐 公司介绍详情图片/视频上传 详情表单保留「媒体类型」图片/视频切换;图片(≤3MB)/ 视频(≤30MB)类型与大小校验与 Web 端一致,视频走 pickVideo;上传路径与返回结构同小类

v6-fix39(2026-08-25)

类型 模块 内容
✅ 已实现 滚动字幕起止时间筛选 「滚动字幕」新增/编辑表单的开始时间、结束时间改为纯 HH:mm:ss 滚轮选择器,不再复用日期时间选择器,与 Web 端 /theme/scrollingText 时间字段格式(HH:mm:ss)一致
✅ 已实现 时间滚轮控件 新增 _TimePickerSheet 底部弹窗:三列 ListWheelScrollView 滚轮(时 00-23 / 分 00-59 / 秒 00-59),FixedExtentScrollController 定位初始值;底部「取消/确定」按钮,确定后回传 DateTime(2000,1,1,h,m,s),与 MarqueeMessage._parseDateTime 基准日期一致
✅ 已对齐 默认值与范围 新增字幕默认起止时间为 00:00:00 ~ 23:59:59;编辑时回显既有 startTime/endTime;秒级精度,可选范围覆盖全天,与 Web 后台一致
✅ 已新增 国际化 i10n.dart 补充 marqueeHour/marqueeMinute/marqueeSecond(时/分/秒)中英 key,供滚轮单位标签使用
✅ 已清理 死代码 移除 _TimePickerSheet._buildWheel 中的未使用 selected 局部变量,消除 analyze 警告
✅ 已更新 版本号 登录页底部版本号 v6-fix38 → v6-fix39

v6-fix37(2026-08-25)

类型 模块 内容
✅ 已修复 组织选择器高亮 OrgPickerSheet 列表项选中时立即通过本地 _selectedId 状态更新高亮背景、文字颜色与对勾图标,并延迟 120ms 后关闭弹窗,解决选中条目需要额外按一次才显示高亮的问题
✅ 已优化 选择器视觉反馈 已选项文字加粗并显示 Icons.check_circle,高亮底色透明度由 0.24 提升至 0.38,选中状态与视觉反馈同步呈现
✅ 已更新 版本号 登录页底部版本号 v6-fix36 → v6-fix37

v6-fix36(2026-08-25)

类型 模块 内容
✅ 已修复 滚动字幕数据源 移动端 MarqueeWebSource 默认接口由 /marquee/list 改为与 Web 后台一致的 /theme/scrollingText/list;解析 totalCount 与 Web 端字段映射(orgId→storeId、orgName→storeName、scrollSpeed→speed、bgColor→backgroundColor),解决移动端列表为空的问题
✅ 已修复 滚动字幕新增/编辑 修复 _MarqueeFormState 中 late String? _storeId 未在 initState 初始化导致的 LateInitializationError;新增「状态」下拉框(启用/禁用),表单提交携带真实状态
✅ 已改造 滚动字幕服务 MarqueeService 新增/编辑/删除/启用/禁用均优先调用 Web 后台 `/theme/scrollingText/save
✅ 已优化 列表卡片 _StatusChip 改为「启用/禁用」;_MarqueeCard 操作按钮改为「启用/禁用」;时间范围展示改为 HH:mm:ss,与 Web 后台一致
✅ 已新增 国际化 i10n.dart 补充 marqueeStatus、marqueeStatusEnabled、marqueeStatusDisabled 中英 key
✅ 已更新 版本号 登录页底部版本号 v6-fix35 → v6-fix36

v6-fix35(2026-08-25)

类型 模块 内容
✅ 已重构 设备详情页 DeviceDetailPage 按需求分四个清晰区块:基本信息(设备名称、设备 ID、型号、状态)、配置参数(所属门店、分组、房号、位置、操作系统、设备序列号、设备 UID、创建时间)、网络信息(IP 地址、MAC 地址)、运行时数据(在线时长、最后活跃时间);原信息卡拆分为带标题的分区块卡片,缺口字段(设备名称 / 设备 ID / 最后活跃时间)已补齐并回显
✅ 已更新 详情头部 标题由「型号」改为「设备名称」(型号降级为副标题),与列表点击进入的语义一致
✅ 已新增 国际化 i10n.dart 补充 basicInfo、configParams、networkInfo、runtimeData、deviceName、deviceId、modelLabel、deviceSnLabel、deviceUidLabel、createTime、lastActiveTime 等中英 key
✅ 已保留 刷新同步 详情页下拉刷新(RefreshIndicator)刷新 deviceDetailProvider,与设备列表数据保持一致;「下发指令 / 修改分组」按钮保持可用
✅ 已更新 版本号 登录页底部版本号 v6-fix34 → v6-fix35

v6-fix34(2026-08-25)

类型 模块 内容
✅ 已实现 Web 端滚动字幕数据源 新增 lib/services/marquee_web_source.dart 作为独立的 Web 端内容获取层;支持配置请求地址(baseUrl / path)与请求方式(GET/POST 等),内置超时、网络异常、HTTP 错误、业务码错误、解析失败等完善错误处理;将结果封装为结构化 MarqueeFetchResult
✅ 已扩展 滚动字幕数据模型 MarqueeMessage 新增 fontColor、backgroundColor、fontSize、level、startTime、endTime 字段,兼容 Web 端返回的 JSON 格式
✅ 已改造 字幕服务 MarqueeService.getMarqueeList 优先调用 MarqueeWebSource 获取 Web 端数据,失败时自动回退到本地 SharedPreferences 缓存
✅ 已更新 UI MarqueeManagementPage 列表卡片展示字体颜色、背景颜色、字体大小、级别、生效时间;新增/编辑表单支持设置颜色、字号、级别与起止时间
✅ 已新增 国际化 i10n.dart 补充字体颜色、背景颜色、字体大小、级别、开始/结束时间等中英 key
✅ 已更新 版本号 登录页底部版本号 v6-fix33 → v6-fix34

v6-fix33(2026-08-25)

类型 模块 内容
✅ 已实现 滚动字幕管理 在「管理」界面新增「滚动字幕管理」入口;新增 MarqueeManagementPage(/admin/marquee),支持按门店查看、新增、编辑、删除、查询滚动字幕,并区分不同门店内容
✅ 已实现 下发/取消下发 字幕状态区分为「待下发」与「已下发」;点击「下发」调用设备指令 marqueeUpdate 按组织下发到门店设备,成功后状态更新为已下发;点击「取消下发」重置为待下发
✅ 已新增 数据模型 lib/models/marquee_message.dart 定义滚动字幕实体;lib/services/marquee_service.dart 基于 SharedPreferences 实现字幕记录本地持久化与 CRUD,并提供下发/取消下发能力
✅ 已新增 国际化 lib/utils/i10n.dart 补充滚动字幕管理相关 key(管理标题、新增/编辑、字幕内容、滚动速度、目标门店、状态、下发/取消下发等)
✅ 已更新 管理首页 lib/screens/admin/admin_hub_page.dart 增加「滚动字幕管理」入口卡片
✅ 已更新 路由 lib/app/router.dart 增加 /admin/marquee 路由
✅ 已更新 版本号 登录页底部版本号 v6-fix32 → v6-fix33

v6-fix32(2026-08-25)

类型 模块 内容
✅ 已修复 激活码管理 英文语言下激活码管理页所有中文硬编码文案(门店选择、当前激活码、复制、最大激活数、已激活数、创建时间、生成/重置激活码、生成弹窗等)全部替换为 AppLocalizations 国际化 key,切换英文后完整显示英文
✅ 已新增 国际化 i10n.dart 补充 copy、generate、generateActivationCodeHint、activationCodeCopied、activationCodeLoadFailed、generateFailedWithError 等 key
✅ 已更新 版本号 登录页底部版本号 v6-fix31 → v6-fix32

v6-fix31(2026-08-25)

类型 模块 内容
✅ 已修复 管理模块返回键 管理中心「设备管理」「激活码」入口原 context.push('/device') / context.push('/device/activation') 会把页面压入设备分支导航栈,导致底部导航错乱 + 左上角返回箭头显示/点击异常 → 在 /admin 分支下新增别名路由 /admin/device(复用 DeviceListPage)与 /admin/activation(复用 DeviceActivationPage),入口改为 context.push('/admin/device') / context.push('/admin/activation');仍保留 push 方式,用户可通过系统返回键回到管理首页
✅ 已修复 设备列表 AppBar DeviceListPage 的 AppBar 增加 automaticallyImplyLeading: false,从管理模块进入时不显示左上角返回箭头(DeviceActivationPage 此前已设置,保持生效)
✅ 已更新 版本号 登录页底部版本号 v6-fix30 → v6-fix31

⚠️ 备注:

  • 原 /device 与 /device/activation 路由保留不变(设备 tab 入口及设备详情内的跳转仍使用),本次仅新增 /admin 分支下的别名路由,无命名冲突。

v6-fix30(2026-08-25)

类型 模块 内容
✅ 已实现 角色选择器 用户编辑页「角色」字段由下拉框改为可视化 ChoiceChip 横向选择器;编辑时根据 roleId/roleName/roleNames 自动选中对应角色,选中项显示主题色高亮背景 + Icons.check 勾选图标;角色来自动态 widget.roles,新增用户默认选中当前登录用户角色
✅ 已删除 全局返回悬浮按钮 移除 AppBottomNav 中的全局返回 FAB(_BackFabLocation、floatingActionButton、floatingActionButtonLocation)及 navigator_key.dart 导入;同步删除不再被引用的 lib/app/navigator_key.dart,并移除 router.dart 中的 navigatorKey 引用
✅ 已删除 AppBar 返回键 扫描 lib/screens/** 所有 AppBar,移除自定义 leading 返回按钮(device_scan/device_group/store_config 三页),并对全部子页面 AppBar 设置 automaticallyImplyLeading: false,统一移除左上角返回箭头,保留标题与 actions
✅ 已更新 版本号 登录页底部版本号 v6-fix29 → v6-fix30

v6-fix29(2026-08-25)

类型 模块 内容
✅ 已实现 组织选择器 新建/编辑门店与用户编辑页「所属组织」字段进入页面时自动弹出选择弹窗,已选项自动高亮勾选;弹窗支持关键字实时搜索与层级缩进展示
✅ 已实现 返回悬浮按钮 在 AppBottomNav 外层 Scaffold 增加全局返回悬浮按钮(左上角、仅非首页显示),点击优先 pop,不可 pop 时回到首页
✅ 已删除 AppBar 返回键 移除「设备管理」「用户管理」「激活码」「公司介绍」四页 AppBar 左上角返回箭头,统一由全局返回悬浮按钮负责返回
✅ 已更新 版本号 登录页底部版本号 v6-fix28 → v6-fix29

v6-fix28(2026-08-25)

类型 模块 内容
✅ 已修复 默认选中 门店编辑页与用户管理编辑页进入时,已关联的组织/角色选项自动高亮选中;用户编辑时若后端未返回 ID,通过名称反向匹配并增加只读占位项兜底展示
✅ 已修复 门店组织搜索 编辑门店「所属组织」搜索框输入关键字后,新增实时搜索结果列表;点击结果立即更新 _parentId、清空搜索关键字并刷新页面,修复「选中无反应」问题
✅ 已优化 门店默认上级 编辑门店加载组织树后,若 store.parentId 为空,自动在组织树中按 store.orgId 查找门店节点并取其 parentId 作为默认上级;新增/仍为空时回退到当前用户所在组织
✅ 已更新 版本号 登录页底部版本号 v6-fix27 → v6-fix28

v6-fix27(2026-08-25)

类型 模块 内容
✅ 已优化 门店表单 编辑门店「所属组织」下拉选项仅渲染渠道(type=1)与代理商(type=2),门店类型(type=3)已过滤隐藏;新增组织名称关键字搜索框,输入时实时模糊匹配并动态筛选渠道/代理组织
✅ 已优化 默认选中 新增门店时,若未指定上级组织则默认选中当前登录用户所在组织;新增用户时,默认选中当前登录用户的所属组织与角色
✅ 已更新 用户模型 User 模型新增 orgId/roleId 字段;AuthService 从登录响应与 /sys/user/info 中解析并持久化,供表单默认选中使用
✅ 已更新 版本号 登录页底部版本号 v6-fix26 → v6-fix27

v6-fix26(2026-08-25)

类型 模块 内容
✅ 已修复 用户编辑 编辑用户时角色字段为空 → 当列表接口未返回角色信息时,自动调用 /sys/user/info/{id} 拉取详情;同时通过 roleName/roleNames 反向匹配 roleId,确保角色下拉与用户信息页/Web 端展示一致
✅ 已优化 用户表单 新增/编辑用户「所属组织」下拉改为按组织层级自上而下排序:优先调用 /sys/org/tree,递归扁平化为带深度的选项并逐层缩进展示;失败时回退到 /sys/org/flatList 并按 parentId 重建层级顺序
✅ 已修复 返回按钮 管理模块入口进入的「设备列表」「激活码管理」「用户管理」页面左上角返回箭头点击无响应 → 统一将返回目标改为 /admin,确保回到管理首页
✅ 已更新 版本号 登录页底部版本号 v6-fix25 → v6-fix26

v6-fix25(2026-08-25)

类型 模块 内容
✅ 已优化 门店表单 编辑门店「所属组织」下拉列表改为按组织层级自上而下排序:调用 /sys/org/tree 获取树形结构,递归扁平化为带深度的选项;列表中从最上级组织开始,逐层缩进展示其下级组织,层级关系清晰
✅ 已更新 版本号 登录页底部版本号 v6-fix24 → v6-fix25

v6-fix24(2026-08-25)

类型 模块 内容
✅ 已修复 修改分组 分组下拉仍展示全部门店分组 → 修复 /device/group/list 接口参数:Web 端按 orgId 过滤门店,移动端此前只传 storeId 导致后端忽略门店过滤;现同时携带 orgId 与 storeId,确保仅返回当前设备所属门店的分组
✅ 已更新 版本号 登录页底部版本号 v6-fix23 → v6-fix24

v6-fix23(2026-08-25)

类型 模块 内容
✅ 已修复 修改分组 分组下拉报 DioException [unknown]: null → 改为调用已有接口 /device/group/list?storeId=xxx;同时增强 Device.storeId 解析,支持从 store/storeInfo/org 嵌套对象取门店 ID
✅ 已修复 新建门店保存 保存仍提示「未知异常」→ _save() 先按 Web 端字段契约(type='STORE'/status='ACTIVE')提交;失败时自动 fallback 到旧后端兼容格式(type=3/status=1),并展示后端返回的具体错误信息
✅ 已修复 首页快捷操作 「系统管理」文字/图标有误 → 改为「用户管理」并替换为 Icons.people
✅ 已修复 返回按钮 管理模块下的「设备管理」「激活码」「用户管理」「公司介绍」页面左上角返回键无响应 → 统一为各页 AppBar 增加显式 leading 返回按钮(可 pop 时 pop,不可 pop 时回退到 /admin)
✅ 已更新 版本号 登录页底部版本号 v6-fix22 → v6-fix23

v6-fix22(2026-08-24)

类型 模块 内容
✅ 已调整 首页快捷操作 移除「媒资管理」入口;当前项目阶段暂不需要,后续如需可在 HomePage._buildDashboard 中恢复 _QuickAction(mediaManagement)
✅ 已更新 版本号 登录页底部版本号 v6-fix21 → v6-fix22

v6-fix21(2026-08-24)

类型 模块 内容
✅ 已修复 修改分组 分组下拉改为仅展示当前设备所属门店的分组:调用门店专用接口 /sys/store/deviceGroups/{storeId},避免 /device/group/list 跨门店返回全部分组;无门店上下文时保留「未分组」与当前分组可选
✅ 已修复 返回按钮 扫码激活页左上角返回键无响应 → AppBar 增加显式 leading 返回按钮;全面排查并把设备列表/扫码页/首页管理入口/管理中心的 context.go 改为 context.push,确保子页面返回正常;为设备分组页、门店配置页也增加显式返回兜底
✅ 已修复 门店保存 门店保存仍失败(提示「未知异常,请联系管理员」)→ 对齐 Web 端 /sys/org/saveOrUpdate 字段契约:type 改为字符串 'STORE',新增 orderNo/status,补充 storeProfile 对象(storeName/phone/address/province/city);移除后端不识别字段;所属组织下拉仅展示代理商(type=2),与 Web 端一致
✅ 已更新 版本号 登录页底部版本号 v6-fix20 → v6-fix21

⚠️ 备注:

  • 门店保存字段已按 Web 端「新增门店」payload 重构;若后端仍返回具体业务错误,弹窗会展示后端 msg,请把完整错误文字发我进一步对齐。
  • 返回按钮修复后,从底部导航进入的 tab 根页(首页/设备/门店/管理/我的)仍保持 go 替换,子页面统一使用 push,返回行为与原生一致。

v6-fix20(2026-08-24)

类型 模块 内容
✅ 已修复 新增门店 门店新增保存时报错 → _save() 增加「所在地区」「所属组织」必选项校验;保存失败/成功/校验失败均通过页面中央 AlertDialog 提示,避免 SnackBar 被遮挡
✅ 已优化 门店表单 新增 i18n 词条 regionRequired/parentOrgRequired;硬编码中文接入国际化
✅ 已修复 激活码管理 「重置激活码」结果提示改为页面居中 AlertDialog 展示(成功/失败均居中),替代原左下角 SnackBar
✅ 已更新 版本号 登录页底部版本号 v6-fix19 → v6-fix20

v6-fix19(2026-08-24)

类型 模块 内容
✅ 已修复 设备列表 顶部搜索框 hint 被截断(搜索设备名称 / 房号)→ 顶部改为两行布局:第一行放门店下拉 + 型号筛选,第二行放全宽搜索框,确保 hint 完整显示;i18n searchDeviceHint 中英文词条已确认同步
✅ 已修复 设备详情 遥测字段(位置 / 操作系统 / 运行时长)全显示空或 0分 → Device.fromJson 新增详情响应兜底解包(`{device
✅ 已修复 修改分组 弹窗原显示「所属分组 ID」文本输入框 → 改为 DropdownButtonFormField 分组名称下拉,进入时按设备所属门店拉取 /device/group/list,下拉显示分组名称(groupName)、提交 groupId,与 Web 端一致;无门店上下文时安全降级
✅ 已修复 公司介绍 左上角返回箭头点击无响应 → AppBar 增加显式 leading 返回按钮:context.pop() 回管理中心,内部层级逐级返回,无法 pop 时兜底跳转 /admin
✅ 已修复 编译 修复 Device.fromJson 引用未定义的 _firstNum 导致的编译错误(原交付版本潜在隐患);补充 num? _firstNum(...) 静态辅助方法
✅ 已优化 i18n 新增 back(返回)、groupListLoading(加载分组列表…)等词条,弹窗内所有硬编码中文均接入 lib/utils/i10n.dart
✅ 已更新 版本号 登录页底部版本号 v6-fix18 → v6-fix19

⚠️ 备注:

  • 设备详情遥测依赖后端 /device/info/info/{id} 实际返回字段;已做 device/info/data 等多层包络与 cpu_usage/os/uptime 等常见别名兼容,若后端确无数据则统一显示「无」,不崩溃。
  • 修改分组下拉依赖设备携带的门店 ID(Device.storeId);若该字段后端未返回,下拉仅含「未分组」与当前分组,仍可正常提交。

⏳ 待验收:4 项修复在真机/模拟器上的实际表现。


v6-fix18(2026-08-24)

类型 模块 内容
✅ 已实现 新增门店 激活码改为由系统依据 web 端已有规则自动生成:移除手动输入框,保存门店后若终端数>0 自动调用 /device/activationCode/generate;每次点击「创建激活码」仅生成一个唯一码
✅ 已实现 门店编辑 编辑页直接展示「最大终端数 / 已用终端数」及当前正在使用的激活码,并提供「创建激活码」按钮
✅ 已修复 门店详情 创建时间字段空白 → StoreInfo 兼容 createTime/create_time/createdTime/createdAt/created_at 等常见别名;列表项与详情弹窗均补充展示创建时间
✅ 已修复 语言切换 切换英文后启动报错「token 失效」→ ApiInterceptor 刷新 token 成功后同步持久化到 CredentialStorage,避免语言切换/进程重启后恢复到旧令牌
✅ 已修复 扫码页 英文模式下扫码页全部文案接入 i10n,包括标题、提示、权限、弹窗、成功/失败提示等
✅ 已优化 门店表单 省市区、详细地址、联系电话、所属组织、保存/创建按钮等剩余硬编码中文全部接入 i10n

⏳ 待验收:新增门店自动生成激活码、编辑页终端数/激活码展示、英文切换不报错、扫码页英文文案。


v6-fix17(2026-08-24)

类型 模块 内容
✅ 已修复 设备模型 新增 Device.model 字段,按 model/modelName/deviceModel/productModel/productName/board/hardware/brand/deviceType/type 等常见别名解析真实型号
✅ 已修复 设备显示 DeviceListTile / DeviceDetailPage 标题统一使用 device.model,避免把 MAC 地址误当型号展示
✅ 已修复 型号过滤 设备列表「型号」筛选框改为基于 Device.model 过滤
✅ 已优化 降级处理 型号解析不到时,依次降级为 name(若 name 不是 MAC)→ deviceSn → mac;并新增 _isMacAddress 识别 MAC 格式,确保 MAC 不会混入型号展示

⏳ 待验收:设备标题是否显示真实型号(非 MAC)。


v6-fix16(2026-08-24)

类型 模块 内容
✅ 已实现 设备列表 顶部搜索区新增「型号」输入框,按 Device.name / deviceSn 实时过滤设备列表
✅ 已优化 设备列表 Riverpod AsyncValue.when 启用 skipLoadingOnRefresh/skipLoadingOnReload,刷新/重新加载时保留已有数据,避免全屏转圈覆盖已加载项
✅ 已优化 设备列表 门店下拉已加载过门店后不再重新显示转圈;状态 Chip 颜色与 DeviceStatus 严格对应(在线绿/离线灰/告警橙)

⏳ 待验收:型号筛选是否生效、刷新是否不再全屏转圈。


v6-fix15(2026-08-24)

类型 模块 内容
✅ 已修复 设备列表 标题前增加「型号:」前缀(如「型号:rk3566_r」),并接入 i10n
✅ 已修复 扫码页 移除 AppBar「相册识别」按钮,进入页面即直接调用摄像头扫描;说明当前代码无「实时截屏/摄像头」选择弹窗,若仍出现请确认版本/入口
✅ 已实现 新增门店 表单新增「终端数」与「激活码」字段;保存门店后若终端数>0,自动调用 /device/activationCode/generate 创建激活码;saveOrUpdateOrg 改为返回 orgId 供后续操作

⏳ 待验收:设备标题前缀、扫码页直接摄像头、新增门店激活码/终端数。


v6-fix14(2026-08-24)

类型 模块 内容
✅ 已修复 设备列表 web 端有房间号但手机端显示「未设置」→ 扩大 Device.fromJson 房号字段兼容:roomNo/room/roomNumber/room_id/roomNum/roomName/houseNumber/roomCode 等常见别名

✅ 已验收:设备列表房号。


v6-fix13(2026-08-24)

类型 模块 内容
✅ 已修复 门店详情 激活码仍显示「—」→ 改从激活码专用接口 /device/activationCode/info/{orgId} 拉取 code 字段,作为真实激活码展示;接口无值时回退门店列表里的 activationCode
✅ 已修复 设备列表 副标题改为用户指定格式:门店:XXX门店 MAC:AA:BB:CC:DD:EE:FF 房号:V888(缺失项显示「未设置」)

✅ 已验收:门店详情激活码、设备副标题格式。


v6-fix12(2026-08-24)

类型 模块 内容
✅ 已修复 用户管理 角色/组织显示「未分配」→ 兼容后端嵌套对象/数组返回(roles/org/dept 等),并建立完整 orgId→name 映射
✅ 已修复 设备列表 副标题改为 MAC · 所属门店 · 房号(原为设备型号/MAC)
✅ 已修复 门店管理 手机端新增/编辑门店真实上报后端(/sys/org/saveOrUpdate),不再本地占位
✅ 已修复 门店列表 按创建时间倒序,最新门店排最前面(与 web 一致)

⏳ 待验收:用户管理角色/组织回显、新增门店 web 可见、门店列表排序。


v6-fix11(2026-08-24)

类型 模块 内容
✅ 已实现 国际化 i18n 设备详情、下发指令、修改分组/房号、激活码管理、用户管理、公司介绍等页面接入英文翻译
✅ 已修复 编译 修复 8 个 analyze error(i10n 重复定义、store_list 误用 t.normal/t.disabled、device_list 漏传参、user_page 漏 t 声明)

v6-fix10(2026-08-24)

类型 模块 内容
✅ 已实现 门店编辑-界面配置 按设备分组展示已启用/添加的主题(接入 /theme/page/org/{orgId}/photos,ThemeGroup→ThemePage[])
✅ 已修复 设备列表 Device.fromJson 兼容 deviceName/ipAddress/deviceIp 等字段,正确回显设备名、房号、MAC、IP

v6-fix9(2026-08-24)

类型 模块 内容
✅ 已实现 国际化 i18n 底部导航、首页、设备列表、门店列表、管理入口、设置页接入英文翻译(首批)

v6-fix8(2026-08-24)

类型 模块 内容
✅ 已修复 门店详情 联系电话/激活码/到期时间/创建时间字段空白 → 调 /sys/org/listByLoginOrg 回填
✅ 已修复 扫码 路由冲突(scan 在 :id 后导致被当 deviceId)→ 路由前置
✅ 已修复 管理页 移除「门店配置」入口(后端 /device/storeConfig/{orgId} 500)

v6-fix7(2026-08-24)

类型 模块 内容
✅ 已修复 登录-记住密码 CredentialStorage 由 Directory.current(Android 不可写)迁移到 shared_preferences,记住账号密码 + 免登录恢复均生效

历史(本会话早段)

版本 类型 模块 内容
v6-fix6 ✅ 已修复 门店编辑 移除扫码绑定按钮/启动图Logo区块;主题皮肤改接 web 模板;所属组织下拉过滤+透传 parentId
v6-fix5 ✅ 已修复 登录灰块 localizationsDelegates 漏默认 delegate 致 TextField 崩溃 → 补全三个默认 delegate
v6-fix3 ✅ 已实现 排障 ErrorWidget.builder 红色错误页 + DIAG 横幅,替代 release 灰屏

⏳ 已知待办 / 未改项

  • ❌ 门店配置 功能:后端 /device/storeConfig/{orgId} 持续 500,前端已移除入口并给友好提示,需后端修复后恢复。
  • ⏳ 门店编辑「界面配置」目前为展示型(显示分组/主题/激活主题),移动端切换激活主题需后端 /theme/page/active 支持,可后续迭代。
  • ⏳ 切换英文后如仍有个别深层弹窗/页面为中文,多为未接 i18n 的入口,截图可继续补。

交付物索引

版本 APK 路径 大小
v6-fix35 E:/Project/ops-console/ops-console-release-v6-fix35.apk 33.5MB
v6-fix34 E:/Project/ops-console/ops-console-release-v6-fix34.apk 33.5MB
v6-fix33 E:/Project/ops-console/ops-console-release-v6-fix33.apk 33.5MB
v6-fix32 E:/Project/ops-console/ops-console-release-v6-fix32.apk 33.5MB
v6-fix31 E:/Project/ops-console/ops-console-release-v6-fix31.apk 33.5MB
v6-fix30 E:/Project/ops-console/ops-console-release-v6-fix30.apk 33.5MB
v6-fix12 E:/Project/ops-console/ops-console-release-v6-fix12.apk 33.4MB
v6-fix11 E:/Project/ops-console/ops-console-release-v6-fix11.apk 35.0MB
v6-fix7~10 E:/Project/ops-console/build/app/outputs/flutter-apk/app-release.apk 33.x MB