gaoluyang
4 天以前 2075144baf459fe5ef89892d189784636f27f862
src/views/collaborativeApproval/vehicleManagement/index.vue
@@ -3,7 +3,7 @@
    <div class="search_form">
      <el-form :model="searchForm" :inline="true">
        <el-form-item label="车牌号:">
          <el-input v-model="searchForm.plateNumber" placeholder="请输入车牌号" clearable prefix-icon="Search"
          <el-input v-model="searchForm.carNo" placeholder="请输入车牌号" clearable prefix-icon="Search"
            @change="handleQuery" />
        </el-form-item>
        <el-form-item label="颜色:">
@@ -15,10 +15,10 @@
            @change="handleQuery" />
        </el-form-item>
        <el-form-item label="使用状态:">
          <el-select v-model="searchForm.status" placeholder="请选择" clearable @change="handleQuery" style="width: 200px">
            <el-option label="空闲" value="idle" />
            <el-option label="使用中" value="in_use" />
            <el-option label="维修中" value="maintenance" />
          <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>
@@ -33,7 +33,7 @@
          <el-button type="primary" @click="openForm('add')">
            新增车辆
          </el-button>
          <el-button @click="handleOut">导出</el-button>
<!--          <el-button @click="handleOut">导出</el-button>-->
          <el-button type="danger" plain @click="handleDelete">删除</el-button>
        </div>
      </div>
@@ -42,8 +42,10 @@
        :column="tableColumns"
        :is-selection="true"
        :border="true"
        :row-key="'id'"
        :expand-row-keys="expandRowKeys"
        :table-loading="tableLoading"
        :table-style="{ width: '100%', height: 'calc(100vh - 18.5em)' }"
        :table-style="{ width: '100%', height: 'calc(100vh - 21.5em)' }"
        :page="{
          current: page.current,
          size: page.size,
@@ -52,14 +54,37 @@
        }"
        @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.status === 'idle'"
            @click="openUseForm(row)">使用车辆</el-button>
          <el-button link type="primary" size="small" v-if="row.status === 'in_use'"
            @click="openReturnForm(row)">还车</el-button>
          <el-button link type="primary" size="small" @click="viewUsageRecords(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>
@@ -70,8 +95,8 @@
      <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="plateNumber">
              <el-input v-model="form.plateNumber" placeholder="请输入车牌号" clearable />
            <el-form-item label="车牌号:" prop="carNo">
              <el-input v-model="form.carNo" placeholder="请输入车牌号" clearable />
            </el-form-item>
          </el-col>
          <el-col :span="12">
@@ -87,11 +112,11 @@
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="使用状态:" prop="status">
              <el-select v-model="form.status" placeholder="请选择" clearable style="width: 100%">
                <el-option label="空闲" value="idle" />
                <el-option label="使用中" value="in_use" />
                <el-option label="维修中" value="maintenance" />
            <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>
@@ -99,7 +124,7 @@
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="表显里程(km):">
              <el-input-number v-model="form.odometer" :min="0" :precision="2" style="width: 100%"
              <el-input-number v-model="form.odometerMileage" :min="0" :precision="2" style="width: 100%"
                placeholder="请输入表显里程" clearable />
            </el-form-item>
          </el-col>
@@ -126,7 +151,7 @@
        <el-row :gutter="30">
          <el-col :span="24">
            <el-form-item label="车牌号:">
              <el-input :value="currentUseRow ? currentUseRow.plateNumber : ''" disabled />
              <el-input :value="currentUseRow ? currentUseRow.carNo : ''" disabled />
            </el-form-item>
          </el-col>
        </el-row>
@@ -138,25 +163,40 @@
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="表显里程(km):" prop="odometer">
              <el-input-number v-model="useForm.odometer" :min="0" :precision="2" style="width: 100%"
                placeholder="请输入表显里程" clearable />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="本次行驶里程(km):" prop="travelDistance">
              <el-input-number v-model="useForm.travelDistance" :min="0" :precision="2" style="width: 100%"
                placeholder="请输入本次行驶里程" clearable />
          <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="userId">
              <el-select v-model="useForm.userId" placeholder="请选择使用人" clearable filterable>
                <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
            <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>
@@ -182,30 +222,23 @@
        <el-row :gutter="30">
          <el-col :span="24">
            <el-form-item label="车牌号:">
              <el-input :value="currentReturnRow ? currentReturnRow.plateNumber : ''" disabled />
              <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="returnTime">
              <el-date-picker style="width: 100%" v-model="returnForm.returnTime" value-format="YYYY-MM-DD HH:mm:ss"
                format="YYYY-MM-DD HH:mm:ss" type="datetime" placeholder="请选择还车时间" clearable />
            <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="12">
            <el-form-item label="表显里程(km):" prop="odometer">
              <el-input-number v-model="returnForm.odometer" :min="0" :precision="2" style="width: 100%"
          <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-col :span="12">
            <el-form-item label="使用人:" prop="userId">
              <el-select v-model="returnForm.userId" placeholder="请选择使用人" clearable filterable>
                <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
