2995840376
|
3120af6464
|
feat(C2-C3): 后台产品/设备管理重构 - 产品中心 + 关系可视化
后端:
- Product 实体新增统计字段(deviceCount/propertyCount/eventCount/
mainSwitchCode/mainSwitchName, 非持久化)
- ProductServiceImpl.fillProductStats(): 列表批量回填
一次 selectBatchIds, 无 N+1; 让产品-设备-物模型的关系在 UI 层可见
(此前关系在数据层存在但 UI 层完全不可见, 这就是'看起来乱'的根因)
- Device 实体新增 productName/productKey 非持久化字段
- DeviceServiceImpl.fillProductInfo(): 设备列表回填所属产品
前端 api/product.ts:
- Product/ProductProperty/ControlItem 接口补齐语义与统计字段
- 新增 syncProductSpec(): 从涂鸦云同步物模型
- 新增 listProductDevices(): 复用设备列表按 productId 过滤
产品列表 (ProductList.vue):
- 新增'物模型'列: DP 数量 + 主开关名 (未同步显示告警标签)
- 新增'设备'列: 挂载台数, 点击跳转设备列表并带 productId 过滤
- 新增'同步'按钮: 从涂鸦云同步物模型
- 新增'详情'按钮 -> 产品详情页
- 删除提示改为动态显示设备数
新增产品详情页 (ProductDetail.vue):
- 概览统计卡: 设备数/DP数/事件数/主开关
- 5 Tab: 基本信息 / 物模型 / 设备 / 固件与OTA
- 物模型 Tab 展示 semantic/grp/isPrimary/dpId, 并可切换属性/事件/服务
设备列表 (DeviceList.vue):
- 新增'所属产品'列, 可点击跳产品详情, 未关联显示'未关联'
- 新增'所属产品'筛选下拉(含各产品设备数)
- 支持从产品页跳转带 productId 参数自动筛选
MainLayout.vue 修复:
- groupedRoutes 未过滤 meta.hidden, 详情页会混进侧边栏菜单
验证: mvn 编译通过; npx vite build 通过(ProductDetail chunk 已产出)
|
2026-10-27 12:45:54 +08:00 |
|
2995840376
|
fdf0e265fc
|
feat(B8-B9): 屏端物模型回流 + 设备级 schema 覆盖层(消除死数据)
问题: device.schema_json 是中控屏上报物模型的唯一落点, 但全仓只写不读,
属死数据; 同时屏端本地设备(zigbee/ble/matter)无平台产品, 产品级物模型里
也查不到东西, 导致这类设备拿不到 control-schema。
新增 PanelSpecAdoptService:
- 归一化: 屏端通用协议类型(BOOLEAN/INTEGER/NUMBER/ENUM/STRING) ->
产品物模型类型(bool/int/float/enum/string);
access(READ/WRITE/READ_WRITE) -> (read/write/read,write)
- 回流: 已存在的属性只补齐/修正屏端明确提供的字段(不做破坏性覆盖),
不存在的补建; 产品级已有而屏端未报的属性保留(产品级是超集)
- 语义: 屏端已上报 semantic/channel 直接落库, 缺失时由
SpecSemanticResolver 兜底推导
- toProperties(): 供无产品设备直接以设备级 schema 作为模型来源
PanelDeviceService: register / updateSchema 均触发回流
ControlSchemaServiceImpl.getDeviceSchema 改造:
- 无 product_id 的设备: 用设备级 schema 构建控制模型(不再直接返回空)
- 有 product_id: 产品基线 + 设备级覆盖层 merge
同 code 以设备级为准, 设备级独有的 code 追加
- 新增 mergeItem(): 仅覆盖屏端明确提供的字段
验证: mvn -pl iot-common,iot-device -am compile 通过
|
2026-10-27 12:39:23 +08:00 |
|
2995840376
|
a8c2d005a8
|
feat(B10): 产品<->设备反向查询 - 设备列表可按产品过滤并展示所属产品
后端:
- DeviceQuery 新增 productId(精确) 与 productKeyword(按产品名/编码模糊)
- DeviceServiceImpl.pageDevices 支持两种产品维度过滤
productKeyword 场景: 先解析匹配的 product_id 集合再约束 device,
集合为空时用 1=0 保证不误返回全部
- 新增 fillProductInfo(): 批量回填设备所属产品名称与业务编码
(一次 selectBatchIds, 避免 N+1)
- Device 实体新增非持久化展示字段 productName / productKey
验证: mvn -pl iot-common,iot-device -am compile 通过
|
2026-10-27 12:35:52 +08:00 |
|
2995840376
|
d7e34efb58
|
feat(B2-B4): 产品生命周期闭环 - 删除防孤儿 / reconcile 幂等全量 / 同步自愈
B2 deleteProduct 引用校验:
- 原实现直接 deleteById, 会留下 product_id 指向已删产品的孤儿设备,
且 reconcile 只补 NULL 的设备 => 孤儿永远无法回收
- 现校验 device / firmware / ota_task 三类引用, 任一存在即拒绝删除并提示数量
(此前前端却提示'已关联设备的产品不可删除', 后端实际毫无校验)
B3 reconcileDevices 幂等全量对齐:
- 原: 仅处理 product_id IS NULL 的设备
- 现: 对所有有 platform_product_id 的设备按 (platform, platform_product_id)
重新解析产品并校正 product_id, 已对齐的跳过(不产生无谓写)
- 无平台产品ID的纯本地手工设备跳过
B4 同步自愈 (新增 ProductService.ensureDeviceProduct):
- TuyaController 同步路径由「仅当 product_id IS NULL 才解析」改为每次校验
- 产品不存在(含已逻辑删除)/平台产品ID不匹配 => 自动重新解析或创建产品
- 配合 B2 引用校验, 产品删除不再产生不可回收的孤儿
验证: mvn -pl iot-common,iot-device -am compile 通过
|
2026-10-27 12:34:27 +08:00 |
|
2995840376
|
6461acecd1
|
feat(B5-B7): 引入 SpecSemanticResolver 作为物模型语义唯一权威
新增 SpecSemanticResolver (356行):
- 语义标签体系: power/switch/backlight/indicator/brightness/color_temp/
mode/scene/countdown/child_lock/temperature/humidity/battery/motion/
contact/fault/raw
- 功能分组 grp: switch/scene/mode/countdown/display/config/measure/status
- resolve(): 单功能点语义推导(非主控词优先 -> 功能语义 -> 开关兜底)
- pickPrimary(): 产品范围内选主开关(power优先 -> switch组首个 -> 唯一可写bool兜底)
- isReadOnly(): 只读语义修正, 修复涂鸦 fnCodes 为空时兜底'全部可写'的缺陷
实体/DTO 补齐语义字段(V19 建了列但代码里没有):
- ProductProperty: semantic/grp/isPrimary/channel/completionMode/enumLabel
- ProductAction: completionMode
- ControlItem: semantic/grp/isPrimary/enumLabels
ControlSchemaServiceImpl 改造:
- toItem(): 搬运语义字段; 物模型无语义时即时推导(旧数据兼容);
状态量被误标 write 时强制只读
- pickMainSwitch(): 优先 is_primary -> semantic=power -> 回退旧启发式
(原实现按名称含 switch/power 猜测, 是 JD2BTSA 背光误控的根因)
- fillValues(): code 优先、dp_id 兜底(修复 dps key 语义分裂导致回填失败)
ProductServiceImpl.reconcileSpecFromTuya:
- 同步物模型时落库 semantic/grp, 并用语义修正 access
- 新增 applyPrimary(): 选主开关并回填 is_primary
验证: mvn -pl iot-common,iot-device -am compile 通过
|
2026-10-27 12:32:06 +08:00 |
|
2995840376
|
9786286ad3
|
fix(B1): 修复 resolveProductId 参数错位污染产品字段 + product_key 确定性化
根因: TuyaController 两处调用把「涂鸦 productId」填进 model 位、把字面量
'tuya' 填进 manufacturer 位, 导致 product.model / manufacturer 被写入
平台产品ID (生产数据已出现 P_tuya_y1ouxiqr_42bff218 的脏记录)。
修复:
- TuyaController: 2 处调用改为 model=null, manufacturer=null
(涂鸦 OpenAPI 确实未提供真实型号/厂商, 此前是错位而非真实值)
- ProductServiceImpl.resolveProductId: 新增 sanitizeDimension() 防御,
对畸形入参(等于平台产品ID / 等于平台编码)统一置空, 杜绝同类错位复发
- resolveProductId 入口 platform 经 PlatformType.normalize() 归一
product_key 确定性化:
- 旧: P_<platform>_<model>_<随机UUID8> -> 不可读、无法反查
- 新: P_<platform>_<platformProductId|model> -> 恒定、可反查
(超 56 字符截断并追加短哈希防碰撞)
验证: mvn -pl iot-common,iot-device -am compile 通过
|
2026-10-27 12:22:39 +08:00 |
|
2995840376
|
a932633c50
|
refactor(A): 产品/物模型/设备三层架构重构 - 地基批次
新增:
- iot-common/PlatformType: 平台维度单一真相源(枚举)
统一 tuya/matter/local/xiaomi/huawei/dueros/alexa/google_home,
提供 legacy 别名归一(miot|mi -> xiaomi)与已知性判定
- backend/sql/V22__product_device_arch_refactor.sql: 幂等迁移(153行)
A. platform_type 平台字典表 + 种子数据(后台可维护)
B. product 加 protocol 列; platform_product_id 空串清洗为 NULL;
清洗 model/manufacturer 被涂鸦 productId 污染的历史脏数据;
加 (platform, platform_product_id, deleted) 唯一约束
C. product_property 加 grp/is_primary/enum_label + (product_id,code) 唯一约束
D. product_event/product_action 加 (product_id,code) 唯一约束;
product_action 加 completion_mode
E. device 加 product_id 索引(OTA 物化目标设备此前全表扫); platform 归一
改造:
- DeviceAdapter 新增 platform() 显式声明平台
- DeviceAdapterManager 改为按 platform() 精确匹配,
移除'类名是否包含平台字符串'的脆弱约定(类名与平台码不同名会静默降级)
- DevicePlatform 委托 PlatformType, 消除第四套平台取值域
验证: mvn -pl iot-common,iot-device -am compile 通过
|
2026-10-27 12:08:44 +08:00 |
|
2995840376
|
0ce191c448
|
chore: 初始化 iotsaas 版本库基线
纳入范围:
- backend/ Spring Boot 多模块后端(iot-common/device/rule/data/alarm/auth)
- frontend/admin/ Vue3 + Element Plus 管理后台
- Android/ 涂鸦原生 APP (com.xhai.iot)
- backend/sql/ Flyway 风格迁移脚本(V2~V21)
- docs/ 对接文档与设计文档
排除范围:
- 构建产物: node_modules/ target/ build/ dist/ .gradle/
- 签名密钥: *.jks *.keystore (严禁入库)
- 本机配置: Android/local.properties
- 运行日志: logs/ *.log
- AI 协作本地数据 .codebuddy/ 与第三方 demo tuya-demo/
.gitattributes 统一以 LF 存储, Windows 批处理保留 CRLF
|
2026-10-27 12:00:41 +08:00 |
|