deviceManager.vue 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976
  1. <template>
  2. <div>
  3. <ag-grid-layout
  4. toolbar
  5. :table-height="tableHeight"
  6. theme="ag-theme-alpine"
  7. :column-defs="columnDefs"
  8. :row-data="rowData"
  9. :locale-text="localeText"
  10. :grid-options="gridOptions"
  11. :debounce-vertical-scrollbar="true"
  12. :default-col-def="defaultColDef"
  13. :animate-rows="true"
  14. :row-selection="rowSelection"
  15. :framework-components="frameworkComponents"
  16. @filterChanged="filterModifed"
  17. @sortChanged="gridSortChange"
  18. >
  19. <div slot="toolbar" class="inner-toolbar">
  20. <div class="toolbar-search">
  21. <en-table-search placeholder="请输入搜索关键字" @search="handlerSearch" />
  22. </div>
  23. <div class="toolbar-btns">
  24. <el-button v-if="part_view" type="primary" size="mini" @click="handleAdd">新增设备</el-button>
  25. <el-button v-if="part_view" type="danger" size="mini" @click="batchDelete">批量删除</el-button>
  26. </div>
  27. </div>
  28. <el-pagination
  29. v-if="pageData"
  30. slot="pagination"
  31. :current-page="pageData.page_no"
  32. :page-sizes="[10, 20, 50, 100]"
  33. :page-size="pageData.page_size"
  34. layout="total, sizes, prev, pager, next, jumper"
  35. :total="pageData.data_total"
  36. @size-change="handlePageSizeChange"
  37. @current-change="handlePageCurrentChange"
  38. />
  39. </ag-grid-layout>
  40. <!-- 设备编辑弹窗 -->
  41. <el-dialog :title="deviceEditTitle" :visible.sync="deviceDialogVisible" width="60%">
  42. <el-form ref="deviceEditForm" :rules="deviceRules" label-width="120px" :model="deviceModel">
  43. <el-row>
  44. <el-col :span="12">
  45. <el-form-item label="设备类型" prop="device_type">
  46. <el-select v-model="deviceModel.device_type" placeholder="请选择设备类型" :disabled="deviceTypeDisabled" clearable @change="deviceTypeChange">
  47. <el-option v-for="(item,index) in deviceTypeTransfer" :key="index" :label="item.key" :value="item.value" />
  48. </el-select>
  49. </el-form-item>
  50. </el-col>
  51. <el-col :span="12">
  52. <el-form-item label="设备别名" prop="name">
  53. <el-input v-model="deviceModel.name" clearable :maxlength="20" placeholder="请输入设备别名" />
  54. </el-form-item>
  55. </el-col>
  56. </el-row>
  57. <el-row>
  58. <el-col :span="12">
  59. <el-form-item label="出厂编号" prop="code">
  60. <el-input v-model="deviceModel.code" clearable placeholder="请输入出厂编号" />
  61. </el-form-item>
  62. </el-col>
  63. <el-col :span="12">
  64. <el-form-item label="设备型号" prop="model">
  65. <el-input v-model="deviceModel.model" clearable placeholder="请输入设备型号" />
  66. </el-form-item>
  67. </el-col>
  68. </el-row>
  69. <el-row>
  70. <el-col :span="12">
  71. <el-form-item label="有线物理地址" prop="eth_mac">
  72. <el-input v-model="deviceModel.eth_mac" clearable placeholder="请输入物理MAC地址" />
  73. </el-form-item>
  74. </el-col>
  75. <el-col :span="12">
  76. <el-form-item label="有线IP地址" prop="eth_ip">
  77. <el-input v-model="deviceModel.eth_ip" clearable placeholder="请输入IP地址" />
  78. </el-form-item>
  79. </el-col>
  80. </el-row>
  81. <el-row>
  82. <el-col :span="12">
  83. <el-form-item label="WIFI物理地址" prop="wifi_mac">
  84. <el-input v-model="deviceModel.wifi_mac" clearable placeholder="请输入WIFI MAC地址" readonly />
  85. </el-form-item>
  86. </el-col>
  87. <el-col :span="12">
  88. <el-form-item label="WIFIIP地址" prop="wifi_ip">
  89. <el-input v-model="deviceModel.wifi_ip" clearable placeholder="请输入WIFI IP地址" readonly />
  90. </el-form-item>
  91. </el-col>
  92. </el-row>
  93. <el-row>
  94. <el-col :span="12">
  95. <el-form-item label="软件版本" prop="soft_ver">
  96. <el-input v-model="deviceModel.soft_ver" clearable placeholder="请输入软件版本号" />
  97. </el-form-item>
  98. </el-col>
  99. <el-col :span="12">
  100. <el-form-item label="硬件版本" prop="hard_ver">
  101. <el-input v-model="deviceModel.hard_ver" clearable placeholder="请输入硬件版本号" />
  102. </el-form-item>
  103. </el-col>
  104. </el-row>
  105. <el-row>
  106. <el-col :span="12">
  107. <el-form-item label="WIFI热点">
  108. <el-input v-model="deviceModel.wifi_hostname" :readonly="true" clearable placeholder="请输入WIFI热点名称" />
  109. </el-form-item>
  110. </el-col>
  111. <el-col :span="12">
  112. <el-form-item label="WIFI密码">
  113. <el-input v-model="deviceModel.wifi_password" :readonly="true" clearable placeholder="请输入WIFI热点密码" />
  114. </el-form-item>
  115. </el-col>
  116. </el-row>
  117. <el-row>
  118. <el-col :span="12">
  119. <el-form-item label="设备位置" prop="frame_id">
  120. <el-select v-model="deviceModel.frame_id" filterable clearable :disabled="frameSelectabled" placeholder="请选择安装位置">
  121. <el-option v-for="(item,index) in typeFrames" :key="index" :label="item.full_name" :value="item.id" />
  122. </el-select>
  123. </el-form-item>
  124. </el-col>
  125. <el-col :span="12">
  126. <el-form-item label="设备电话号码">
  127. <el-input v-model="deviceModel.phone_number" clearable placeholder="请输入设备电话号码" />
  128. </el-form-item>
  129. </el-col>
  130. </el-row>
  131. <el-row>
  132. <el-col :span="12">
  133. <el-form-item label="设备优先级">
  134. <el-input-number v-model="deviceModel.priority" controls-position="right" :min="1" :max="99" />
  135. </el-form-item>
  136. </el-col>
  137. <el-col :span="12">
  138. <el-form-item label="后备设备ID">
  139. <el-input v-model="deviceModel.backup_id" clearable placeholder="" />
  140. </el-form-item>
  141. </el-col>
  142. <el-col :span="12">
  143. <el-form-item label="是否启用">
  144. <el-checkbox v-model="deviceModel.status" :true-label="1" :false-label="0">启用设备</el-checkbox>
  145. <!-- <el-radio v-model="formmodel.status" :label="1">启用</el-radio>-->
  146. <!-- <el-radio v-model="formmodel.status" :label="0">不启用</el-radio>-->
  147. </el-form-item>
  148. </el-col>
  149. </el-row>
  150. <el-row v-if="hasRoleId">
  151. <el-col :span="12">
  152. <el-form-item label="适用角色" prop="role_id">
  153. <el-select v-model="deviceModel.role_id" placeholder="适用角色" clearable>
  154. <el-option v-for="item in rolesOptions" :key="item.role_id" :label="item.role_name" :value="item.role_id" />
  155. </el-select>
  156. </el-form-item>
  157. </el-col>
  158. </el-row>
  159. <el-row v-if="hasAudioId">
  160. <el-col :span="12">
  161. <el-form-item label="上属总线转换盒" prop="trans_audio_id">
  162. <el-select v-model="deviceModel.trans_audio_id" placeholder="上属总线转换盒" clearable>
  163. <el-option v-for="item in audioOptions" :key="item.id" :label="item.name" :value="item.id" />
  164. </el-select>
  165. </el-form-item>
  166. </el-col>
  167. <el-col :span="12">
  168. <el-form-item label="上属485转换盒" prop="trans_rs485_id">
  169. <el-select v-model="deviceModel.trans_rs485_id" placeholder="上属485转换盒" clearable>
  170. <el-option v-for="item in rs485Options" :key="item.id" :label="item.name" :value="item.id" />
  171. </el-select>
  172. </el-form-item>
  173. </el-col>
  174. </el-row>
  175. <el-row v-if="hasAudioId">
  176. <el-col :span="12">
  177. <el-form-item label="485地址" prop="sip_id">
  178. <el-input v-model="deviceModel.sip_id" clearable placeholder="请输入485地址" />
  179. </el-form-item>
  180. </el-col>
  181. </el-row>
  182. <el-row v-if="hasSosDeviceSettings">
  183. <el-col :span="12">
  184. <el-form-item label="报警设备模式" prop="type">
  185. <el-select v-model="sosDeviceSetting.type" placeholder="报警设备模式" clearable>
  186. <el-option v-for="item in sosDeviceSettingsTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
  187. </el-select>
  188. </el-form-item>
  189. </el-col>
  190. </el-row>
  191. <el-row v-if="hasSosDeviceSettings">
  192. <el-col :span="12">
  193. <el-form-item label="报警时间" prop="setting_time">
  194. <el-input-number v-model="sosDeviceSetting.setting_time" controls-position="right" :min="0" :max="60" />
  195. </el-form-item>
  196. </el-col>
  197. <el-col :span="12">
  198. <el-form-item label="报警时间单位" prop="unit">
  199. <el-radio-group v-model="sosDeviceSetting.unit" size="mini" prop="unit">
  200. <el-radio label="小时">小时</el-radio>
  201. <el-radio label="分钟">分钟</el-radio>
  202. <el-radio label="秒">秒</el-radio>
  203. </el-radio-group>
  204. </el-form-item>
  205. </el-col>
  206. </el-row>
  207. <el-row v-if="isLedDevice">
  208. <el-col :span="12">
  209. <el-form-item label="点阵屏规格" prop="led_resolution_ratio">
  210. <el-input v-model="deviceModel.led_resolution_ratio" clearable placeholder="点阵屏规格" />
  211. </el-form-item>
  212. </el-col>
  213. <el-col :span="12">
  214. <el-form-item label="语音播放" prop="led_voice">
  215. <el-radio-group v-model="deviceModel.led_voice" size="mini" prop="unit">
  216. <el-radio :label=1>开启语音</el-radio>
  217. <el-radio :label=0>关闭语音</el-radio>
  218. </el-radio-group>
  219. </el-form-item>
  220. </el-col>
  221. </el-row>
  222. <el-row v-if="isLedDevice">
  223. <el-col :span="12">
  224. <el-form-item label="字体大小" prop="led_font_size">
  225. <el-input-number v-model="deviceModel.led_font_size" controls-position="right" :min="0" :max="60" />
  226. </el-form-item>
  227. </el-col>
  228. </el-row>
  229. </el-form>
  230. <div slot="footer" class="dialog-footer">
  231. <el-button type="primary" @click="handlerFormSubmit('deviceEditForm')">确 定</el-button>
  232. </div>
  233. </el-dialog>
  234. <!-- 设备编辑弹窗 -->
  235. </div>
  236. </template>
  237. <script>
  238. import { AG_GRID_LOCALE_CN } from '@/utils/AgGridVueLocaleCn'
  239. import { unix2Date } from '@/utils/Foundation'
  240. import ButtonCellRender from '@/components/AgGridCellRender/ButtonCellRender'
  241. import ListFilter from '@/components/AgGridCustomFilter/ListFilter'
  242. import RadioFilter from '@/components/AgGridCustomFilter/RadioFilter'
  243. import * as API_Device from '@/api/ncs_device'
  244. import * as API_Frame from '@/api/ncs_hospitalFrame'
  245. import * as API_SosDeviceSetting from '@/api/ncs_sos_device_settings'
  246. import * as clerk_API from '@/api/ncs_clerk'
  247. import { DeviceUrl } from '@/utils/domain'
  248. import { FRAME_TYPE } from '@/utils/enum/FrameTypeEnum'
  249. import { DEVICE_TYPE } from '@/utils/enum/DeviceTypeEnum'
  250. export default {
  251. name: 'DeviceManager',
  252. components: { ButtonCellRender, ListFilter, RadioFilter },
  253. props: {
  254. frame: {
  255. type: Object,
  256. default: () => {}
  257. },
  258. part_view: { // 是否为科室视图
  259. type: Boolean,
  260. default: true
  261. }
  262. },
  263. data() {
  264. return {
  265. /** ag-grid参数 **/
  266. pageData: {}, // 翻页数据
  267. errorId: null,
  268. shopVisible: false,
  269. columnDefs: null,
  270. rowData: null,
  271. defaultColDef: null,
  272. gridOptions: null,
  273. gridApi: null,
  274. columnApi: null,
  275. localeText: AG_GRID_LOCALE_CN,
  276. filterState: null,
  277. rowSelection: null,
  278. frameworkComponents: null,
  279. /** 列表参数 */
  280. params: {
  281. page_size: 20,
  282. page_no: 1,
  283. fixedCondition: this.part_view ? ('part_id=' + this.$store.getters.partId) : '1=1'
  284. },
  285. /** device 弹窗 **/
  286. deviceDialogVisible: false,
  287. deviceEditTitle: '添加设备',
  288. deviceModel: {},
  289. deviceTypeDisabled: false,
  290. deviceRules: {
  291. name: [
  292. this.MixinRequired('请输入设备别名!')
  293. ],
  294. device_type: [
  295. { required: true, message: '请选择设备类型', trigger: 'blur' }
  296. ],
  297. code: [
  298. { required: true, message: '请输入设备编码', trigger: 'blur' }
  299. ],
  300. model: [
  301. { required: true, message: '请输入设备型号', trigger: 'blur' }
  302. ],
  303. eth_mac: [
  304. { required: true, message: '请输入设备MAC地址', trigger: 'blur' },
  305. // { pattern: /^([0-9A-Fa-f]{2}:?){6}/gi, message: '请输入正确的MAC地址', trigger: 'blur' }
  306. { pattern: null, message: '请输入正确的MAC地址', trigger: 'blur' }
  307. ],
  308. frame_id: [
  309. { required: Object.keys(this.frame).length === 0, message: '请选安装位置!', trigger: 'blur' } // 没有传入frame 属性,必须选择安装位置
  310. ],
  311. phone_number: [
  312. { required: true, message: '请输入设备电话号码', trigger: 'blur' }
  313. ],
  314. role_id: [
  315. { required: true, message: '请选择适用人', trigger: 'blur' }
  316. ],
  317. trans_audio_id: [
  318. { required: true, message: '请选择总线转换盒', trigger: 'blur' }
  319. ],
  320. // trans_rs485_id: [
  321. // { required: true, message: '请选择485转换盒', trigger: 'blur' }
  322. // ],
  323. // sip_id: [
  324. // { required: true, message: '请输入485地址', trigger: 'blur' }
  325. // ]
  326. // type: [
  327. // { required: true, message: '报警设备模式', trigger: 'blur' }
  328. // ],
  329. // sosDeviceSetting: [
  330. // { required: true, message: '报警时间', trigger: 'blur' }
  331. // ],
  332. // unit: [
  333. // { required: true, message: '报警时间单位', trigger: 'blur' }
  334. // ],
  335. led_resolution_ratio: [
  336. { required: true, message: '点阵屏规格', trigger: 'blur' }
  337. ],
  338. led_voice: [
  339. { required: true, message: '点阵屏语音播放', trigger: 'blur' }
  340. ],
  341. led_font_size: [
  342. { required: true, message: '点阵屏字体大小', trigger: 'blur' }
  343. ],
  344. },
  345. partFrames: [],
  346. typeFrames: [],
  347. /** 设备类型转换数组 **/
  348. deviceTypeTransfer: [
  349. { key: '护士主机', value: 1 },
  350. { key: '医生主机', value: 2 },
  351. { key: '门口机', value: 3 },
  352. { key: '床位分机', value: 4 },
  353. { key: 'LCD走廊屏', value: 5 },
  354. { key: 'LED点阵屏', value: 6 },
  355. { key: '移动设备', value: 7 },
  356. // { key: '护工腕表', value: 8 },
  357. { key: '病人腕表', value: 9 },
  358. { key: '手机App', value: 10 },
  359. { key: '总线转换盒', value: 11 },
  360. { key: '模拟分机', value: 12 },
  361. { key: '模拟紧急按钮', value: 13 },
  362. { key: '模拟门灯', value: 14 },
  363. { key: '遥控器', value: 15 },
  364. { key: '信标', value: 16 },
  365. { key: '看板', value: 17 },
  366. { key: '门禁设备', value: 18 },
  367. { key: '探视机', value: 19 },
  368. { key: '485转换盒', value: 20 },
  369. { key: '紧急按钮', value: 21 },
  370. { key: '485门口机', value: 22 },
  371. { key: '红外报警器', value: 23 },
  372. { key: '用水监控器', value: 24 },
  373. { key: '家用燃起报警器', value: 25 },
  374. { key: '家用烟雾报警器', value: 26 },
  375. { key: '一键报警器', value: 27 },
  376. { key: '门磁传感器', value: 30 }
  377. ],
  378. deviceStatusTransfer: [
  379. { key: '启用', value: 1, color: 'green' },
  380. { key: '未启用', value: 0, color: 'red' }
  381. ],
  382. rolesOptions: [],
  383. hasRoleId: false,
  384. audioOptions: [],
  385. rs485Options: [],
  386. hasAudioId: false,
  387. hasSosDeviceSettings: false,
  388. sosDeviceSetting: {},
  389. sosDeviceSettingsTypeOptions: [
  390. {
  391. value: 0,
  392. label: '不开启'
  393. }, {
  394. value: 1,
  395. label: '疫情防控模式'
  396. }, {
  397. value: 2,
  398. label: '关爱老人模式'
  399. }
  400. ],
  401. isLedDevice: false,
  402. websock: null,
  403. onlineDevice: []
  404. }
  405. },
  406. computed: {
  407. tableHeight() {
  408. return Object.keys(this.frame).length === 0 ? this.mainAreaHeight - 130 : this.mainAreaHeight - 174
  409. },
  410. frameSelectabled() { return Object.keys(this.frame).length > 0 }
  411. },
  412. watch: {
  413. frame(val, oldvalue) {
  414. console.log('watch', val)
  415. this.params.fixedCondition = Object.keys(this.frame).length === 0 ? 'part_id=' + this.$store.getters.partId : 'part_id=' + this.$store.getters.partId + ' and frame_id =' + this.frame.id
  416. this.getList()
  417. }
  418. },
  419. beforeMount() {
  420. this.gridOptions = {
  421. }
  422. this.columnDefs = [
  423. {
  424. headerName: '#',
  425. headerCheckboxSelection: true,
  426. headerCheckboxSelectionFilteredOnly: true,
  427. checkboxSelection: true,
  428. sortable: false, filter: false,
  429. width: 80,
  430. resizable: false,
  431. valueGetter: this.hashValueGetter
  432. },
  433. { headerName: 'ID', field: 'id', sortable: true, filter: 'agNumberColumnFilter', width: 100 },
  434. { headerName: '设备类型', field: 'device_type', sortable: true,
  435. filterFramework: 'ListFilter', width: 160,
  436. filterParams: {
  437. listData: this.deviceTypeTransfer
  438. },
  439. valueGetter: this.deviceTypeGetter
  440. },
  441. // lockPosition 锁定位置,会在第一列
  442. // lockPinned = true 不能拖动然后固定
  443. // resizeable 单元个大小是否可以调整
  444. { headerName: '设备别名', field: 'name', sortable: true, filter: 'agTextColumnFilter' },
  445. { headerName: '设备状态', field: 'status', sortable: true,
  446. filterFramework: 'RadioFilter',
  447. filterParams: {
  448. listData: this.deviceStatusTransfer
  449. },
  450. cellRenderer: this.deviceStatusFormatter
  451. },
  452. { headerName: '连接状态', field: 'online_state', sortable: false, filter: 'agTextColumnFilter',
  453. filterParams: {
  454. textCustomComparator: (filter, value, filterText) => {
  455. if (filterText) {
  456. const filterTextLowerCase = filterText.toLowerCase()
  457. const valueLowerCase = value.toString().toLowerCase()
  458. switch (filter) {
  459. case 'contains':
  460. return valueLowerCase.indexOf(filterTextLowerCase) >= 0
  461. case 'notContains':
  462. return valueLowerCase.indexOf(filterTextLowerCase) === -1
  463. case 'equals':
  464. return valueLowerCase === filterTextLowerCase
  465. case 'notEqual':
  466. return valueLowerCase !== filterTextLowerCase
  467. case 'startsWith':
  468. return valueLowerCase.indexOf(filterTextLowerCase) === 0
  469. case 'endsWith':
  470. var index = valueLowerCase.lastIndexOf(filterTextLowerCase)
  471. return index >= 0 && index === (valueLowerCase.length - filterTextLowerCase.length)
  472. default:
  473. // should never happen
  474. console.warn('invalid filter type ' + filter)
  475. return false
  476. }
  477. }
  478. }
  479. },
  480. cellRenderer: this.onlineStateFormatter
  481. },
  482. { headerName: '部署位置', field: 'full_name', sortable: true, filter: 'agTextColumnFilter' },
  483. { headerName: '设备号码', field: 'phone_number', sortable: true, filter: 'agTextColumnFilter' },
  484. { headerName: '以太网MAC地址', field: 'eth_mac', sortable: true, filter: 'agTextColumnFilter' },
  485. { headerName: '以太网IP地址', field: 'eth_ip', sortable: true, filter: 'agTextColumnFilter' },
  486. { headerName: '通讯端口', field: 'eth_ip_port', sortable: true, filter: 'agNumberColumnFilter' },
  487. { headerName: '设备型号', field: 'model', sortable: true, filter: 'agTextColumnFilter' },
  488. { headerName: '出厂编号', field: 'code', sortable: true, filter: 'agTextColumnFilter' },
  489. { headerName: '软件版本', field: 'soft_ver', sortable: true, filter: 'agTextColumnFilter' },
  490. { headerName: '硬件版本', field: 'hard_ver', sortable: true, filter: 'agTextColumnFilter' },
  491. { headerName: '无线MAC地址', field: 'wifi_mac', sortable: true, filter: 'agTextColumnFilter' },
  492. { headerName: '无线IP地址', field: 'wifi_ip', sortable: true, filter: 'agTextColumnFilter' },
  493. { headerName: 'SIP账号', field: 'sip_id', sortable: true, filter: 'agTextColumnFilter' },
  494. { headerName: '更新时间', field: 'update_time', sortable: true, filter: 'agDateColumnFilter', valueFormatter: this.unixDateFormatter, filterParams: {
  495. comparator: (filterLocalDateAtMidnight, cellValue) => { // 所有数据都由服务器端过滤,此处只需返回0 即可
  496. const celldate = unixToDate(cellValue, 'yyyy-MM-dd 00:00:00')
  497. return (new Date(celldate).getTime() / 1000) - (filterLocalDateAtMidnight.getTime() / 1000)
  498. }
  499. }},
  500. { headerName: '编辑', field: 'id',
  501. cellRendererFramework: 'ButtonCellRender',
  502. cellRendererParams: {
  503. onClick: this.handleEdit,
  504. label: '编辑',
  505. buttonType: 'primary',
  506. buttonSize: 'mini'
  507. },
  508. filter: false,
  509. pinned: 'right',
  510. lockPinned: true,
  511. width: 90,
  512. resizable: false,
  513. sortable: false },
  514. { headerName: '删除', field: 'id',
  515. cellRendererFramework: 'ButtonCellRender',
  516. cellRendererParams: param => {
  517. return {
  518. onClick: this.deleteSingle,
  519. label: '删除',
  520. buttonType: 'danger',
  521. buttonSize: 'mini',
  522. disabled: param.data['member_name'] === 'superadmin'
  523. }
  524. },
  525. pinned: 'right',
  526. lockPinned: true,
  527. width: 90,
  528. resizable: false,
  529. filter: false,
  530. sortable: false }
  531. ]
  532. this.defaultColDef = {
  533. // filter: 'agTextColumnFilter',
  534. sortable: true,
  535. resizable: true,
  536. enableValue: true,
  537. filter: true,
  538. // comparator: this.dateCustomComparator,
  539. filterParams: {
  540. debounceMs: 500,
  541. newRowsAction: 'keep',
  542. textCustomComparator: this.textCustomComparator
  543. }
  544. }
  545. this.rowSelection = 'multiple'
  546. },
  547. mounted() {
  548. window.onresize = this.windowResize
  549. this.gridApi = this.gridOptions.api
  550. this.gridColumnApi = this.gridOptions.columnApi
  551. this.gridColumnApi.applyColumnState({
  552. state: [
  553. {
  554. colId: 'id',
  555. sort: 'desc'
  556. }
  557. ]
  558. })
  559. /** 加载科室空间节点 **/
  560. if (this.part_view) {
  561. // this.getPartFrames(this.$store.getters.partId)
  562. this.getTypeFrame(this.$store.getters.partId)
  563. }
  564. this.initWebSocket()
  565. },
  566. methods: {
  567. windowResize() {
  568. this.$set(this, 'mainAreaHeight', Number(document.documentElement.clientHeight) - 84)
  569. },
  570. /** 加载列表数据 */
  571. getList() {
  572. const param = this.MixinClone(this.params)
  573. this.gridApi.showLoadingOverlay()
  574. API_Device.getList(param).then(response => {
  575. const deviceData = [...response.data]
  576. deviceData.forEach(item => {
  577. if (this.onlineDevice.length > 0) {
  578. if (item.eth_mac) {
  579. const mac = this.onlineDevice.filter(p => p.toLowerCase() === item.eth_mac.toLowerCase())[0]
  580. // console.log('在线设备1', mac)
  581. if (mac !== undefined && mac !== null) {
  582. item['online_state'] = '在线'
  583. } else {
  584. item['online_state'] = '离线'
  585. }
  586. }
  587. } else {
  588. item['online_state'] = '离线'
  589. }
  590. })
  591. this.rowData = deviceData
  592. this.pageData = {
  593. page_no: response.page_no,
  594. page_size: response.page_size,
  595. data_total: response.data_total
  596. }
  597. this.$nextTick(() => {
  598. const node = this.gridApi.getDisplayedRowAtIndex(0)
  599. if (node !== null && node !== undefined) {
  600. node.setSelected(true)
  601. }
  602. })
  603. })
  604. this.typeFrames = this.partFrames
  605. },
  606. getTypeFrame(partId) {
  607. API_Frame.getFramesPartId(partId).then(res => {
  608. this.partFrames = [...res]
  609. })
  610. },
  611. /** 将partFrames做分割 */
  612. getFramesByType(device_type) {
  613. if (this.partFrames != null) {
  614. this.typeFrames = this.partFrames.filter(item => item.type === device_type)
  615. }
  616. },
  617. /**
  618. * 过滤状态发生变化,发送到服务器检索数据
  619. */
  620. filterModifed(param) {
  621. var model = param.api.getFilterModel()
  622. // 连接状态不经过服务器过滤
  623. delete model.online_state
  624. this.params.filter = JSON.stringify(model)
  625. this.getList()
  626. },
  627. gridSortChange(param) {
  628. const columnState = param.columnApi.getColumnState()
  629. // 排序状态
  630. const sortState = columnState.filter(function(s) {
  631. return s.sort != null
  632. }).map(function(s) {
  633. return {
  634. colId: s.colId,
  635. sort: s.sort,
  636. sortIndex: s.sortIndex
  637. }
  638. }).sort(function(a, b) {
  639. return a.sortIndex - b.sortIndex
  640. })
  641. if (sortState.length > 0) {
  642. if (sortState.length === 1) {
  643. this.params.sort = sortState[0].colId
  644. this.params.dir = sortState[0].sort
  645. } else {
  646. let sortstring = ''
  647. sortState.forEach(function(item) {
  648. sortstring += item.colId + ' ' + item.sort + ','
  649. })
  650. this.params.sort = sortstring.substring(0, sortstring.length - 1)
  651. this.params.dir = ' '
  652. }
  653. } else {
  654. delete this.params.sort
  655. delete this.params.dir
  656. }
  657. this.getList()
  658. },
  659. /** 处理搜索 */
  660. handlerSearch(keywords) {
  661. this.params.query = keywords
  662. this.getList()
  663. },
  664. /** 获取设备类型文字显示,从deviceTypeTransfer 中找出value值对应的key显示出来 */
  665. deviceTypeGetter(params) {
  666. const gridVal = params.data.device_type
  667. return this.deviceTypeTransfer.filter(p => p.value === gridVal).map(p => p.key)
  668. },
  669. /** 格式化时间函数 */
  670. unixDateFormatter(param) {
  671. if (!param.value) return ''
  672. return unix2Date(param.value * 1000)
  673. },
  674. /** 设备状态格式化 **/
  675. deviceStatusFormatter(params) {
  676. if (params.value === null || params.value === undefined) return ''
  677. const item = this.deviceStatusTransfer.filter(p => p.value === params.value)[0]
  678. if (item) {
  679. return '<span style="color:' + item.color + ';">' + item.key + '</span>'
  680. } else {
  681. return ''
  682. }
  683. },
  684. /** 设备连接状态格式化 **/
  685. onlineStateFormatter(params) {
  686. if (params.value === '在线') {
  687. return '<span style="color:green;">在线</span>'
  688. } else {
  689. return '<span style="color:gray;">离线</span>'
  690. }
  691. },
  692. /** 删除设备 **/
  693. deleteSingle(row) {
  694. this.handlerDelete(row.id)
  695. },
  696. /** 删除设备 **/
  697. handlerDelete(id) {
  698. this.$confirm('删除操作后数据不可复原,您确定要删除此数据?', '警告', {
  699. confirmButtonText: '确定',
  700. cancelButtonText: '取消',
  701. type: 'warning'
  702. }).then(() => {
  703. API_Device.remove(id).then(
  704. response => {
  705. this.getList()
  706. }
  707. ).catch(response => {
  708. this.$message({
  709. type: 'info',
  710. message: response.message
  711. })
  712. })
  713. if (this.hasSosDeviceSettings) {
  714. API_SosDeviceSetting.deleteByDeviceId(id).then(() => {
  715. this.hasSosDeviceSettings = false
  716. this.getList()
  717. })
  718. }
  719. }).catch(() => {
  720. this.$message({
  721. type: 'info',
  722. message: '已取消删除'
  723. })
  724. })
  725. },
  726. /** 设备类型选中变化 **/
  727. deviceTypeChange(val) {
  728. this.deviceTypeChangeToFrameTypeChange(val)
  729. if (val === DEVICE_TYPE.SIMULATE_BED_DEVICE || // 只能直接在后面加设备,会判断错误,必须重新用val = 设备
  730. val === DEVICE_TYPE.RS485_DOOR ||
  731. val === DEVICE_TYPE.SIMULATE_EMERGENCY_BUTTON ||
  732. val === DEVICE_TYPE.SIMULATE_DOOR_LIGHT ||
  733. val === DEVICE_TYPE.EMERGENCY_BUTTON) { // 模拟设备不需要mac地址
  734. this.deviceRules.eth_mac[0].required = false
  735. this.deviceRules.eth_mac[1].pattern = null
  736. } else if (val === DEVICE_TYPE.REMOTE_CONTROL) {
  737. this.deviceRules.eth_mac[1].pattern = null
  738. this.deviceRules.eth_mac[0].required = true
  739. } else if (val === DEVICE_TYPE.DIGIT_BED_DEVICE) {
  740. this.deviceRules.eth_mac[1].pattern = null
  741. this.deviceRules.eth_mac[0].required = true
  742. } else {
  743. // this.deviceRules.eth_mac[1].pattern = /^([0-9A-Fa-f]{2}:?){6}/gi
  744. this.deviceRules.eth_mac[1].pattern = null
  745. this.deviceRules.eth_mac[0].required = true
  746. }
  747. this.hasRoleId = val === DEVICE_TYPE.NURSE_WATCH
  748. this.hasAudioId = val === DEVICE_TYPE.SIMULATE_BED_DEVICE ||
  749. val === DEVICE_TYPE.RS485_DOOR ||
  750. val === DEVICE_TYPE.SIMULATE_EMERGENCY_BUTTON ||
  751. val === DEVICE_TYPE.SIMULATE_DOOR_LIGHT
  752. this.hasSosDeviceSettings = val === DEVICE_TYPE.ALARM_BODY_INDUCTIVE ||
  753. val === DEVICE_TYPE.DOOR_LOCK
  754. this.isLedDevice = val === DEVICE_TYPE.LED_SCREEN ||
  755. val === DEVICE_TYPE.LCD_SCREEN
  756. },
  757. /** 设备类型选中对应的空间结构 **/
  758. deviceTypeChangeToFrameTypeChange(val) {
  759. if (val === DEVICE_TYPE.NURSE_HOST ||
  760. val === DEVICE_TYPE.DOCTOR_HOST ||
  761. val === DEVICE_TYPE.LED_SCREEN ||
  762. val === DEVICE_TYPE.LCD_SCREEN ||
  763. val === DEVICE_TYPE.NURSE_WATCH ||
  764. val === DEVICE_TYPE.WORKER_WATCH ||
  765. val === DEVICE_TYPE.TRANSFER_DEVICE ||
  766. val === DEVICE_TYPE.INFORMATION_BOARD ||
  767. val === DEVICE_TYPE.RS485_TRANSFER) {
  768. this.getFramesByType(FRAME_TYPE.PART)
  769. } else if (val === DEVICE_TYPE.DOOR_DEVICE ||
  770. val === DEVICE_TYPE.SIMULATE_EMERGENCY_BUTTON ||
  771. val === DEVICE_TYPE.RS485_DOOR ||
  772. val === DEVICE_TYPE.SIMULATE_DOOR_LIGHT ||
  773. val === DEVICE_TYPE.BEACON) {
  774. this.getFramesByType(FRAME_TYPE.ROOM)
  775. } else if (val === DEVICE_TYPE.DIGIT_BED_DEVICE ||
  776. val === DEVICE_TYPE.SIMULATE_BED_DEVICE ||
  777. val === DEVICE_TYPE.REMOTE_CONTROL ||
  778. val === DEVICE_TYPE.CELL_PHONE ||
  779. val === DEVICE_TYPE.ALARM_BODY_INDUCTIVE ||
  780. val === DEVICE_TYPE.ALARM_WATER_OVERFLOW ||
  781. val === DEVICE_TYPE.ALARM_HOUSEHOLD_GAS ||
  782. val === DEVICE_TYPE.ALARM_HOUSEHOLD_SMOKE ||
  783. val === DEVICE_TYPE.ALARM_BUTTON_SOS ||
  784. val === DEVICE_TYPE.DOOR_LOCK
  785. ) {
  786. this.getFramesByType(FRAME_TYPE.BED)
  787. } else {
  788. this.getTypeFrame(this.$store.getters.partId)
  789. this.typeFrames = this.partFrames
  790. }
  791. },
  792. /** 添加设备事件 **/
  793. handleAdd() {
  794. this.deviceModel = {
  795. soft_ver: 'SV1.0',
  796. hard_ver: 'HV1.0',
  797. priority: 1,
  798. code: 'C' + parseInt(Math.random() * 100000),
  799. model: 'M' + parseInt(Math.random() * 100000),
  800. part_id: this.$store.getters.partId,
  801. status: 1
  802. }
  803. this.sosDeviceSetting = {
  804. type: 0,
  805. unit: '小时',
  806. setting_time: 0,
  807. }
  808. if (Object.keys(this.frame).length > 0) {
  809. this.$set(this.deviceModel, 'frame_id', this.frame.id)
  810. }
  811. delete this.deviceModel.id
  812. this.hasRoleId = false
  813. this.getRoles({ page_size: 200, page_no: 1, fixedCondition: ' shop_id = -1', sort: ' role_id', dir: 'desc' })
  814. this.hasAudioId = false
  815. this.hasSosDeviceSettings = false
  816. this.isLedDevice = false
  817. this.getDevices(this.$store.getters.partId)
  818. this.deviceEditTitle = '添加设备'
  819. this.deviceDialogVisible = true
  820. this.deviceTypeDisabled = false // 新增设备可以选择设备类型
  821. this.typeFrames = this.partFrames
  822. },
  823. /** 修改设备 **/
  824. handleEdit(params) {
  825. this.getRoles({ page_size: 200, page_no: 1, fixedCondition: ' shop_id = -1', sort: ' role_id', dir: 'desc' })
  826. this.getDevices(params.part_id)
  827. this.getSosDeviceSetting(params.id)
  828. this.deviceTypeChangeToFrameTypeChange(params.device_type)
  829. this.hasRoleId = params.device_type === DEVICE_TYPE.NURSE_WATCH
  830. this.hasAudioId = params.device_type === DEVICE_TYPE.SIMULATE_BED_DEVICE ||
  831. params.device_type === DEVICE_TYPE.RS485_DOOR ||
  832. params.device_type === DEVICE_TYPE.SIMULATE_EMERGENCY_BUTTON ||
  833. params.device_type === DEVICE_TYPE.SIMULATE_DOOR_LIGHT
  834. this.hasSosDeviceSettings = params.device_type === DEVICE_TYPE.ALARM_BODY_INDUCTIVE ||
  835. params.device_type === DEVICE_TYPE.DOOR_LOCK
  836. this.isLedDevice = params.device_type === DEVICE_TYPE.LED_SCREEN ||
  837. params.device_type === DEVICE_TYPE.LCD_SCREEN
  838. this.deviceModel = {
  839. ...params
  840. }
  841. this.deviceEditTitle = '修改设备'
  842. this.deviceDialogVisible = true
  843. this.deviceTypeDisabled = true // 修改设备时,不能改变设备类型
  844. },
  845. /** 新增 提交表单 */
  846. handlerFormSubmit(formName) {
  847. this.$refs[formName].validate((valid) => {
  848. if (valid) {
  849. const _this = this;
  850. /** 新增 */
  851. if (!this.deviceModel.id) {
  852. API_Device.add(this.deviceModel).then(r => {
  853. this.$message.success('保存成功!')
  854. _this.device = r
  855. this.sosDeviceSetting.device_id = _this.device.id
  856. this.sosDeviceSetting.part_id = _this.device.part_id
  857. if (this.hasSosDeviceSettings) {
  858. API_SosDeviceSetting.add(this.sosDeviceSetting).then(() => {
  859. this.$message.success('保存成功!')
  860. this.hasSosDeviceSettings = false
  861. })
  862. }
  863. this.deviceDialogVisible = false
  864. this.getList()
  865. })
  866. } else {
  867. /** 修改 */
  868. API_Device.update(this.deviceModel.id, this.deviceModel).then(() => {
  869. this.$message.success('修改成功!')
  870. if (this.hasSosDeviceSettings) {
  871. this.sosDeviceSetting.device_id = this.deviceModel.id
  872. this.sosDeviceSetting.part_id = this.deviceModel.part_id
  873. API_SosDeviceSetting.updateByDeviceId(this.deviceModel.id, this.sosDeviceSetting).then(() => {
  874. this.$message.success('保存成功!')
  875. this.hasSosDeviceSettings = false
  876. })
  877. }
  878. this.deviceDialogVisible = false
  879. this.getList()
  880. })
  881. }
  882. }
  883. })
  884. },
  885. /** 分页大小发生改变 */
  886. handlePageSizeChange(size) {
  887. this.params.page_size = size
  888. this.getList()
  889. },
  890. /** 分页页数发生改变 */
  891. handlePageCurrentChange(page) {
  892. this.params.page_no = page
  893. this.getList()
  894. },
  895. getRoles(param) {
  896. // 获取角色
  897. clerk_API.getRoles(param).then(response => {
  898. this.rolesOptions = response.data
  899. })
  900. },
  901. getDevices(partId) {
  902. // 获取设备列表
  903. API_Device.getDeviceByType(partId, DEVICE_TYPE.TRANSFER_DEVICE).then(response => {
  904. this.audioOptions = response
  905. })
  906. API_Device.getDeviceByType(partId, DEVICE_TYPE.RS485_TRANSFER).then(response => {
  907. this.rs485Options = response
  908. })
  909. },
  910. getSosDeviceSetting(deviceId) {
  911. API_SosDeviceSetting.getSosDeviceSetting(deviceId).then(r => {
  912. this.sosDeviceSetting = r;
  913. })
  914. },
  915. initWebSocket: function() {
  916. var stockbase = DeviceUrl.replace('http', 'ws')
  917. this.websock = new WebSocket(stockbase + '/deviceonline/' + this.$store.getters.uuid)
  918. this.websock.onopen = this.websocketonopen
  919. this.websock.onerror = this.websocketonerror
  920. this.websock.onmessage = this.websocketonmessage
  921. this.websock.onclose = this.websocketclose
  922. },
  923. websocketonopen: function() {
  924. console.log('WebSocket连接成功')
  925. },
  926. websocketonerror: function(e) {
  927. console.log('WebSocket连接发生错误')
  928. },
  929. websocketonmessage: function(e) {
  930. this.onlineDevice = JSON.parse(e.data)
  931. if (this.rowData !== null) {
  932. for (let i = 0; i < this.rowData.length; i++) {
  933. if (this.rowData[i].eth_mac) {
  934. const mac = this.onlineDevice.filter(p => p.toLowerCase() === this.rowData[i].eth_mac.toLowerCase())[0]
  935. this.rowData[i]['online_state'] = (mac !== undefined && mac !== null) ? '在线' : '离线'
  936. }
  937. }
  938. const rowData = [...this.rowData]
  939. this.$set(this, 'rowData', rowData)
  940. }
  941. },
  942. websocketclose: function(e) {
  943. console.log('connection closed (' + e.code + ')')
  944. },
  945. batchDelete() {
  946. const rows = this.gridApi.getSelectedRows()
  947. if (rows.length === 0) {
  948. this.$message({ type: 'info', message: '请先勾选需要删除的数据' })
  949. return
  950. }
  951. const ids = []
  952. rows.forEach(function(item) {
  953. ids.push(item.id)
  954. })
  955. this.handlerDelete(ids.join(','))
  956. }
  957. }
  958. }
  959. </script>
  960. <style scoped>
  961. </style>