index.vue 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989
  1. <template>
  2. <component ref="modelRef" :loading="loading" :is="modelComponent" />
  3. <div class="scene-box">
  4. <div class="top-box">
  5. <div class="top-center row">
  6. <div v-if="hasPermission('btn:control')" class="button-box" @click="setControl('frontGateOpen_S', '打开前门')">打开前门</div>
  7. <div v-if="hasPermission('btn:control')" class="button-box" @click="setControl('frontGateClose_S', '关闭前门')">关闭前门</div>
  8. <div v-if="hasPermission('btn:control_stop')" class="button-box" @click="setControl('frontGateStop_S', '暂停前门')">暂停前门</div>
  9. <div v-if="hasPermission('btn:control') && selectData.ndoorcount == '3'" class="button-box" @click="setControl('midGateOpen_S', '打开中间门')"
  10. >打开中间门
  11. </div>
  12. <div
  13. v-if="hasPermission('btn:control') && selectData.ndoorcount == '3'"
  14. class="button-box"
  15. @click="setControl('midGateClose_S', '关闭中间门')"
  16. >关闭中间门
  17. </div>
  18. <div
  19. v-if="hasPermission('btn:control') && (selectData.ndoorcount == '2' || selectData.ndoorcount == '3')"
  20. class="button-box"
  21. @click="setControl('rearGateOpen_S', '打开后门')"
  22. >打开后门
  23. </div>
  24. <div
  25. v-if="hasPermission('btn:control') && (selectData.ndoorcount == '2' || selectData.ndoorcount == '3')"
  26. class="button-box"
  27. @click="setControl('rearGateClose_S', '关闭后门')"
  28. >关闭后门
  29. </div>
  30. <div
  31. v-if="hasPermission('btn:control_stop') && (selectData.ndoorcount == '2' || selectData.ndoorcount == '3')"
  32. class="button-box"
  33. @click="setControl('rearGateStop_S', '暂停后门')"
  34. >暂停后门
  35. </div>
  36. <div
  37. v-if="
  38. hasPermission('btn:totalControl') ||
  39. (selectData['isShowGatesContrl'] == 1 && (selectData.ndoorcount == '2' || selectData.ndoorcount == '3'))
  40. "
  41. class="button-box"
  42. @click="setControl('sameTimeOpen', '同时打开')"
  43. >同时打开
  44. </div>
  45. <div
  46. v-if="
  47. hasPermission('btn:totalControl') ||
  48. (selectData['isShowGatesContrl'] == 1 && (selectData.ndoorcount == '2' || selectData.ndoorcount == '3'))
  49. "
  50. class="button-box"
  51. @click="setControl('sameTimeClose', '同时关闭')"
  52. >同时关闭
  53. </div>
  54. <template v-if="selectData['gateStyle'] && selectData['gateStyle'].includes('fm_fc')">
  55. <template v-if="selectData['nwindownum'] == 4">
  56. <div v-if="hasPermission('btn:controlWindow')" class="button-box" @click="setControl('frontSetValue1', 'A窗控制')">A窗控制</div>
  57. <div v-if="hasPermission('btn:controlWindow')" class="button-box" @click="setControl('frontSetValue2', 'B窗控制')">B窗控制</div>
  58. <div v-if="hasPermission('btn:controlWindow')" class="button-box" @click="setControl('rearSetValue1', 'C窗控制')">C窗控制</div>
  59. <div v-if="hasPermission('btn:controlWindow')" class="button-box" @click="setControl('rearSetValue2', 'D窗控制')">D窗控制</div>
  60. </template>
  61. <template v-if="selectData['nwindownum'] == 2">
  62. <div v-if="hasPermission('btn:controlWindow')" class="button-box" @click="setControl('frontSetValue', '前窗控制')">前窗控制</div>
  63. <div v-if="hasPermission('btn:controlWindow')" class="button-box" @click="setControl('rearSetValue', '后窗控制')">后窗控制</div>
  64. </template>
  65. </template>
  66. </div>
  67. <!-- 控制模式 -->
  68. <div class="top-right row" v-if="hasPermission('btn:remote')">
  69. <!-- -->
  70. <div class="vent-flex-m row" v-if="selectData.contrlMod == 'loopCtrl' && modelList.length > 0">
  71. <div class="control-title">控制模式:</div>
  72. <a-radio-group v-model:value="selectData.autoRoManual">
  73. <template v-for="(item, index) in modelList" :key="index">
  74. <a-radio :value="item.value" :disabled="true">{{ item.text }}</a-radio>
  75. </template>
  76. </a-radio-group>
  77. <div class="button-box" @click="setControlMode()">切换模式</div>
  78. </div>
  79. <!-- 控制指令是多个,每个状态需要下发单独的指令 -->
  80. <div class="vent-flex-m row" v-else-if="selectData.contrlMod == 'codeCtrl' && modelList.length > 0">
  81. <div class="control-title">控制模式:</div>
  82. <a-radio-group v-model:value="selectData.autoRoManual">
  83. <template v-for="(item, index) in modelList" :key="index">
  84. <a-radio :value="item.value" :disabled="true">{{ item.text }}</a-radio>
  85. </template>
  86. </a-radio-group>
  87. <div class="button-box" v-for="(item, index) in modelList" @click="setControlMode(item.value)" :key="index"> {{ item.text }}</div>
  88. </div>
  89. <!-- 济南嘉鸿远程、就地、自动控制,自动切换,点位为true就是选中状态 -->
  90. <div class="vent-flex-m row" v-else-if="selectData.contrlMod == 'jnjhCtrl' && modelList.length > 0">
  91. <div class="control-title">控制模式:</div>
  92. <a-radio v-model:checked="selectData['autoRoManual']" :disabled="true">远程</a-radio>
  93. <a-radio v-model:checked="selectData['autoRoManual1']" :disabled="true">自动</a-radio>
  94. <a-radio v-model:checked="selectData['autoRoManual2']" :disabled="true">手动</a-radio>
  95. <div class="button-box" @click="setControlMode()">模式切换</div>
  96. </div>
  97. <div class="vent-flex-m row" v-else-if="modelList.length > 0">
  98. <div class="control-title">控制模式:</div>
  99. <a-radio-group v-model:value="selectData.autoRoManual">
  100. <template v-for="(item, index) in modelList" :key="index">
  101. <a-radio :value="item.value" :disabled="true">{{ item.text }}</a-radio>
  102. </template>
  103. </a-radio-group>
  104. <div class="button-box" v-for="(item, index) in modelList" @click="setControlMode(item.value)" :key="index"> {{ item.text }}</div>
  105. </div>
  106. </div>
  107. <div v-if="hasPermission('gate:overhaul')" class="run-type row">
  108. <div class="control-title">是否检修:</div>
  109. <a-radio-group v-model:value="selectData.runRoRecondition" @change="changeOverhaul">
  110. <a-radio :value="`1`">是</a-radio>
  111. <a-radio :value="`0`">否</a-radio>
  112. </a-radio-group>
  113. </div>
  114. <div v-if="hasPermission('gata:manualAutoModeBtn')" class="vent-flex-m row">
  115. <div class="control-title"></div>
  116. <a-switch
  117. :checked="selectData.manualAutoMode_r"
  118. checked-children="手动"
  119. un-checked-children="自动"
  120. :checked-value="'1'"
  121. :un-checked-value="'0'"
  122. @change="handleSwitchChange"
  123. />
  124. </div>
  125. </div>
  126. <div class="title-text"> {{ selectData.supplyAirAddr || selectData.strinstallpos || selectData.strname }} </div>
  127. <div class="bottom-tabs-box" @mousedown="setDivHeight($event, 50, scroll)">
  128. <dv-border-box8 :dur="5" :style="`padding: 5px; height: ${scroll.y + 120}px`">
  129. <a-tabs class="tabs-box" v-model:activeKey="activeKey" @change="tabChange">
  130. <a-tab-pane v-if="!hasPermission('show:noMonitor')" key="1" tab="实时监测">
  131. <MonitorTable
  132. v-if="activeKey === '1'"
  133. ref="MonitorDataTable"
  134. class="monitor-table"
  135. :columnsType="deviceType"
  136. :isShowActionColumn="true"
  137. :dataSource="dataSource"
  138. design-scope="gate-monitor"
  139. @select-row="getSelectRow"
  140. :scroll="{ y: scroll.y - 40 }"
  141. title="风门监测"
  142. :isShowPagination="true"
  143. >
  144. <template #filterCell="{ column, record }">
  145. <a-tag v-if="column.dataIndex === 'frontGateOpen' && record.frontGateOpen == '0' && record.frontGateClose == '0'" color="red"
  146. >正在运行
  147. </a-tag>
  148. <a-tag v-else-if="column.dataIndex === 'frontGateOpen' && record.frontGateOpen == '0' && record.frontGateClose == 1" color="default"
  149. >关闭
  150. </a-tag>
  151. <a-tag v-else-if="column.dataIndex === 'frontGateOpen' && record.frontGateOpen == '1' && record.frontGateClose == '0'" color="#46C66F"
  152. >打开
  153. </a-tag>
  154. <a-tag v-else-if="column.dataIndex === 'frontGateOpen' && record.frontGateOpen == '1' && record.frontGateClose == '1'" color="#FF0000"
  155. >点位异常
  156. </a-tag>
  157. <a-tag v-if="column.dataIndex === 'rearGateOpen' && record.rearGateOpen == '0' && record.rearGateClose == '0'" color="red"
  158. >正在运行
  159. </a-tag>
  160. <a-tag v-else-if="column.dataIndex === 'rearGateOpen' && record.rearGateOpen == '0' && record.rearGateClose == '1'" color="default"
  161. >关闭
  162. </a-tag>
  163. <a-tag v-else-if="column.dataIndex === 'rearGateOpen' && record.rearGateOpen == '1' && record.rearGateClose == '0'" color="#46C66F"
  164. >打开
  165. </a-tag>
  166. <a-tag v-else-if="column.dataIndex === 'rearGateOpen' && record.rearGateOpen == '1' && record.rearGateClose == '1'" color="#FF0000"
  167. >点位异常
  168. </a-tag>
  169. <a-tag v-if="column.dataIndex === 'midGateOpen' && record.midGateOpen == '0' && record.midGateClose == '0'" color="red"
  170. >正在运行
  171. </a-tag>
  172. <a-tag v-else-if="column.dataIndex === 'midGateOpen' && record.midGateOpen == '0' && record.midGateClose == 1" color="default"
  173. >关闭
  174. </a-tag>
  175. <a-tag v-else-if="column.dataIndex === 'midGateOpen' && record.midGateOpen == '1' && record.midGateClose == '0'" color="#46C66F"
  176. >打开
  177. </a-tag>
  178. <a-tag v-else-if="column.dataIndex === 'midGateOpen' && record.midGateOpen == '1' && record.midGateClose == '1'" color="#FF0000"
  179. >点位异常
  180. </a-tag>
  181. <template v-if="column.dataIndex === 'ndoortype'">
  182. <span>{{ render.renderDictText(record.ndoortype, 'ndoortype') }}</span>
  183. </template>
  184. <template v-if="column.dataIndex === 'doorUse'">
  185. <span>{{ render.renderDictText(record.doorUse, 'doorUse') }}</span>
  186. </template>
  187. <template v-else-if="column.dataIndex === 'warnLevel'">
  188. <a-tag v-if="record.warnLevel == '101'" color="green">低风险</a-tag>
  189. <a-tag v-else-if="record.warnLevel == '102'" color="#FF5812">一般风险</a-tag>
  190. <a-tag v-else-if="record.warnLevel == '103'" color="#FF5812">较大风险</a-tag>
  191. <a-tag v-else-if="record.warnLevel == '104'" color="#FF5812">重大风险</a-tag>
  192. <a-tag v-else-if="record.warnLevel == '201'" color="#FF0000">报警</a-tag>
  193. <a-tag v-else-if="record.warnLevel == '10000'" color="#FF5812">数据超限</a-tag>
  194. <a-tag v-else-if="record.warnLevel == '1001'" color="default">网络中断</a-tag>
  195. <a-tag v-else color="green">正常</a-tag>
  196. </template>
  197. <a-tag v-else-if="column.dataIndex === 'warnFlag'" :color="record.warnFlag == '0' ? 'green' : 'red'">{{
  198. record.warnFlag == '0' ? '正常' : '报警'
  199. }}</a-tag>
  200. <a-tag v-if="column.dataIndex === 'runRoRecondition'" :color="record.runRoRecondition == '1' ? '#f00' : 'green'">{{
  201. record.runRoRecondition == '1' ? '检修' : '运行'
  202. }}</a-tag>
  203. <a-tag v-if="column.dataIndex === 'netStatus'" :color="record.netStatus == '0' ? '#f00' : 'green'">{{
  204. record.netStatus == '0' ? '断开' : '连接'
  205. }}</a-tag>
  206. </template>
  207. <template #action="{ record }">
  208. <a v-if="globalConfig?.showReport" class="table-action-link" @click="deviceEdit($event, 'reportInfo', record)">报表录入</a>
  209. <a class="table-action-link" @click="deviceEdit($event, 'deviceInfo', record)">设备编辑</a>
  210. </template>
  211. </MonitorTable>
  212. </a-tab-pane>
  213. <!-- <a-tab-pane key="2" tab="实时曲线图" force-render>
  214. <div class="tab-item" v-if="activeKey === '2'">
  215. <DeviceEcharts chartsColumnsType="gate_chart" xAxisPropType="strname" :dataSource="dataSource" height="100%"
  216. :chartsColumns="chartsColumns" :device-list-api="list" device-type="gate" />
  217. </div>
  218. </a-tab-pane> -->
  219. <a-tab-pane v-if="!hasPermission('show:noHistory')" key="3" tab="历史数据">
  220. <div class="tab-item" v-if="activeKey === '3'">
  221. <HistoryTable :columnsType="deviceType" :device-type="deviceType" designScope="gate-history" :scroll="scroll">
  222. <template #filterCell="{ column, record }">
  223. <a-tag v-if="column.dataIndex === 'frontGateOpen' && record.frontGateOpen == '0' && record.frontGateClose == '0'" color="red"
  224. >正在运行
  225. </a-tag>
  226. <a-tag v-else-if="column.dataIndex === 'frontGateOpen' && record.frontGateOpen == '0' && record.frontGateClose == 1" color="default"
  227. >关闭
  228. </a-tag>
  229. <a-tag
  230. v-else-if="column.dataIndex === 'frontGateOpen' && record.frontGateOpen == '1' && record.frontGateClose == '0'"
  231. color="#46C66F"
  232. >打开
  233. </a-tag>
  234. <a-tag
  235. v-else-if="column.dataIndex === 'frontGateOpen' && record.frontGateOpen == '1' && record.frontGateClose == '1'"
  236. color="#FF0000"
  237. >点位异常
  238. </a-tag>
  239. <a-tag v-if="column.dataIndex === 'rearGateOpen' && record.rearGateOpen == '0' && record.rearGateClose == '0'" color="red"
  240. >正在运行
  241. </a-tag>
  242. <a-tag v-else-if="column.dataIndex === 'rearGateOpen' && record.rearGateOpen == '0' && record.rearGateClose == '1'" color="default"
  243. >关闭
  244. </a-tag>
  245. <a-tag v-else-if="column.dataIndex === 'rearGateOpen' && record.rearGateOpen == '1' && record.rearGateClose == '0'" color="#46C66F"
  246. >打开
  247. </a-tag>
  248. <a-tag v-else-if="column.dataIndex === 'rearGateOpen' && record.rearGateOpen == '1' && record.rearGateClose == '1'" color="#FF0000"
  249. >点位异常
  250. </a-tag>
  251. <a-tag v-if="column.dataIndex === 'midGateOpen' && record.midGateOpen == '0' && record.midGateClose == '0'" color="red"
  252. >正在运行
  253. </a-tag>
  254. <a-tag v-else-if="column.dataIndex === 'midGateOpen' && record.midGateOpen == '0' && record.midGateClose == 1" color="default"
  255. >关闭
  256. </a-tag>
  257. <a-tag v-else-if="column.dataIndex === 'midGateOpen' && record.midGateOpen == '1' && record.midGateClose == '0'" color="#46C66F"
  258. >打开
  259. </a-tag>
  260. <a-tag v-else-if="column.dataIndex === 'midGateOpen' && record.midGateOpen == '1' && record.midGateClose == '1'" color="#FF0000"
  261. >点位异常
  262. </a-tag>
  263. <template v-if="column.dataIndex === 'ndoortype'">
  264. <span v-if="record.ndoortype == '0'">气动风门</span>
  265. <span v-else color="default">液压风门</span>
  266. </template>
  267. <template v-if="column.dataIndex === 'doorUse'">
  268. <span v-if="record.doorUse == 1" color="default">行车风门</span>
  269. <span v-else-if="record.doorUse == 2">行人风门</span>
  270. <span v-else-if="record.doorUse == 3">短路风门</span>
  271. <span v-else-if="record.doorUse == 4">行车/短路风门</span>
  272. </template>
  273. <template v-else-if="column.dataIndex === 'warnLevel'">
  274. <a-tag v-if="record.warnLevel == '101'" color="green">低风险</a-tag>
  275. <a-tag v-else-if="record.warnLevel == '102'" color="#FF5812">一般风险</a-tag>
  276. <a-tag v-else-if="record.warnLevel == '103'" color="#FF5812">较大风险</a-tag>
  277. <a-tag v-else-if="record.warnLevel == '104'" color="#FF5812">重大风险</a-tag>
  278. <a-tag v-else-if="record.warnLevel == '201'" color="#FF0000">报警</a-tag>
  279. <a-tag v-else-if="record.warnLevel == '10000'" color="#FF5812">数据超限</a-tag>
  280. <a-tag v-else-if="record.warnLevel == '1001'" color="default">网络中断</a-tag>
  281. <a-tag v-else color="green">正常</a-tag>
  282. </template>
  283. </template>
  284. </HistoryTable>
  285. </div>
  286. </a-tab-pane>
  287. <a-tab-pane v-if="!hasPermission('show:noAlarm')" key="4" tab="报警历史">
  288. <div class="tab-item" v-if="activeKey === '4'">
  289. <template v-if="sysOrgCode != 'zmhjhzmy'">
  290. <AlarmHistoryTable
  291. columns-type="alarm"
  292. :device-type="deviceType"
  293. :device-list-api="getTableList"
  294. designScope="alarm-history"
  295. :scroll="scroll"
  296. >
  297. <template #filterCell="{ column, record }">
  298. <a-tag
  299. v-if="column.dataIndex === 'warnFlag'"
  300. :color="record.warnFlag == '0' ? 'green' : record.warnFlag == 1 ? '#FF5812' : 'gray'"
  301. >
  302. {{ record.warnFlag == '0' ? '正常' : record.warnFlag == 1 ? '报警' : record.warnFlag == 2 ? '断开' : '未监测' }}
  303. </a-tag>
  304. <a-tag v-if="column.dataIndex === 'netStatus'" :color="record.netStatus == '0' ? '#f00' : 'green'">{{
  305. record.netStatus == '0' ? '断开' : '连接'
  306. }}</a-tag>
  307. </template>
  308. </AlarmHistoryTable>
  309. </template>
  310. <template v-else>
  311. <AlarmHistoryTableHj :scroll="scroll" />
  312. </template>
  313. </div>
  314. </a-tab-pane>
  315. <a-tab-pane v-if="!hasPermission('show:noHandleHistory')" key="5" tab="操作历史">
  316. <div class="tab-item" v-if="activeKey === '5'">
  317. <HandlerHistoryTable
  318. columns-type="operator_history"
  319. :device-type="deviceType"
  320. :device-list-api="getTableList"
  321. designScope="operator_history"
  322. :scroll="scroll"
  323. />
  324. </div>
  325. </a-tab-pane>
  326. <a-tab-pane v-if="hasPermission('gate:list')" key="6" tab="风门故障统计分析">
  327. <div class="tab-item" v-if="activeKey === '6'">
  328. <WindDoorFaultTable :device-list-api="getOrderByCount" :device-type="deviceType" />
  329. </div>
  330. </a-tab-pane>
  331. <a-tab-pane v-if="hasPermission('gate:list')" key="7" tab="车辆损坏排查">
  332. <div class="tab-item" v-if="activeKey === '7'">
  333. <CarDamageTable :device-list-api="getCarList" :gateId="gateId" :device-type="deviceType" />
  334. </div>
  335. </a-tab-pane>
  336. <!-- v-if="sysOrgCode === 'sdmtjtswmk'" -->
  337. <a-tab-pane v-if="sysOrgCode === 'sdmtjtswmk'" key="2" tab="风门轴反馈推力曲线">
  338. <div class="tab-item" v-if="activeKey === '2'">
  339. <!-- <div class="history-chart">
  340. <BarAndLine
  341. :charts-columns="chartsColumns"
  342. chartsType="history"
  343. :option="Option"
  344. :data-source="sharedData"
  345. height="290px"
  346. :x-axis-prop-type="stationType !== 'redis' ? 'ttime' : 'time'"
  347. />
  348. </div> -->
  349. <HistoryTableChart
  350. chartsColumnsType="gate_chart"
  351. :dataSource="sharedData"
  352. height="100%"
  353. :chartsColumns="chartsColumns"
  354. device-type="gate"
  355. :is-show-child-type="true"
  356. />
  357. </div>
  358. </a-tab-pane>
  359. </a-tabs>
  360. </dv-border-box8>
  361. </div>
  362. </div>
  363. <div
  364. v-if="renderPlayer"
  365. ref="playerRef"
  366. style="
  367. z-index: 1;
  368. position: absolute;
  369. top: 100px;
  370. right: 0px;
  371. width: 100%;
  372. height: 800px;
  373. pointer-events: none;
  374. overflow-y: auto;
  375. flex-direction: column;
  376. "
  377. >
  378. </div>
  379. <LivePlayer
  380. id="fm-player1"
  381. style="height: 220px; width: 300px; position: absolute; top: 0px; z-index: -1"
  382. ref="player1"
  383. :videoUrl="flvURL1()"
  384. muted
  385. live
  386. loading
  387. controls
  388. />
  389. <HandleModal
  390. v-if="!globalConfig?.simulatedPassword"
  391. :modal-is-show="modalIsShow"
  392. :modal-title="modalTitle"
  393. :modal-type="modalType"
  394. @handle-ok="handleOK"
  395. @handle-cancel="handleCancel"
  396. />
  397. <DeviceBaseInfo @register="registerModal" :device-type="selectData['deviceType']" />
  398. </template>
  399. <script setup lang="ts">
  400. import { onBeforeUnmount, onUnmounted, onMounted, ref, reactive, nextTick, inject, unref, defineAsyncComponent, provide } from 'vue';
  401. import MonitorTable from '../comment/MonitorTable.vue';
  402. import HistoryTable from '../comment/HistoryTable.vue';
  403. import AlarmHistoryTable from '../comment/AlarmHistoryTable.vue';
  404. import HandlerHistoryTable from '../comment/HandlerHistoryTable.vue';
  405. import WindDoorFaultTable from './components/WindDoorFaultTable.vue';
  406. import CarDamageTable from './components/CarDamageTable.vue';
  407. import AlarmHistoryTableHj from './components/AlarmHistoryTableHj.vue';
  408. import HandleModal from './modal.vue';
  409. import DeviceBaseInfo from '../comment/components/DeviceBaseInfo.vue';
  410. import { mountedThree, addMonitorText, play, destroy, setModelType, computePlay } from './gate.threejs';
  411. import { deviceControlApi } from '/@/api/vent/index';
  412. import { message } from 'ant-design-vue';
  413. import { list, getTableList, cameraList, cameraAddrList, getOrderByCount, getCarList } from './gate.api';
  414. import { chartsColumns, getModelComponent } from './gate.data';
  415. import { cloneDeep } from 'lodash-es';
  416. import { setDivHeight } from '/@/utils/event';
  417. import { BorderBox8 as DvBorderBox8 } from '@kjgl77/datav-vue3';
  418. import { useRouter } from 'vue-router';
  419. import LivePlayer from '@liveqing/liveplayer-v3';
  420. import { useModal } from '/@/components/Modal';
  421. import { useCamera } from '/@/hooks/system/useCamera';
  422. import { usePermission } from '/@/hooks/web/usePermission';
  423. import { getDictItems } from '/@/api/common/api';
  424. import { render } from '/@/utils/common/renderUtils';
  425. import { useGlobSetting } from '/@/hooks/setting';
  426. import { getDictItemsByCode } from '/@/utils/dict';
  427. import HistoryTableChart from '../comment/HistoryTableChart.vue';
  428. const { hasPermission } = usePermission();
  429. const { sysOrgCode } = useGlobSetting();
  430. const globalConfig = inject<any>('globalConfig');
  431. const modelRef = ref();
  432. /** 模型对应的组件,根据实际情况分为二维三维 */
  433. const modelComponent = getModelComponent(globalConfig.is2DModel);
  434. const { currentRoute } = useRouter();
  435. const gateId = ref(''); //风门ID
  436. const MonitorDataTable = ref();
  437. let contrlValue = '';
  438. const playerRef = ref();
  439. const deviceType = ref('gate');
  440. const activeKey = ref('1'); // tab
  441. const loading = ref(false);
  442. const renderPlayer = ref(true);
  443. // const stationType = ref('plc1');
  444. const scroll = reactive({
  445. y: 230,
  446. });
  447. const modelList = ref<{ text: string; value: string }[]>([]);
  448. const frontDoorIsOpen = ref(false); //前门是否开启
  449. const backDoorIsOpen = ref(false); //后门是否开启
  450. const midDoorIsOpen = ref(false); //中间门是否开启
  451. const modalIsShow = ref<boolean>(false); // 是否显示模态框
  452. const modalTitle = ref(''); // 模态框标题显示内容,根据设备操作类型决定
  453. const modalType = ref(''); // 模态框内容显示类型,设备操作类型
  454. const selectRowIndex = ref(-1); // 选中行
  455. const dataSource = ref([]);
  456. const sharedData = ref([]);
  457. const deviceBaseList = ref([]); // 设备基本信息
  458. const updateSharedData = (data) => {
  459. sharedData.value = data;
  460. };
  461. const Option = {
  462. grid: {
  463. top: '20%',
  464. left: '5%',
  465. right: '5%',
  466. bottom: '3%',
  467. containLabel: true,
  468. },
  469. toolbox: {
  470. feature: null,
  471. },
  472. };
  473. /** 封装通用的模态框打开方法(setControl 模式:点位code直接传参) */
  474. const openGateControlModal = (paramcode: string, title: string) => {
  475. modalType.value = paramcode;
  476. modalTitle.value = title;
  477. modalIsShow.value = true;
  478. // 模拟密码模式下直接执行操作
  479. if (globalConfig?.simulatedPassword) {
  480. handleOK('', paramcode);
  481. }
  482. };
  483. /** 统一控制入口:点位code + 标题 直接传参(与 windowMonitor 的 setControl 模式一致) */
  484. const setControl = (paramcode: string, title: string) => {
  485. openGateControlModal(paramcode, title);
  486. };
  487. /** 控制模式切换(paramcode 需根据 contrlMod + contrlValue 动态决定) */
  488. const setControlMode = (value?: string) => {
  489. contrlValue = value;
  490. openGateControlModal('modeSwitch', '控制模式切换');
  491. };
  492. const [registerModal, { openModal, closeModal }] = useModal();
  493. const { getCamera, removeCamera } = useCamera();
  494. const tabChange = (activeKeyVal) => {
  495. activeKey.value = activeKeyVal;
  496. if (activeKeyVal == 1) {
  497. nextTick(() => {
  498. if (MonitorDataTable.value) MonitorDataTable.value.setSelectedRowKeys([selectData.deviceID]);
  499. });
  500. }
  501. };
  502. const initData = {
  503. deviceID: '',
  504. deviceType: '',
  505. strname: '',
  506. frontRearDP: '-', //压差
  507. // sourcePressure: '-', //气源压力
  508. runRoRecondition: null,
  509. autoRoManual: null,
  510. netStatus: '0', //通信状态
  511. frontGateOpen: '0',
  512. frontGateClose: '1',
  513. rearGateOpen: '0',
  514. rearGateClose: '1',
  515. midGateOpen: '0',
  516. midGateClose: '1',
  517. fault: '气源压力超限',
  518. masterComputer: 0,
  519. frontGateOpenCtrl: false,
  520. rearGateOpenCtrl: false,
  521. cameras: [],
  522. };
  523. // 监测数据
  524. const selectData = reactive(cloneDeep(initData));
  525. const flvURL1 = () => {
  526. // return ''
  527. return `/video/gate.mp4`;
  528. };
  529. function deviceEdit(e: Event, type: string, record) {
  530. e.stopPropagation();
  531. openModal(true, {
  532. type,
  533. deviceId: record['deviceID'],
  534. });
  535. }
  536. // 获取设备基本信息列表
  537. function getDeviceBaseList() {
  538. getTableList({ pageSize: 1000 }).then((res) => {
  539. deviceBaseList.value = res.records;
  540. });
  541. }
  542. // https获取监测数据
  543. let timer: null | NodeJS.Timeout = null;
  544. async function getMonitor(flag?) {
  545. if (Object.prototype.toString.call(timer) === '[object Null]') {
  546. timer = await setTimeout(
  547. async () => {
  548. const res = await list({ devicetype: deviceType.value, pagetype: 'normal' });
  549. if (res.msgTxt && res.msgTxt[0]) {
  550. dataSource.value = res.msgTxt[0].datalist || [];
  551. dataSource.value.forEach((data: any) => {
  552. const readData = data.readData;
  553. data = Object.assign(data, readData);
  554. });
  555. if (dataSource.value.length > 0 && selectRowIndex.value == -1 && MonitorDataTable.value) {
  556. // 初始打开页面
  557. if (currentRoute.value && currentRoute.value['query'] && currentRoute.value['query']['id']) {
  558. MonitorDataTable.value.setSelectedRowKeys([currentRoute.value['query']['id']]);
  559. } else {
  560. MonitorDataTable.value.setSelectedRowKeys([dataSource.value[0]['deviceID']]);
  561. }
  562. }
  563. Object.assign(selectData, dataSource.value[selectRowIndex.value]);
  564. if (selectData.contrlMod == 'jnjhCtrl') {
  565. selectData['autoRoManual'] = selectData['autoRoManual'] == 1 ? true : false;
  566. selectData['autoRoManual1'] = selectData['autoRoManual1'] == 1 ? true : false;
  567. selectData['autoRoManual2'] = selectData['autoRoManual2'] == 1 ? true : false;
  568. }
  569. addMonitorText(selectData);
  570. monitorAnimation(selectData);
  571. if (timer) {
  572. timer = null;
  573. }
  574. getMonitor();
  575. }
  576. },
  577. flag ? 0 : 1000
  578. );
  579. }
  580. }
  581. // 切换检测数据
  582. async function getSelectRow(selectRow, index) {
  583. if (!selectRow) return;
  584. loading.value = true;
  585. selectRowIndex.value = index;
  586. gateId.value = selectRow.deviceID;
  587. const baseData: any = deviceBaseList.value.find((baseData: any) => baseData.id === selectRow.deviceID);
  588. Object.assign(selectData, initData, selectRow, baseData);
  589. isFrontOpenRunning = false; //开关门动作是否在进行
  590. isRearOpenRunning = false; //开关门动作是否在进行
  591. isMidOpenRunning = false; //开关门动作是否在进行
  592. frontDeviceState = 0; //记录设备状态,为了与下一次监测数据做比较
  593. rearDeviceState = 0; //记录设备状态,为了与下一次监测数据做比较
  594. midDeviceState = 0; //记录设备状态,为了与下一次监测数据做比较
  595. let type;
  596. const dictCodes = getDictItemsByCode('gateStyle');
  597. if (selectData && dictCodes && dictCodes.length > 0) {
  598. const gateStyle = selectData['gateStyle'];
  599. switch (gateStyle) {
  600. case 'gate_qd':
  601. type = 'fm3';
  602. break;
  603. case 'fmtl3':
  604. type = 'fmThreeTl';
  605. break;
  606. case 'fmSs':
  607. type = 'fmTwoSs';
  608. break;
  609. case 'fm_fc':
  610. type = 'fmWindow';
  611. break;
  612. case 'fmXr':
  613. type = 'fmXr';
  614. break;
  615. case 'fmYy':
  616. type = 'fm1';
  617. break;
  618. case 'fmSs3':
  619. type = 'fm2';
  620. break;
  621. case 'fm_fc_hjg':
  622. type = 'fmWindowHjg';
  623. break;
  624. case 'fm_fc_zhq':
  625. type = 'fmWindowZhq';
  626. break;
  627. default:
  628. type = gateStyle;
  629. }
  630. } else {
  631. type = selectData.nwindownum == 1 ? 'singleWindow' : 'doubleWindow';
  632. if (selectData['doorUse'] == 2) {
  633. type = 'fmXr';
  634. } else if (selectData.ndoorcount == '3' || selectData.deviceType == 'gate_nomal3') {
  635. type = 'fmThreeTl';
  636. } else {
  637. if (selectData.deviceType == 'gate_ss') {
  638. type = 'fm2';
  639. } else if (selectData.deviceType == 'gate_qd' || selectData.deviceType == 'gate_normal') {
  640. type = 'fm3';
  641. } else if (selectData.deviceType == 'gate_ss_two' || selectData.deviceType == 'gate_ss_two1') {
  642. type = 'fmTwoSs';
  643. } else if (selectData.deviceType == 'gate_tj') {
  644. type = 'fmWindow';
  645. } else {
  646. type = 'fm1'; // 液压
  647. }
  648. }
  649. }
  650. await setSVGModelType(type);
  651. await setModelType(type);
  652. addMonitorText(selectData);
  653. // playAnimation(selectRow, selectData.value.maxarea, true);
  654. loading.value = false;
  655. await getCamera(selectRow.deviceID, playerRef, renderPlayer);
  656. }
  657. /** 检修切换 */
  658. const changeOverhaul = (e) => {
  659. // 检修值需要在打开模态框前设置(handleOK 中按 toggle 逻辑计算下发值)
  660. openGateControlModal('overhaul', '检修控制');
  661. contrlValue = e;
  662. };
  663. /** 统一下发控制指令(仿 windowMonitor 模式:handlerState 即点位code,特殊情况单独判断) */
  664. function handleOK(passWord, handlerState, value?) {
  665. if (!passWord && !globalConfig?.simulatedPassword) {
  666. message.warning('请输入密码');
  667. return;
  668. }
  669. const data = {
  670. deviceid: selectData.deviceID,
  671. devicetype: selectData.deviceType,
  672. paramcode: '',
  673. value: value ?? null,
  674. password: passWord || globalConfig?.simulatedPassword,
  675. masterComputer: selectData.masterComputer,
  676. };
  677. // 特殊:控制模式切换(paramcode 根据 contrlMod + contrlValue 动态决定)
  678. if (handlerState === 'modeSwitch') {
  679. if (selectData.contrlMod == 'codeCtrl') {
  680. if (contrlValue == '1') {
  681. data.paramcode = 'autoRoManualControl1';
  682. } else if (contrlValue == '0') {
  683. data.paramcode = 'autoRoManualControl2';
  684. } else {
  685. data.paramcode = 'autoRoManualControl0';
  686. }
  687. data.value = '';
  688. } else if (selectData.contrlMod == 'loopCtrl' || selectData.contrlMod == 'jnjhCtrl') {
  689. data.paramcode = 'autoRoManualControl';
  690. data.value = '';
  691. } else {
  692. data.paramcode = 'autoRoManualControl';
  693. data.value = contrlValue;
  694. }
  695. selectData.autoRoManual = null;
  696. }
  697. // 特殊:检修控制(value 取反 toggle)
  698. else if (handlerState === 'overhaul') {
  699. data.paramcode = 'runRoRecondition_S';
  700. data.value = selectData['runRoRecondition'] == 0 ? '1' : '0';
  701. }
  702. // 默认:handlerState 即点位code(setControl 直接传参)
  703. else {
  704. data.paramcode = handlerState;
  705. data.value = value ?? contrlValue;
  706. }
  707. if (data.paramcode) {
  708. deviceControlApi(data)
  709. .then((res) => {
  710. if (res.success) {
  711. modalIsShow.value = false;
  712. if (globalConfig.History_Type == 'remote') {
  713. message.success('指令已下发至生产管控平台成功!');
  714. } else {
  715. message.success('指令已下发成功!');
  716. }
  717. } else {
  718. message.error(res.message);
  719. }
  720. contrlValue = '';
  721. })
  722. .catch(() => {
  723. message.error('控制异常,请排查问题。。。');
  724. contrlValue = '';
  725. });
  726. }
  727. }
  728. let isOpenRunning = false; //开关门动作是否在进行
  729. /** 开关门动画调用 */
  730. let isFrontOpenRunning = false; //开关门动作是否在进行
  731. // let isFrontCloseRunning = false; //开关门动作是否在进行
  732. let isRearOpenRunning = false; //开关门动作是否在进行
  733. // let isRearCloseRunning = false; //开关门动作是否在进行
  734. let isMidOpenRunning = false; //中间门动作是否在进行
  735. // let isMidCloseRunning = false; //中间门动作是否在进行
  736. // 0 关闭 1 正在打开 2 打开 3正在关闭
  737. let frontDeviceState = 0; //记录设备状态,为了与下一次监测数据做比较
  738. let rearDeviceState = 0; //记录设备状态,为了与下一次监测数据做比较
  739. let midDeviceState = 0; //记录设备状态,为了与下一次监测数据做比较
  740. function monitorAnimation(selectData) {
  741. const timeScale = 0.005;
  742. // 带风窗 风窗动画
  743. if (selectData['gateStyle'] && selectData['gateStyle'].includes('fm_fc')) playWindowAnimation(selectData);
  744. if (selectData.frontGateOpen == '1' && selectData.frontGateClose == '0' && !isFrontOpenRunning) {
  745. isFrontOpenRunning = true;
  746. if (frontDeviceState != 1) {
  747. // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(1, timeScale) : play(1);
  748. play(1, timeScale);
  749. frontDeviceState = 1;
  750. frontDoorIsOpen.value = false;
  751. backDoorIsOpen.value = true;
  752. }
  753. }
  754. if (selectData.frontGateOpen == '0' && selectData.frontGateClose == '0' && !isFrontOpenRunning) {
  755. isFrontOpenRunning = true;
  756. if (frontDeviceState != 1) {
  757. // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(1, timeScale) : play(1);
  758. play(1, timeScale);
  759. frontDeviceState = 1;
  760. frontDoorIsOpen.value = false;
  761. backDoorIsOpen.value = true;
  762. }
  763. }
  764. if (selectData.frontGateClose == '1' && selectData.frontGateOpen == '0' && isFrontOpenRunning) {
  765. isFrontOpenRunning = false;
  766. if (frontDeviceState != 0) {
  767. // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(2, timeScale) : play(2);
  768. play(2, timeScale);
  769. frontDeviceState = 0;
  770. frontDoorIsOpen.value = false;
  771. // backDoorIsOpen.value = false
  772. }
  773. }
  774. if (selectData.rearGateOpen == '1' && selectData.rearGateClose == '0' && !isRearOpenRunning) {
  775. isRearOpenRunning = true;
  776. if (rearDeviceState != 1) {
  777. // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(3, timeScale) : play(3);
  778. play(3, timeScale);
  779. rearDeviceState = 1;
  780. backDoorIsOpen.value = false;
  781. frontDoorIsOpen.value = true;
  782. }
  783. }
  784. if (selectData.rearGateOpen == '0' && selectData.rearGateClose == '0' && !isRearOpenRunning) {
  785. isRearOpenRunning = true;
  786. if (rearDeviceState != 1) {
  787. // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(3, timeScale) : play(3);
  788. play(3, timeScale);
  789. rearDeviceState = 1;
  790. backDoorIsOpen.value = false;
  791. frontDoorIsOpen.value = true;
  792. }
  793. }
  794. if (selectData.rearGateClose == '1' && selectData.rearGateOpen == '0' && isRearOpenRunning) {
  795. isRearOpenRunning = false;
  796. if (rearDeviceState != 0) {
  797. // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(4, timeScale) : play(4);
  798. play(4, timeScale);
  799. rearDeviceState = 0;
  800. backDoorIsOpen.value = false;
  801. }
  802. }
  803. if (selectData.midGateOpen == '1' && selectData.midGateClose == '0' && !isMidOpenRunning) {
  804. isMidOpenRunning = true;
  805. if (midDeviceState != 1) {
  806. // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(3, timeScale) : play(3);
  807. play(8, timeScale);
  808. midDeviceState = 1;
  809. backDoorIsOpen.value = false;
  810. frontDoorIsOpen.value = true;
  811. }
  812. }
  813. if (selectData.midGateOpen == '0' && selectData.midGateClose == '0' && !isMidOpenRunning) {
  814. isMidOpenRunning = true;
  815. if (midDeviceState != 1) {
  816. // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(3, timeScale) : play(3);
  817. play(8, timeScale);
  818. midDeviceState = 1;
  819. backDoorIsOpen.value = false;
  820. frontDoorIsOpen.value = true;
  821. }
  822. }
  823. if (selectData.midGateClose == '1' && selectData.midGateOpen == '0' && isMidOpenRunning) {
  824. isMidOpenRunning = false;
  825. if (midDeviceState != 0) {
  826. // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(4, timeScale) : play(4);
  827. play(9, timeScale);
  828. midDeviceState = 0;
  829. backDoorIsOpen.value = false;
  830. }
  831. }
  832. modelRef.value?.animate?.(selectData.frontGateOpen == '1', selectData.midGateOpen == '1', selectData.rearGateOpen == '1');
  833. }
  834. function playWindowAnimation(data, maxarea = 90, isFirst = false) {
  835. computePlay(data, maxarea, isFirst);
  836. }
  837. function handleCancel() {
  838. modalIsShow.value = false;
  839. modalTitle.value = '';
  840. modalType.value = '';
  841. }
  842. const handleSwitchChange = (checked: boolean) => {
  843. contrlValue = checked;
  844. setControl('manualAutoMode_w', '手动/自动模式切换');
  845. };
  846. function setSVGModelType(type) {
  847. modelComponent.value = getModelComponent(globalConfig.is2DModel, type);
  848. return nextTick();
  849. }
  850. onMounted(async () => {
  851. const { query } = unref(currentRoute);
  852. if (query['deviceType']) deviceType.value = query['deviceType'] as string;
  853. modelList.value = await getDictItems('gateModel');
  854. if (globalConfig.is2DModel) {
  855. await getMonitor(true);
  856. } else {
  857. loading.value = true;
  858. // const playerDom = document.getElementById('fm-player1')?.getElementsByClassName('vjs-tech')[0];
  859. mountedThree()
  860. .then(async () => {
  861. if (sysOrgCode != 'zmhjhzmy') {
  862. await getMonitor(true);
  863. loading.value = false;
  864. } else {
  865. // 韩咀无风门设备,只有报警历史数据,无其他数据
  866. setModelType('fm1').then(async () => {
  867. loading.value = false;
  868. dataSource.value = [];
  869. addMonitorText(selectData);
  870. });
  871. }
  872. })
  873. .catch((e) => {
  874. console.log(e);
  875. });
  876. }
  877. });
  878. onBeforeUnmount(() => {
  879. removeCamera(playerRef);
  880. getDeviceBaseList();
  881. });
  882. onUnmounted(() => {
  883. if (timer) {
  884. clearTimeout(timer);
  885. timer = undefined;
  886. }
  887. destroy();
  888. });
  889. </script>
  890. <style lang="less" scoped>
  891. @import '/@/design/theme.less';
  892. @import '/@/design/vent/modal.less';
  893. .scene-box {
  894. .bottom-tabs-box {
  895. height: 350px;
  896. }
  897. }
  898. .button-box {
  899. border: none !important;
  900. height: 34px !important;
  901. &:hover {
  902. background: var(--vent-device-manager-control-btn-hover) !important;
  903. }
  904. &::before {
  905. height: 27px !important;
  906. background: var(--vent-device-manager-control-btn) !important;
  907. }
  908. &::after {
  909. top: 35px !important;
  910. }
  911. }
  912. :deep(.@{ventSpace}-tabs-tabpane-active) {
  913. height: 100%;
  914. }
  915. ::-webkit-scrollbar-thumb {
  916. -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
  917. background: #4288a444;
  918. }
  919. :deep(.zxm-radio-disabled + span) {
  920. color: var(--vent-font-color) !important;
  921. }
  922. :deep(.zxm-radio-disabled .zxm-radio-inner::after) {
  923. background-color: #127cb5 !important;
  924. }
  925. :deep(.@{ventSpace}-picker-datetime-panel) {
  926. height: 200px !important;
  927. overflow-y: auto !important;
  928. }
  929. </style>