Act.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. <template>
  2. <div class="safety-platform-container">
  3. <header class="safety-platform-container__header">
  4. <div class="breadcrumb-title"> 违规行为记录 </div>
  5. </header>
  6. <main class="safety-platform-container__main">
  7. <div class="search-table-container">
  8. <header>
  9. <div>
  10. <el-button type="primary" class="search-table-container--button" :icon="Plus" @click="handleCreateAct">
  11. 新建记录
  12. </el-button>
  13. <el-button plain class="search-table-container--button" @click=""> 批量导入 </el-button>
  14. <RealtimeNotice />
  15. </div>
  16. <div class="act-search">
  17. <section class="select-box">
  18. <SelectableInput ref="selectableInputRef" :options="ACT_TABLE_SEARCH_OPTIONS" />
  19. <div class="select-box--item">
  20. <span>违规类型:</span>
  21. <el-select
  22. v-model="searchData.violationType"
  23. placeholder="请选择违规类型"
  24. class="select-box--select"
  25. clearable
  26. >
  27. <el-option
  28. v-for="item in ACT_VIOLATION_TYPE_OPTIONS"
  29. :key="item.value"
  30. :value="item.value"
  31. :label="item.label"
  32. :disabled="item.disabled"
  33. />
  34. </el-select>
  35. </div>
  36. <div class="select-box--item">
  37. <span>通知状态:</span>
  38. <el-select
  39. v-model="searchData.isNotice"
  40. placeholder="请选择通知状态"
  41. class="select-box--select"
  42. clearable
  43. >
  44. <el-option
  45. v-for="item in ACT_NOTICE_STATE_OPTIONS"
  46. :key="item.value"
  47. :value="item.value"
  48. :label="item.label"
  49. :disabled="item.disabled"
  50. />
  51. </el-select>
  52. </div>
  53. <div>
  54. <span>时间:</span>
  55. <el-date-picker
  56. v-model="searchData.searchTime"
  57. type="datetimerange"
  58. range-separator="至"
  59. start-placeholder="开始时间"
  60. end-placeholder="结束时间"
  61. />
  62. </div>
  63. </section>
  64. <section class="search-btn">
  65. <el-button type="primary" @click="handleSearch">查询</el-button>
  66. <el-button @click="handleReset">重置</el-button>
  67. <el-button @click="handleDownload">导出</el-button>
  68. </section>
  69. </div>
  70. </header>
  71. <!-- 表格 -->
  72. <BasicTable
  73. :tableData="tableData"
  74. :tableConfig="tableConfig"
  75. @update:pageSize="handleSizeChange"
  76. @update:pageNumber="handleCurrentChange"
  77. @update:selection="handleSelectionChange"
  78. >
  79. <template #violateType="scope">
  80. <span>{{ ACT_VIOLATION_TYPE_LABEL[scope.row.violateType] }}</span>
  81. </template>
  82. <template #capturePhotos="scope">
  83. <ImageViewer :file-list="scope.row.capturePhotos" />
  84. </template>
  85. <template #createSource="scope">
  86. <span>{{ ACT_NOTICE_DATA_SOURCE_LABEL[scope.row.createSource] }}</span>
  87. </template>
  88. <template #isNotice="scope">
  89. <div class="notice-state">
  90. <div
  91. :style="{
  92. backgroundColor: ACT_NOTICE_STATE_COLOR[scope.row.isNotice],
  93. width: '6px',
  94. height: '6px',
  95. borderRadius: '50%',
  96. marginRight: '5px',
  97. }"
  98. ></div>
  99. <span>{{ ACT_NOTICE_STATE_LABEL[scope.row.isNotice] }}</span>
  100. </div>
  101. </template>
  102. <template #action="scope">
  103. <ActionButton
  104. v-if="scope.row.isNotice === ACT_NOTICE_STATE.INACTIVE"
  105. text="编辑"
  106. @click="handleEditAct(scope.row.id)"
  107. />
  108. <ActionButton
  109. v-if="scope.row.isNotice === ACT_NOTICE_STATE.INACTIVE"
  110. text="通知"
  111. @click="handleNoticeAct(scope.row.id)"
  112. />
  113. <ActionButton
  114. text="删除"
  115. :popconfirm="{
  116. title: '确定要删除?',
  117. }"
  118. @confirm="handleDeleteAct(scope.row.id)"
  119. />
  120. </template>
  121. </BasicTable>
  122. </div>
  123. </main>
  124. </div>
  125. </template>
  126. <script setup lang="ts">
  127. import BasicTable from '@/components/BasicTable.vue';
  128. import useTableConfig from '@/hooks/useTableConfigHook';
  129. import SelectableInput from '@/components/formItems/selectableInput/SelectableInput.vue';
  130. import ActionButton from '@/components/ActionButton.vue';
  131. import RealtimeNotice from './components/RealtimeNotice.vue';
  132. import { ElMessage } from 'element-plus';
  133. import { TABLE_OPTIONS, VIOLATION_ACT_TABLE_COLUMNS } from './configs/tables';
  134. import {
  135. ACT_NOTICE_DATA_SOURCE_LABEL,
  136. ACT_VIOLATION_TYPE,
  137. ACT_VIOLATION_TYPE_LABEL,
  138. ACT_TABLE_SEARCH_OPTIONS,
  139. ACT_VIOLATION_TYPE_OPTIONS,
  140. ACT_NOTICE_STATE_OPTIONS,
  141. ACT_NOTICE_STATE,
  142. ACT_NOTICE_STATE_LABEL,
  143. ACT_NOTICE_STATE_COLOR,
  144. } from './constants';
  145. import { ref, reactive, onMounted } from 'vue';
  146. import { Search, Plus } from '@element-plus/icons-vue';
  147. import { useRouter } from 'vue-router';
  148. import { openMessageBox } from '@/utils/element-plus/messageBox';
  149. import type { QueryPageRequest } from '@/types/basic-query';
  150. import type { ActTableSearch, ActTableQuery, ActTableData, UpdateActQuery } from './types';
  151. import {
  152. getActTableList,
  153. noticeActData,
  154. deleteActData,
  155. exportActViolation,
  156. } from '@/api/traffic-violation/traffic-act';
  157. import { downloadFile } from '@/views/disaster/utils/download';
  158. import ImageViewer from './components/ImageViewer.vue';
  159. import dayjs from 'dayjs';
  160. const router = useRouter();
  161. // 搜索栏
  162. const selectableInputRef = ref<InstanceType<typeof SelectableInput>>();
  163. const searchData = reactive<ActTableSearch>({});
  164. function getQuery() {
  165. if (!selectableInputRef.value) return;
  166. tabelQuery.queryParam = {
  167. pageType: 1,
  168. };
  169. const selectableSearch = selectableInputRef.value.getValue();
  170. if (selectableSearch) {
  171. tabelQuery.queryParam[selectableSearch.key as string] = selectableSearch.value;
  172. }
  173. if (searchData.isNotice) {
  174. tabelQuery.queryParam.isNotice = searchData.isNotice;
  175. }
  176. if (searchData.violationType) {
  177. tabelQuery.queryParam.violationType = searchData.violationType;
  178. }
  179. if (searchData.searchTime) {
  180. tabelQuery.queryParam.startTime = dayjs(searchData.searchTime[0]).format('YYYY-MM-DD HH:MM:ss');
  181. tabelQuery.queryParam.endTime = dayjs(searchData.searchTime[1]).format('YYYY-MM-DD HH:MM:ss');
  182. }
  183. }
  184. function handleSearch() {
  185. getQuery();
  186. getTabelData();
  187. }
  188. function handleReset() {
  189. selectableInputRef.value?.clearValue();
  190. searchData.carNumber = undefined;
  191. searchData.violateName = undefined;
  192. searchData.deptName = undefined;
  193. searchData.violationType = undefined;
  194. searchData.searchTime = undefined;
  195. }
  196. async function handleDownload() {
  197. getQuery();
  198. try {
  199. const res = await exportActViolation(tabelQuery.queryParam);
  200. if (res.size === 0) return;
  201. const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
  202. const url = window.URL.createObjectURL(blob);
  203. downloadFile(url, '违规行为记录.xlsx');
  204. } catch (e) {
  205. ElMessage.error('下载失败');
  206. console.log(e);
  207. }
  208. }
  209. // 表格
  210. const basicTableRef = ref<InstanceType<typeof BasicTable>>();
  211. const { tableConfig, pagination } = useTableConfig(VIOLATION_ACT_TABLE_COLUMNS, TABLE_OPTIONS);
  212. const tableData = ref<ActTableData[]>([]);
  213. const tabelQuery = reactive<QueryPageRequest<ActTableQuery>>({
  214. pageNumber: pagination.pageNumber,
  215. pageSize: pagination.pageSize,
  216. queryParam: {
  217. pageType: 1,
  218. },
  219. });
  220. const handleSizeChange = (value: number) => {
  221. pagination.pageNumber = value;
  222. tabelQuery.pageSize = value;
  223. getTabelData();
  224. };
  225. const handleCurrentChange = (value: number) => {
  226. pagination.pageNumber = value;
  227. tabelQuery.pageSize = value;
  228. getTabelData();
  229. };
  230. const handleSelectionChange = (value: any[]) => {};
  231. // const handleCloseBatchOperation = () => {
  232. // if (!basicTableRef.value) return;
  233. // basicTableRef.value.clearSelection();
  234. // };
  235. // const handleBatchNotice = async () => {
  236. // const confirmed = await openMessageBox('', '确认通知任务吗?', 'warning');
  237. // if (!confirmed) return;
  238. // const noticeIds = getSelectionIds(ACTIVE_STATUS.NOT_EFFECTIVE);
  239. // await noticeActData(noticeIds);
  240. // ElMessage.success('批量通知成功');
  241. // getTableData();
  242. // };
  243. // const handleBatchDelete = async () => {
  244. // const confirmed = await openMessageBox('', '删除后任务不可恢复,确认删除吗?', 'warning');
  245. // if (!confirmed) return;
  246. // const deleteIds = getSelectionIds(ACTIVE_STATUS.NOT_EFFECTIVE);
  247. // await deleteActData(deleteIds);
  248. // ElMessage.success('批量删除成功');
  249. // getTableData();
  250. // };
  251. async function getTabelData() {
  252. tableConfig.loading = true;
  253. const res = await getActTableList(tabelQuery);
  254. tableData.value = res.records;
  255. pagination.total = res.totalRow;
  256. tableConfig.loading = false;
  257. }
  258. onMounted(async () => {
  259. await getTabelData();
  260. });
  261. function handleCreateAct() {
  262. router.push({
  263. name: 'traffic-violation-act-item',
  264. query: {
  265. operate: 'act-create',
  266. },
  267. });
  268. }
  269. function handleEditAct(id: number) {
  270. router.push({
  271. name: 'traffic-violation-act-item',
  272. query: {
  273. id,
  274. operate: 'act-edit',
  275. },
  276. });
  277. }
  278. async function handleNoticeAct(id: number) {
  279. tableConfig.loading = true;
  280. try {
  281. await noticeActData(id);
  282. } catch (e) {
  283. ElMessage.error('通知失败');
  284. return;
  285. } finally {
  286. tableConfig.loading = false;
  287. }
  288. getTabelData();
  289. }
  290. async function handleDeleteAct(id: number) {
  291. tableConfig.loading = true;
  292. try {
  293. await deleteActData(id);
  294. } catch (e) {
  295. ElMessage.error('删除失败');
  296. return;
  297. } finally {
  298. tableConfig.loading = false;
  299. }
  300. getTabelData();
  301. }
  302. </script>
  303. <style scoped lang="scss">
  304. @use '@/styles/page-details-layout.scss' as *;
  305. @use '@/styles/page-main-layout.scss' as *;
  306. @use '@/styles/basic-table-action.scss' as *;
  307. .act-search-input {
  308. max-width: 500px;
  309. }
  310. .act-search {
  311. display: flex;
  312. align-items: center;
  313. justify-content: space-between;
  314. width: 100%;
  315. }
  316. .select-box {
  317. display: flex;
  318. align-items: center;
  319. flex-wrap: wrap;
  320. gap: 32px;
  321. &--item {
  322. @include flex-center;
  323. white-space: nowrap;
  324. }
  325. span {
  326. color: rgba(0, 0, 0, 0.85);
  327. font-size: 14px;
  328. }
  329. .el-select {
  330. width: 200px;
  331. }
  332. }
  333. .search-btn {
  334. display: flex;
  335. }
  336. .notice-state {
  337. display: flex;
  338. align-items: center;
  339. justify-self: center;
  340. }
  341. </style>