carInfo.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. <template>
  2. <div>
  3. <!-- 搜索表单 -->
  4. <el-form inline>
  5. <el-form-item label="车牌号">
  6. <el-input
  7. v-model="queryForm.plate_number"
  8. placeholder="请输入车牌号"
  9. clearable
  10. />
  11. </el-form-item>
  12. <el-form-item label="车辆类型">
  13. <el-select
  14. v-model="queryForm.vehicle_type_id"
  15. placeholder="全部"
  16. clearable
  17. style="width:160px"
  18. >
  19. <el-option
  20. v-for="item in typeList"
  21. :key="item.ID"
  22. :label="item.name"
  23. :value="item.ID"
  24. />
  25. </el-select>
  26. </el-form-item>
  27. <el-form-item label="车主">
  28. <el-select
  29. v-model="queryForm.owner_id"
  30. clearable
  31. placeholder="请选择车主"
  32. style="width: 180px"
  33. >
  34. <el-option
  35. v-for="item in ownerList"
  36. :key="item.ID"
  37. :label="item.owner_name"
  38. :value="item.ID"
  39. />
  40. </el-select>
  41. </el-form-item>
  42. <el-form-item>
  43. <el-button
  44. icon="Search"
  45. type="primary"
  46. @click="getVehicleList"
  47. >搜索</el-button>
  48. <el-button
  49. icon="Refresh"
  50. @click="resetQuery"
  51. >重置</el-button>
  52. </el-form-item>
  53. <el-form-item>
  54. <el-button
  55. icon="Plus"
  56. type="primary"
  57. @click="openDialog('新增车辆', null)"
  58. >新增</el-button>
  59. <el-button
  60. type="warning"
  61. @click="openTypeDrawer"
  62. >管理车辆类型</el-button>
  63. </el-form-item>
  64. </el-form>
  65. <!-- 车辆列表 -->
  66. <el-table
  67. :data="vehicleList"
  68. height="605"
  69. border
  70. >
  71. <el-table-column
  72. label="ID"
  73. align="center"
  74. prop="ID"
  75. width="80"
  76. />
  77. <el-table-column
  78. label="车牌号"
  79. align="center"
  80. prop="plate_number"
  81. />
  82. <el-table-column
  83. label="电子标签"
  84. align="center"
  85. prop="rfid_tag"
  86. />
  87. <el-table-column
  88. label="车辆类型"
  89. align="center"
  90. >
  91. <template #default="scope">
  92. <el-tag type="primary">
  93. {{ scope.row.vehicle_type?.name || "未知" }}
  94. </el-tag>
  95. </template>
  96. </el-table-column>
  97. <el-table-column
  98. label="品牌"
  99. align="center"
  100. prop="vehicle_brand"
  101. />
  102. <el-table-column
  103. label="颜色"
  104. align="center"
  105. prop="vehicle_color"
  106. />
  107. <el-table-column
  108. label="车主"
  109. align="center"
  110. >
  111. <template #default="scope">
  112. {{ scope.row.owner?.owner_name || "临时车辆" }}
  113. </template>
  114. </el-table-column>
  115. <el-table-column
  116. label="操作"
  117. align="center"
  118. width="180"
  119. >
  120. <template #default="scope">
  121. <el-button
  122. icon="Edit"
  123. type="primary"
  124. text
  125. @click="openDialog('编辑车辆', scope.row)"
  126. >编辑</el-button>
  127. <el-button
  128. icon="Delete"
  129. type="danger"
  130. text
  131. @click="deleteVehicle(scope.row.ID)"
  132. >删除</el-button>
  133. </template>
  134. </el-table-column>
  135. </el-table>
  136. <!-- 分页 -->
  137. <div class="pagination-box">
  138. <el-pagination
  139. :current-page="queryForm.page"
  140. :page-size="queryForm.pageSize"
  141. :page-sizes="[10, 30, 50, 100]"
  142. :total="total"
  143. layout="total, sizes, prev, pager, next, jumper"
  144. @current-change="handlePageChange"
  145. @size-change="handleSizeChange"
  146. />
  147. </div>
  148. <!-- 新增/编辑弹窗 -->
  149. <el-dialog
  150. v-model="dialogVisible"
  151. :title="dialogTitle"
  152. width="520px"
  153. >
  154. <el-form
  155. label-width="100px"
  156. :model="formData"
  157. >
  158. <el-form-item label="车牌号:">
  159. <el-input
  160. v-model="formData.plate_number"
  161. placeholder="请输入车牌号"
  162. />
  163. </el-form-item>
  164. <el-form-item label="电子标签:">
  165. <el-input
  166. v-model="formData.rfid_tag"
  167. placeholder="RFID标签(UHF用)"
  168. />
  169. </el-form-item>
  170. <el-form-item label="车辆类型:">
  171. <el-select
  172. v-model="formData.vehicle_type_id"
  173. placeholder="请选择"
  174. style="width:100%"
  175. >
  176. <el-option
  177. v-for="item in typeList"
  178. :key="item.ID"
  179. :label="item.name"
  180. :value="item.ID"
  181. />
  182. </el-select>
  183. </el-form-item>
  184. <el-form-item label="车辆品牌:">
  185. <el-input
  186. v-model="formData.vehicle_brand"
  187. placeholder="如:保时捷"
  188. />
  189. </el-form-item>
  190. <el-form-item label="车辆颜色">
  191. <el-input
  192. v-model="formData.vehicle_color"
  193. placeholder="如:黑色"
  194. />
  195. </el-form-item>
  196. <el-form-item label="绑定车主:">
  197. <el-select
  198. v-model="formData.owner_id"
  199. placeholder="临时车可不选"
  200. clearable
  201. style="width: 100%"
  202. >
  203. <el-option
  204. v-for="item in ownerList"
  205. :key="item.ID"
  206. :label="item.owner_name"
  207. :value="item.ID"
  208. />
  209. </el-select>
  210. </el-form-item>
  211. </el-form>
  212. <template #footer>
  213. <el-button @click="dialogVisible = false">取消</el-button>
  214. <el-button
  215. type="primary"
  216. @click="submitForm"
  217. >确认保存</el-button>
  218. </template>
  219. </el-dialog>
  220. <!-- ===================== 车辆类型抽屉(Drawer)===================== -->
  221. <el-drawer
  222. v-model="typeDrawerVisible"
  223. title="车辆类型管理"
  224. size="700px"
  225. >
  226. <div style="display:flex; justify-content:space-between; margin-bottom:10px">
  227. <el-input
  228. v-model="typeQuery.name"
  229. placeholder="搜索类型名称"
  230. clearable
  231. style="width:200px"
  232. @input="getTypeList"
  233. />
  234. <el-button
  235. type="primary"
  236. icon="Plus"
  237. @click="openTypeForm('新增')"
  238. >新增类型</el-button>
  239. </div>
  240. <el-table
  241. :data="typeList"
  242. border
  243. >
  244. <el-table-column
  245. label="ID"
  246. prop="ID"
  247. />
  248. <el-table-column
  249. label="类型名称"
  250. prop="name"
  251. />
  252. <el-table-column
  253. label="备注"
  254. prop="remarks"
  255. />
  256. <el-table-column label="操作">
  257. <template #default="scope">
  258. <el-button
  259. text
  260. type="primary"
  261. @click="openTypeForm('编辑', scope.row)"
  262. >编辑</el-button>
  263. <el-button
  264. text
  265. type="danger"
  266. @click="deleteType(scope.row.ID)"
  267. >删除</el-button>
  268. </template>
  269. </el-table-column>
  270. </el-table>
  271. <el-pagination
  272. v-model:current-page="typeQuery.page"
  273. v-model:page-size="typeQuery.pageSize"
  274. :total="typeTotal"
  275. layout="total, prev, pager, next"
  276. style="margin-top:10px; text-align:right"
  277. @current-change="getTypeList"
  278. />
  279. </el-drawer>
  280. <!-- 车辆类型 新增/编辑 弹窗 -->
  281. <el-dialog
  282. v-model="typeDialogVisible"
  283. :title="typeTitle"
  284. width="450px"
  285. >
  286. <el-form
  287. label-width="80px"
  288. :model="typeForm"
  289. >
  290. <el-form-item label="类型名称">
  291. <el-input
  292. v-model="typeForm.name"
  293. placeholder="如:月租车、VIP车"
  294. />
  295. </el-form-item>
  296. <el-form-item label="备注">
  297. <el-input
  298. v-model="typeForm.remarks"
  299. type="textarea"
  300. rows="3"
  301. />
  302. </el-form-item>
  303. </el-form>
  304. <template #footer>
  305. <el-button @click="typeDialogVisible = false">取消</el-button>
  306. <el-button
  307. type="primary"
  308. @click="saveType"
  309. >保存</el-button>
  310. </template>
  311. </el-dialog>
  312. </div>
  313. </template>
  314. <script setup>
  315. import { ref, reactive, onMounted } from 'vue'
  316. import { ElMessage, ElMessageBox } from 'element-plus'
  317. import {
  318. obtainVehicleList,
  319. addVehicle,
  320. editVehicle,
  321. removeVehicleList
  322. } from '@/api/vehicle'
  323. import { obtainCarOwnerList } from '@/api/carOwner'
  324. // 车辆类型接口
  325. import {
  326. obtainVehicleTypeList,
  327. createVehicleType,
  328. editVehicleType,
  329. removeVehicleType,
  330. getAllVehicleTypes
  331. } from '@/api/vehicle'
  332. // ==================== 车辆管理原有逻辑 ====================
  333. const queryForm = reactive({
  334. plate_number: '',
  335. vehicle_type_id: null,
  336. owner_id: null,
  337. page: 1,
  338. pageSize: 10
  339. })
  340. const vehicleList = ref([])
  341. const total = ref(0)
  342. const ownerList = ref([])
  343. const typeList = ref([])
  344. const dialogVisible = ref(false)
  345. const dialogTitle = ref('')
  346. const formData = reactive({
  347. ID: 0,
  348. plate_number: '',
  349. rfid_tag: '',
  350. vehicle_type_id: null,
  351. vehicle_brand: '',
  352. vehicle_color: '',
  353. owner_id: null
  354. })
  355. const getVehicleList = async() => {
  356. try {
  357. const res = await obtainVehicleList(queryForm)
  358. if (res.code === 0) {
  359. vehicleList.value = res.data.list
  360. total.value = res.data.total
  361. }
  362. } catch (err) {
  363. ElMessage.error('获取列表失败')
  364. }
  365. }
  366. const resetQuery = () => {
  367. queryForm.plate_number = ''
  368. queryForm.vehicle_type_id = null
  369. queryForm.owner_id = null
  370. queryForm.page = 1
  371. getVehicleList()
  372. }
  373. const openDialog = (title, row) => {
  374. dialogTitle.value = title
  375. dialogVisible.value = true
  376. if (!row) {
  377. Object.assign(formData, {
  378. ID: 0, plate_number: '', rfid_tag: '',
  379. vehicle_type_id: null, vehicle_brand: '',
  380. vehicle_color: '', owner_id: null
  381. })
  382. return
  383. }
  384. Object.assign(formData, row)
  385. }
  386. const submitForm = async() => {
  387. if (!formData.plate_number) {
  388. ElMessage.warning('请输入车牌号')
  389. return
  390. }
  391. try {
  392. if (formData.ID > 0) {
  393. await editVehicle(formData)
  394. ElMessage.success('编辑成功')
  395. } else {
  396. await addVehicle(formData)
  397. ElMessage.success('新增成功')
  398. }
  399. dialogVisible.value = false
  400. getVehicleList()
  401. } catch (err) {
  402. ElMessage.error('保存失败')
  403. }
  404. }
  405. const deleteVehicle = async(id) => {
  406. await ElMessageBox.confirm('确定删除该车辆?', '提示', { type: 'warning' })
  407. try {
  408. await removeVehicleList({ id })
  409. ElMessage.success('删除成功')
  410. getVehicleList()
  411. } catch (err) {
  412. ElMessage.error('删除失败')
  413. }
  414. }
  415. const handlePageChange = (page) => {
  416. queryForm.page = page
  417. getVehicleList()
  418. }
  419. const handleSizeChange = (size) => {
  420. queryForm.pageSize = size
  421. queryForm.page = 1
  422. getVehicleList()
  423. }
  424. // ==================== 车辆类型 抽屉逻辑 ====================
  425. const typeDrawerVisible = ref(false)
  426. const typeDialogVisible = ref(false)
  427. const typeTitle = ref('')
  428. const typeQuery = reactive({
  429. name: '',
  430. page: 1,
  431. pageSize: 10
  432. })
  433. const typeTotal = ref(0)
  434. const typeForm = reactive({
  435. ID: 0,
  436. name: '',
  437. remarks: ''
  438. })
  439. // 打开类型抽屉
  440. const openTypeDrawer = () => {
  441. typeDrawerVisible.value = true
  442. getTypeList()
  443. }
  444. // 获取类型列表
  445. const getTypeList = async() => {
  446. const res = await obtainVehicleTypeList(typeQuery)
  447. if (res.code === 0) {
  448. typeList.value = res.data.list
  449. typeTotal.value = res.data.total
  450. }
  451. }
  452. // 打开新增/编辑
  453. const openTypeForm = (title, row = null) => {
  454. typeTitle.value = title
  455. typeDialogVisible.value = true
  456. if (!row) {
  457. Object.assign(typeForm, { ID: 0, name: '', remarks: '' })
  458. return
  459. }
  460. Object.assign(typeForm, row)
  461. }
  462. // 保存
  463. const saveType = async() => {
  464. if (!typeForm.name) {
  465. ElMessage.warning('请输入类型名称')
  466. return
  467. }
  468. try {
  469. if (typeForm.ID > 0) {
  470. await editVehicleType(typeForm)
  471. ElMessage.success('编辑成功')
  472. } else {
  473. await createVehicleType(typeForm)
  474. ElMessage.success('新增成功')
  475. }
  476. typeDialogVisible.value = false
  477. getTypeList()
  478. loadAllTypes()
  479. } catch (e) {
  480. ElMessage.error('保存失败')
  481. }
  482. }
  483. // 删除
  484. const deleteType = async(id) => {
  485. await ElMessageBox.confirm('确定删除?')
  486. await removeVehicleType(id)
  487. ElMessage.success('删除成功')
  488. getTypeList()
  489. loadAllTypes()
  490. }
  491. // 加载所有类型(下拉框)
  492. const loadAllTypes = async() => {
  493. const res = await getAllVehicleTypes()
  494. if (res.code === 0) typeList.value = res.data
  495. }
  496. // ==================== 初始化 ====================
  497. const getOwnerList = async() => {
  498. const res = await obtainCarOwnerList()
  499. if (res.code === 0) ownerList.value = res.data.list
  500. }
  501. onMounted(async() => {
  502. await loadAllTypes()
  503. getVehicleList()
  504. getOwnerList()
  505. })
  506. </script>
  507. <style scoped lang="scss">
  508. .pagination-box {
  509. width: 100%;
  510. display: flex;
  511. justify-content: end;
  512. padding: 10px;
  513. }
  514. </style>