vehicle.vue 4.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. <template>
  2. <div>
  3. <el-form inline>
  4. <el-form-item label="停车场">
  5. <el-select v-model="lotID" clearable placeholder="全部" style="width:180px" @change="fetchData">
  6. <el-option v-for="lot in lotList" :key="lot.ID" :label="lot.lot_name" :value="lot.ID" />
  7. </el-select>
  8. </el-form-item>
  9. <el-form-item :label="$t.value.LicensePlateNo">
  10. <el-input v-model="plateNumber" :placeholder="$t.value.carPlateInput" clearable style="width:160px" @keyup.enter="fetchData" />
  11. </el-form-item>
  12. <el-form-item>
  13. <el-button type="primary" icon="Search" @click="fetchData">{{ $t.value.Search }}</el-button>
  14. <el-button icon="Refresh" @click="fetchData">{{ $t.value.reload }}</el-button>
  15. </el-form-item>
  16. <el-form-item>
  17. <el-text type="success">空闲车位:{{ available }}</el-text>
  18. </el-form-item>
  19. <el-form-item>
  20. <el-text type="warning">在场车辆:{{ list.length }} 台</el-text>
  21. </el-form-item>
  22. </el-form>
  23. <el-row :gutter="12">
  24. <el-col :span="17">
  25. <div class="car-grid">
  26. <div v-for="(v, i) in list" :key="v.record_id" class="car-item" :class="{ active: selected === i }" @click="select(i)">
  27. <span class="car-plate">{{ v.plate_number }}</span>
  28. <span class="car-time">{{ formatStay(v.stay_minutes) }}</span>
  29. </div>
  30. <el-empty v-if="list.length === 0" description="暂无在场车辆" style="width:100%" />
  31. </div>
  32. </el-col>
  33. <el-col :span="7">
  34. <div class="info-box" v-if="selected !== null">
  35. <h4>车辆详情</h4>
  36. <el-descriptions :column="1" border size="small">
  37. <el-descriptions-item label="车牌">{{ cur.plate_number }}</el-descriptions-item>
  38. <el-descriptions-item label="车辆类型">{{ cur.vehicle_type || '-' }}</el-descriptions-item>
  39. <el-descriptions-item label="车主">{{ cur.owner_name || '-' }}</el-descriptions-item>
  40. <el-descriptions-item label="手机">{{ cur.owner_phone || '-' }}</el-descriptions-item>
  41. <el-descriptions-item label="入场时间">{{ cur.entry_time }}</el-descriptions-item>
  42. <el-descriptions-item label="停留时长">{{ formatStay(cur.stay_minutes) }}</el-descriptions-item>
  43. <el-descriptions-item label="停车场">{{ cur.parking_lot || '-' }}</el-descriptions-item>
  44. </el-descriptions>
  45. </div>
  46. <div class="info-box empty" v-else>
  47. <el-empty description="点击车辆查看详情" :image-size="80" />
  48. </div>
  49. </el-col>
  50. </el-row>
  51. </div>
  52. </template>
  53. <script setup>
  54. import { ref, computed, onMounted } from 'vue'
  55. import { getInParkVehicles } from '@/api/vehicle'
  56. import { obtainPullOverList } from '@/api/pullOver'
  57. const lotID = ref(null), plateNumber = ref('')
  58. const list = ref([]), lotList = ref([]), selected = ref(null)
  59. const cur = computed(() => selected.value !== null ? list.value[selected.value] : {})
  60. const available = computed(() => {
  61. const total = lotList.value.reduce((s, l) => s + (l.capacity || 0), 0)
  62. return total - list.value.length
  63. })
  64. function formatStay(m) { if (!m && m !== 0) return '-'; const h = Math.floor(m / 60); return h > 0 ? `${h}h${m % 60}m` : `${m}m` }
  65. function select(i) { selected.value = selected.value === i ? null : i }
  66. async function fetchData() {
  67. try {
  68. const [vehicles, lots] = await Promise.all([
  69. getInParkVehicles({ parking_lot_id: lotID.value || '', plate_number: plateNumber.value }),
  70. obtainPullOverList({ page: 1, pageSize: 100 })
  71. ])
  72. if (vehicles.code === 0) list.value = vehicles.data || []
  73. if (lots.code === 0) lotList.value = lots.data?.list || []
  74. } catch (e) { console.error(e) }
  75. }
  76. onMounted(() => fetchData())
  77. </script>
  78. <style scoped>
  79. .car-grid { display: flex; flex-wrap: wrap; gap: 8px; min-height: 200px; align-content: flex-start; }
  80. .car-item { width: 110px; height: 70px; border: 1px solid #dcdfe6; border-radius: 6px; display: flex; flex-direction: column; align-items: center; justify-content: center; cursor: pointer; transition: all .2s; background: #fff; }
  81. .car-item:hover { border-color: #409eff; box-shadow: 0 2px 8px rgba(64,158,255,.15); }
  82. .car-item.active { border-color: #409eff; background: #ecf5ff; }
  83. .car-plate { font-weight: 700; font-size: 15px; }
  84. .car-time { font-size: 11px; color: #909399; margin-top: 4px; }
  85. .info-box { border: 1px solid #e4e7ed; border-radius: 6px; padding: 16px; background: #fafafa; min-height: 400px; }
  86. .info-box.empty { display: flex; align-items: center; justify-content: center; }
  87. .info-box h4 { margin: 0 0 12px; font-size: 15px; }
  88. </style>