From c187fd9fd3c94701a5f81d100a200d9de0fe9643 Mon Sep 17 00:00:00 2001 From: liujiangyong Date: Wed, 17 Jun 2026 19:53:34 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=95=B0=E6=8D=AE=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=E7=B3=BB=E6=95=B0=E6=94=AF=E6=8C=81=E6=AD=A3=E8=B4=9F=E5=80=BC?= =?UTF-8?q?=E5=88=86=E7=BB=84=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOGS/V1.2.4.md | 61 +++++++ package.json | 2 +- .../SystemSettings/SystemSettings.jsx | 155 ++++++++++++----- .../SystemSettings/SystemSettings.module.css | 26 +++ src/renderer/src/stores/deviceStore.js | 19 +-- .../src/utils/deflectionCorrection.js | 158 ++++++++++++++---- 6 files changed, 333 insertions(+), 88 deletions(-) create mode 100644 CHANGELOGS/V1.2.4.md diff --git a/CHANGELOGS/V1.2.4.md b/CHANGELOGS/V1.2.4.md new file mode 100644 index 0000000..23045de --- /dev/null +++ b/CHANGELOGS/V1.2.4.md @@ -0,0 +1,61 @@ +# V1.2.4 更新日志 + +- **更新日期**: 2026年06月17日 +- **版本号**: 1.2.4 + +## 新增功能 + +### 1. 数据修正系数支持正负值分组配置 +- **新增正负值双组修正系数**:每个距离配置下,分别维护“正值配置”和“负值配置”两套 `xK/xB/yK/yB` +- **按原始值符号自动应用**:当原始采集值大于等于 `0` 时使用正值配置,小于 `0` 时使用负值配置 +- **X/Y 独立判断**:`xReal` 和 `yReal` 分别按各自原始值符号选择对应修正系数,不共享判断结果 +- **保持历史冻结语义**:修正系数变更后仅影响后续新采集数据,已进入历史链路的数据保持采集当时的修正结果 + +### 2. 修正系数配置界面升级 +- **卡片内新增正负值配置区**:每张距离配置卡片内新增“正值配置”和“负值配置”两个分组 +- **支持 8 项参数编辑**:每个距离可分别编辑正值组和负值组的 `xK/xB/yK/yB` +- **保留多距离管理能力**:继续支持距离配置的新增、编辑、删除和当前应用项切换 +- **保留控制台调试输出**:修正计算时继续输出原始值、命中的正负组、K、B 和修正后值,便于排查数据口径 + +## 技术细节 + +### 本地存储结构 +```json +{ + "profiles": [ + { + "distance": 10, + "positive": { "xK": 1, "xB": 0, "yK": 1, "yB": 0 }, + "negative": { "xK": 1, "xB": 0, "yK": 1, "yB": 0 } + } + ], + "activeDistance": 10 +} +``` + +### 数据处理策略 +- `0` 归入正值配置 +- 正负值判断基于传感器原始值,而不是修正后的结果 +- 空值、缺失值或不可转数字的原始值不参与修正计算,保持“无数据”语义 +- 页面曲线、实时数据显示、报警判断、实时 CSV、报警 CSV 继续共享冻结后的 `correctedX/correctedY` + +## 影响范围 +- 系统设置中的数据修正系数配置区域 +- 多距离修正系数本地持久化结构 +- 挠度采集页 X/Y 曲线与右侧实时数据 +- 报警判断逻辑 +- 实时数据 CSV 导出 +- 报警数据 CSV 导出 + +## 依赖更新 +- 无依赖包更新 + +## 注意事项 +1. 本版本不兼容 V1.2.3 的单组修正系数本地结构,读取到旧结构或异常结构时会重建为新的默认 `10 米` 正负值双组配置。 +2. 距离仍仅作为上位机修正系数配置的管理维度,不会根据设备状态或测点距离自动切换。 +3. 当前应用项切换后,仅影响后续新采集数据;历史数据仍保持采集当时的修正结果。 +4. 设备侧“测点设置”中的“计算系数”仍为独立参数,与本地正负值数据修正系数不互相替代。 + +--- + +**完整更新内容请查看项目 Git 提交记录** diff --git a/package.json b/package.json index 31a314b..5398aee 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "FlexometerSetup", - "version": "1.2.3", + "version": "1.2.4", "description": "An Electron application with React", "main": "./out/main/index.js", "author": "cles", diff --git a/src/renderer/src/components/SystemSettings/SystemSettings.jsx b/src/renderer/src/components/SystemSettings/SystemSettings.jsx index 9c2546c..63229f7 100644 --- a/src/renderer/src/components/SystemSettings/SystemSettings.jsx +++ b/src/renderer/src/components/SystemSettings/SystemSettings.jsx @@ -798,8 +798,21 @@ function SystemSettings() { return } + const [groupKey, factorKey] = field.split('.') + if (!groupKey || !factorKey) { + return + } + const nextProfiles = correctionProfiles.map((profile) => - profile.distance === distance ? { ...profile, [field]: Number(value) } : profile + profile.distance === distance + ? { + ...profile, + [groupKey]: { + ...profile[groupKey], + [factorKey]: Number(value) + } + } + : profile ) const nextConfig = persistCorrectionConfig(nextProfiles, activeCorrectionDistance) @@ -1198,49 +1211,105 @@ function SystemSettings() {
-
- xK - - handleCorrectionProfileChange(profile.distance, 'xK', nextValue) - } - className={styles.correctionFieldInput} - /> -
-
- xB - - handleCorrectionProfileChange(profile.distance, 'xB', nextValue) - } - className={styles.correctionFieldInput} - /> -
-
- yK - - handleCorrectionProfileChange(profile.distance, 'yK', nextValue) - } - className={styles.correctionFieldInput} - /> +
+
正值配置
+
原始值大于等于 0 时使用
+
+
+ xK + + handleCorrectionProfileChange(profile.distance, 'positive.xK', nextValue) + } + className={styles.correctionFieldInput} + /> +
+
+ xB + + handleCorrectionProfileChange(profile.distance, 'positive.xB', nextValue) + } + className={styles.correctionFieldInput} + /> +
+
+ yK + + handleCorrectionProfileChange(profile.distance, 'positive.yK', nextValue) + } + className={styles.correctionFieldInput} + /> +
+
+ yB + + handleCorrectionProfileChange(profile.distance, 'positive.yB', nextValue) + } + className={styles.correctionFieldInput} + /> +
+
-
- yB - - handleCorrectionProfileChange(profile.distance, 'yB', nextValue) - } - className={styles.correctionFieldInput} - /> +
+
负值配置
+
原始值小于 0 时使用
+
+
+ xK + + handleCorrectionProfileChange(profile.distance, 'negative.xK', nextValue) + } + className={styles.correctionFieldInput} + /> +
+
+ xB + + handleCorrectionProfileChange(profile.distance, 'negative.xB', nextValue) + } + className={styles.correctionFieldInput} + /> +
+
+ yK + + handleCorrectionProfileChange(profile.distance, 'negative.yK', nextValue) + } + className={styles.correctionFieldInput} + /> +
+
+ yB + + handleCorrectionProfileChange(profile.distance, 'negative.yB', nextValue) + } + className={styles.correctionFieldInput} + /> +
+
diff --git a/src/renderer/src/components/SystemSettings/SystemSettings.module.css b/src/renderer/src/components/SystemSettings/SystemSettings.module.css index aeea9c8..b0ead8c 100644 --- a/src/renderer/src/components/SystemSettings/SystemSettings.module.css +++ b/src/renderer/src/components/SystemSettings/SystemSettings.module.css @@ -198,6 +198,32 @@ } .correctionFactorGrid { + display: grid; + grid-template-columns: 1fr; + gap: 10px; +} + +.correctionFactorGroup { + border: 1px solid #e5e7eb; + border-radius: 6px; + padding: 10px; + background: #fff; +} + +.correctionFactorGroupTitle { + font-size: 13px; + font-weight: 600; + color: #222; +} + +.correctionFactorGroupHint { + margin-top: 2px; + margin-bottom: 8px; + font-size: 12px; + color: #666; +} + +.correctionFactorSubGrid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 8px; diff --git a/src/renderer/src/stores/deviceStore.js b/src/renderer/src/stores/deviceStore.js index 5124983..a20dcdb 100644 --- a/src/renderer/src/stores/deviceStore.js +++ b/src/renderer/src/stores/deviceStore.js @@ -1,6 +1,8 @@ import { createDefaultCorrectionConfig, + createDefaultDualCorrectionFactors, getActiveCorrectionFactors, + sanitizeDualCorrectionFactors, sanitizeCorrectionProfiles } from '../utils/deflectionCorrection' @@ -64,12 +66,11 @@ const useDeviceStore = create((set) => ({ // 数据修正系数管理 setCorrectionFactors: (factors) => - set((state) => ({ - correctionFactors: { - ...state.correctionFactors, - ...factors - } - })), + set({ + correctionFactors: factors + ? sanitizeDualCorrectionFactors(factors) ?? createDefaultDualCorrectionFactors() + : createDefaultDualCorrectionFactors() + }), setCorrectionProfiles: (profiles) => set({ correctionProfiles: sanitizeCorrectionProfiles(profiles) @@ -89,10 +90,8 @@ const useDeviceStore = create((set) => ({ return { activeCorrectionDistance: distance, correctionFactors: { - xK: activeProfile.xK, - xB: activeProfile.xB, - yK: activeProfile.yK, - yB: activeProfile.yB + positive: { ...activeProfile.positive }, + negative: { ...activeProfile.negative } } } }), diff --git a/src/renderer/src/utils/deflectionCorrection.js b/src/renderer/src/utils/deflectionCorrection.js index 4b0bcd3..b8d0da6 100644 --- a/src/renderer/src/utils/deflectionCorrection.js +++ b/src/renderer/src/utils/deflectionCorrection.js @@ -9,9 +9,18 @@ export const DEFAULT_CORRECTION_FACTORS = { export const DEFAULT_CORRECTION_DISTANCE = 10 +export const createDefaultFactorGroup = () => ({ + ...DEFAULT_CORRECTION_FACTORS +}) + +export const createDefaultDualCorrectionFactors = () => ({ + positive: createDefaultFactorGroup(), + negative: createDefaultFactorGroup() +}) + export const createDefaultCorrectionProfile = (distance = DEFAULT_CORRECTION_DISTANCE) => ({ distance, - ...DEFAULT_CORRECTION_FACTORS + ...createDefaultDualCorrectionFactors() }) export const createDefaultCorrectionConfig = () => ({ @@ -44,6 +53,21 @@ export const sanitizeCorrectionFactors = (value) => { } } +export const sanitizeDualCorrectionFactors = (value) => { + const next = value && typeof value === 'object' ? value : {} + const hasPositiveGroup = next.positive && typeof next.positive === 'object' + const hasNegativeGroup = next.negative && typeof next.negative === 'object' + + if (!hasPositiveGroup || !hasNegativeGroup) { + return null + } + + return { + positive: sanitizeCorrectionFactors(next.positive), + negative: sanitizeCorrectionFactors(next.negative) + } +} + export const sanitizeCorrectionProfile = (value) => { const next = value && typeof value === 'object' ? value : {} const distance = toPositiveInteger(next.distance) @@ -52,9 +76,14 @@ export const sanitizeCorrectionProfile = (value) => { return null } + const normalizedGroups = sanitizeDualCorrectionFactors(next) + if (!normalizedGroups) { + return null + } + return { distance, - ...sanitizeCorrectionFactors(next) + ...normalizedGroups } } @@ -110,24 +139,8 @@ export const getActiveCorrectionFactors = (config) => { ) return activeProfile - ? sanitizeCorrectionFactors(activeProfile) - : { ...DEFAULT_CORRECTION_FACTORS } -} - -export const ensureDefaultDistanceProfile = (profiles) => { - const normalizedProfiles = sanitizeCorrectionProfiles(profiles) - const hasDefaultDistance = normalizedProfiles.some( - (profile) => profile.distance === DEFAULT_CORRECTION_DISTANCE - ) - - if (hasDefaultDistance) { - return normalizedProfiles - } - - return [ - ...normalizedProfiles, - createDefaultCorrectionProfile(DEFAULT_CORRECTION_DISTANCE) - ] + ? sanitizeDualCorrectionFactors(activeProfile) ?? createDefaultDualCorrectionFactors() + : createDefaultDualCorrectionFactors() } export const removeCorrectionProfileWithFallback = (profiles, activeDistance, distanceToDelete) => { @@ -162,7 +175,7 @@ export const removeCorrectionProfileWithFallback = (profiles, activeDistance, di } } -export const correctAxisValue = (originalValue, k, b) => { +const getFactorGroupNameByValue = (originalValue) => { if (originalValue === null || originalValue === undefined || originalValue === '') { return null } @@ -172,7 +185,72 @@ export const correctAxisValue = (originalValue, k, b) => { return null } - return k * numericOriginal + b + return numericOriginal < 0 ? 'negative' : 'positive' +} + +export const correctAxisValue = (originalValue, factors) => { + if (originalValue === null || originalValue === undefined || originalValue === '') { + return { correctedValue: null, appliedGroup: null, appliedFactors: null } + } + + const numericOriginal = Number(originalValue) + if (!Number.isFinite(numericOriginal)) { + return { correctedValue: null, appliedGroup: null, appliedFactors: null } + } + + const normalizedGroups = sanitizeDualCorrectionFactors(factors) + if (!normalizedGroups) { + return { correctedValue: null, appliedGroup: null, appliedFactors: null } + } + const appliedGroup = getFactorGroupNameByValue(numericOriginal) + const appliedFactors = appliedGroup ? normalizedGroups[appliedGroup] : null + + if (!appliedFactors) { + return { correctedValue: null, appliedGroup: null, appliedFactors: null } + } + + return { + correctedValue: appliedFactors.xK * numericOriginal + appliedFactors.xB, + appliedGroup, + appliedFactors: { + xK: appliedFactors.xK, + xB: appliedFactors.xB + } + } +} + +const correctAxisWithKeys = (originalValue, factors, axis) => { + if (originalValue === null || originalValue === undefined || originalValue === '') { + return { correctedValue: null, appliedGroup: null, appliedFactors: null } + } + + const numericOriginal = Number(originalValue) + if (!Number.isFinite(numericOriginal)) { + return { correctedValue: null, appliedGroup: null, appliedFactors: null } + } + + const normalizedGroups = sanitizeDualCorrectionFactors(factors) + if (!normalizedGroups) { + return { correctedValue: null, appliedGroup: null, appliedFactors: null } + } + const appliedGroup = getFactorGroupNameByValue(numericOriginal) + const appliedFactors = appliedGroup ? normalizedGroups[appliedGroup] : null + + if (!appliedFactors) { + return { correctedValue: null, appliedGroup: null, appliedFactors: null } + } + + const kKey = `${axis}K` + const bKey = `${axis}B` + + return { + correctedValue: appliedFactors[kKey] * numericOriginal + appliedFactors[bKey], + appliedGroup, + appliedFactors: { + [kKey]: appliedFactors[kKey], + [bKey]: appliedFactors[bKey] + } + } } export const applyCorrectionToSensor = (sensor, correctionFactors) => { @@ -180,32 +258,44 @@ export const applyCorrectionToSensor = (sensor, correctionFactors) => { return sensor } - const normalizedFactors = sanitizeCorrectionFactors(correctionFactors) - const correctedX = correctAxisValue(sensor.xReal, normalizedFactors.xK, normalizedFactors.xB) - const correctedY = correctAxisValue(sensor.yReal, normalizedFactors.yK, normalizedFactors.yB) + const normalizedFactors = + sanitizeDualCorrectionFactors(correctionFactors) ?? createDefaultDualCorrectionFactors() + const xResult = correctAxisWithKeys(sensor.xReal, normalizedFactors, 'x') + const yResult = correctAxisWithKeys(sensor.yReal, normalizedFactors, 'y') console.log('[DeflectionCorrection]', { pos: sensor.pos ?? null, des: sensor.des ?? '', x: { originalValue: sensor.xReal ?? null, - k: normalizedFactors.xK, - b: normalizedFactors.xB, - correctedValue: correctedX + appliedGroup: xResult.appliedGroup, + k: xResult.appliedFactors?.xK ?? null, + b: xResult.appliedFactors?.xB ?? null, + correctedValue: xResult.correctedValue }, y: { originalValue: sensor.yReal ?? null, - k: normalizedFactors.yK, - b: normalizedFactors.yB, - correctedValue: correctedY + appliedGroup: yResult.appliedGroup, + k: yResult.appliedFactors?.yK ?? null, + b: yResult.appliedFactors?.yB ?? null, + correctedValue: yResult.correctedValue } }) return { ...sensor, - appliedCorrectionFactors: normalizedFactors, - correctedX, - correctedY + appliedCorrectionFactors: { + x: { + group: xResult.appliedGroup, + factors: xResult.appliedFactors + }, + y: { + group: yResult.appliedGroup, + factors: yResult.appliedFactors + } + }, + correctedX: xResult.correctedValue, + correctedY: yResult.correctedValue } }