index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. <template>
  2. <div class="container">
  3. <a-card class="general-card">
  4. <a-row>
  5. <a-col :flex="1">
  6. <a-form
  7. :model="formModel"
  8. :label-col-props="{ span: 4 }"
  9. :wrapper-col-props="{ span: 18 }"
  10. label-align="left"
  11. >
  12. <a-row :gutter="16">
  13. <a-col :span="6">
  14. <a-form-item
  15. field="address"
  16. :label="t('dashboard.form.address')"
  17. label-col-flex="50px"
  18. >
  19. <a-input
  20. v-model="formModel.address"
  21. :placeholder="t('dashboard.form.address')"
  22. allow-clear
  23. />
  24. </a-form-item>
  25. </a-col>
  26. <a-col :span="6">
  27. <a-form-item
  28. field="name"
  29. :label="t('dashboard.form.name')"
  30. label-col-flex="50px"
  31. >
  32. <a-input
  33. v-model="formModel.name"
  34. :placeholder="t('dashboard.form.name')"
  35. allow-clear
  36. />
  37. </a-form-item>
  38. </a-col>
  39. <a-col :span="6">
  40. <a-form-item
  41. field="entityType"
  42. :label="t('dashboard.form.entityType')"
  43. label-col-flex="60px"
  44. >
  45. <a-select
  46. v-model="formModel.entityType"
  47. :placeholder="t('dashboard.form.entityType')"
  48. allow-clear
  49. @clear="formModel.entityType = null"
  50. >
  51. <a-option
  52. v-for="item of deviceTypeList"
  53. :value="item.dictCode"
  54. :label="item.name"
  55. />
  56. </a-select>
  57. </a-form-item>
  58. </a-col>
  59. <a-col :span="6">
  60. <a-form-item
  61. field="statusTypeList"
  62. :label="t('dashboard.form.status')"
  63. label-col-flex="60px"
  64. >
  65. <a-select
  66. v-model="formModel.status"
  67. :placeholder="t('dashboard.form.status')"
  68. allow-clear
  69. @clear="formModel.status = null"
  70. >
  71. <a-option
  72. v-for="item of deviceStatusList"
  73. :value="item.dictCode"
  74. :label="item.name"
  75. />
  76. </a-select>
  77. </a-form-item>
  78. </a-col>
  79. <a-col :span="6">
  80. <a-form-item
  81. :label="t('dashboard.form.timeRange')"
  82. label-col-flex="60px"
  83. >
  84. <a-range-picker v-model="formModel.time" />
  85. </a-form-item>
  86. </a-col>
  87. </a-row>
  88. </a-form>
  89. </a-col>
  90. <a-divider :style="{ height: '84px' }" direction="vertical" />
  91. <a-col :flex="'86px'">
  92. <a-space :size="10">
  93. <a-button type="primary" @click="search">
  94. <template #icon>
  95. <icon-search />
  96. </template>
  97. {{ t('searchTable.form.search') }}
  98. </a-button>
  99. <a-button @click="reset">
  100. <template #icon>
  101. <icon-refresh />
  102. </template>
  103. {{ t('searchTable.form.reset') }}
  104. </a-button>
  105. </a-space>
  106. <a-button
  107. type="primary"
  108. class="right-side"
  109. @click="showEditDialog = true"
  110. >
  111. <template #icon>
  112. <icon-plus />
  113. </template>
  114. {{ t('searchTable.form.add') }}
  115. </a-button>
  116. </a-col>
  117. </a-row>
  118. <a-table
  119. class="table-list"
  120. row-key="name"
  121. :loading="loading"
  122. :pagination="pagination"
  123. :columns="cloneColumns"
  124. :data="renderData"
  125. :bordered="false"
  126. :size="size"
  127. :scrollbar="true"
  128. @page-change="onPageChange"
  129. @row-dblclick="handleClick"
  130. >
  131. <template #index="{ rowIndex }">
  132. {{ rowIndex + 1 + (pagination.current - 1) * pagination.pageSize }}
  133. </template>
  134. <template #entityType="{ record }">
  135. <span>
  136. {{
  137. deviceTypeList.find(item => item.dictCode === record.entityType)
  138. ?.name
  139. }}
  140. </span>
  141. </template>
  142. <template #status="{ record }">
  143. <BTag :status="record.status">
  144. {{
  145. deviceStatusList.find(item => item.dictCode === record.status)
  146. ?.name
  147. }}
  148. </BTag>
  149. </template>
  150. <template #time="{ record }">
  151. <span>{{
  152. record.time && dayjs(record.time).format('YYYY-MM-DD HH:mm:ss')
  153. }}</span>
  154. </template>
  155. <template #optional="{ record }">
  156. <a-button
  157. type="primary"
  158. size="mini"
  159. class="action-button"
  160. @click="
  161. () => {
  162. ((deviceId = record.id), (showEditDialog = true));
  163. }
  164. "
  165. >
  166. {{ t('searchTable.form.edit') }}
  167. </a-button>
  168. <a-button
  169. status="danger"
  170. size="mini"
  171. @click="handleDeleteFun(record.id)"
  172. >
  173. {{ t('searchTable.form.delete') }}
  174. </a-button>
  175. </template>
  176. </a-table>
  177. </a-card>
  178. <a-modal
  179. v-model:visible="visible"
  180. title-align="start"
  181. @cancel="handleCancel"
  182. >
  183. <template #title>{{ t('dashboard.dialog.title') }}</template>
  184. <div>
  185. <a-descriptions :data="deviceInfo" bordered :column="2" />
  186. </div>
  187. <template #footer>
  188. <a-button @click="handleCancel">取消</a-button>
  189. <!-- 只保留取消按钮,确认按钮被隐藏 -->
  190. </template>
  191. </a-modal>
  192. <EditDialog
  193. v-model="showEditDialog"
  194. :id="deviceId"
  195. @updateList="updateListFun"
  196. ></EditDialog>
  197. </div>
  198. </template>
  199. <script lang="ts" setup name="Dashboard">
  200. import {
  201. ref,
  202. reactive,
  203. shallowRef,
  204. h,
  205. getCurrentInstance,
  206. computed,
  207. } from 'vue';
  208. import {
  209. queryDashboardList,
  210. exportDashboardList,
  211. deleteDeviceDetails,
  212. } from '@/api/dashboard';
  213. import type { DashboardParams, DataList } from '@/api/dashboard';
  214. import { SizeProps, Pagination } from '@/types/global';
  215. import BTag from '@/components/business/b-tag/index.vue';
  216. import EditDialog from './edit.vue';
  217. import type { TableColumnData } from '@arco-design/web-vue';
  218. import useLoading from '@/hooks/loading';
  219. import { useI18n } from 'vue-i18n';
  220. import dayjs from 'dayjs';
  221. import { downLoadFun, DeviceInfo } from '@/utils/const';
  222. import { useIntervalFn } from '@vueuse/core';
  223. import { Modal } from '@arco-design/web-vue';
  224. import type { AdditionalProp } from '@/api/dict';
  225. import { getDictQueryList } from '@/api/dict';
  226. const { t } = useI18n();
  227. const { loading, setLoading } = useLoading(true);
  228. const cloneColumns = computed(() => [
  229. {
  230. title: t('searchTable.table.number'),
  231. dataIndex: 'index',
  232. slotName: 'index',
  233. ellipsis: true,
  234. tooltip: true,
  235. width: 70,
  236. },
  237. {
  238. title: t('dashboard.table.time'),
  239. dataIndex: 'time',
  240. slotName: 'time',
  241. ellipsis: true,
  242. },
  243. // {
  244. // title: t('dashboard.form.status'),
  245. // dataIndex: 'status',
  246. // slotName: 'status',
  247. // width: 120,
  248. // },
  249. {
  250. title: t('dashboard.form.name'),
  251. dataIndex: 'name',
  252. slotName: 'name',
  253. },
  254. {
  255. title: t('dashboard.form.entityType'),
  256. dataIndex: 'entityType',
  257. slotName: 'entityType',
  258. },
  259. {
  260. title: t('dashboard.form.address'),
  261. dataIndex: 'address',
  262. ellipsis: true,
  263. tooltip: true,
  264. },
  265. {
  266. title: t('searchTable.table.optional'),
  267. align: 'center',
  268. slotName: 'optional',
  269. },
  270. ]);
  271. const basePagination: Pagination = {
  272. current: 1,
  273. pageSize: 20,
  274. };
  275. const pagination = reactive({
  276. ...basePagination,
  277. });
  278. const generateFormModel = () => {
  279. return {
  280. pageIndex: 1,
  281. pageSize: 20,
  282. name: null,
  283. address: null,
  284. status: null,
  285. startTime: null,
  286. endTime: null,
  287. time: ['', ''],
  288. entityType: null,
  289. } as DashboardParams;
  290. };
  291. const renderData = ref<DataList[]>([] as DataList[]);
  292. const size = ref<SizeProps>('medium');
  293. const formModel = ref<DashboardParams>(generateFormModel());
  294. const visible = shallowRef<boolean>(false);
  295. const showEditDialog = shallowRef<boolean>(false);
  296. const deviceId = ref<number | null>(null);
  297. const this_ = getCurrentInstance()?.appContext.config.globalProperties;
  298. const deviceInfo = ref<DeviceInfo[]>([] as DeviceInfo[]);
  299. const deviceTypeList = ref<AdditionalProp[]>([] as AdditionalProp[]);
  300. const deviceStatusList = ref<AdditionalProp[]>([] as AdditionalProp[]);
  301. getDictQueryList({ names: ['DeviceType', 'DeviceStatus'] }).then(res => {
  302. deviceTypeList.value.push(...res.data['DeviceType']);
  303. deviceStatusList.value.push(...res.data['DeviceStatus']);
  304. });
  305. function searchTable() {
  306. // setLoading(true);
  307. const [startTime, endTime] = formModel.value.time
  308. ? formModel.value.time
  309. : ['', ''];
  310. formModel.value.startTime = startTime ? startTime : null;
  311. formModel.value.endTime = endTime ? endTime : null;
  312. queryDashboardList(formModel.value)
  313. .then(res => {
  314. pagination.current = formModel.value.pageIndex;
  315. pagination.pageSize = pagination.pageSize;
  316. pagination.total = res.totalCount;
  317. renderData.value = res.data;
  318. })
  319. .finally(() => {
  320. setLoading(false);
  321. });
  322. }
  323. searchTable();
  324. const search = () => {
  325. searchTable();
  326. };
  327. const reset = () => {
  328. formModel.value = generateFormModel();
  329. };
  330. const onPageChange = (current: number) => {
  331. formModel.value.pageIndex = current;
  332. searchTable();
  333. };
  334. const handleClick = (value: DataList) => {
  335. if (value.data) {
  336. deviceInfo.value.length = 0;
  337. const obj = JSON.parse(value.data);
  338. for (const key in obj) {
  339. deviceInfo.value.push({
  340. label: key,
  341. value: obj[key],
  342. });
  343. }
  344. visible.value = true;
  345. } else {
  346. this_ &&
  347. this_.$message.warning('No device information available at the moment');
  348. }
  349. };
  350. const handleCancel = () => {
  351. visible.value = false;
  352. };
  353. const updateListFun = () => {
  354. deviceId.value = null;
  355. searchTable();
  356. };
  357. const handleDeleteFun = (id: number) => {
  358. Modal.warning({
  359. title: t('modal.warning.title'),
  360. content: t('modal.warning.content'),
  361. okText: t('searchTable.form.confirm'),
  362. onBeforeOk: (done: (closed: boolean) => void) => {
  363. deleteDeviceDetails({ id })
  364. .then(res => {
  365. if (res.success) {
  366. this_?.$message.success(t('message.success'));
  367. searchTable();
  368. }
  369. })
  370. .finally(() => {
  371. done(true); // 确定关闭模态框
  372. });
  373. },
  374. });
  375. };
  376. </script>
  377. <style lang="less" scoped>
  378. .container {
  379. padding: 10px 10px 20px;
  380. .general-card {
  381. padding-top: 20px;
  382. .right-side {
  383. margin-top: 20px;
  384. }
  385. }
  386. .table-list {
  387. margin-top: 0;
  388. }
  389. .action-button {
  390. margin-right: 10px;
  391. }
  392. }
  393. </style>