<template>
|
<div class="app-container">
|
<div class="search_form">
|
<el-form :model="searchForm" :inline="true">
|
<el-form-item label="车牌号:">
|
<el-input v-model="searchForm.carNo" placeholder="请输入车牌号" clearable prefix-icon="Search"
|
@change="handleQuery" />
|
</el-form-item>
|
<el-form-item label="颜色:">
|
<el-input v-model="searchForm.color" placeholder="请输入颜色" clearable prefix-icon="Search"
|
@change="handleQuery" />
|
</el-form-item>
|
<el-form-item label="品牌:">
|
<el-input v-model="searchForm.brand" placeholder="请输入品牌" clearable prefix-icon="Search"
|
@change="handleQuery" />
|
</el-form-item>
|
<el-form-item label="使用状态:">
|
<el-select v-model="searchForm.usageStatus" placeholder="请选择" clearable @change="handleQuery" style="width: 200px">
|
<el-option label="空闲" value="空闲" />
|
<el-option label="使用中" value="使用中" />
|
<el-option label="维修中" value="维修中" />
|
</el-select>
|
</el-form-item>
|
<el-form-item>
|
<el-button type="primary" @click="handleQuery">搜索</el-button>
|
</el-form-item>
|
</el-form>
|
</div>
|
<div class="table_list">
|
<div class="actions">
|
<div></div>
|
<div>
|
<el-button type="primary" @click="openForm('add')">
|
新增车辆
|
</el-button>
|
<!-- <el-button @click="handleOut">导出</el-button>-->
|
<el-button type="danger" plain @click="handleDelete">删除</el-button>
|
</div>
|
</div>
|
<PIMTable
|
:table-data="tableData"
|
:column="tableColumns"
|
:is-selection="true"
|
:border="true"
|
:row-key="'id'"
|
:expand-row-keys="expandRowKeys"
|
:table-loading="tableLoading"
|
:table-style="{ width: '100%', height: 'calc(100vh - 21.5em)' }"
|
:page="{
|
current: page.current,
|
size: page.size,
|
total: total,
|
layout: 'total, sizes, prev, pager, next, jumper'
|
}"
|
@selection-change="handleSelectionChange"
|
@pagination="paginationChange"
|
@expand-change="handleExpandChange"
|
>
|
<template #expand="{ row }">
|
<div class="expand-wrapper">
|
<el-skeleton v-if="expandChildLoading[row.id]" animated :rows="3" />
|
<template v-else>
|
<el-empty v-if="!(expandChildData[row.id] && expandChildData[row.id].length)" description="暂无使用记录" />
|
<el-table
|
v-else
|
:data="expandChildData[row.id]"
|
size="small"
|
border
|
style="width: 100%"
|
:header-cell-style="{ background: '#F7F8FA' }"
|
>
|
<el-table-column prop="userName" label="使用人" width="140" />
|
<el-table-column prop="desc" label="目的地" width="180" />
|
<el-table-column prop="useTime" label="使用时间" width="180" />
|
<el-table-column prop="carReturnDate" label="还车时间" width="180" />
|
<el-table-column prop="odometerBefore" label="使用前里程(km)" width="140" />
|
<el-table-column prop="odometerAfter" label="还车时里程(km)" width="140" />
|
<el-table-column prop="thisTripMileage" label="本次行驶里程(km)" width="160" />
|
</el-table>
|
</template>
|
</div>
|
</template>
|
<template #operation="{ row }">
|
<el-button link type="primary" size="small" @click="openForm('edit', row)">编辑</el-button>
|
<el-button link type="primary" size="small" v-if="row.usageStatus === '空闲'"
|
@click="openUseForm(row)">用车</el-button>
|
<el-button link type="primary" size="small" v-if="row.usageStatus === '使用中'"
|
@click="openReturnForm(row)">还车</el-button>
|
<el-button link type="primary" size="small" @click="openUsageRecordsDialog(row)">使用记录</el-button>
|
</template>
|
</PIMTable>
|
</div>
|
|
<!-- 新增/编辑车辆弹窗 -->
|
<el-dialog v-model="dialogFormVisible" :title="operationType === 'add' ? '新增车辆' : '编辑车辆'" width="50%"
|
@close="closeDia">
|
<el-form :model="form" label-width="120px" label-position="top" :rules="rules" ref="formRef">
|
<el-row :gutter="30">
|
<el-col :span="12">
|
<el-form-item label="车牌号:" prop="carNo">
|
<el-input v-model="form.carNo" placeholder="请输入车牌号" clearable />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="颜色:" prop="color">
|
<el-input v-model="form.color" placeholder="请输入颜色" clearable />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="12">
|
<el-form-item label="品牌:" prop="brand">
|
<el-input v-model="form.brand" placeholder="请输入品牌" clearable />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="使用状态:" prop="usageStatus">
|
<el-select v-model="form.usageStatus" placeholder="请选择" clearable style="width: 100%">
|
<el-option label="空闲" value="空闲" />
|
<el-option label="使用中" value="使用中" />
|
<el-option label="维修中" value="维修中" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="12">
|
<el-form-item label="表显里程(km):">
|
<el-input-number v-model="form.odometerMileage" :min="0" :precision="2" style="width: 100%"
|
placeholder="请输入表显里程" clearable />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item label="备注:">
|
<el-input v-model="form.remark" placeholder="请输入备注" clearable type="textarea" :rows="3" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
</el-form>
|
<template #footer>
|
<div class="dialog-footer">
|
<el-button type="primary" @click="submitForm">确认</el-button>
|
<el-button @click="closeDia">取消</el-button>
|
</div>
|
</template>
|
</el-dialog>
|
|
<!-- 使用车辆弹窗 -->
|
<el-dialog v-model="useFormVisible" title="使用车辆" width="50%" @close="closeUseDia">
|
<el-form :model="useForm" label-width="140px" label-position="top" :rules="useRules" ref="useFormRef">
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item label="车牌号:">
|
<el-input :value="currentUseRow ? currentUseRow.carNo : ''" disabled />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item label="目的地:" prop="destination">
|
<el-input v-model="useForm.destination" placeholder="请输入目的地" clearable />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item label="借用时间:" prop="carRentalDate">
|
<el-date-picker
|
style="width: 100%"
|
v-model="useForm.carRentalDate"
|
type="date"
|
value-format="YYYY-MM-DD"
|
format="YYYY-MM-DD"
|
placeholder="请选择借用时间"
|
clearable
|
/>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item label="使用人:" prop="userName">
|
<el-select v-model="useForm.userName" placeholder="请选择使用人" clearable filterable>
|
<el-option v-for="item in userList" :key="item.nickName" :label="item.nickName" :value="item.nickName" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="12">
|
<el-form-item label="表显里程(km):" prop="odometerMileage">
|
<el-input-number v-model="useForm.odometerMileage" :min="0" :precision="2" style="width: 100%"
|
placeholder="请输入表显里程" clearable />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="本次预计行驶里程(km):" prop="thisTripMileage">
|
<el-input-number v-model="useForm.thisTripMileage" :min="0" :precision="2" style="width: 100%"
|
placeholder="请输入本次预计行驶里程" clearable />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item label="备注:">
|
<el-input v-model="useForm.remark" placeholder="请输入备注" clearable type="textarea" :rows="3" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
</el-form>
|
<template #footer>
|
<div class="dialog-footer">
|
<el-button type="primary" @click="submitUseForm">确认</el-button>
|
<el-button @click="closeUseDia">取消</el-button>
|
</div>
|
</template>
|
</el-dialog>
|
|
<!-- 还车弹窗 -->
|
<el-dialog v-model="returnFormVisible" title="还车" width="50%" @close="closeReturnDia">
|
<el-form :model="returnForm" label-width="140px" label-position="top" :rules="returnRules" ref="returnFormRef">
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item label="车牌号:">
|
<el-input :value="currentReturnRow ? currentReturnRow.carNo : ''" disabled />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item label="还车时间:" prop="carReturnDate">
|
<el-date-picker style="width: 100%" v-model="returnForm.carReturnDate" value-format="YYYY-MM-DD"
|
format="YYYY-MM-DD" type="date" placeholder="请选择还车时间" clearable />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item label="表显里程(km):" prop="odometerMileage">
|
<el-input-number v-model="returnForm.odometerMileage" :min="0" :precision="2" style="width: 100%"
|
placeholder="请输入表显里程" clearable />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item label="备注:">
|
<el-input v-model="returnForm.remark" placeholder="请输入备注" clearable type="textarea" :rows="3" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
</el-form>
|
<template #footer>
|
<div class="dialog-footer">
|
<el-button type="primary" @click="submitReturnForm">确认</el-button>
|
<el-button @click="closeReturnDia">取消</el-button>
|
</div>
|
</template>
|
</el-dialog>
|
|
<!-- 使用记录弹窗 -->
|
<el-dialog v-model="usageRecordsVisible" title="使用记录" width="70%" @close="closeUsageRecords">
|
<PIMTable
|
:table-data="usageRecordsData"
|
:column="usageRecordsColumns"
|
:border="true"
|
:table-loading="usageRecordsLoading"
|
:table-style="{ height: 'calc(100vh - 24em)', width: '100%' }"
|
:page="{
|
current: usageRecordsPage.current,
|
size: usageRecordsPage.size,
|
total: usageRecordsTotal,
|
layout: 'total, sizes, prev, pager, next, jumper'
|
}"
|
@pagination="usageRecordsPaginationChange"
|
/>
|
</el-dialog>
|
</div>
|
</template>
|
|
<script setup>
|
import { onMounted, ref, reactive, toRefs, getCurrentInstance } from "vue";
|
import PIMTable from "@/components/PIMTable/PIMTable.vue";
|
import { ElMessageBox } from "element-plus";
|
import useUserStore from "@/store/modules/user";
|
import { userListNoPage } from "@/api/system/user.js";
|
import {
|
listVehicle,
|
addVehicle,
|
updateVehicle,
|
delVehicle,
|
getVehicleById,
|
useVehicle,
|
returnVehicle,
|
getVehicleUsageRecords,
|
} from "@/api/collaborativeApproval/vehicleManagement.js";
|
import useFormData from "@/hooks/useFormData.js";
|
import dayjs from "dayjs";
|
|
const userStore = useUserStore();
|
const { proxy } = getCurrentInstance();
|
const tableData = ref([]);
|
const selectedRows = ref([]);
|
const userList = ref([]);
|
const tableLoading = ref(false);
|
const expandRowKeys = ref([]);
|
const page = reactive({
|
current: 1,
|
size: 100,
|
});
|
const total = ref(0);
|
|
// 使用记录弹窗
|
const usageRecordsVisible = ref(false);
|
const usageRecordsData = ref([]);
|
const usageRecordsLoading = ref(false);
|
const usageRecordsPage = reactive({
|
current: 1,
|
size: 10,
|
});
|
const usageRecordsTotal = ref(0);
|
const usageRecordsColumns = ref([
|
{ label: "使用人", prop: "userName", width: "120" },
|
{ label: "目的地", prop: "destination", width: "150" },
|
{ label: "借用时间", prop: "carRentalDate", },
|
{ label: "还车时间", prop: "carReturnDate",},
|
{ label: "使用前里程(km)", prop: "odometerMileage", },
|
{ label: "本次行驶里程(km)", prop: "thisTripMileage",},
|
]);
|
|
// 搜索表单
|
const data = reactive({
|
searchForm: {
|
carNo: "",
|
color: "",
|
brand: "",
|
usageStatus: "",
|
},
|
form: {
|
carNo: "",
|
color: "",
|
brand: "",
|
usageStatus: "空闲",
|
odometerMileage: 0,
|
remark: "",
|
},
|
rules: {
|
carNo: [{ required: true, message: "请输入车牌号", trigger: "blur" }],
|
color: [{ required: true, message: "请输入颜色", trigger: "blur" }],
|
brand: [{ required: true, message: "请输入品牌", trigger: "blur" }],
|
usageStatus: [{ required: true, message: "请选择使用状态", trigger: "change" }],
|
},
|
});
|
const { form, rules } = toRefs(data);
|
const { form: searchForm } = useFormData(data.searchForm);
|
|
// 使用车辆表单
|
const useFormVisible = ref(false);
|
const currentUseRow = ref(null);
|
const useVehicleFormData = reactive({
|
useForm: {
|
carInfoId: "",
|
destination: "",
|
carRentalDate: dayjs().format("YYYY-MM-DD"),
|
odometerMileage: 0,
|
thisTripMileage: 0,
|
userName: "",
|
remark: "",
|
},
|
useRules: {
|
destination: [{ required: true, message: "请输入目的地", trigger: "blur" }],
|
carRentalDate: [{ required: true, message: "请选择借用时间", trigger: "change" }],
|
odometerMileage: [{ required: true, message: "请输入表显里程", trigger: "blur" }],
|
thisTripMileage: [{ required: true, message: "请输入本次行驶里程", trigger: "blur" }],
|
userName: [{ required: true, message: "请选择使用人", trigger: "change" }],
|
},
|
});
|
const { useForm, useRules } = toRefs(useVehicleFormData);
|
|
// 还车表单
|
const returnFormVisible = ref(false);
|
const currentReturnRow = ref(null);
|
const returnFormData = reactive({
|
returnForm: {
|
carInfoId: "",
|
carReturnDate: "",
|
odometerMileage: 0,
|
remark: "",
|
},
|
returnRules: {
|
carReturnDate: [{ required: true, message: "请选择还车时间", trigger: "change" }],
|
odometerMileage: [{ required: true, message: "请输入表显里程", trigger: "blur" }],
|
},
|
});
|
const { returnForm, returnRules } = toRefs(returnFormData);
|
|
const expandChildData = reactive({});
|
const expandChildLoading = reactive({});
|
|
// 用户信息表单弹框数据
|
const operationType = ref("");
|
const dialogFormVisible = ref(false);
|
const currentId = ref("");
|
|
// 表格列配置
|
const tableColumns = ref([
|
{ label: "车牌号", prop: "carNo", width: "120" },
|
{ label: "颜色", prop: "color", width: "100" },
|
{ label: "品牌", prop: "brand", width: "120" },
|
{
|
label: "使用状态",
|
prop: "usageStatus",
|
dataType: "tag",
|
formatType: (val) => {
|
if (val === "空闲") return "success";
|
if (val === "使用中") return "warning";
|
if (val === "维修中") return "danger";
|
return "info";
|
},
|
},
|
{ label: "当前使用人", prop: "currentUserName", },
|
{ label: "表显里程(km)", prop: "odometerMileage",},
|
{ label: "创建时间", prop: "createTime", width: "180" },
|
{
|
label: "操作",
|
dataType: "slot",
|
slot: "operation",
|
align: "center",
|
fixed: "right",
|
width: "180",
|
},
|
]);
|
|
// 查询列表
|
const handleQuery = () => {
|
page.current = 1;
|
expandRowKeys.value = [];
|
getList();
|
};
|
|
const paginationChange = (obj) => {
|
page.current = obj.page;
|
page.size = obj.limit;
|
getList();
|
};
|
|
const getList = () => {
|
tableLoading.value = true;
|
listVehicle(page, searchForm)
|
.then((res) => {
|
tableLoading.value = false;
|
tableData.value = res.data.records;
|
total.value = res.data.total || 0;
|
})
|
.catch(() => {
|
tableLoading.value = false;
|
});
|
};
|
|
// 表格选择数据
|
const handleSelectionChange = (selection) => {
|
selectedRows.value = selection;
|
};
|
|
// 展开子表数据
|
const handleExpandChange = (row, expandedRows) => {
|
expandRowKeys.value = expandedRows.map((item) => item.id);
|
if (expandRowKeys.value.includes(row.id)) {
|
loadChildRecords(row.id);
|
}
|
};
|
|
const loadChildRecords = (carInfoId) => {
|
if (expandChildLoading[carInfoId]) return;
|
expandChildLoading[carInfoId] = true;
|
getVehicleUsageRecords({ current: 1, size: 20 }, { carInfoId })
|
.then((res) => {
|
expandChildData[carInfoId] = res.records || res.data || [];
|
})
|
.finally(() => {
|
expandChildLoading[carInfoId] = false;
|
});
|
};
|
|
// 打开弹框
|
const openForm = async (type, row) => {
|
operationType.value = type;
|
form.value = {
|
carNo: "",
|
color: "",
|
brand: "",
|
usageStatus: "空闲",
|
odometerMileage: 0,
|
remark: "",
|
};
|
|
const userLists = await userListNoPage();
|
userList.value = userLists.data || [];
|
|
if (type !== "add") {
|
currentId.value = row.id;
|
// 直接使用表格行数据,不再调用API
|
form.value = { ...row };
|
}
|
dialogFormVisible.value = true;
|
};
|
|
// 提交表单
|
const submitForm = () => {
|
proxy.$refs["formRef"].validate((valid) => {
|
if (valid) {
|
if (operationType.value === "add") {
|
addVehicle(form.value).then(() => {
|
proxy.$modal.msgSuccess("新增成功");
|
closeDia();
|
getList();
|
});
|
} else {
|
form.value.id = currentId.value;
|
updateVehicle(form.value).then(() => {
|
proxy.$modal.msgSuccess("修改成功");
|
closeDia();
|
getList();
|
});
|
}
|
}
|
});
|
};
|
|
// 关闭弹框
|
const closeDia = () => {
|
proxy.resetForm("formRef");
|
dialogFormVisible.value = false;
|
currentId.value = "";
|
};
|
|
// 打开使用车辆弹框
|
const openUseForm = async (row) => {
|
currentUseRow.value = row;
|
useForm.value = {
|
carInfoId: row.id,
|
destination: "",
|
carRentalDate: dayjs().format("YYYY-MM-DD"),
|
odometerMileage: row.odometerMileage || 0,
|
thisTripMileage: 0,
|
userName: "",
|
remark: "",
|
};
|
|
const userLists = await userListNoPage();
|
userList.value = userLists.data || [];
|
|
useFormVisible.value = true;
|
};
|
|
// 提交使用车辆表单
|
const submitUseForm = () => {
|
proxy.$refs["useFormRef"].validate((valid) => {
|
if (valid) {
|
useVehicle(useForm.value).then(() => {
|
proxy.$modal.msgSuccess("使用车辆成功");
|
closeUseDia();
|
getList();
|
});
|
}
|
});
|
};
|
|
// 关闭使用车辆弹框
|
const closeUseDia = () => {
|
try {
|
proxy.resetForm("useFormRef");
|
} catch (error) {
|
console.error("Error resetting form:", error);
|
}
|
useFormVisible.value = false;
|
currentUseRow.value = null;
|
};
|
|
// 打开使用记录弹窗
|
const openUsageRecordsDialog = async (row) => {
|
usageRecordsVisible.value = true;
|
usageRecordsPage.current = 1;
|
loadUsageRecords(row.id);
|
};
|
|
// 加载使用记录
|
const loadUsageRecords = (carInfoId) => {
|
usageRecordsLoading.value = true;
|
getVehicleUsageRecords(usageRecordsPage, { carInfoId: carInfoId })
|
.then((res) => {
|
usageRecordsData.value = res.data.records;
|
usageRecordsTotal.value = res.data.total || 0;
|
})
|
.finally(() => {
|
usageRecordsLoading.value = false;
|
});
|
};
|
|
// 使用记录分页
|
const usageRecordsPaginationChange = (obj) => {
|
usageRecordsPage.current = obj.page;
|
usageRecordsPage.size = obj.limit;
|
loadUsageRecords(currentUseRow.value.id);
|
};
|
|
// 关闭使用记录弹窗
|
const closeUsageRecords = () => {
|
usageRecordsVisible.value = false;
|
};
|
|
// 打开还车弹框
|
const openReturnForm = async (row) => {
|
currentReturnRow.value = row;
|
returnForm.value = {
|
carInfoId: row.id,
|
carReturnDate: dayjs().format("YYYY-MM-DD"),
|
odometerMileage: row.odometerMileage || 0,
|
remark: "",
|
};
|
|
const userLists = await userListNoPage();
|
userList.value = userLists.data || [];
|
|
returnFormVisible.value = true;
|
};
|
|
// 提交还车表单
|
const submitReturnForm = () => {
|
proxy.$refs["returnFormRef"].validate((valid) => {
|
if (valid) {
|
// 自动设置使用状态为空闲并添加车辆记录ID
|
const formData = {
|
...returnForm.value,
|
usageStatus: "空闲",
|
id: currentReturnRow.value.carInfoRecordId
|
};
|
returnVehicle(formData).then(() => {
|
proxy.$modal.msgSuccess("还车成功");
|
closeReturnDia();
|
getList();
|
});
|
}
|
});
|
};
|
|
// 关闭还车弹框
|
const closeReturnDia = () => {
|
proxy.resetForm("returnFormRef");
|
returnFormVisible.value = false;
|
currentReturnRow.value = null;
|
};
|
|
// 导出
|
const handleOut = () => {
|
ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
|
confirmButtonText: "确认",
|
cancelButtonText: "取消",
|
type: "warning",
|
})
|
.then(() => {
|
proxy.download("/vehicleManagement/export", {}, "车辆管理.xlsx");
|
})
|
.catch(() => {
|
proxy.$modal.msg("已取消");
|
});
|
};
|
|
// 删除
|
const handleDelete = () => {
|
let ids = [];
|
if (selectedRows.value.length > 0) {
|
ids = selectedRows.value.map((item) => item.id);
|
} else {
|
proxy.$modal.msgWarning("请选择数据");
|
return;
|
}
|
ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "删除", {
|
confirmButtonText: "确认",
|
cancelButtonText: "取消",
|
type: "warning",
|
})
|
.then(() => {
|
delVehicle(ids).then(() => {
|
proxy.$modal.msgSuccess("删除成功");
|
getList();
|
});
|
})
|
.catch(() => {
|
proxy.$modal.msg("已取消");
|
});
|
};
|
|
onMounted(() => {
|
getList();
|
});
|
</script>
|
|
<style scoped lang="scss">
|
.ml-10 {
|
margin-left: 10px;
|
}
|
|
.table_list {
|
margin-top: unset;
|
}
|
|
.actions {
|
display: flex;
|
justify-content: space-between;
|
margin-bottom: 10px;
|
}
|
</style>
|