|
|
@@ -0,0 +1,380 @@
|
|
|
+<template>
|
|
|
+ <div class="safety-platform-container">
|
|
|
+ <div class="safety-platform-container__header">
|
|
|
+ <div class="breadcrumb-title">车辆信息管理</div>
|
|
|
+ </div>
|
|
|
+ <div class="safety-platform-container__main">
|
|
|
+ <div class="search-table-container">
|
|
|
+ <header class="disaster-precaution__header">
|
|
|
+ <el-button
|
|
|
+ v-if="vehicleManagePermission"
|
|
|
+ class="search-table-container--button"
|
|
|
+ type="primary"
|
|
|
+ :icon="Plus"
|
|
|
+ @click="handleAddVehicleInfo"
|
|
|
+ >
|
|
|
+ 添加车辆信息记录
|
|
|
+ </el-button>
|
|
|
+ <el-button
|
|
|
+ v-if="vehicleManagePermission"
|
|
|
+ class="search-table-container--button"
|
|
|
+ @click="batchImportVisible = true"
|
|
|
+ >
|
|
|
+ 批量导入
|
|
|
+ </el-button>
|
|
|
+ <div class="search-container">
|
|
|
+ <el-input
|
|
|
+ v-model="searchKeyword"
|
|
|
+ :placeholder="`请输入${curSearchTypeLabel}进行搜索`"
|
|
|
+ clearable
|
|
|
+ @input="handleSearch"
|
|
|
+ @clear="handleClear"
|
|
|
+ @keyup.enter="handleSearch"
|
|
|
+ style="width: 340px"
|
|
|
+ >
|
|
|
+ <template #prefix>
|
|
|
+ <el-icon color="#1777ff"><Search /></el-icon>
|
|
|
+ </template>
|
|
|
+ <template #prepend>
|
|
|
+ <el-select
|
|
|
+ v-model="searchSelectedType"
|
|
|
+ placeholder="选择搜索项"
|
|
|
+ @change="handleSelectedTypeChange"
|
|
|
+ style="width: 90px"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="item in vehicleQueryOptions"
|
|
|
+ :key="item.value"
|
|
|
+ :label="item.label"
|
|
|
+ :value="item.value"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </template>
|
|
|
+ </el-input>
|
|
|
+ <div class="search-container-btn">
|
|
|
+ <el-button type="primary" @click="handleSearch">查询</el-button>
|
|
|
+ <el-button @click="handleReset">重置</el-button>
|
|
|
+ <el-button @click="handleExport">导出</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </header>
|
|
|
+ <div class="batch-table">
|
|
|
+ <div class="batch-operation--div" v-show="vehicleManagePermission && selectionItems.length > 0">
|
|
|
+ <span>已选{{ selectionItems.length }}项</span>
|
|
|
+ <div class="batch-operation--div--close">
|
|
|
+ <div class="batch-operation--div--button">
|
|
|
+ <el-button class="custom-el-button" @click="handleBatchDelete">批量删除</el-button>
|
|
|
+ </div>
|
|
|
+ <el-icon class="close-icon" @click="handleCloseBatchOperation"><Close /></el-icon>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <BasicTable
|
|
|
+ ref="basicTableRef"
|
|
|
+ :tableData="tableData"
|
|
|
+ :tableConfig="tableConfig"
|
|
|
+ @update:page-number="handleCurrentPageChange"
|
|
|
+ @update:page-size="handlePageSizeChange"
|
|
|
+ @update:selection="handleSelectionChange"
|
|
|
+ >
|
|
|
+ <template #action="scope">
|
|
|
+ <div class="action-container--div">
|
|
|
+ <ActionButton text="编辑" @click="handleEditVehicleInfo(scope.row)" />
|
|
|
+ <ActionButton
|
|
|
+ text="删除"
|
|
|
+ :popconfirm="{
|
|
|
+ title: '是否删除该车辆信息?',
|
|
|
+ }"
|
|
|
+ @confirm="handleDeleteVehicleInfo(scope.row)"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </BasicTable>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <ManageDrawer v-if="drawerVisible" :type="drawerType" :initial-data="initialData" @close="handleCloseDrawer" />
|
|
|
+ <!-- <BatchImport
|
|
|
+ class="batch-import"
|
|
|
+ v-if="showBatchImportPopover"
|
|
|
+ @update="handleUpdateBatchImport"
|
|
|
+ @close="handleCloseBatchImport"
|
|
|
+ /> -->
|
|
|
+ <BatchImport
|
|
|
+ :visible="batchImportVisible"
|
|
|
+ :importApiUrl="importApiUrl"
|
|
|
+ :templateUrl="templateUrl"
|
|
|
+ :templateName="'车辆信息管理-批量导入模版'"
|
|
|
+ :successMessage="'车辆信息添加成功'"
|
|
|
+ @close="() => (batchImportVisible = false)"
|
|
|
+ @update="handleUpdate"
|
|
|
+ />
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+ import { computed, onMounted, ref } from 'vue';
|
|
|
+ import urlJoin from 'url-join';
|
|
|
+ import { ElMessage } from 'element-plus';
|
|
|
+ import { Plus, Search, Close } from '@element-plus/icons-vue';
|
|
|
+ import { openMessageBox } from '@/utils/element-plus/messageBox';
|
|
|
+ import BasicTable from '@/components/BasicTable.vue';
|
|
|
+ import ActionButton from '@/components/ActionButton.vue';
|
|
|
+ import ManageDrawer from './components/ManageDrawer.vue';
|
|
|
+ import { BatchImport } from '@/components/batch-import';
|
|
|
+ import { downloadByData } from '@/utils/file/download';
|
|
|
+ import { msgConfirm } from '@/utils/element-plus/messageBox';
|
|
|
+ import { getCurrentDateTimeString } from '@/utils/dateUtil';
|
|
|
+ import type { QueryPageRequest } from '@/types/basic-query';
|
|
|
+ import { useGlobSetting } from '@/hooks/setting';
|
|
|
+ import useTableConfig from '@/hooks/useTableConfigHook';
|
|
|
+ import { useUserInfoHook } from '@/hooks/useUserInfoHook';
|
|
|
+ import { TRAFFIC_PERMISSIONS } from '@/views/traffic/constant';
|
|
|
+ import {
|
|
|
+ VEHICLE_LIST_TABLE_MAX_HEIGHT_DEFAULT,
|
|
|
+ VEHICLE_LIST_TABLE_MAX_HEIGHT_PERMISSION,
|
|
|
+ VEHICLE_LIST_TABLE_OPTIONS,
|
|
|
+ VEHICLE_LIST_TABLE_COLUMNS,
|
|
|
+ } from './config';
|
|
|
+ import { FIELDTYPE, FIELD_CONTENT, vehicleQueryOptions } from './constant';
|
|
|
+ import {
|
|
|
+ VehicleListQuery,
|
|
|
+ VehicleInfoStruct,
|
|
|
+ getVehicleInfoList,
|
|
|
+ deleteVehicleInfo,
|
|
|
+ exportVehicleInfo,
|
|
|
+ } from '@/api/traffic-vehicle';
|
|
|
+
|
|
|
+ const { tableConfig, pagination } = useTableConfig(VEHICLE_LIST_TABLE_COLUMNS, VEHICLE_LIST_TABLE_OPTIONS);
|
|
|
+
|
|
|
+ const { permissions } = useUserInfoHook();
|
|
|
+ const vehicleManagePermission = ref<boolean>(false);
|
|
|
+
|
|
|
+ const searchSelectedType = ref(FIELDTYPE.VEHICLE_NUMBER);
|
|
|
+ const searchKeyword = ref('');
|
|
|
+ const curSearchTypeLabel = computed(() => {
|
|
|
+ const option = vehicleQueryOptions.find((item) => item.value === searchSelectedType.value);
|
|
|
+ return option ? option.label : FIELD_CONTENT[searchSelectedType.value];
|
|
|
+ });
|
|
|
+
|
|
|
+ const vehicleTableQuery: QueryPageRequest<VehicleListQuery> = {
|
|
|
+ pageNumber: pagination.pageNumber,
|
|
|
+ pageSize: pagination.pageSize,
|
|
|
+ queryParam: {},
|
|
|
+ };
|
|
|
+
|
|
|
+ const basicTableRef = ref<InstanceType<typeof BasicTable>>();
|
|
|
+ const tableData = ref<VehicleInfoStruct[]>([]);
|
|
|
+
|
|
|
+ const selectionItems = ref<any[]>([]);
|
|
|
+
|
|
|
+ // add or edit
|
|
|
+ const drawerVisible = ref(false);
|
|
|
+ const drawerType = ref('');
|
|
|
+ const initialData = ref<VehicleInfoStruct>({});
|
|
|
+
|
|
|
+ const handleSelectedTypeChange = () => {
|
|
|
+ searchKeyword.value = '';
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleSearch = () => {
|
|
|
+ if (!searchKeyword.value.trim()) {
|
|
|
+ handleClear();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ getTableData();
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleClear = () => {
|
|
|
+ searchKeyword.value = '';
|
|
|
+ vehicleTableQuery.pageNumber = 1;
|
|
|
+ vehicleTableQuery.pageSize = 20;
|
|
|
+ getTableData();
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleReset = () => {
|
|
|
+ searchSelectedType.value = FIELDTYPE.VEHICLE_NUMBER;
|
|
|
+ searchKeyword.value = '';
|
|
|
+ vehicleTableQuery.pageNumber = 1;
|
|
|
+ vehicleTableQuery.pageSize = 20;
|
|
|
+ getTableData();
|
|
|
+ };
|
|
|
+
|
|
|
+ // 导出
|
|
|
+ const handleExport = () => {
|
|
|
+ msgConfirm('确定导出所查询数据?', '导出', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ showCancelButton: true,
|
|
|
+ type: 'warning',
|
|
|
+ })
|
|
|
+ .then(() => {
|
|
|
+ exportVehicleInfo(vehicleTableQuery.queryParam).then(async (responnse) => {
|
|
|
+ if (!responnse) {
|
|
|
+ throw new Error('下载文件失败');
|
|
|
+ }
|
|
|
+ downloadByData(responnse, `车辆信息记录_${getCurrentDateTimeString()}.xlsx`);
|
|
|
+ ElMessage.success('下载文件成功');
|
|
|
+ });
|
|
|
+ })
|
|
|
+ .catch(() => {
|
|
|
+ ElMessage({
|
|
|
+ type: 'info',
|
|
|
+ message: '取消导出',
|
|
|
+ });
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleCurrentPageChange = (pageNumber: number) => {
|
|
|
+ pagination.pageNumber = pageNumber;
|
|
|
+ vehicleTableQuery.pageNumber = pageNumber;
|
|
|
+ getTableData();
|
|
|
+ };
|
|
|
+
|
|
|
+ const handlePageSizeChange = (pageSize: number) => {
|
|
|
+ pagination.pageSize = pageSize;
|
|
|
+ vehicleTableQuery.pageSize = pageSize;
|
|
|
+ getTableData();
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleAddVehicleInfo = () => {
|
|
|
+ drawerVisible.value = true;
|
|
|
+ drawerType.value = 'add';
|
|
|
+ initialData.value = {};
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleEditVehicleInfo = (row: VehicleInfoStruct) => {
|
|
|
+ drawerVisible.value = true;
|
|
|
+ drawerType.value = 'edit';
|
|
|
+ initialData.value = row;
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleCloseDrawer = () => {
|
|
|
+ drawerVisible.value = false;
|
|
|
+ vehicleTableQuery.pageNumber = 1;
|
|
|
+ vehicleTableQuery.pageSize = 20;
|
|
|
+ getTableData();
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleDeleteVehicleInfo = (row: VehicleInfoStruct) => {
|
|
|
+ if (!row.id) return;
|
|
|
+ deleteVehicleInfo({ vehicleInfoIds: [row.id] }).then(() => {
|
|
|
+ ElMessage.success('删除成功');
|
|
|
+ vehicleTableQuery.pageNumber = 1;
|
|
|
+ vehicleTableQuery.pageSize = 20;
|
|
|
+ getTableData();
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ // 批量删除
|
|
|
+ const handleSelectionChange = (selection: any[]) => {
|
|
|
+ selectionItems.value = selection;
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleCloseBatchOperation = () => {
|
|
|
+ if (!basicTableRef.value) return;
|
|
|
+ basicTableRef.value.clearSelection();
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleBatchDelete = async () => {
|
|
|
+ const confirmed = await openMessageBox('', '删除后信息不可恢复,确认删除吗?', 'warning');
|
|
|
+ if (!confirmed) return;
|
|
|
+ const deleteIds = selectionItems.value.map((item) => item.id);
|
|
|
+ if (!deleteIds.length) return;
|
|
|
+ deleteVehicleInfo({ vehicleInfoIds: deleteIds }).then(() => {
|
|
|
+ ElMessage.success('批量删除成功');
|
|
|
+ vehicleTableQuery.pageNumber = 1;
|
|
|
+ vehicleTableQuery.pageSize = 20;
|
|
|
+ getTableData();
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ // 批量导入
|
|
|
+ const batchImportVisible = ref(false);
|
|
|
+ const { urlPrefix } = useGlobSetting();
|
|
|
+ const importApiUrl = ref(urlJoin(urlPrefix, '/vehicleInfo/importVehicleInfo'));
|
|
|
+ const templateUrl = ref('./skyeye-file-upload/sfysecurity/TEMPLATE/import-vehicle-template.xlsx');
|
|
|
+
|
|
|
+ const handleUpdate = () => {
|
|
|
+ batchImportVisible.value = false;
|
|
|
+ vehicleTableQuery.pageNumber = 1;
|
|
|
+ vehicleTableQuery.pageSize = 20;
|
|
|
+ getTableData();
|
|
|
+ };
|
|
|
+
|
|
|
+ const getTableData = () => {
|
|
|
+ tableConfig.loading = true;
|
|
|
+ vehicleTableQuery.queryParam = {
|
|
|
+ fieldType: searchSelectedType.value,
|
|
|
+ fieldContent: searchKeyword.value,
|
|
|
+ };
|
|
|
+ getVehicleInfoList(vehicleTableQuery).then((res) => {
|
|
|
+ tableData.value = res?.records || [];
|
|
|
+ pagination.total = res?.totalRow || 0;
|
|
|
+ });
|
|
|
+ tableConfig.loading = false;
|
|
|
+ };
|
|
|
+
|
|
|
+ // 动态生成表格列配置
|
|
|
+ const getTableColumns = () => {
|
|
|
+ if (vehicleManagePermission.value) {
|
|
|
+ return VEHICLE_LIST_TABLE_COLUMNS;
|
|
|
+ } else {
|
|
|
+ // 过滤掉操作列
|
|
|
+ return VEHICLE_LIST_TABLE_COLUMNS.filter((column) => column.prop !== 'action');
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ onMounted(() => {
|
|
|
+ getTableData();
|
|
|
+ vehicleManagePermission.value = Boolean(
|
|
|
+ permissions.find((item: { code: string }) => item.code === TRAFFIC_PERMISSIONS.VEHICLE_MANAGE),
|
|
|
+ );
|
|
|
+ tableConfig.maxHeight = vehicleManagePermission.value
|
|
|
+ ? VEHICLE_LIST_TABLE_MAX_HEIGHT_PERMISSION
|
|
|
+ : VEHICLE_LIST_TABLE_MAX_HEIGHT_DEFAULT;
|
|
|
+ tableConfig.columns = getTableColumns();
|
|
|
+ });
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="scss">
|
|
|
+ @use '@/styles/page-main-layout.scss' as *;
|
|
|
+ @use '@/styles/page-details-layout.scss' as *;
|
|
|
+ @use '@/styles/basic-table-action.scss' as *;
|
|
|
+
|
|
|
+ .search-container {
|
|
|
+ display: flex;
|
|
|
+
|
|
|
+ .search-container-btn {
|
|
|
+ margin-left: auto;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .batch-table {
|
|
|
+ position: relative;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+ .batch-operation--div {
|
|
|
+ @include flex-center;
|
|
|
+ justify-content: flex-start;
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ gap: 60px;
|
|
|
+ width: 100%;
|
|
|
+ height: 48px;
|
|
|
+ border: 4px;
|
|
|
+ padding: 16px 25px;
|
|
|
+ background-color: #ddefff;
|
|
|
+ z-index: 100;
|
|
|
+ &--close {
|
|
|
+ @include flex-center;
|
|
|
+ justify-content: space-between;
|
|
|
+ flex: 1;
|
|
|
+ }
|
|
|
+ .close-icon {
|
|
|
+ font-size: 20px;
|
|
|
+ color: #ff4d4f;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+ }
|
|
|
+</style>
|