github.com/e154/smart-home@v0.17.2-0.20240311175135-e530a6e5cd45/static_source/admin/src/views/Automation/Tasks/index.vue (about) 1 <script setup lang="ts"> 2 import {useI18n} from '@/hooks/web/useI18n' 3 import {Table} from '@/components/Table' 4 import {h, onMounted, onUnmounted, reactive, ref, watch} from 'vue' 5 import {Pagination, TableColumn} from '@/types/table' 6 import api from "@/api/api"; 7 import {ElButton, ElMessage} from 'element-plus' 8 import {ApiTask} from "@/api/stub"; 9 import {useRouter} from "vue-router"; 10 import {ContentWrap} from "@/components/ContentWrap"; 11 import {parseTime} from "@/utils"; 12 import {EventStateChange, EventTaskCompleted} from "@/api/types"; 13 import {UUID} from "uuid-generator-ts"; 14 import stream from "@/api/stream"; 15 import {useCache} from "@/hooks/web/useCache"; 16 17 const {push} = useRouter() 18 const {t} = useI18n() 19 const {wsCache} = useCache() 20 21 interface TableObject { 22 tableList: ApiTask[] 23 params?: any 24 loading: boolean 25 sort?: string 26 } 27 28 interface Params { 29 page?: number; 30 limit?: number; 31 sort?: string; 32 } 33 34 const cachePref = 'tasks' 35 const tableObject = reactive<TableObject>( 36 { 37 tableList: [], 38 loading: false, 39 sort: wsCache.get(cachePref + 'Sort') || '-createdAt' 40 } 41 ); 42 43 const currentID = ref('') 44 45 const onStateChanged = (event: EventStateChange) => { 46 getList() 47 } 48 49 const onEventTaskActivated = (event: EventTaskCompleted) => { 50 for (const i in tableObject.tableList) { 51 if (tableObject.tableList[i].id == event.id) { 52 tableObject.tableList[i].completed = true; 53 setTimeout(() => { 54 tableObject.tableList[i].completed = false 55 }, 500) 56 return 57 } 58 } 59 } 60 61 onMounted(() => { 62 const uuid = new UUID() 63 currentID.value = uuid.getDashFreeUUID() 64 65 setTimeout(() => { 66 stream.subscribe('event_task_loaded', currentID.value, onStateChanged); 67 stream.subscribe('event_task_unloaded', currentID.value, onStateChanged); 68 stream.subscribe('event_task_completed', currentID.value, onEventTaskActivated); 69 }, 1000) 70 }) 71 72 onUnmounted(() => { 73 stream.unsubscribe('event_task_loaded', currentID.value); 74 stream.unsubscribe('event_task_unloaded', currentID.value); 75 stream.unsubscribe('event_task_completed', currentID.value); 76 }) 77 78 const columns: TableColumn[] = [ 79 { 80 field: 'id', 81 label: t('automation.id'), 82 sortable: true, 83 width: "60px" 84 }, 85 { 86 field: 'name', 87 label: t('automation.name'), 88 sortable: true, 89 width: "170px" 90 }, 91 { 92 field: 'areaId', 93 label: t('automation.area'), 94 width: "100px", 95 sortable: true, 96 formatter: (row: ApiTask) => { 97 return h( 98 'span', 99 row.area?.name 100 ) 101 } 102 }, 103 { 104 field: 'actions', 105 label: t('automation.tasks.actions'), 106 width: "100px", 107 formatter: (row: ApiTask) => { 108 return h( 109 'span', 110 row?.actions?.length || t('automation.nothing') 111 ) 112 } 113 }, 114 { 115 field: 'triggers', 116 label: t('automation.tasks.triggers'), 117 width: "100px", 118 formatter: (row: ApiTask) => { 119 return h( 120 'span', 121 row?.triggers?.length || t('automation.nothing') 122 ) 123 } 124 }, 125 { 126 field: 'description', 127 label: t('automation.description'), 128 sortable: true, 129 formatter: (row: ApiTask) => { 130 return h( 131 'span', 132 row?.description || t('automation.nothing') 133 ) 134 } 135 }, 136 { 137 field: 'status', 138 label: t('entities.status'), 139 width: "70px", 140 }, 141 { 142 field: 'createdAt', 143 label: t('main.createdAt'), 144 type: 'time', 145 sortable: true, 146 width: "170px", 147 formatter: (row: ApiTask) => { 148 return h( 149 'span', 150 parseTime(row.createdAt) 151 ) 152 } 153 }, 154 { 155 field: 'updatedAt', 156 label: t('main.updatedAt'), 157 type: 'time', 158 sortable: true, 159 width: "170px", 160 formatter: (row: ApiTask) => { 161 return h( 162 'span', 163 parseTime(row.updatedAt) 164 ) 165 } 166 }, 167 ] 168 const paginationObj = ref<Pagination>({ 169 currentPage: wsCache.get(cachePref + 'CurrentPage') || 1, 170 pageSize: wsCache.get(cachePref + 'PageSize') || 50, 171 total: 0, 172 pageSizes: [50, 100, 150, 250], 173 }) 174 175 const getList = async () => { 176 tableObject.loading = true 177 178 wsCache.set(cachePref + 'CurrentPage', paginationObj.value.currentPage) 179 wsCache.set(cachePref + 'PageSize', paginationObj.value.pageSize) 180 wsCache.set(cachePref + 'Sort', tableObject.sort) 181 182 let params: Params = { 183 page: paginationObj.value.currentPage, 184 limit: paginationObj.value.pageSize, 185 sort: tableObject.sort, 186 } 187 188 const res = await api.v1.automationServiceGetTaskList(params) 189 .catch(() => { 190 }) 191 .finally(() => { 192 tableObject.loading = false 193 }) 194 if (res) { 195 const {items, meta} = res.data; 196 tableObject.tableList = items; 197 paginationObj.value.currentPage = meta.pagination.page; 198 paginationObj.value.total = meta.pagination.total; 199 } else { 200 tableObject.tableList = []; 201 } 202 } 203 204 watch( 205 () => paginationObj.value.currentPage, 206 () => { 207 getList() 208 } 209 ) 210 211 watch( 212 () => paginationObj.value.pageSize, 213 () => { 214 getList() 215 } 216 ) 217 218 const sortChange = (data) => { 219 const {column, prop, order} = data; 220 const pref: string = order === 'ascending' ? '+' : '-' 221 tableObject.sort = pref + prop 222 getList() 223 } 224 225 getList() 226 227 const addNew = () => { 228 push('/automation/tasks/new') 229 } 230 231 232 const selectRow = (row) => { 233 if (!row) { 234 return 235 } 236 const {id} = row 237 push(`/automation/tasks/edit/${id}`) 238 } 239 240 const enable = async (task: ApiTask) => { 241 if (!task?.id) return; 242 await api.v1.automationServiceEnableTask(task.id); 243 ElMessage({ 244 title: t('Success'), 245 message: t('message.requestSentSuccessfully'), 246 type: 'success', 247 duration: 2000 248 }); 249 } 250 251 const disable = async (task: ApiTask) => { 252 if (!task?.id) return; 253 await api.v1.automationServiceDisableTask(task.id); 254 ElMessage({ 255 title: t('Success'), 256 message: t('message.requestSentSuccessfully'), 257 type: 'success', 258 duration: 2000 259 }); 260 } 261 262 const tableRowClassName = (data) => { 263 const {row, rowIndex} = data 264 let style = '' 265 if (row.completed) { 266 style = 'completed' 267 } 268 return style 269 } 270 271 </script> 272 273 <template> 274 <ContentWrap> 275 <ElButton class="flex mb-20px items-left" type="primary" @click="addNew()" plain> 276 <Icon icon="ep:plus" class="mr-5px"/> 277 {{ t('automation.addNew') }} 278 </ElButton> 279 280 <Table 281 :selection="false" 282 v-model:pageSize="paginationObj.pageSize" 283 v-model:currentPage="paginationObj.currentPage" 284 :columns="columns" 285 :data="tableObject.tableList" 286 :loading="tableObject.loading" 287 :pagination="paginationObj" 288 @sort-change="sortChange" 289 :row-class-name="tableRowClassName" 290 style="width: 100%" 291 :showUpPagination="20" 292 > 293 <template #name="{ row }"> 294 <span @click.prevent.stop="selectRow(row)" style="cursor: pointer"> 295 {{ row.name }} 296 </span> 297 </template> 298 299 <template #status="{ row }"> 300 <div class="w-[100%] text-center"> 301 <ElButton :link="true" @click.prevent.stop="enable(row)" v-if="!row?.isLoaded"> 302 <Icon icon="noto:red-circle" class="mr-5px"/> 303 </ElButton> 304 <ElButton :link="true" @click.prevent.stop="disable(row)" v-if="row?.isLoaded"> 305 <Icon icon="noto:green-circle" class="mr-5px"/> 306 </ElButton> 307 </div> 308 </template> 309 </Table> 310 311 </ContentWrap> 312 313 </template> 314 315 <style lang="less"> 316 317 .light { 318 .el-table__row { 319 &.completed { 320 --el-table-tr-bg-color: var(--el-color-primary-light-7); 321 -webkit-transition: background-color 200ms linear; 322 -ms-transition: background-color 200ms linear; 323 transition: background-color 200ms linear; 324 } 325 } 326 } 327 328 .dark { 329 .el-table__row { 330 &.completed { 331 --el-table-tr-bg-color: var(--el-color-primary-dark-2); 332 -webkit-transition: background-color 200ms linear; 333 -ms-transition: background-color 200ms linear; 334 transition: background-color 200ms linear; 335 } 336 } 337 } 338 339 </style>