1
0

view-model.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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, settingsState = settingsService.getState()) {
  50. if (settingsState.parameterCardControlEnabled === false) return 'parameterGroups'
  51. return currentView === 'parameterGroup' ? currentView : 'parameterGroups'
  52. }
  53. function getSettingsPageState(currentData, settingsState) {
  54. const isNoProtocol = settingsService.isNoProtocol(settingsState.protocolMode)
  55. const isModbusProtocol = settingsService.isModbusProtocol(settingsState.protocolMode)
  56. const isStorageAccessProtocol = settingsService.isStorageAccessProtocol(settingsState.protocolMode)
  57. return {
  58. ...settingsState,
  59. activeParamView: resolveActiveParamView(currentData.activeParamView, settingsState),
  60. isNoProtocol,
  61. isModbusProtocol,
  62. isStorageAccessProtocol
  63. }
  64. }
  65. function getVisiblePageState(currentData) {
  66. const settingsState = settingsService.getState()
  67. const transportState = transport.getState()
  68. const isNoProtocol = settingsService.isNoProtocol(settingsState.protocolMode)
  69. const isModbusProtocol = settingsService.isModbusProtocol(settingsState.protocolMode)
  70. const isStorageAccessProtocol = settingsService.isStorageAccessProtocol(settingsState.protocolMode)
  71. const pageState = {
  72. ...parameterGroupService.getState(),
  73. ...themeService.getState(),
  74. ...settingsState,
  75. connectedDevice: transportState.connectedDevice,
  76. isNoProtocol,
  77. isModbusProtocol,
  78. isStorageAccessProtocol
  79. }
  80. return {
  81. ...pageState,
  82. activeParamView: resolveActiveParamView(currentData.activeParamView, settingsState)
  83. }
  84. }
  85. function getTransportPageState(transportState = transport.getState()) {
  86. return {
  87. connectedDevice: transportState.connectedDevice
  88. }
  89. }
  90. function createParameterDialogState(overrides = {}) {
  91. const registerType = getOption(parameterGroupService.REGISTER_TYPE_OPTIONS, 0)
  92. const dataType = getOption(parameterGroupService.DATA_TYPE_OPTIONS, 0)
  93. return {
  94. cancelText: '取消',
  95. confirmText: '确认',
  96. dataTypeIndex: 0,
  97. dataTypeText: dataType.label || '',
  98. groupId: '',
  99. groupName: '',
  100. mode: '',
  101. name: '',
  102. quantity: '1',
  103. registerIndex: -1,
  104. registerTypeIndex: 0,
  105. registerTypeText: registerType.label || '',
  106. remark: '',
  107. startAddress: '0000',
  108. title: '',
  109. textByteLength: '32',
  110. showTextLength: false,
  111. unit: '',
  112. visible: false,
  113. maxValue: '',
  114. minValue: '',
  115. conversionFormula: '',
  116. conversionFormulaErrorText: '',
  117. addressText: '',
  118. displayValue: '',
  119. rawValueText: '',
  120. showDataType: false,
  121. showRange: false,
  122. showUnit: false,
  123. readOnly: false,
  124. parsedStructRegisters: [],
  125. pollEnabled: true,
  126. showPollEnabled: false,
  127. sourceByteLength: '',
  128. sourceEntryKind: '',
  129. structDefinition: '',
  130. structParsedSummary: '',
  131. ...overrides
  132. }
  133. }
  134. function createParameterGroupDialogState(group) {
  135. const isEdit = !!group
  136. const isStorageGroup = !!(group && group.sourceMemoryArea)
  137. const registerTypeIndex = isEdit ? (group.registerTypeIndex || 0) : 0
  138. const registerType = getOption(parameterGroupService.REGISTER_TYPE_OPTIONS, registerTypeIndex)
  139. return createParameterDialogState({
  140. confirmText: isEdit ? '保存' : '确认',
  141. groupId: isEdit ? group.id : '',
  142. groupName: isEdit ? group.name : (isStorageGroup ? '结构体组' : '寄存器组'),
  143. layout: isEdit ? (group.layout || 'register') : 'register',
  144. mode: isEdit ? 'editGroup' : 'createGroup',
  145. quantity: isEdit ? String(group.quantity || 1) : '1',
  146. pollEnabled: isEdit ? group.pollEnabled !== false : true,
  147. registerTypeIndex,
  148. registerTypeText: registerType.label || '',
  149. showPollEnabled: true,
  150. startAddress: isEdit && group.startAddressText ? group.startAddressText.replace(/^0x/i, '') : '0000',
  151. title: isStorageGroup
  152. ? (isEdit ? '编辑结构体组' : '添加结构体组')
  153. : (isEdit ? '编辑寄存器组' : '添加寄存器组'),
  154. visible: true
  155. })
  156. }
  157. function createParameterRegisterDialogState(mode, group, register, registerIndex) {
  158. const isView = mode === 'viewRegister'
  159. const dataTypeIndex = register.dataTypeIndex || 0
  160. const dataType = getOption(parameterGroupService.DATA_TYPE_OPTIONS, dataTypeIndex)
  161. return createParameterDialogState({
  162. cancelText: isView ? '关闭' : '取消',
  163. confirmText: isView ? '' : '保存',
  164. dataTypeIndex,
  165. dataTypeText: register.dataTypeText || dataType.label || '',
  166. groupId: group.id,
  167. groupName: group.name,
  168. mode,
  169. name: register.name,
  170. registerIndex,
  171. registerTypeIndex: group.registerTypeIndex || 0,
  172. remark: register.remark || '',
  173. startAddress: group.startAddressText ? group.startAddressText.replace(/^0x/i, '') : '0000',
  174. title: isView ? '寄存器信息' : '寄存器配置',
  175. textByteLength: String(register.textByteLength || '32'),
  176. showTextLength: !!register.showTextLength,
  177. unit: register.unit || '',
  178. visible: true,
  179. conversionFormula: register.conversionFormula || '',
  180. conversionFormulaErrorText: register.conversionFormulaErrorText || '',
  181. maxValue: register.maxValue || '',
  182. minValue: register.minValue || '',
  183. addressText: register.addressRangeText || register.addressText || '',
  184. displayValue: register.displayValue || '',
  185. rawValueText: register.rawValueText || '--',
  186. sourceByteLength: register.sourceByteLength || '',
  187. sourceEntryKind: register.sourceEntryKind || '',
  188. sourceMetaText: register.sourceMetaText || '',
  189. showDataType: !!register.showDataType,
  190. showRange: !!register.showRange,
  191. showUnit: !!register.showUnit,
  192. readOnly: isView
  193. })
  194. }
  195. function getDialogDataTypeState(dialog, dataTypeOptions, dataTypeIndex) {
  196. const dataType = getOption(dataTypeOptions, dataTypeIndex)
  197. const isTextType = dataType.kind === 'text'
  198. const showUnit = dataType.kind === 'number' && dataType.key !== 'hex'
  199. return {
  200. dataTypeIndex,
  201. dataTypeText: dataType.label || '',
  202. maxValue: isTextType ? '' : dialog.maxValue,
  203. minValue: isTextType ? '' : dialog.minValue,
  204. showRange: !isTextType,
  205. showTextLength: isTextType,
  206. showUnit,
  207. textByteLength: isTextType ? (dialog.textByteLength || '32') : dialog.textByteLength,
  208. unit: showUnit ? dialog.unit : ''
  209. }
  210. }
  211. function createParameterGroupConfig(dialog) {
  212. const registers = Array.isArray(dialog.parsedStructRegisters)
  213. ? dialog.parsedStructRegisters
  214. : []
  215. return {
  216. groupName: dialog.groupName,
  217. layout: registers.length ? 'struct' : (dialog.layout || 'register'),
  218. pollEnabled: dialog.pollEnabled !== false,
  219. quantity: registers.length ? String(registers.length) : dialog.quantity,
  220. registerTypeIndex: dialog.registerTypeIndex,
  221. startAddress: dialog.startAddress,
  222. ...(registers.length ? {
  223. registers: registers.map((register) => ({
  224. bitOffset: register.bitOffset,
  225. bitWidth: register.bitWidth,
  226. byteStart: register.byteStart,
  227. dataType: register.dataType,
  228. isBitField: !!register.isBitField,
  229. isStructField: true,
  230. name: register.name,
  231. structByteLength: register.structByteLength,
  232. textByteLength: register.textByteLength
  233. }))
  234. } : {})
  235. }
  236. }
  237. function createParameterRegisterChangedData(dialog, dataTypeOptions) {
  238. const dataType = getOption(dataTypeOptions, dialog.dataTypeIndex)
  239. const isTextType = dataType.kind === 'text'
  240. const showUnit = dataType.kind === 'number' && dataType.key !== 'hex'
  241. const conversionFormula = String(dialog.conversionFormula || '').trim()
  242. validateValueFormula(conversionFormula)
  243. validateCodeInfoVariableDataType(dialog, dataType)
  244. return {
  245. name: dialog.name,
  246. conversionFormula,
  247. dataType: dataType.key,
  248. maxValue: isTextType ? '' : dialog.maxValue,
  249. minValue: isTextType ? '' : dialog.minValue,
  250. remark: dialog.remark,
  251. textByteLength: isTextType ? dialog.textByteLength : '',
  252. unit: showUnit ? dialog.unit : ''
  253. }
  254. }
  255. function findParameterGroup(groups, groupId) {
  256. return (groups || []).find((item) => item.id === groupId) || null
  257. }
  258. function findParameterRegister(groups, groupId, registerIndex) {
  259. const group = findParameterGroup(groups, groupId)
  260. const register = group && group.registers ? group.registers[registerIndex] : null
  261. return {
  262. group,
  263. register
  264. }
  265. }
  266. function getActiveParameterGroup(groups, groupId) {
  267. return findParameterGroup(groups, groupId) || null
  268. }
  269. module.exports = {
  270. createParameterGroupConfig,
  271. createParameterGroupDialogState,
  272. createParameterDialogState,
  273. createParameterRegisterChangedData,
  274. createParameterRegisterDialogState,
  275. findParameterGroup,
  276. findParameterRegister,
  277. getActiveParameterGroup,
  278. getDialogDataTypeState,
  279. getOption,
  280. getPageState,
  281. getSettingsPageState,
  282. getTransportPageState,
  283. getVisiblePageState,
  284. resolveActiveParamView
  285. }