@@ -232,7 +265,7 @@
        :column="usageRecordsColumns"
        :border="true"
        :table-loading="usageRecordsLoading"
        :table-style="{ width: '100%' }"
            :table-style="{ height: 'calc(100vh - 24em)', width: '100%' }"
        :page="{
          current: usageRecordsPage.current,
          size: usageRecordsPage.size,
@@ -270,33 +303,52 @@
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: {
    plateNumber: "",
    carNo: "",
    color: "",
    brand: "",
    status: "",
      usageStatus: "",
  },
  form: {
    plateNumber: "",
    carNo: "",
    color: "",
    brand: "",
    status: "idle",
    odometer: 0,
      usageStatus: "空闲",
    odometerMileage: 0,
    remark: "",
  },
  rules: {
    plateNumber: [{ required: true, message: "请输入车牌号", trigger: "blur" }],
    carNo: [{ required: true, message: "请输入车牌号", trigger: "blur" }],
    color: [{ required: true, message: "请输入颜色", trigger: "blur" }],
    brand: [{ required: true, message: "请输入品牌", trigger: "blur" }],
    status: [{ required: true, message: "请选择使用状态", trigger: "change" }],
      usageStatus: [{ required: true, message: "请选择使用状态", trigger: "change" }],
  },
});
const { form, rules } = toRefs(data);
@@ -307,18 +359,20 @@
const currentUseRow = ref(null);
const useVehicleFormData = reactive({
  useForm: {
    vehicleId: "",
    carInfoId: "",
    destination: "",
    odometer: 0,
    travelDistance: 0,
    userId: "",
    carRentalDate: dayjs().format("YYYY-MM-DD"),
    odometerMileage: 0,
    thisTripMileage: 0,
    userName: "",
    remark: "",
  },
  useRules: {
    destination: [{ required: true, message: "请输入目的地", trigger: "blur" }],
    odometer: [{ required: true, message: "请输入表显里程", trigger: "blur" }],
    travelDistance: [{ required: true, message: "请输入本次行驶里程", trigger: "blur" }],
    userId: [{ required: true, message: "请选择使用人", trigger: "change" }],
    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);
@@ -328,40 +382,20 @@
const currentReturnRow = ref(null);
const returnFormData = reactive({
  returnForm: {
    vehicleId: "",
    returnTime: "",
    odometer: 0,
    userId: "",
    carInfoId: "",
    carReturnDate: "",
    odometerMileage: 0,
    remark: "",
  },
  returnRules: {
    returnTime: [{ required: true, message: "请选择还车时间", trigger: "change" }],
    odometer: [{ required: true, message: "请输入表显里程", trigger: "blur" }],
    userId: [{ required: true, message: "请选择使用人", trigger: "change" }],
    carReturnDate: [{ required: true, message: "请选择还车时间", trigger: "change" }],
    odometerMileage: [{ required: true, message: "请输入表显里程", trigger: "blur" }],
  },
});
const { returnForm, returnRules } = toRefs(returnFormData);
// 使用记录
const usageRecordsVisible = ref(false);
const usageRecordsData = ref([]);
const usageRecordsLoading = ref(false);
const usageRecordsPage = reactive({
  current: 1,
  size: 100,
});
const usageRecordsTotal = ref(0);
const usageRecordsColumns = ref([
  { label: "车牌号", prop: "plateNumber", width: "120" },
  { label: "使用人", prop: "userName", width: "120" },
  { label: "目的地", prop: "destination", width: "150" },
  { label: "使用时间", prop: "useTime", width: "180" },
  { label: "还车时间", prop: "returnTime", width: "180" },
  { label: "使用前里程(km)", prop: "odometerBefore", width: "130" },
  { label: "还车时里程(km)", prop: "odometerAfter", width: "130" },
  { label: "本次行驶里程(km)", prop: "travelDistance", width: "140" },
]);
const currentVehicleId = ref(null);
const expandChildData = reactive({});
const expandChildLoading = reactive({});
// 用户信息表单弹框数据
const operationType = ref("");
@@ -370,29 +404,22 @@
// 表格列配置
const tableColumns = ref([
  { label: "车牌号", prop: "plateNumber", width: "120" },
  { label: "车牌号", prop: "carNo", width: "120" },
  { label: "颜色", prop: "color", width: "100" },
  { label: "品牌", prop: "brand", width: "120" },
  {
    label: "使用状态",
    prop: "status",
    width: "100",
    prop: "usageStatus",
    dataType: "tag",
    formatData: (val) => {
      if (val === "idle") return "空闲";
      if (val === "in_use") return "使用中";
      if (val === "maintenance") return "维修中";
      return val || "-";
    },
    formatType: (val) => {
      if (val === "idle") return "success";
      if (val === "in_use") return "warning";
      if (val === "maintenance") return "danger";
      if (val === "空闲") return "success";
      if (val === "使用中") return "warning";
      if (val === "维修中") return "danger";
      return "info";
    },
  },
  { label: "当前使用人", prop: "currentUser", width: "120" },
  { label: "表显里程(km)", prop: "odometer", width: "120" },
  { label: "当前使用人", prop: "currentUserName", },
  { label: "表显里程(km)", prop: "odometerMileage",},
  { label: "创建时间", prop: "createTime", width: "180" },
  {
    label: "操作",
@@ -400,13 +427,14 @@
    slot: "operation",
    align: "center",
    fixed: "right",
    width: "250",
    width: "180",
  },
]);
// 查询列表
const handleQuery = () => {
  page.current = 1;
  expandRowKeys.value = [];
  getList();
};
@@ -421,8 +449,8 @@
  listVehicle(page, searchForm)
    .then((res) => {
      tableLoading.value = false;
      tableData.value = res.records || res.data || [];
      total.value = res.total || 0;
      tableData.value = res.data.records;
      total.value = res.data.total || 0;
    })
    .catch(() => {
      tableLoading.value = false;
@@ -434,15 +462,35 @@
  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 = {
    plateNumber: "",
    carNo: "",
    color: "",
    brand: "",
    status: "idle",
    odometer: 0,
      usageStatus: "空闲",
    odometerMileage: 0,
    remark: "",
  };
@@ -451,9 +499,8 @@
  if (type !== "add") {
    currentId.value = row.id;
    getVehicleById(row.id).then((res) => {
      form.value = { ...(res.data || res) };
    });
    // 直接使用表格行数据,不再调用API
    form.value = { ...row };
  }
  dialogFormVisible.value = true;
};
@@ -484,17 +531,19 @@
const closeDia = () => {
  proxy.resetForm("formRef");
  dialogFormVisible.value = false;
  currentId.value = "";
};
// 打开使用车辆弹框
const openUseForm = async (row) => {
  currentUseRow.value = row;
  useForm.value = {
    vehicleId: row.id,
    carInfoId: row.id,
    destination: "",
    odometer: row.odometer || 0,
    travelDistance: 0,
    userId: "",
    carRentalDate: dayjs().format("YYYY-MM-DD"),
    odometerMileage: row.odometerMileage || 0,
    thisTripMileage: 0,
    userName: "",
    remark: "",
  };
@@ -519,19 +568,54 @@
// 关闭使用车辆弹框
const closeUseDia = () => {
  proxy.resetForm("useFormRef");
  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 = {
    vehicleId: row.id,
    returnTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
    odometer: row.odometer || 0,
    userId: "",
    carInfoId: row.id,
    carReturnDate: dayjs().format("YYYY-MM-DD"),
    odometerMileage: row.odometerMileage || 0,
    remark: "",
  };
@@ -545,7 +629,13 @@
const submitReturnForm = () => {
  proxy.$refs["returnFormRef"].validate((valid) => {
    if (valid) {
      returnVehicle(returnForm.value).then(() => {
      // 自动设置使用状态为空闲并添加车辆记录ID
      const formData = {
        ...returnForm.value,
        usageStatus: "空闲",
        id: currentReturnRow.value.carInfoRecordId
      };
      returnVehicle(formData).then(() => {
        proxy.$modal.msgSuccess("还车成功");
        closeReturnDia();
        getList();
@@ -559,42 +649,6 @@
  proxy.resetForm("returnFormRef");
  returnFormVisible.value = false;
  currentReturnRow.value = null;
};
// 查看使用记录
const viewUsageRecords = (row) => {
  currentVehicleId.value = row.id;
  usageRecordsPage.current = 1;
  getUsageRecords();
  usageRecordsVisible.value = true;
};
// 获取使用记录
const getUsageRecords = () => {
  usageRecordsLoading.value = true;
  getVehicleUsageRecords(usageRecordsPage, { vehicleId: currentVehicleId.value })
    .then((res) => {
      usageRecordsLoading.value = false;
      usageRecordsData.value = res.records || res.data || [];
      usageRecordsTotal.value = res.total || 0;
    })
    .catch(() => {
      usageRecordsLoading.value = false;
    });
};
// 使用记录分页
const usageRecordsPaginationChange = (obj) => {
  usageRecordsPage.current = obj.page;
  usageRecordsPage.size = obj.limit;
  getUsageRecords();
};
// 关闭使用记录弹框
const closeUsageRecords = () => {
  usageRecordsVisible.value = false;
  usageRecordsData.value = [];
  currentVehicleId.value = null;
};
// 导出