_gateway.vue 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. <script setup lang="ts" name="Gateway">
  2. import apis from "@a"
  3. import message from "@@/utils/message"
  4. import dayjs from "dayjs"
  5. const emits = defineEmits<{
  6. (e: "query-meter", v: number): void
  7. (e: "create-meter", v: number): void
  8. }>()
  9. const groupIdOptions = ref<any[]>([])
  10. const onlineStatusOptions = computed(() => {
  11. return [
  12. { label: "在线", value: 2, type: "success" },
  13. { label: "离线", value: 1, type: "danger" }
  14. ]
  15. })
  16. const isAdd = ref(false)
  17. const tableRef = ref()
  18. const modalRef = ref()
  19. const opts = reactive<any>({
  20. columns: [
  21. { field: "id", name: "ID", width: 100, visible: false, isSort: false, tooltip: true },
  22. { field: "groupName", name: "设备分组", width: 150, visible: true, tooltip: true },
  23. { field: "sn", name: "设备编码(SN)", width: 130, isSort: true, visible: true },
  24. { field: "name", name: "设备名称", width: "auto", isSort: true, visible: true, tooltip: true },
  25. { field: "type", name: "设备类型", width: 80, isSort: false, visible: true },
  26. { field: "cycle", name: "周期", width: 50, isSort: false, visible: true },
  27. { field: "status", name: "启用状态", width: 100, isSort: true, visible: true },
  28. { field: "onlineStatus", name: "在线状态", width: 100, isSort: true, visible: true },
  29. // { field: "timeOnline", name: "上线时间", width: 155, isSort: true, visible: true },
  30. { field: "timeOffline", name: "离线时间", width: 155, isSort: true, visible: true },
  31. { field: "createdAt", name: "创建时间", width: 155, isSort: true, visible: true },
  32. { field: "actions", name: `操作`, width: 130 }
  33. ],
  34. queryParams: {
  35. groupId: undefined,
  36. sn: undefined,
  37. name: undefined,
  38. status: undefined,
  39. type: 1
  40. },
  41. searchFormItems: [
  42. {
  43. field: "groupId",
  44. label: "分组",
  45. class: "w-100",
  46. component: "VS",
  47. data: () => groupIdOptions.value,
  48. props: {
  49. type: "select",
  50. clearable: true,
  51. placeholder: "请选择设备分组",
  52. props: {
  53. label: "name",
  54. value: "id"
  55. }
  56. }
  57. },
  58. {
  59. field: "sn",
  60. label: "SN",
  61. class: "w-100",
  62. component: "I",
  63. listeners: {
  64. keyup: (e: any) => {
  65. if (e.code == "Enter") {
  66. handleQuery()
  67. }
  68. }
  69. }
  70. },
  71. {
  72. field: "name",
  73. label: "名称",
  74. class: "w-100",
  75. component: "I",
  76. listeners: {
  77. keyup: (e: any) => {
  78. if (e.code == "Enter") {
  79. handleQuery()
  80. }
  81. }
  82. }
  83. },
  84. {
  85. field: "status",
  86. label: "状态",
  87. class: "w-100",
  88. component: "dict",
  89. props: {
  90. valueIsNumber: true,
  91. placeholder: "请选择设备状态",
  92. dictType: "sys_normal_disable"
  93. }
  94. }
  95. ] as any,
  96. permission: "iot:device",
  97. handleFuns: {
  98. handleRefresh,
  99. handleCreate
  100. },
  101. customBtns: [],
  102. tableListFun: apis.iot.deviceApi.listDevice,
  103. getEntityFun: apis.iot.deviceApi.getDevice,
  104. deleteEntityFun: apis.iot.deviceApi.delDevice,
  105. formItems: [
  106. {
  107. show: () => !isAdd.value,
  108. field: "sn",
  109. label: "设备编码",
  110. class: "w-100",
  111. component: "I",
  112. required: true,
  113. props: {
  114. disabled: true
  115. },
  116. span: 24
  117. },
  118. {
  119. field: "groupId",
  120. label: "设备分组",
  121. class: "w-100",
  122. required: true,
  123. component: "VS",
  124. data: () => groupIdOptions.value,
  125. props: {
  126. type: "select",
  127. valueIsNumber: true,
  128. clearable: true,
  129. placeholder: "请选择分组",
  130. props: {
  131. label: "name",
  132. value: "id"
  133. }
  134. },
  135. span: 24
  136. },
  137. {
  138. field: "name",
  139. label: "设备名称",
  140. class: "w-100",
  141. component: "I",
  142. required: true,
  143. span: 24
  144. },
  145. {
  146. field: "cycle",
  147. label: "上报周期",
  148. class: "w-100",
  149. component: "I",
  150. type: "number",
  151. required: true,
  152. span: 24
  153. },
  154. {
  155. field: "description",
  156. label: "设备描述",
  157. class: "w-100",
  158. component: "I",
  159. type: "textarea",
  160. required: false,
  161. span: 24
  162. },
  163. {
  164. field: "status",
  165. label: "设备状态",
  166. class: "w-100",
  167. component: "dict",
  168. props: {
  169. type: "radio",
  170. valueIsNumber: true,
  171. placeholder: "请选择设备状态",
  172. dictType: "sys_normal_disable"
  173. },
  174. span: 24
  175. }
  176. ] as any,
  177. resetForm: () => {
  178. form.value = emptyFormData.value
  179. },
  180. modalTitle: "网关",
  181. emptyFormData: {
  182. id: undefined,
  183. parentId: 0,
  184. groupId: undefined,
  185. sn: undefined,
  186. name: undefined,
  187. type: 1,
  188. mode: undefined,
  189. cycle: undefined,
  190. status: 2,
  191. description: undefined,
  192. protocol: undefined,
  193. address: undefined
  194. }
  195. })
  196. const { queryParams, emptyFormData } = toRefs(opts)
  197. const form = ref<any>(emptyFormData.value)
  198. /** 添加按钮操作 */
  199. function handleCreate() {
  200. opts.resetForm()
  201. isAdd.value = true
  202. modalRef.value.changePrefixTitle("添加")
  203. modalRef.value.show()
  204. }
  205. /** 修改按钮操作 */
  206. function handleUpdate(row: any) {
  207. isAdd.value = false
  208. tableRef.value.defaultHandleFuns.handleUpdate("", row)
  209. }
  210. /** 删除按钮操作 */
  211. function handleDelete(rows: any[]) {
  212. tableRef.value.defaultHandleFuns.handleDelete("", rows)
  213. }
  214. /** 提交按钮 */
  215. function submitForm() {
  216. if (form.value.id != undefined) {
  217. apis.iot.deviceApi.updateDevice(form.value).then(() => {
  218. message.msgSuccess("修改成功")
  219. queryParams.value.orgId = undefined
  220. handleQuery()
  221. })
  222. } else {
  223. apis.iot.deviceApi.addDevice(form.value).then(() => {
  224. message.msgSuccess("新增成功")
  225. queryParams.value.orgId = undefined
  226. handleQuery()
  227. })
  228. }
  229. }
  230. function handleRefresh() {
  231. message.confirm("确定要重新加载设备吗?", "重新加载").then(() => {
  232. apis.iot.deviceApi.refresh().then(() => {
  233. message.msgSuccess("重新加载成功")
  234. handleQuery()
  235. })
  236. })
  237. }
  238. /** 查询按钮 */
  239. function handleQuery() {
  240. addDateRange(queryParams.value, queryParams.value.dateRange)
  241. tableRef.value?.search()
  242. let count = 0
  243. let timer: any = 0
  244. function handle() {
  245. const row = tableRef.value?.getData()[0]
  246. if (row) {
  247. clearTimeout(timer)
  248. emits("query-meter", row.id)
  249. } else if (count < 50) {
  250. count++
  251. timer = setTimeout(handle, 100)
  252. }
  253. }
  254. handle()
  255. }
  256. /** 查询重置按钮 */
  257. function resetQuery() {
  258. queryParams.value.dateRange = []
  259. addDateRange(queryParams.value, queryParams.value.dateRange)
  260. }
  261. function handleCreateMeter(row: any) {
  262. emits("create-meter", row.id)
  263. }
  264. function init() {
  265. apis.iot.groupApi.listGroup({ pageSize: 10000, pageIndex: 1 }).then((res) => {
  266. groupIdOptions.value = res.data.rows
  267. })
  268. }
  269. function onRowClick(row: any) {
  270. emits("query-meter", row.id)
  271. }
  272. function query(orgId: number) {
  273. queryParams.value.orgId = orgId
  274. handleQuery()
  275. }
  276. onMounted(init)
  277. defineExpose({ query })
  278. </script>
  279. <template>
  280. <div class="w-100 h-100">
  281. <VbDataTable
  282. ref="tableRef"
  283. style="height: 100%"
  284. :handle-perm="opts.permission"
  285. :handle-funs="opts.handleFuns"
  286. :search-form-items="opts.searchFormItems"
  287. :columns="opts.columns"
  288. :custom-btns="opts.customBtns"
  289. :remote-fun="opts.tableListFun"
  290. :get-entity-fun="opts.getEntityFun"
  291. :delete-entity-fun="opts.deleteEntityFun"
  292. :page-size="10"
  293. :page-size-array="[10, 25, 50]"
  294. sortField="createdAt"
  295. sort-order="desc"
  296. :modal="modalRef"
  297. :reset-form-fun="opts.resetForm"
  298. v-model:form-data="form"
  299. :query-params="queryParams"
  300. :check-multiple="true"
  301. :has-checkbox="true"
  302. :row-click="onRowClick"
  303. :reset-search-form-fun="resetQuery"
  304. :custom-search-fun="handleQuery">
  305. <template #status="{ row }">
  306. <DictTag valueIsNumber :value="row.status" type="sys_normal_disable"></DictTag>
  307. </template>
  308. <template #type="{ row }">
  309. <DictTag valueIsNumber :value="row.type" type="iot_device_type"></DictTag>
  310. </template>
  311. <template #mode="{ row }">
  312. <DictTag valueIsNumber :value="row.mode" type="iot_device_mode"></DictTag>
  313. </template>
  314. <template #onlineStatus="{ row }">
  315. <VbTag valueIsNumber :value="row.onlineStatus" :data="onlineStatusOptions"></VbTag>
  316. </template>
  317. <template #timeOnline="{ row }">
  318. <span :class="{ 'text-success': row.onlineStatus == 2 }">
  319. {{ row.timeOnline.Valid ? dayjs(row.timeOnline.Time).format("YYYY-MM-DD HH:mm:ss") : "" }}
  320. </span>
  321. </template>
  322. <template #timeOffline="{ row }">
  323. <span :class="{ 'text-danger': row.onlineStatus == 1 }">
  324. {{
  325. row.timeOffline.Valid ? dayjs(row.timeOffline.Time).format("YYYY-MM-DD HH:mm:ss") : ""
  326. }}
  327. </span>
  328. </template>
  329. <template #createdAt="{ row }">
  330. <span>{{ dayjs(row.createdAt).format("YYYY-MM-DD HH:mm:ss") }}</span>
  331. </template>
  332. <template #actions="{ row }">
  333. <vb-tooltip content="修改" placement="top">
  334. <el-button
  335. link
  336. type="primary"
  337. @click="handleUpdate(row)"
  338. v-hasPermission="'iot:device:edit'">
  339. <template #icon>
  340. <VbIcon icon-name="notepad-edit" icon-type="duotone" class="fs-3"></VbIcon>
  341. </template>
  342. </el-button>
  343. </vb-tooltip>
  344. <vb-tooltip content="删除" placement="top">
  345. <el-button
  346. link
  347. type="primary"
  348. @click="handleDelete([row])"
  349. v-hasPermission="'iot:device:remove'">
  350. <template #icon>
  351. <VbIcon icon-name="trash-square" icon-type="duotone" class="fs-3"></VbIcon>
  352. </template>
  353. </el-button>
  354. </vb-tooltip>
  355. <vb-tooltip content="新增表计" placement="top">
  356. <el-button link type="danger" @click="handleCreateMeter(row)">
  357. <template #icon>
  358. <VbIcon icon-name="plus-square" icon-type="duotone" class="fs-3"></VbIcon>
  359. </template>
  360. </el-button>
  361. </vb-tooltip>
  362. </template>
  363. </VbDataTable>
  364. <VbModal
  365. v-model:modal="modalRef"
  366. :title="opts.modalTitle"
  367. :form-items="opts.formItems as any"
  368. :form-data="form"
  369. @confirm="submitForm"
  370. append-to-body></VbModal>
  371. </div>
  372. </template>