Notice.vue 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  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 class="act-search">
  10. <section class="select-box">
  11. <SelectableInput ref="selectableInputRef" :options="ACT_TABLE_SEARCH_OPTIONS" />
  12. <div class="select-box--item">
  13. <span>违规类型:</span>
  14. <el-select
  15. v-model="searchData.violateType"
  16. placeholder="请选择违规类型"
  17. class="select-box--select"
  18. clearable
  19. >
  20. <el-option
  21. v-for="item in ACT_VIOLATION_TYPE_OPTIONS"
  22. :key="item.value"
  23. :value="item.value"
  24. :label="item.label"
  25. :disabled="item.disabled"
  26. />
  27. </el-select>
  28. </div>
  29. <div class="select-box--item">
  30. <span>通知状态:</span>
  31. <el-select
  32. v-model="searchData.isNotice"
  33. placeholder="请选择通知状态"
  34. class="select-box--select"
  35. clearable
  36. >
  37. <el-option
  38. v-for="item in ACT_NOTICE_STATE_OPTIONS"
  39. :key="item.value"
  40. :value="item.value"
  41. :label="item.label"
  42. :disabled="item.disabled"
  43. />
  44. </el-select>
  45. </div>
  46. <div>
  47. <span>时间:</span>
  48. <el-date-picker
  49. v-model="searchData.searchTime"
  50. type="datetimerange"
  51. range-separator="至"
  52. start-placeholder="开始时间"
  53. end-placeholder="结束时间"
  54. />
  55. </div>
  56. </section>
  57. <section class="search-btn">
  58. <el-button type="primary" @click="handleSearch">查询</el-button>
  59. <el-button @click="handleReset">重置</el-button>
  60. <el-button v-if="noticeManagementPermission" @click="handleDownload">导出</el-button>
  61. </section>
  62. </div>
  63. </header>
  64. <!-- 表格 -->
  65. <BasicTable
  66. ref="basicTableRef"
  67. :tableData="tableData"
  68. :tableConfig="tableConfig"
  69. @update:pageSize="handleSizeChange"
  70. @update:pageNumber="handleCurrentChange"
  71. >
  72. <template #violateName="scope">
  73. <span>{{ scope.row.violateName ? scope.row.violateName + '(' + scope.row.staffNo + ')' : '-' }}</span>
  74. </template>
  75. <template #deptName="scope">
  76. <span>{{ scope.row.deptName || '-' }}</span>
  77. </template>
  78. <template #violateType="scope">
  79. <span>{{ ACT_VIOLATION_TYPE_LABEL[scope.row.violateType] }}</span>
  80. </template>
  81. <template #speed="scope">
  82. <span>{{ scope.row.speed || '-' }}</span>
  83. </template>
  84. <template #capturePhotos="scope">
  85. <ImageViewer :file-list="scope.row.capturePhotos" />
  86. </template>
  87. <template #violateLocation="scope">
  88. <span>{{ scope.row.violateLocation || '-' }}</span>
  89. </template>
  90. <template #createSource="scope">
  91. <span>{{ ACT_NOTICE_DATA_SOURCE_LABEL[scope.row.createSource] }}</span>
  92. </template>
  93. <template #isNotice="scope">
  94. <div class="notice-state">
  95. <div
  96. :style="{
  97. backgroundColor: ACT_NOTICE_STATE_COLOR[scope.row.isNotice],
  98. width: '6px',
  99. height: '6px',
  100. borderRadius: '50%',
  101. marginRight: '5px',
  102. }"
  103. ></div>
  104. <span>{{ ACT_NOTICE_STATE_LABEL[scope.row.isNotice] }}</span>
  105. </div>
  106. </template>
  107. </BasicTable>
  108. </div>
  109. </main>
  110. </div>
  111. </template>
  112. <script setup lang="ts">
  113. import BasicTable from '@/components/BasicTable.vue';
  114. import useTableConfig from '@/hooks/useTableConfigHook';
  115. import SelectableInput from '@/components/formItems/selectableInput/SelectableInput.vue';
  116. import dayjs from 'dayjs';
  117. import { ElMessage } from 'element-plus';
  118. import {
  119. TABLE_OPTIONS,
  120. VIOLATION_NOTICE_TABLE_COLUMNS,
  121. VIOLATION_NOTICE_TABLE_COLUMNS_CHECKONLY,
  122. } from '../act/configs/tables';
  123. import {
  124. ACT_NOTICE_DATA_SOURCE_LABEL,
  125. ACT_VIOLATION_TYPE,
  126. ACT_VIOLATION_TYPE_LABEL,
  127. ACT_TABLE_SEARCH_OPTIONS,
  128. ACT_VIOLATION_TYPE_OPTIONS,
  129. ACT_NOTICE_STATE_OPTIONS,
  130. ACT_NOTICE_STATE,
  131. ACT_NOTICE_STATE_LABEL,
  132. ACT_NOTICE_STATE_COLOR,
  133. NOTICE_MANAGEMENT_PROMISSION_CODE,
  134. } from '../act/constants';
  135. import { ref, reactive, onMounted } from 'vue';
  136. import { useRouter } from 'vue-router';
  137. import type { QueryPageRequest } from '@/types/basic-query';
  138. import type { ActTableSearch, ActTableQuery, ActTableData } from '../act/types';
  139. import { getActTableList, exportActViolation } from '@/api/traffic-violation/traffic-act';
  140. import { downloadFile } from '@/views/disaster/utils/download';
  141. import ImageViewer from '../act/components/ImageViewer.vue';
  142. import { useUserInfoHook } from '@/hooks/useUserInfoHook';
  143. const { permissions } = useUserInfoHook();
  144. const noticeManagementPermission = ref<Boolean>(
  145. Boolean(permissions.find((item: { code: string }) => item.code === NOTICE_MANAGEMENT_PROMISSION_CODE)),
  146. );
  147. // 搜索栏
  148. const selectableInputRef = ref<InstanceType<typeof SelectableInput>>();
  149. const searchData = reactive<ActTableSearch>({});
  150. function getQuery() {
  151. if (!selectableInputRef.value) return;
  152. tableQuery.queryParam = {
  153. pageType: 2,
  154. };
  155. const selectableSearch = selectableInputRef.value.getValue();
  156. if (selectableSearch) {
  157. tableQuery.queryParam[selectableSearch.key as string] = selectableSearch.value;
  158. }
  159. if (searchData.isNotice != null) {
  160. tableQuery.queryParam.isNotice = searchData.isNotice;
  161. }
  162. if (searchData.violateType != null) {
  163. tableQuery.queryParam.violateType = searchData.violateType;
  164. }
  165. if (searchData.searchTime) {
  166. tableQuery.queryParam.startTime = dayjs(searchData.searchTime[0]).format('YYYY-MM-DD HH:MM:ss');
  167. tableQuery.queryParam.endTime = dayjs(searchData.searchTime[1]).format('YYYY-MM-DD HH:MM:ss');
  168. }
  169. }
  170. function handleSearch() {
  171. getQuery();
  172. getTableData();
  173. }
  174. function handleReset() {
  175. selectableInputRef.value?.clearValue();
  176. searchData.carNumber = undefined;
  177. searchData.violateName = undefined;
  178. searchData.deptName = undefined;
  179. searchData.isNotice = undefined;
  180. searchData.violateType = undefined;
  181. searchData.searchTime = undefined;
  182. }
  183. async function handleDownload() {
  184. getQuery();
  185. try {
  186. const res = await exportActViolation(tableQuery.queryParam);
  187. if (res.size === 0) return;
  188. const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
  189. const url = window.URL.createObjectURL(blob);
  190. downloadFile(url, '违规行为记录.xlsx');
  191. } catch (e) {
  192. ElMessage.error('下载失败');
  193. console.log(e);
  194. }
  195. }
  196. // 表格
  197. const basicTableRef = ref<InstanceType<typeof BasicTable>>();
  198. const { tableConfig, pagination } = useTableConfig(
  199. noticeManagementPermission.value ? VIOLATION_NOTICE_TABLE_COLUMNS : VIOLATION_NOTICE_TABLE_COLUMNS_CHECKONLY,
  200. TABLE_OPTIONS,
  201. );
  202. const tableData = ref<ActTableData[]>([]);
  203. const tableQuery = reactive<QueryPageRequest<ActTableQuery>>({
  204. pageNumber: pagination.pageNumber,
  205. pageSize: pagination.pageSize,
  206. queryParam: {
  207. pageType: 2,
  208. },
  209. });
  210. const handleSizeChange = (value: number) => {
  211. pagination.pageSize = value;
  212. tableQuery.pageSize = value;
  213. getTableData();
  214. };
  215. const handleCurrentChange = (value: number) => {
  216. pagination.pageNumber = value;
  217. tableQuery.pageNumber = value;
  218. getTableData();
  219. };
  220. async function getTableData() {
  221. tableConfig.loading = true;
  222. const res = await getActTableList(tableQuery);
  223. tableData.value = res.records;
  224. pagination.total = res.totalRow;
  225. tableConfig.loading = false;
  226. }
  227. onMounted(async () => {
  228. await getTableData();
  229. });
  230. </script>
  231. <style scoped lang="scss">
  232. @use '@/styles/page-details-layout.scss' as *;
  233. @use '@/styles/page-main-layout.scss' as *;
  234. @use '@/styles/basic-table-action.scss' as *;
  235. .act-search-input {
  236. max-width: 500px;
  237. }
  238. .act-search {
  239. display: flex;
  240. align-items: center;
  241. justify-content: space-between;
  242. width: 100%;
  243. }
  244. .select-box {
  245. display: flex;
  246. align-items: center;
  247. flex-wrap: wrap;
  248. gap: 32px;
  249. &--item {
  250. @include flex-center;
  251. white-space: nowrap;
  252. }
  253. span {
  254. color: rgba(0, 0, 0, 0.85);
  255. font-size: 14px;
  256. }
  257. .el-select {
  258. width: 200px;
  259. }
  260. }
  261. .search-btn {
  262. display: flex;
  263. }
  264. .notice-state {
  265. display: flex;
  266. align-items: center;
  267. justify-self: center;
  268. }
  269. </style>