params.wxml 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. <navigation-bar background="{{themeMode === 'dark' ? '#111827' : '#FFF'}}"></navigation-bar>
  2. <view wx:if="{{toastText}}" class="page-toast page-toast--{{toastType}} {{themeClass}}">
  3. {{toastText}}
  4. </view>
  5. <view class="subpage-fixed-header subpage-fixed-header--generic {{themeClass}}">
  6. <view class="subpage-page-header">
  7. <view wx:if="{{activeParamView == 'genericModbus'}}" class="panel-actions subpage-actions generic-protocol-actions">
  8. <view class="panel-action-button {{isPrivateProtocol && !connectedDevice ? 'is-disabled' : ''}}" bindtap="syncGenericModbusGroups">同步</view>
  9. <view wx:if="{{isPrivateProtocol}}" class="panel-action-button {{connectedDevice ? '' : 'is-disabled'}} {{genericModbusAutoPollEnabled ? 'is-active' : ''}}" bindtap="toggleGenericModbusPolling">轮询</view>
  10. <view class="panel-action-button" bindtap="saveGenericModbusJson">保存</view>
  11. <view class="panel-action-button" bindtap="importGenericModbusJson">加载</view>
  12. <view wx:if="{{isPrivateProtocol}}" class="panel-action-button" bindtap="completeGenericModbusStructs">结构</view>
  13. <view wx:if="{{isGenericProtocol}}" class="panel-action-button panel-action-button--icon" bindtap="openGenericModbusDraft">+</view>
  14. </view>
  15. <view wx:elif="{{activeParamView == 'genericModbusGroup' && isGenericProtocol}}" class="panel-actions subpage-actions">
  16. <view
  17. class="panel-action-button {{connectedDevice && !activeGenericGroup.addressOverflow ? '' : 'is-disabled'}}"
  18. data-group-id="{{activeGenericGroup.id}}"
  19. bindtap="readGenericModbusGroup"
  20. >读取</view>
  21. <view
  22. wx:if="{{activeGenericGroup.writable}}"
  23. class="panel-action-button {{connectedDevice && !activeGenericGroup.addressOverflow ? '' : 'is-disabled'}}"
  24. data-group-id="{{activeGenericGroup.id}}"
  25. bindtap="writeGenericModbusGroup"
  26. >写入</view>
  27. <view class="panel-action-button" bindtap="backToParamsHome">返回</view>
  28. </view>
  29. </view>
  30. </view>
  31. <scroll-view class="scrollarea {{themeClass}} scrollarea--subpage scrollarea--generic" scroll-y type="list">
  32. <view class="page-shell">
  33. <block wx:if="{{activeParamView == 'genericModbus'}}">
  34. <view
  35. wx:for="{{genericModbusGroups}}"
  36. wx:for-item="group"
  37. wx:key="id"
  38. class="generic-group-shell {{group.deleteVisible ? 'is-delete-visible' : ''}}"
  39. >
  40. <view
  41. wx:if="{{!group.expanded && group.deleteVisible}}"
  42. class="generic-delete-action"
  43. data-group-id="{{group.id}}"
  44. bindtap="deleteGenericModbusGroup"
  45. >
  46. -
  47. </view>
  48. <view
  49. class="panel generic-group-panel {{group.expanded ? '' : 'panel--collapsed'}}"
  50. data-group-id="{{group.id}}"
  51. bindtouchstart="onGenericGroupTouchStart"
  52. bindtouchend="onGenericGroupTouchEnd"
  53. >
  54. <view class="panel-header panel-header--with-actions">
  55. <view
  56. class="panel-heading-toggle"
  57. data-group-id="{{group.id}}"
  58. bindtap="openGenericModbusGroup"
  59. >
  60. <view class="panel-icon icon-terminal">
  61. <image class="panel-icon-image" src="/assets/icons/terminal-white.png" mode="aspectFit" />
  62. </view>
  63. <view class="generic-group-title-wrap">
  64. <view class="panel-title" data-group-id="{{group.id}}" catchlongpress="openGenericGroupEdit">{{group.name}}</view>
  65. <view class="param-meta generic-group-meta">{{group.addressRangeText}} · {{group.quantity}}/{{group.wordQuantity}}{{group.sourceMetaText ? ' · ' + group.sourceMetaText : ''}}{{group.addressWarningText ? ' · ' + group.addressWarningText : ''}}</view>
  66. </view>
  67. </view>
  68. <view wx:if="{{isGenericProtocol}}" class="panel-actions generic-group-actions">
  69. <view
  70. class="panel-action-button {{connectedDevice && !group.addressOverflow ? '' : 'is-disabled'}}"
  71. data-group-id="{{group.id}}"
  72. bindtap="readGenericModbusGroup"
  73. >
  74. 读取
  75. </view>
  76. <view
  77. wx:if="{{group.writable}}"
  78. class="panel-action-button {{connectedDevice && !group.addressOverflow ? '' : 'is-disabled'}}"
  79. data-group-id="{{group.id}}"
  80. bindtap="writeGenericModbusGroup"
  81. >
  82. 写入
  83. </view>
  84. <view class="entry-chevron"></view>
  85. </view>
  86. </view>
  87. </view>
  88. </view>
  89. </block>
  90. <block wx:elif="{{activeParamView == 'genericModbusGroup'}}">
  91. <view wx:if="{{activeGenericGroup}}" class="panel generic-group-detail-panel">
  92. <view class="generic-group-detail-meta">
  93. {{activeGenericGroup.addressRangeText}} · {{activeGenericGroup.quantity}}/{{activeGenericGroup.wordQuantity}}{{activeGenericGroup.sourceMetaText ? ' · ' + activeGenericGroup.sourceMetaText : ''}}{{activeGenericGroup.addressWarningText ? ' · ' + activeGenericGroup.addressWarningText : ''}}
  94. </view>
  95. <view
  96. wx:for="{{activeGenericRegisterRows.length ? activeGenericRegisterRows : activeGenericGroup.registers}}"
  97. wx:for-item="register"
  98. wx:for-index="registerIndex"
  99. wx:key="id"
  100. class="generic-register-row {{register.dragClass}}"
  101. style="{{register.dragStyle}}"
  102. >
  103. <view
  104. wx:if="{{!activeGenericGroup.isStructLayout}}"
  105. class="generic-register-drag-handle {{register.dragHandleClass}}"
  106. data-group-id="{{activeGenericGroup.id}}"
  107. data-index="{{register.sourceIndex !== undefined ? register.sourceIndex : registerIndex}}"
  108. catchtouchstart="onGenericRegisterDragStart"
  109. catchtouchmove="onGenericRegisterDragMove"
  110. catchtouchend="onGenericRegisterDragEnd"
  111. catchtouchcancel="onGenericRegisterDragCancel"
  112. >
  113. <view class="generic-register-drag-bar"></view>
  114. <view class="generic-register-drag-bar"></view>
  115. <view class="generic-register-drag-bar"></view>
  116. </view>
  117. <view wx:else class="generic-register-layout-spacer"></view>
  118. <view class="generic-register-main">
  119. <view
  120. class="generic-register-name"
  121. data-group-id="{{activeGenericGroup.id}}"
  122. data-index="{{register.sourceIndex !== undefined ? register.sourceIndex : registerIndex}}"
  123. bindtap="openGenericRegisterInfo"
  124. catchlongpress="openGenericRegisterEdit"
  125. >
  126. {{register.name}}
  127. </view>
  128. <view class="generic-register-meta">
  129. <text>{{register.addressText}} {{register.rawValueText}}</text>
  130. </view>
  131. </view>
  132. <view class="generic-register-input-wrap {{register.showUnit && register.unit ? 'generic-register-input-wrap--unit' : ''}}">
  133. <block wx:if="{{activeGenericGroup.writable}}">
  134. <input
  135. class="value-input generic-register-value {{register.isDirty ? 'value-input--dirty' : ''}}"
  136. placeholder="--"
  137. data-group-id="{{activeGenericGroup.id}}"
  138. data-index="{{register.sourceIndex !== undefined ? register.sourceIndex : registerIndex}}"
  139. value="{{register.inputValue}}"
  140. bindinput="onGenericRegisterValueInput"
  141. bindblur="onGenericRegisterValueBlur"
  142. />
  143. <view wx:if="{{register.showUnit && register.unit}}" class="generic-register-unit">{{register.unit}}</view>
  144. </block>
  145. <view wx:else class="param-value generic-readonly-value">{{register.displayValue || '--'}}{{register.showUnit && register.unit ? ' ' + register.unit : ''}}</view>
  146. </view>
  147. </view>
  148. </view>
  149. </block>
  150. </view>
  151. </scroll-view>
  152. <view wx:if="{{genericModbusDialog.visible}}" class="generic-dialog-mask {{themeClass}}" bindtap="closeGenericModbusDraft">
  153. <view class="generic-dialog" catchtap="noop">
  154. <view class="generic-dialog-header">
  155. <view class="generic-dialog-title">{{genericModbusDialog.title}}</view>
  156. <view class="generic-dialog-close" bindtap="closeGenericModbusDraft">×</view>
  157. </view>
  158. <block wx:if="{{genericModbusDialog.mode == 'createGroup' || genericModbusDialog.mode == 'editGroup'}}">
  159. <view class="generic-dialog-body">
  160. <view class="generic-config-row">
  161. <view class="param-main">
  162. <view class="param-name">寄存器组名</view>
  163. <view class="param-meta">每组寄存器地址连续</view>
  164. </view>
  165. <input
  166. class="value-input generic-value-input"
  167. data-field="groupName"
  168. value="{{genericModbusDialog.groupName}}"
  169. bindinput="onGenericDraftInput"
  170. />
  171. </view>
  172. <view class="generic-config-row">
  173. <view class="param-main">
  174. <view class="param-name">寄存器类型</view>
  175. <view class="param-meta">决定读取功能码与是否可写</view>
  176. </view>
  177. <picker
  178. mode="selector"
  179. range="{{genericModbusRegisterTypeOptions}}"
  180. range-key="label"
  181. value="{{genericModbusDialog.registerTypeIndex}}"
  182. bindchange="onGenericDraftTypeChange"
  183. >
  184. <view class="generic-picker-value">{{genericModbusDialog.registerTypeText}}</view>
  185. </picker>
  186. </view>
  187. <view class="generic-config-row">
  188. <view class="param-main">
  189. <view class="param-name">寄存器起始地址</view>
  190. <view class="param-meta">16进制,例如 00A0</view>
  191. </view>
  192. <input
  193. class="value-input generic-value-input"
  194. data-field="startAddress"
  195. value="{{genericModbusDialog.startAddress}}"
  196. bindinput="onGenericDraftInput"
  197. />
  198. </view>
  199. <view class="generic-config-row">
  200. <view class="param-main">
  201. <view class="param-name">寄存器数量</view>
  202. <view class="param-meta">{{genericModbusDialog.structParsedSummary || '1 - 256'}}</view>
  203. </view>
  204. <input
  205. class="value-input generic-value-input"
  206. type="number"
  207. data-field="quantity"
  208. value="{{genericModbusDialog.quantity}}"
  209. bindinput="onGenericDraftInput"
  210. />
  211. </view>
  212. <view wx:if="{{genericModbusDialog.mode == 'createGroup'}}" class="generic-struct-section">
  213. <view class="generic-struct-header">
  214. <view class="param-main">
  215. <view class="param-name">结构体定义</view>
  216. <view class="param-meta">支持 typedef struct、typedef 别名与数组</view>
  217. </view>
  218. <view class="panel-action-button" bindtap="parseGenericStructDefinition">解析</view>
  219. </view>
  220. <textarea
  221. class="generic-struct-input"
  222. maxlength="-1"
  223. placeholder="粘贴 C 结构体定义"
  224. data-field="structDefinition"
  225. value="{{genericModbusDialog.structDefinition}}"
  226. bindinput="onGenericDraftInput"
  227. />
  228. </view>
  229. </view>
  230. </block>
  231. <block wx:elif="{{genericModbusDialog.mode == 'editRegister' || genericModbusDialog.mode == 'viewRegister'}}">
  232. <view class="generic-dialog-body">
  233. <view class="generic-info-stack">
  234. <view class="generic-info-row">
  235. <view class="generic-info-label">名称</view>
  236. <view wx:if="{{genericModbusDialog.mode == 'viewRegister'}}" class="generic-info-value">{{genericModbusDialog.name}}</view>
  237. <input wx:else class="value-input generic-value-input" data-field="name" value="{{genericModbusDialog.name}}" bindinput="onGenericDraftInput" />
  238. </view>
  239. <view class="generic-info-row">
  240. <view class="generic-info-label">地址</view>
  241. <view class="generic-info-value">{{genericModbusDialog.addressText}}</view>
  242. </view>
  243. <view wx:if="{{genericModbusDialog.sourceMetaText}}" class="generic-info-row">
  244. <view class="generic-info-label">来源</view>
  245. <view class="generic-info-value">{{genericModbusDialog.sourceMetaText}}</view>
  246. </view>
  247. <view wx:if="{{genericModbusDialog.showDataType}}" class="generic-info-row">
  248. <view class="generic-info-label">类型</view>
  249. <view wx:if="{{genericModbusDialog.mode == 'viewRegister'}}" class="generic-info-value">{{genericModbusDialog.dataTypeText}}</view>
  250. <picker wx:else mode="selector" range="{{genericModbusDataTypeOptions}}" range-key="label" value="{{genericModbusDialog.dataTypeIndex}}" bindchange="onGenericDialogDataTypeChange">
  251. <view class="generic-picker-value">{{genericModbusDialog.dataTypeText}}</view>
  252. </picker>
  253. </view>
  254. <view wx:if="{{genericModbusDialog.showTextLength}}" class="generic-info-row">
  255. <view class="generic-info-label">长度</view>
  256. <view wx:if="{{genericModbusDialog.mode == 'viewRegister'}}" class="generic-info-value">{{genericModbusDialog.textByteLength || '--'}}B</view>
  257. <input wx:else class="value-input generic-value-input" type="number" data-field="textByteLength" value="{{genericModbusDialog.textByteLength}}" bindinput="onGenericDraftInput" />
  258. </view>
  259. <view class="generic-info-row">
  260. <view class="generic-info-label">备注</view>
  261. <view wx:if="{{genericModbusDialog.mode == 'viewRegister'}}" class="generic-info-value">{{genericModbusDialog.remark || '--'}}</view>
  262. <input wx:else class="value-input generic-value-input" data-field="remark" value="{{genericModbusDialog.remark}}" bindinput="onGenericDraftInput" />
  263. </view>
  264. <view wx:if="{{genericModbusDialog.showUnit}}" class="generic-info-row">
  265. <view class="generic-info-label">单位</view>
  266. <view wx:if="{{genericModbusDialog.mode == 'viewRegister'}}" class="generic-info-value">{{genericModbusDialog.unit || '--'}}</view>
  267. <input wx:else class="value-input generic-value-input" data-field="unit" value="{{genericModbusDialog.unit}}" bindinput="onGenericDraftInput" />
  268. </view>
  269. <view wx:if="{{genericModbusDialog.mode == 'viewRegister' || genericModbusDialog.showRange}}" class="generic-info-row">
  270. <view class="generic-info-label">最小值</view>
  271. <view wx:if="{{genericModbusDialog.mode == 'viewRegister'}}" class="generic-info-value">{{genericModbusDialog.minValue || '--'}}</view>
  272. <input wx:else class="value-input generic-value-input" data-field="minValue" value="{{genericModbusDialog.minValue}}" bindinput="onGenericDraftInput" />
  273. </view>
  274. <view wx:if="{{genericModbusDialog.mode == 'viewRegister' || genericModbusDialog.showRange}}" class="generic-info-row">
  275. <view class="generic-info-label">最大值</view>
  276. <view wx:if="{{genericModbusDialog.mode == 'viewRegister'}}" class="generic-info-value">{{genericModbusDialog.maxValue || '--'}}</view>
  277. <input wx:else class="value-input generic-value-input" data-field="maxValue" value="{{genericModbusDialog.maxValue}}" bindinput="onGenericDraftInput" />
  278. </view>
  279. </view>
  280. </view>
  281. </block>
  282. <view class="generic-draft-actions">
  283. <view class="panel-action-button" bindtap="closeGenericModbusDraft">{{genericModbusDialog.cancelText}}</view>
  284. <view wx:if="{{genericModbusDialog.confirmText}}" class="panel-action-button is-active" bindtap="confirmGenericModbusDialog">{{genericModbusDialog.confirmText}}</view>
  285. </view>
  286. </view>
  287. </view>