view-model.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. const parameterGroupService = require('./service.js')
  2. const {
  3. validateValueFormula
  4. } = require('../../domain/parameter-groups/value-formula.js')
  5. const settingsService = require('../../store/settings-store.js')
  6. const themeService = require('../../store/theme-store.js')
  7. const transport = require('../../transport/ble-core.js')
  8. function getOption(options, index) {
  9. return options[Number(index)] || options[0] || {}
  10. }
  11. function getCodeInfoVariableByteLength(dialog = {}) {
  12. const entryKind = String(dialog.sourceEntryKind || '').trim().toLowerCase()
  13. const byteLength = Number(dialog.sourceByteLength)
  14. if (entryKind !== 'variable' || !Number.isFinite(byteLength) || byteLength <= 0) return 0
  15. return Math.floor(byteLength)
  16. }
  17. function getDataTypeConfigByteLength(dataType = {}, dialog = {}) {
  18. if (dataType.kind === 'raw') return getCodeInfoVariableByteLength(dialog)
  19. if (dataType.kind === 'text') return Number(dialog.textByteLength) || Number(dataType.byteLength) || 0
  20. return Number(dataType.byteLength) || Number(dataType.wordCount || 0) * 2
  21. }
  22. function validateCodeInfoVariableDataType(dialog = {}, dataType = {}) {
  23. const sourceByteLength = getCodeInfoVariableByteLength(dialog)
  24. if (!sourceByteLength || dataType.kind === 'raw') return
  25. if (dataType.kind === 'text' || dataType.kind === 'hex') {
  26. throw new Error('单独变量类型请选择有符号/无符号整数、float 或 enum 对应整数类型')
  27. }
  28. const dataTypeByteLength = getDataTypeConfigByteLength(dataType, dialog)
  29. if (dataTypeByteLength !== sourceByteLength) {
  30. throw new Error(`单独变量 TLV 长度为 ${sourceByteLength}B,不能选择 ${dataType.label || dataType.key || '该类型'}`)
  31. }
  32. }
  33. function getPageState() {
  34. const settingsState = settingsService.getState()
  35. const transportState = transport.getState()
  36. const isNoProtocol = settingsService.isNoProtocol(settingsState.protocolMode)
  37. const isModbusProtocol = settingsService.isModbusProtocol(settingsState.protocolMode)
  38. const isStorageAccessProtocol = settingsService.isStorageAccessProtocol(settingsState.protocolMode)
  39. return {
  40. ...parameterGroupService.getState(),
  41. ...themeService.getState(),
  42. ...settingsState,
  43. connectedDevice: transportState.connectedDevice,
  44. isNoProtocol,
  45. isModbusProtocol,
  46. isStorageAccessProtocol
  47. }
  48. }
  49. function resolveActiveParamView(currentView) {
  50. return currentView === 'parameterGroup' ? currentView : 'parameterGroups'
  51. }
  52. function getSettingsPageState(currentData, settingsState) {
  53. const isNoProtocol = settingsService.isNoProtocol(settingsState.protocolMode)
  54. const isModbusProtocol = settingsService.isModbusProtocol(settingsState.protocolMode)
  55. const isStorageAccessProtocol = settingsService.isStorageAccessProtocol(settingsState.protocolMode)
  56. return {
  57. ...settingsState,
  58. activeParamView: resolveActiveParamView(currentData.activeParamView),
  59. isNoProtocol,
  60. isModbusProtocol,
  61. isStorageAccessProtocol
  62. }
  63. }
  64. function getVisiblePageState(currentData) {
  65. const settingsState = settingsService.getState()
  66. const transportState = transport.getState()
  67. const isNoProtocol = settingsService.isNoProtocol(settingsState.protocolMode)
  68. const isModbusProtocol = settingsService.isModbusProtocol(settingsState.protocolMode)
  69. const isStorageAccessProtocol = settingsService.isStorageAccessProtocol(settingsState.protocolMode)
  70. const pageState = {
  71. ...parameterGroupService.getState(),
  72. ...themeService.getState(),
  73. ...settingsState,
  74. connectedDevice: transportState.connectedDevice,
  75. isNoProtocol,
  76. isModbusProtocol,
  77. isStorageAccessProtocol
  78. }
  79. return {
  80. ...pageState,
  81. activeParamView: resolveActiveParamView(currentData.activeParamView)
  82. }
  83. }
  84. function getTransportPageState(transportState = transport.getState()) {
  85. return {
  86. connectedDevice: transportState.connectedDevice
  87. }
  88. }
  89. function createParameterDialogState(overrides = {}) {
  90. const registerType = getOption(parameterGroupService.REGISTER_TYPE_OPTIONS, 0)
  91. const dataType = getOption(parameterGroupService.DATA_TYPE_OPTIONS, 0)
  92. return {
  93. cancelText: '取消',
  94. confirmText: '确认',
  95. dataTypeIndex: 0,
  96. dataTypeText: dataType.label || '',
  97. groupId: '',
  98. groupName: '',
  99. mode: '',
  100. name: '',
  101. quantity: '1',
  102. registerIndex: -1,
  103. registerTypeIndex: 0,
  104. registerTypeText: registerType.label || '',
  105. remark: '',
  106. startAddress: '0000',
  107. title: '',
  108. textByteLength: '32',
  109. showTextLength: false,
  110. unit: '',
  111. visible: false,
  112. maxValue: '',
  113. minValue: '',
  114. conversionFormula: '',
  115. conversionFormulaErrorText: '',
  116. addressText: '',
  117. displayValue: '',
  118. rawValueText: '',
  119. showDataType: false,
  120. showRange: false,
  121. showUnit: false,
  122. readOnly: false,
  123. parsedStructRegisters: [],
  124. pollEnabled: true,
  125. showPollEnabled: false,
  126. sourceByteLength: '',
  127. sourceEntryKind: '',
  128. structDefinition: '',
  129. structParsedSummary: '',
  130. ...overrides
  131. }
  132. }
  133. function createParameterGroupDialogState(group) {
  134. const isEdit = !!group
  135. const isStorageGroup = !!(group && group.sourceMemoryArea)
  136. const registerTypeIndex = isEdit ? (group.registerTypeIndex || 0) : 0
  137. const registerType = getOption(parameterGroupService.REGISTER_TYPE_OPTIONS, registerTypeIndex)
  138. return createParameterDialogState({
  139. confirmText: isEdit ? '保存' : '确认',
  140. groupId: isEdit ? group.id : '',
  141. groupName: isEdit ? group.name : (isStorageGroup ? '结构体组' : '寄存器组'),
  142. layout: isEdit ? (group.layout || 'register') : 'register',
  143. mode: isEdit ? 'editGroup' : 'createGroup',
  144. quantity: isEdit ? String(group.quantity || 1) : '1',
  145. pollEnabled: isEdit ? group.pollEnabled !== false : true,
  146. registerTypeIndex,
  147. registerTypeText: registerType.label || '',
  148. showPollEnabled: true,
  149. startAddress: isEdit && group.startAddressText ? group.startAddressText.replace(/^0x/i, '') : '0000',
  150. title: isStorageGroup
  151. ? (isEdit ? '编辑结构体组' : '添加结构体组')
  152. : (isEdit ? '编辑寄存器组' : '添加寄存器组'),
  153. visible: true
  154. })
  155. }
  156. function createParameterRegisterDialogState(mode, group, register, registerIndex) {
  157. const isView = mode === 'viewRegister'
  158. const dataTypeIndex = register.dataTypeIndex || 0
  159. const dataType = getOption(parameterGroupService.DATA_TYPE_OPTIONS, dataTypeIndex)
  160. return createParameterDialogState({
  161. cancelText: isView ? '关闭' : '取消',
  162. confirmText: isView ? '' : '保存',
  163. dataTypeIndex,
  164. dataTypeText: register.dataTypeText || dataType.label || '',
  165. groupId: group.id,
  166. groupName: group.name,
  167. mode,
  168. name: register.name,
  169. registerIndex,
  170. registerTypeIndex: group.registerTypeIndex || 0,
  171. remark: register.remark || '',
  172. startAddress: group.startAddressText ? group.startAddressText.replace(/^0x/i, '') : '0000',
  173. title: isView ? '寄存器信息' : '寄存器配置',
  174. textByteLength: String(register.textByteLength || '32'),
  175. showTextLength: !!register.showTextLength,
  176. unit: register.unit || '',
  177. visible: true,
  178. conversionFormula: register.conversionFormula || '',
  179. conversionFormulaErrorText: register.conversionFormulaErrorText || '',
  180. maxValue: register.maxValue || '',
  181. minValue: register.minValue || '',
  182. addressText: register.addressRangeText || register.addressText || '',
  183. displayValue: register.displayValue || '',
  184. rawValueText: register.rawValueText || '--',
  185. sourceByteLength: register.sourceByteLength || '',
  186. sourceEntryKind: register.sourceEntryKind || '',
  187. sourceMetaText: register.sourceMetaText || '',
  188. showDataType: !!register.showDataType,
  189. showRange: !!register.showRange,
  190. showUnit: !!register.showUnit,
  191. readOnly: isView
  192. })
  193. }
  194. function getDialogDataTypeState(dialog, dataTypeOptions, dataTypeIndex) {
  195. const dataType = getOption(dataTypeOptions, dataTypeIndex)
  196. const isTextType = dataType.kind === 'text'
  197. const showUnit = dataType.kind === 'number' && dataType.key !== 'hex'
  198. return {
  199. dataTypeIndex,
  200. dataTypeText: dataType.label || '',
  201. maxValue: isTextType ? '' : dialog.maxValue,
  202. minValue: isTextType ? '' : dialog.minValue,
  203. showRange: !isTextType,
  204. showTextLength: isTextType,
  205. showUnit,
  206. textByteLength: isTextType ? (dialog.textByteLength || '32') : dialog.textByteLength,
  207. unit: showUnit ? dialog.unit : ''
  208. }
  209. }
  210. function createParameterGroupConfig(dialog) {
  211. const registers = Array.isArray(dialog.parsedStructRegisters)
  212. ? dialog.parsedStructRegisters
  213. : []
  214. return {
  215. groupName: dialog.groupName,
  216. layout: registers.length ? 'struct' : (dialog.layout || 'register'),
  217. pollEnabled: dialog.pollEnabled !== false,
  218. quantity: registers.length ? String(registers.length) : dialog.quantity,
  219. registerTypeIndex: dialog.registerTypeIndex,
  220. startAddress: dialog.startAddress,
  221. ...(registers.length ? {
  222. registers: registers.map((register) => ({
  223. bitOffset: register.bitOffset,
  224. bitWidth: register.bitWidth,
  225. byteStart: register.byteStart,
  226. dataType: register.dataType,
  227. isBitField: !!register.isBitField,
  228. isStructField: true,
  229. name: register.name,
  230. structByteLength: register.structByteLength,
  231. textByteLength: register.textByteLength
  232. }))
  233. } : {})
  234. }
  235. }
  236. function createParameterRegisterChangedData(dialog, dataTypeOptions) {
  237. const dataType = getOption(dataTypeOptions, dialog.dataTypeIndex)
  238. const isTextType = dataType.kind === 'text'
  239. const showUnit = dataType.kind === 'number' && dataType.key !== 'hex'
  240. const conversionFormula = String(dialog.conversionFormula || '').trim()
  241. validateValueFormula(conversionFormula)
  242. validateCodeInfoVariableDataType(dialog, dataType)
  243. return {
  244. name: dialog.name,
  245. conversionFormula,
  246. dataType: dataType.key,
  247. maxValue: isTextType ? '' : dialog.maxValue,
  248. minValue: isTextType ? '' : dialog.minValue,
  249. remark: dialog.remark,
  250. textByteLength: isTextType ? dialog.textByteLength : '',
  251. unit: showUnit ? dialog.unit : ''
  252. }
  253. }
  254. function findParameterGroup(groups, groupId) {
  255. return (groups || []).find((item) => item.id === groupId) || null
  256. }
  257. function findParameterRegister(groups, groupId, registerIndex) {
  258. const group = findParameterGroup(groups, groupId)
  259. const register = group && group.registers ? group.registers[registerIndex] : null
  260. return {
  261. group,
  262. register
  263. }
  264. }
  265. function getActiveParameterGroup(groups, groupId) {
  266. return findParameterGroup(groups, groupId) || null
  267. }
  268. module.exports = {
  269. createParameterGroupConfig,
  270. createParameterGroupDialogState,
  271. createParameterDialogState,
  272. createParameterRegisterChangedData,
  273. createParameterRegisterDialogState,
  274. findParameterGroup,
  275. findParameterRegister,
  276. getActiveParameterGroup,
  277. getDialogDataTypeState,
  278. getOption,
  279. getPageState,
  280. getSettingsPageState,
  281. getTransportPageState,
  282. getVisiblePageState,
  283. resolveActiveParamView
  284. }