Commit eafabeed42c8a0fad9c27ae92e5b27e426633f05
1 parent
e18d1bbb
开发完成业主车辆
Showing
25 changed files
with
3619 additions
and
8 deletions
src/api/car/carAddParkingSpaceApi.js
0 → 100644
| 1 | +import request from '@/utils/request' | |
| 2 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 3 | + | |
| 4 | +// 查询车辆信息 | |
| 5 | +export function getCarInfo(params) { | |
| 6 | + return new Promise((resolve, reject) => { | |
| 7 | + request({ | |
| 8 | + url: '/owner.queryOwnerCars', | |
| 9 | + method: 'get', | |
| 10 | + params: { | |
| 11 | + ...params, | |
| 12 | + communityId: getCommunityId() | |
| 13 | + } | |
| 14 | + }).then(response => { | |
| 15 | + const res = response.data | |
| 16 | + if (res.code === 0) { | |
| 17 | + resolve(res) | |
| 18 | + } else { | |
| 19 | + reject(new Error(res.msg || '获取车辆信息失败')) | |
| 20 | + } | |
| 21 | + }).catch(error => { | |
| 22 | + reject(error) | |
| 23 | + }) | |
| 24 | + }) | |
| 25 | +} | |
| 26 | + | |
| 27 | +// 添加车辆停车位 | |
| 28 | +export function addCarParkingSpace(data) { | |
| 29 | + return new Promise((resolve, reject) => { | |
| 30 | + request({ | |
| 31 | + url: '/owner.carAddParkingSpace', | |
| 32 | + method: 'post', | |
| 33 | + data: { | |
| 34 | + ...data, | |
| 35 | + communityId: getCommunityId() | |
| 36 | + } | |
| 37 | + }).then(response => { | |
| 38 | + const res = response.data | |
| 39 | + if (res.code === 0) { | |
| 40 | + resolve(res) | |
| 41 | + } else { | |
| 42 | + reject(new Error(res.msg || '添加停车位失败')) | |
| 43 | + } | |
| 44 | + }).catch(error => { | |
| 45 | + reject(error) | |
| 46 | + }) | |
| 47 | + }) | |
| 48 | +} | |
| 49 | + | |
| 50 | +// 查询停车位列表 | |
| 51 | +export function queryParkingSpaces(params) { | |
| 52 | + return new Promise((resolve, reject) => { | |
| 53 | + request({ | |
| 54 | + url: '/parkingSpace.queryParkingSpaces', | |
| 55 | + method: 'get', | |
| 56 | + params: { | |
| 57 | + ...params, | |
| 58 | + communityId: getCommunityId() | |
| 59 | + } | |
| 60 | + }).then(response => { | |
| 61 | + const res = response.data | |
| 62 | + if (res.code === 0) { | |
| 63 | + resolve(res) | |
| 64 | + } else { | |
| 65 | + reject(new Error(res.msg || '查询停车位失败')) | |
| 66 | + } | |
| 67 | + }).catch(error => { | |
| 68 | + reject(error) | |
| 69 | + }) | |
| 70 | + }) | |
| 71 | +} | |
| 72 | + | |
| 73 | +// 查询停车场列表 | |
| 74 | +export function listParkingAreas() { | |
| 75 | + return new Promise((resolve, reject) => { | |
| 76 | + request({ | |
| 77 | + url: '/parkingArea.listParkingAreas', | |
| 78 | + method: 'get', | |
| 79 | + params: { | |
| 80 | + page: 1, | |
| 81 | + row: 50, | |
| 82 | + communityId: getCommunityId() | |
| 83 | + } | |
| 84 | + }).then(response => { | |
| 85 | + const res = response.data | |
| 86 | + if (res.code === 0) { | |
| 87 | + resolve(res) | |
| 88 | + } else { | |
| 89 | + reject(new Error(res.msg || '查询停车场失败')) | |
| 90 | + } | |
| 91 | + }).catch(error => { | |
| 92 | + reject(error) | |
| 93 | + }) | |
| 94 | + }) | |
| 95 | +} | |
| 0 | 96 | \ No newline at end of file | ... | ... |
src/api/car/hireParkingSpaceApi.js
0 → 100644
| 1 | +import request from '@/utils/request' | |
| 2 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 3 | + | |
| 4 | +// 保存车辆信息 | |
| 5 | +export function saveOwnerCar(data) { | |
| 6 | + return new Promise((resolve, reject) => { | |
| 7 | + request({ | |
| 8 | + url: '/owner.saveOwnerCar', | |
| 9 | + method: 'post', | |
| 10 | + data: { | |
| 11 | + ...data, | |
| 12 | + communityId: getCommunityId() | |
| 13 | + } | |
| 14 | + }).then(response => { | |
| 15 | + const res = response.data | |
| 16 | + if (res.code === 0) { | |
| 17 | + resolve(res) | |
| 18 | + } else { | |
| 19 | + reject(new Error(res.msg || '保存车辆信息失败')) | |
| 20 | + } | |
| 21 | + }).catch(error => { | |
| 22 | + reject(error) | |
| 23 | + }) | |
| 24 | + }) | |
| 25 | +} | |
| 26 | + | |
| 27 | +// 查询业主列表 | |
| 28 | +export function queryOwners(params) { | |
| 29 | + return new Promise((resolve, reject) => { | |
| 30 | + request({ | |
| 31 | + url: '/owner.queryOwners', | |
| 32 | + method: 'get', | |
| 33 | + params: { | |
| 34 | + ...params, | |
| 35 | + communityId: getCommunityId() | |
| 36 | + } | |
| 37 | + }).then(response => { | |
| 38 | + const res = response.data | |
| 39 | + if (res.code === 0) { | |
| 40 | + resolve({ | |
| 41 | + data: res.data, | |
| 42 | + total: res.records | |
| 43 | + }) | |
| 44 | + } else { | |
| 45 | + reject(new Error(res.msg || '查询业主列表失败')) | |
| 46 | + } | |
| 47 | + }).catch(error => { | |
| 48 | + reject(error) | |
| 49 | + }) | |
| 50 | + }) | |
| 51 | +} | |
| 52 | + | |
| 53 | +// 查询停车位列表 | |
| 54 | +export function queryParkingSpaces(params) { | |
| 55 | + return new Promise((resolve, reject) => { | |
| 56 | + request({ | |
| 57 | + url: '/parkingSpace.queryParkingSpaces', | |
| 58 | + method: 'get', | |
| 59 | + params: { | |
| 60 | + ...params, | |
| 61 | + communityId: getCommunityId() | |
| 62 | + } | |
| 63 | + }).then(response => { | |
| 64 | + const res = response.data | |
| 65 | + resolve(res) | |
| 66 | + }).catch(error => { | |
| 67 | + reject(error) | |
| 68 | + }) | |
| 69 | + }) | |
| 70 | +} | |
| 71 | + | |
| 72 | +// 获取停车场区域列表 | |
| 73 | +export function listParkingAreas(params) { | |
| 74 | + return new Promise((resolve, reject) => { | |
| 75 | + request({ | |
| 76 | + url: '/parkingArea.listParkingAreas', | |
| 77 | + method: 'get', | |
| 78 | + params: { | |
| 79 | + ...params, | |
| 80 | + communityId: getCommunityId() | |
| 81 | + } | |
| 82 | + }).then(response => { | |
| 83 | + const res = response.data | |
| 84 | + resolve(res) | |
| 85 | + }).catch(error => { | |
| 86 | + reject(error) | |
| 87 | + }) | |
| 88 | + }) | |
| 89 | +} | |
| 90 | + | |
| 91 | +// 获取车辆属性规格 | |
| 92 | +export function getCarAttrSpec() { | |
| 93 | + return new Promise((resolve, reject) => { | |
| 94 | + request({ | |
| 95 | + url: '/attr.getAttrSpec', | |
| 96 | + method: 'get', | |
| 97 | + params: { | |
| 98 | + specCd: 'owner_car_attr', | |
| 99 | + communityId: getCommunityId() | |
| 100 | + } | |
| 101 | + }).then(response => { | |
| 102 | + const res = response.data | |
| 103 | + if (res.code === 0) { | |
| 104 | + resolve(res.data) | |
| 105 | + } else { | |
| 106 | + reject(new Error(res.msg || '获取车辆属性规格失败')) | |
| 107 | + } | |
| 108 | + }).catch(error => { | |
| 109 | + reject(error) | |
| 110 | + }) | |
| 111 | + }) | |
| 112 | +} | |
| 113 | + | |
| 114 | +// 获取字典数据 | |
| 115 | +export function getDict(dictType, dictCd) { | |
| 116 | + return new Promise((resolve, reject) => { | |
| 117 | + request({ | |
| 118 | + url: '/dict.getDict', | |
| 119 | + method: 'get', | |
| 120 | + params: { | |
| 121 | + dictType, | |
| 122 | + dictCd, | |
| 123 | + communityId: getCommunityId() | |
| 124 | + } | |
| 125 | + }).then(response => { | |
| 126 | + const res = response.data | |
| 127 | + if (res.code === 0) { | |
| 128 | + resolve(res.data) | |
| 129 | + } else { | |
| 130 | + reject(new Error(res.msg || '获取字典数据失败')) | |
| 131 | + } | |
| 132 | + }).catch(error => { | |
| 133 | + reject(error) | |
| 134 | + }) | |
| 135 | + }) | |
| 136 | +} | |
| 0 | 137 | \ No newline at end of file | ... | ... |
src/api/car/listOwnerCarApi.js
0 → 100644
| 1 | +import request from '@/utils/request' | |
| 2 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 3 | + | |
| 4 | +// 查询业主车辆 | |
| 5 | +export function queryOwnerCars(params) { | |
| 6 | + return new Promise((resolve, reject) => { | |
| 7 | + const communityId = getCommunityId() | |
| 8 | + request({ | |
| 9 | + url: '/owner.queryOwnerCars', | |
| 10 | + method: 'get', | |
| 11 | + params: { | |
| 12 | + ...params, | |
| 13 | + communityId | |
| 14 | + } | |
| 15 | + }).then(response => { | |
| 16 | + const res = response.data | |
| 17 | + if (res.code === 0) { | |
| 18 | + resolve(res) | |
| 19 | + } else { | |
| 20 | + reject(new Error(res.msg || '查询业主车辆失败')) | |
| 21 | + } | |
| 22 | + }).catch(error => { | |
| 23 | + reject(error) | |
| 24 | + }) | |
| 25 | + }) | |
| 26 | +} | |
| 27 | + | |
| 28 | +// 删除业主车辆 | |
| 29 | +export function deleteOwnerCars(data) { | |
| 30 | + return new Promise((resolve, reject) => { | |
| 31 | + const communityId = getCommunityId() | |
| 32 | + request({ | |
| 33 | + url: '/owner.deleteOwnerCars', | |
| 34 | + method: 'post', | |
| 35 | + data: { | |
| 36 | + ...data, | |
| 37 | + communityId | |
| 38 | + } | |
| 39 | + }).then(response => { | |
| 40 | + const res = response.data | |
| 41 | + if (res.code === 0) { | |
| 42 | + resolve(res) | |
| 43 | + } else { | |
| 44 | + reject(new Error(res.msg || '删除业主车辆失败')) | |
| 45 | + } | |
| 46 | + }).catch(error => { | |
| 47 | + reject(error) | |
| 48 | + }) | |
| 49 | + }) | |
| 50 | +} | |
| 51 | + | |
| 52 | +// 释放车位 | |
| 53 | +export function deleteCarParkingSpace(data) { | |
| 54 | + return new Promise((resolve, reject) => { | |
| 55 | + const communityId = getCommunityId() | |
| 56 | + request({ | |
| 57 | + url: '/owner.deleteCarParkingSpace', | |
| 58 | + method: 'post', | |
| 59 | + data: { | |
| 60 | + ...data, | |
| 61 | + communityId | |
| 62 | + } | |
| 63 | + }).then(response => { | |
| 64 | + const res = response.data | |
| 65 | + if (res.code === 0) { | |
| 66 | + resolve(res) | |
| 67 | + } else { | |
| 68 | + reject(new Error(res.msg || '释放车位失败')) | |
| 69 | + } | |
| 70 | + }).catch(error => { | |
| 71 | + reject(error) | |
| 72 | + }) | |
| 73 | + }) | |
| 74 | +} | |
| 75 | + | |
| 76 | +// 导入车辆数据 | |
| 77 | +export function importData(data) { | |
| 78 | + return new Promise((resolve, reject) => { | |
| 79 | + const communityId = getCommunityId() | |
| 80 | + const formData = new FormData() | |
| 81 | + formData.append('uploadFile', data.file) | |
| 82 | + formData.append('communityId', communityId) | |
| 83 | + formData.append('importAdapt', data.importAdapt || 'importOwnerCar') | |
| 84 | + | |
| 85 | + request({ | |
| 86 | + url: '/callComponent/upload/assetImport/importData', | |
| 87 | + method: 'post', | |
| 88 | + data: formData, | |
| 89 | + headers: { | |
| 90 | + 'Content-Type': 'multipart/form-data' | |
| 91 | + } | |
| 92 | + }).then(response => { | |
| 93 | + const res = response.data | |
| 94 | + if (res.code === 0) { | |
| 95 | + resolve(res) | |
| 96 | + } else { | |
| 97 | + reject(new Error(res.msg || '导入失败')) | |
| 98 | + } | |
| 99 | + }).catch(error => { | |
| 100 | + reject(error) | |
| 101 | + }) | |
| 102 | + }) | |
| 103 | +} | |
| 104 | + | |
| 105 | +// 修改车辆信息 | |
| 106 | +export function editOwnerCar(data) { | |
| 107 | + return new Promise((resolve, reject) => { | |
| 108 | + const communityId = getCommunityId() | |
| 109 | + request({ | |
| 110 | + url: '/owner.editOwnerCar', | |
| 111 | + method: 'post', | |
| 112 | + data: { | |
| 113 | + ...data, | |
| 114 | + communityId | |
| 115 | + } | |
| 116 | + }).then(response => { | |
| 117 | + const res = response.data | |
| 118 | + if (res.code === 0) { | |
| 119 | + resolve(res) | |
| 120 | + } else { | |
| 121 | + reject(new Error(res.msg || '修改车辆信息失败')) | |
| 122 | + } | |
| 123 | + }).catch(error => { | |
| 124 | + reject(error) | |
| 125 | + }) | |
| 126 | + }) | |
| 127 | +} | |
| 128 | + | |
| 129 | +// 导出车辆数据 | |
| 130 | +export function exportData(params) { | |
| 131 | + return new Promise((resolve, reject) => { | |
| 132 | + const communityId = getCommunityId() | |
| 133 | + request({ | |
| 134 | + url: '/export.exportData', | |
| 135 | + method: 'get', | |
| 136 | + params: { | |
| 137 | + ...params, | |
| 138 | + communityId, | |
| 139 | + pagePath: 'exportOwnerCar' | |
| 140 | + } | |
| 141 | + }).then(response => { | |
| 142 | + const res = response.data | |
| 143 | + if (res.code === 0) { | |
| 144 | + resolve(res) | |
| 145 | + } else { | |
| 146 | + reject(new Error(res.msg || '导出失败')) | |
| 147 | + } | |
| 148 | + }).catch(error => { | |
| 149 | + reject(error) | |
| 150 | + }) | |
| 151 | + }) | |
| 152 | +} | |
| 0 | 153 | \ No newline at end of file | ... | ... |
src/api/car/parkingBoxManageApi.js
0 → 100644
| 1 | +import request from '@/utils/request' | |
| 2 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 3 | + | |
| 4 | +// 查询岗亭列表 | |
| 5 | +export function getParkingBoxList(params) { | |
| 6 | + return new Promise((resolve, reject) => { | |
| 7 | + const communityId = getCommunityId() | |
| 8 | + request({ | |
| 9 | + url: '/iot.getOpenApi', | |
| 10 | + method: 'get', | |
| 11 | + params: { | |
| 12 | + ...params, | |
| 13 | + communityId, | |
| 14 | + iotApiCode: 'listParkingBoxBmoImpl' | |
| 15 | + } | |
| 16 | + }).then(response => { | |
| 17 | + const res = response.data | |
| 18 | + if (res.code === 0) { | |
| 19 | + resolve(res) | |
| 20 | + } else { | |
| 21 | + reject(new Error(res.msg || '获取岗亭列表失败')) | |
| 22 | + } | |
| 23 | + }).catch(error => { | |
| 24 | + reject(error) | |
| 25 | + }) | |
| 26 | + }) | |
| 27 | +} | |
| 28 | + | |
| 29 | +// 添加岗亭 | |
| 30 | +export function addParkingBox(data) { | |
| 31 | + return new Promise((resolve, reject) => { | |
| 32 | + const communityId = getCommunityId() | |
| 33 | + request({ | |
| 34 | + url: '/parkingBox.saveParkingBox', | |
| 35 | + method: 'post', | |
| 36 | + data: { | |
| 37 | + ...data, | |
| 38 | + communityId | |
| 39 | + } | |
| 40 | + }).then(response => { | |
| 41 | + const res = response.data | |
| 42 | + if (res.code === 0) { | |
| 43 | + resolve(res) | |
| 44 | + } else { | |
| 45 | + reject(new Error(res.msg || '添加岗亭失败')) | |
| 46 | + } | |
| 47 | + }).catch(error => { | |
| 48 | + reject(error) | |
| 49 | + }) | |
| 50 | + }) | |
| 51 | +} | |
| 52 | + | |
| 53 | +// 更新岗亭 | |
| 54 | +export function updateParkingBox(data) { | |
| 55 | + return new Promise((resolve, reject) => { | |
| 56 | + const communityId = getCommunityId() | |
| 57 | + request({ | |
| 58 | + url: '/parkingBox.updateParkingBox', | |
| 59 | + method: 'post', | |
| 60 | + data: { | |
| 61 | + ...data, | |
| 62 | + communityId | |
| 63 | + } | |
| 64 | + }).then(response => { | |
| 65 | + const res = response.data | |
| 66 | + if (res.code === 0) { | |
| 67 | + resolve(res) | |
| 68 | + } else { | |
| 69 | + reject(new Error(res.msg || '更新岗亭失败')) | |
| 70 | + } | |
| 71 | + }).catch(error => { | |
| 72 | + reject(error) | |
| 73 | + }) | |
| 74 | + }) | |
| 75 | +} | |
| 76 | + | |
| 77 | +// 删除岗亭 | |
| 78 | +export function deleteParkingBox(data) { | |
| 79 | + return new Promise((resolve, reject) => { | |
| 80 | + const communityId = getCommunityId() | |
| 81 | + request({ | |
| 82 | + url: '/parkingBox.deleteParkingBox', | |
| 83 | + method: 'post', | |
| 84 | + data: { | |
| 85 | + ...data, | |
| 86 | + communityId | |
| 87 | + } | |
| 88 | + }).then(response => { | |
| 89 | + const res = response.data | |
| 90 | + if (res.code === 0) { | |
| 91 | + resolve(res) | |
| 92 | + } else { | |
| 93 | + reject(new Error(res.msg || '删除岗亭失败')) | |
| 94 | + } | |
| 95 | + }).catch(error => { | |
| 96 | + reject(error) | |
| 97 | + }) | |
| 98 | + }) | |
| 99 | +} | |
| 100 | + | |
| 101 | +// 获取停车场列表 | |
| 102 | +export function getParkingAreaList() { | |
| 103 | + return new Promise((resolve, reject) => { | |
| 104 | + const communityId = getCommunityId() | |
| 105 | + request({ | |
| 106 | + url: '/parkingArea.listParkingAreas', | |
| 107 | + method: 'get', | |
| 108 | + params: { | |
| 109 | + page: 1, | |
| 110 | + row: 50, | |
| 111 | + communityId | |
| 112 | + } | |
| 113 | + }).then(response => { | |
| 114 | + const res = response.data | |
| 115 | + if (res.code === 0) { | |
| 116 | + resolve(res.data.parkingAreas || []) | |
| 117 | + } else { | |
| 118 | + reject(new Error(res.msg || '获取停车场列表失败')) | |
| 119 | + } | |
| 120 | + }).catch(error => { | |
| 121 | + reject(error) | |
| 122 | + }) | |
| 123 | + }) | |
| 124 | +} | |
| 0 | 125 | \ No newline at end of file | ... | ... |
src/api/fee/buyCarMonthCardApi.js
0 → 100644
| 1 | +import request from '@/utils/request' | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * 购买月卡订单 | |
| 5 | + * @param {Object} data 订单数据 | |
| 6 | + * @returns {Promise} | |
| 7 | + */ | |
| 8 | +export function buyCarMonthOrder(data) { | |
| 9 | + return new Promise((resolve, reject) => { | |
| 10 | + request({ | |
| 11 | + url: '/carMonth.buyCarMonthOrder', | |
| 12 | + method: 'post', | |
| 13 | + data | |
| 14 | + }).then(response => { | |
| 15 | + const res = response.data | |
| 16 | + if (res.code === 0) { | |
| 17 | + resolve(res) | |
| 18 | + } else { | |
| 19 | + reject(new Error(res.msg || '购买月卡失败')) | |
| 20 | + } | |
| 21 | + }).catch(error => { | |
| 22 | + reject(error) | |
| 23 | + }) | |
| 24 | + }) | |
| 25 | +} | |
| 26 | + | |
| 27 | +/** | |
| 28 | + * 查询车主车辆 | |
| 29 | + * @param {Object} params 查询参数 | |
| 30 | + * @returns {Promise} | |
| 31 | + */ | |
| 32 | +export function queryOwnerCars(params) { | |
| 33 | + return new Promise((resolve, reject) => { | |
| 34 | + request({ | |
| 35 | + url: '/owner.queryOwnerCars', | |
| 36 | + method: 'get', | |
| 37 | + params | |
| 38 | + }).then(response => { | |
| 39 | + const res = response.data | |
| 40 | + if (res.code === 0) { | |
| 41 | + resolve(res) | |
| 42 | + } else { | |
| 43 | + reject(new Error(res.msg || '查询车主车辆失败')) | |
| 44 | + } | |
| 45 | + }).catch(error => { | |
| 46 | + reject(error) | |
| 47 | + }) | |
| 48 | + }) | |
| 49 | +} | |
| 50 | + | |
| 51 | +/** | |
| 52 | + * 获取月卡列表 | |
| 53 | + * @param {Object} params 查询参数 | |
| 54 | + * @returns {Promise} | |
| 55 | + */ | |
| 56 | +export function getOpenApi(params) { | |
| 57 | + return new Promise((resolve, reject) => { | |
| 58 | + request({ | |
| 59 | + url: '/iot.getOpenApi', | |
| 60 | + method: 'get', | |
| 61 | + params | |
| 62 | + }).then(response => { | |
| 63 | + const res = response.data | |
| 64 | + if (res.code === 0) { | |
| 65 | + resolve(res) | |
| 66 | + } else { | |
| 67 | + reject(new Error(res.msg || '获取月卡列表失败')) | |
| 68 | + } | |
| 69 | + }).catch(error => { | |
| 70 | + reject(error) | |
| 71 | + }) | |
| 72 | + }) | |
| 73 | +} | |
| 0 | 74 | \ No newline at end of file | ... | ... |
src/components/car/SearchParkingSpace.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog :title="$t('searchParkingSpace.title')" :visible.sync="visible" width="80%" @close="handleClose"> | |
| 3 | + <el-card> | |
| 4 | + <el-row v-if="showSearchCondition" :gutter="20"> | |
| 5 | + <el-col :span="8"> | |
| 6 | + <el-select v-model="searchParkingSpaceInfo.areaNum" class="w-full" | |
| 7 | + :placeholder="$t('searchParkingSpace.parkingAreaPlaceholder')"> | |
| 8 | + <el-option v-for="item in parkingAreas" :key="item.num" :label="item.num" :value="item.num" /> | |
| 9 | + </el-select> | |
| 10 | + </el-col> | |
| 11 | + <el-col :span="8"> | |
| 12 | + <el-input v-model="searchParkingSpaceInfo.num" :placeholder="$t('searchParkingSpace.numPlaceholder')" /> | |
| 13 | + </el-col> | |
| 14 | + <el-col :span="8"> | |
| 15 | + <el-button type="primary" @click="searchParkingSpaces"> | |
| 16 | + {{ $t('common.search') }} | |
| 17 | + </el-button> | |
| 18 | + <el-button @click="resetParkingSpaces"> | |
| 19 | + {{ $t('common.reset') }} | |
| 20 | + </el-button> | |
| 21 | + </el-col> | |
| 22 | + </el-row> | |
| 23 | + | |
| 24 | + <el-table :data="searchParkingSpaceInfo.parkingSpaces" class="mt-20"> | |
| 25 | + <el-table-column prop="areaNum" :label="$t('searchParkingSpace.areaNum')" align="center" /> | |
| 26 | + <el-table-column prop="num" :label="$t('searchParkingSpace.num')" align="center" /> | |
| 27 | + <el-table-column :label="$t('searchParkingSpace.type')" align="center"> | |
| 28 | + <template slot-scope="scope"> | |
| 29 | + {{ scope.row.typeCd === '1001' ? $t('searchParkingSpace.ground') : $t('searchParkingSpace.underground') }} | |
| 30 | + </template> | |
| 31 | + </el-table-column> | |
| 32 | + <el-table-column prop="parkingTypeName" :label="$t('searchParkingSpace.parkingType')" align="center" /> | |
| 33 | + <el-table-column prop="stateName" :label="$t('searchParkingSpace.state')" align="center" /> | |
| 34 | + <el-table-column prop="area" :label="$t('searchParkingSpace.area')" align="center" /> | |
| 35 | + <el-table-column :label="$t('common.operation')" align="center" width="120"> | |
| 36 | + <template slot-scope="scope"> | |
| 37 | + <el-button type="primary" size="small" @click="chooseParkingSpace(scope.row)"> | |
| 38 | + {{ $t('common.select') }} | |
| 39 | + </el-button> | |
| 40 | + </template> | |
| 41 | + </el-table-column> | |
| 42 | + </el-table> | |
| 43 | + | |
| 44 | + <el-pagination class="mt-20" :current-page="pagination.currentPage" :page-sizes="[10, 20, 30, 50]" | |
| 45 | + :page-size="pagination.pageSize" :total="pagination.total" layout="total, sizes, prev, pager, next, jumper" | |
| 46 | + @size-change="handleSizeChange" @current-change="handleCurrentChange" /> | |
| 47 | + </el-card> | |
| 48 | + </el-dialog> | |
| 49 | +</template> | |
| 50 | + | |
| 51 | +<script> | |
| 52 | +import { queryParkingSpaces, listParkingAreas } from '@/api/car/hireParkingSpaceApi' | |
| 53 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 54 | + | |
| 55 | +export default { | |
| 56 | + name: 'SearchParkingSpace', | |
| 57 | + props: { | |
| 58 | + parkingSpaceFlag: { | |
| 59 | + type: String, | |
| 60 | + default: 'F' | |
| 61 | + }, | |
| 62 | + showSearchCondition: { | |
| 63 | + type: Boolean, | |
| 64 | + default: true | |
| 65 | + } | |
| 66 | + }, | |
| 67 | + data() { | |
| 68 | + return { | |
| 69 | + visible: false, | |
| 70 | + searchParkingSpaceInfo: { | |
| 71 | + parkingSpaces: [], | |
| 72 | + areaNum: '', | |
| 73 | + num: '', | |
| 74 | + carNum: '' | |
| 75 | + }, | |
| 76 | + parkingAreas: [], | |
| 77 | + pagination: { | |
| 78 | + currentPage: 1, | |
| 79 | + pageSize: 10, | |
| 80 | + total: 0 | |
| 81 | + } | |
| 82 | + } | |
| 83 | + }, | |
| 84 | + async created() { | |
| 85 | + await this.listParkingAreas() | |
| 86 | + }, | |
| 87 | + methods: { | |
| 88 | + open() { | |
| 89 | + this.visible = true | |
| 90 | + this.resetParkingSpaces() | |
| 91 | + this.loadAllParkingSpaceInfo() | |
| 92 | + }, | |
| 93 | + | |
| 94 | + handleClose() { | |
| 95 | + this.visible = false | |
| 96 | + }, | |
| 97 | + | |
| 98 | + async listParkingAreas() { | |
| 99 | + try { | |
| 100 | + const params = { | |
| 101 | + page: 1, | |
| 102 | + row: 50, | |
| 103 | + communityId: getCommunityId() | |
| 104 | + } | |
| 105 | + | |
| 106 | + const { data } = await listParkingAreas(params) | |
| 107 | + this.parkingAreas = data | |
| 108 | + } catch (error) { | |
| 109 | + console.error('加载停车场区域失败:', error) | |
| 110 | + } | |
| 111 | + }, | |
| 112 | + | |
| 113 | + async loadAllParkingSpaceInfo() { | |
| 114 | + try { | |
| 115 | + const params = { | |
| 116 | + page: this.pagination.currentPage, | |
| 117 | + row: this.pagination.pageSize, | |
| 118 | + communityId: getCommunityId(), | |
| 119 | + num: this.searchParkingSpaceInfo.num, | |
| 120 | + areaNum: this.searchParkingSpaceInfo.areaNum, | |
| 121 | + carNum: this.searchParkingSpaceInfo.carNum, | |
| 122 | + state: this.parkingSpaceFlag | |
| 123 | + } | |
| 124 | + | |
| 125 | + const { parkingSpaces, total } = await queryParkingSpaces(params) | |
| 126 | + this.searchParkingSpaceInfo.parkingSpaces = parkingSpaces | |
| 127 | + this.pagination.total = total | |
| 128 | + } catch (error) { | |
| 129 | + console.error('加载停车位信息失败:', error) | |
| 130 | + this.$message.error(this.$t('searchParkingSpace.loadError')) | |
| 131 | + } | |
| 132 | + }, | |
| 133 | + | |
| 134 | + chooseParkingSpace(parkingSpace) { | |
| 135 | + this.$emit('choose-parking-space', parkingSpace) | |
| 136 | + this.visible = false | |
| 137 | + }, | |
| 138 | + | |
| 139 | + searchParkingSpaces() { | |
| 140 | + this.pagination.currentPage = 1 | |
| 141 | + this.loadAllParkingSpaceInfo() | |
| 142 | + }, | |
| 143 | + | |
| 144 | + resetParkingSpaces() { | |
| 145 | + this.searchParkingSpaceInfo.carNum = '' | |
| 146 | + this.searchParkingSpaceInfo.num = '' | |
| 147 | + this.searchParkingSpaceInfo.areaNum = '' | |
| 148 | + this.pagination.currentPage = 1 | |
| 149 | + this.loadAllParkingSpaceInfo() | |
| 150 | + }, | |
| 151 | + | |
| 152 | + handleSizeChange(size) { | |
| 153 | + this.pagination.pageSize = size | |
| 154 | + this.loadAllParkingSpaceInfo() | |
| 155 | + }, | |
| 156 | + | |
| 157 | + handleCurrentChange(page) { | |
| 158 | + this.pagination.currentPage = page | |
| 159 | + this.loadAllParkingSpaceInfo() | |
| 160 | + } | |
| 161 | + } | |
| 162 | +} | |
| 163 | +</script> | |
| 164 | + | |
| 165 | +<style scoped> | |
| 166 | +.w-full { | |
| 167 | + width: 100%; | |
| 168 | +} | |
| 169 | + | |
| 170 | +.mt-20 { | |
| 171 | + margin-top: 20px; | |
| 172 | +} | |
| 173 | +</style> | |
| 0 | 174 | \ No newline at end of file | ... | ... |
src/components/car/addParkingBox.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog | |
| 3 | + :title="$t('addParkingBox.title')" | |
| 4 | + :visible.sync="visible" | |
| 5 | + width="50%" | |
| 6 | + @close="handleClose" | |
| 7 | + > | |
| 8 | + <el-form ref="form" :model="formData" label-width="120px"> | |
| 9 | + <el-form-item | |
| 10 | + :label="$t('addParkingBox.boothName')" | |
| 11 | + prop="boxName" | |
| 12 | + :rules="[ | |
| 13 | + { required: true, message: $t('addParkingBox.required') + $t('addParkingBox.boothName'), trigger: 'blur' }, | |
| 14 | + { max: 64, message: $t('addParkingBox.maxLength'), trigger: 'blur' } | |
| 15 | + ]" | |
| 16 | + > | |
| 17 | + <el-input | |
| 18 | + v-model="formData.boxName" | |
| 19 | + :placeholder="$t('addParkingBox.required') + $t('addParkingBox.boothName')" | |
| 20 | + /> | |
| 21 | + </el-form-item> | |
| 22 | + | |
| 23 | + <el-form-item | |
| 24 | + :label="$t('addParkingBox.parkingLot')" | |
| 25 | + prop="paId" | |
| 26 | + :rules="[ | |
| 27 | + { required: true, message: $t('addParkingBox.required') + $t('addParkingBox.parkingLot'), trigger: 'change' } | |
| 28 | + ]" | |
| 29 | + > | |
| 30 | + <el-select | |
| 31 | + v-model="formData.paId" | |
| 32 | + :placeholder="$t('addParkingBox.required') + $t('addParkingBox.parkingLot')" | |
| 33 | + style="width:100%" | |
| 34 | + > | |
| 35 | + <el-option | |
| 36 | + v-for="item in parkingAreas" | |
| 37 | + :key="item.paId" | |
| 38 | + :label="item.num" | |
| 39 | + :value="item.paId" | |
| 40 | + /> | |
| 41 | + </el-select> | |
| 42 | + </el-form-item> | |
| 43 | + | |
| 44 | + <el-form-item | |
| 45 | + :label="$t('addParkingBox.tempCarIn')" | |
| 46 | + prop="tempCarIn" | |
| 47 | + :rules="[ | |
| 48 | + { required: true, message: $t('addParkingBox.required') + $t('addParkingBox.tempCarIn'), trigger: 'change' } | |
| 49 | + ]" | |
| 50 | + > | |
| 51 | + <el-select | |
| 52 | + v-model="formData.tempCarIn" | |
| 53 | + :placeholder="$t('addParkingBox.required') + $t('addParkingBox.tempCarIn')" | |
| 54 | + style="width:100%" | |
| 55 | + > | |
| 56 | + <el-option value="Y" :label="$t('parkingBoxManage.yes')" /> | |
| 57 | + <el-option value="N" :label="$t('parkingBoxManage.no')" /> | |
| 58 | + </el-select> | |
| 59 | + </el-form-item> | |
| 60 | + | |
| 61 | + <el-form-item | |
| 62 | + :label="$t('addParkingBox.tempAuth')" | |
| 63 | + prop="tempAuth" | |
| 64 | + :rules="[ | |
| 65 | + { required: true, message: $t('addParkingBox.required') + $t('addParkingBox.tempAuth'), trigger: 'change' } | |
| 66 | + ]" | |
| 67 | + > | |
| 68 | + <el-select | |
| 69 | + v-model="formData.tempAuth" | |
| 70 | + :placeholder="$t('addParkingBox.required') + $t('addParkingBox.tempAuth')" | |
| 71 | + style="width:100%" | |
| 72 | + > | |
| 73 | + <el-option value="Y" :label="$t('parkingBoxManage.yes')" /> | |
| 74 | + <el-option value="N" :label="$t('parkingBoxManage.no')" /> | |
| 75 | + </el-select> | |
| 76 | + </el-form-item> | |
| 77 | + | |
| 78 | + <el-form-item | |
| 79 | + :label="$t('addParkingBox.fee')" | |
| 80 | + prop="fee" | |
| 81 | + :rules="[ | |
| 82 | + { required: true, message: $t('addParkingBox.required') + $t('addParkingBox.fee'), trigger: 'change' } | |
| 83 | + ]" | |
| 84 | + > | |
| 85 | + <el-select | |
| 86 | + v-model="formData.fee" | |
| 87 | + :placeholder="$t('addParkingBox.required') + $t('addParkingBox.fee')" | |
| 88 | + style="width:100%" | |
| 89 | + > | |
| 90 | + <el-option value="Y" :label="$t('parkingBoxManage.yes')" /> | |
| 91 | + <el-option value="N" :label="$t('parkingBoxManage.no')" /> | |
| 92 | + </el-select> | |
| 93 | + </el-form-item> | |
| 94 | + | |
| 95 | + <el-form-item | |
| 96 | + :label="$t('addParkingBox.blueCarIn')" | |
| 97 | + prop="blueCarIn" | |
| 98 | + :rules="[ | |
| 99 | + { required: true, message: $t('addParkingBox.required') + $t('addParkingBox.blueCarIn'), trigger: 'change' } | |
| 100 | + ]" | |
| 101 | + > | |
| 102 | + <el-select | |
| 103 | + v-model="formData.blueCarIn" | |
| 104 | + :placeholder="$t('addParkingBox.required') + $t('addParkingBox.blueCarIn')" | |
| 105 | + style="width:100%" | |
| 106 | + > | |
| 107 | + <el-option value="Y" :label="$t('addParkingBox.canEnter')" /> | |
| 108 | + <el-option value="N" :label="$t('addParkingBox.cannotEnter')" /> | |
| 109 | + </el-select> | |
| 110 | + </el-form-item> | |
| 111 | + | |
| 112 | + <el-form-item | |
| 113 | + :label="$t('addParkingBox.yelowCarIn')" | |
| 114 | + prop="yelowCarIn" | |
| 115 | + :rules="[ | |
| 116 | + { required: true, message: $t('addParkingBox.required') + $t('addParkingBox.yelowCarIn'), trigger: 'change' } | |
| 117 | + ]" | |
| 118 | + > | |
| 119 | + <el-select | |
| 120 | + v-model="formData.yelowCarIn" | |
| 121 | + :placeholder="$t('addParkingBox.required') + $t('addParkingBox.yelowCarIn')" | |
| 122 | + style="width:100%" | |
| 123 | + > | |
| 124 | + <el-option value="Y" :label="$t('addParkingBox.canExit')" /> | |
| 125 | + <el-option value="N" :label="$t('addParkingBox.cannotExit')" /> | |
| 126 | + </el-select> | |
| 127 | + </el-form-item> | |
| 128 | + | |
| 129 | + <el-form-item :label="$t('addParkingBox.remark')"> | |
| 130 | + <el-input | |
| 131 | + v-model="formData.remark" | |
| 132 | + type="textarea" | |
| 133 | + :placeholder="$t('addParkingBox.optional') + $t('addParkingBox.remark')" | |
| 134 | + /> | |
| 135 | + </el-form-item> | |
| 136 | + </el-form> | |
| 137 | + | |
| 138 | + <div slot="footer" class="dialog-footer"> | |
| 139 | + <el-button @click="visible = false"> | |
| 140 | + {{ $t('addParkingBox.cancel') }} | |
| 141 | + </el-button> | |
| 142 | + <el-button type="primary" @click="handleSubmit"> | |
| 143 | + {{ $t('addParkingBox.save') }} | |
| 144 | + </el-button> | |
| 145 | + </div> | |
| 146 | + </el-dialog> | |
| 147 | +</template> | |
| 148 | + | |
| 149 | +<script> | |
| 150 | +import { addParkingBox, getParkingAreaList } from '@/api/car/parkingBoxManageApi' | |
| 151 | + | |
| 152 | +export default { | |
| 153 | + name: 'AddParkingBox', | |
| 154 | + data() { | |
| 155 | + return { | |
| 156 | + visible: false, | |
| 157 | + formData: { | |
| 158 | + boxName: '', | |
| 159 | + paId: '', | |
| 160 | + tempCarIn: '', | |
| 161 | + tempAuth: '', | |
| 162 | + fee: '', | |
| 163 | + blueCarIn: '', | |
| 164 | + yelowCarIn: '', | |
| 165 | + remark: '' | |
| 166 | + }, | |
| 167 | + parkingAreas: [] | |
| 168 | + } | |
| 169 | + }, | |
| 170 | + methods: { | |
| 171 | + open() { | |
| 172 | + this.visible = true | |
| 173 | + this.loadParkingAreas() | |
| 174 | + }, | |
| 175 | + | |
| 176 | + async loadParkingAreas() { | |
| 177 | + try { | |
| 178 | + this.parkingAreas = await getParkingAreaList() | |
| 179 | + } catch (error) { | |
| 180 | + console.error('获取停车场列表失败:', error) | |
| 181 | + this.$message.error(this.$t('parkingBoxManage.fetchParkingAreaError')) | |
| 182 | + } | |
| 183 | + }, | |
| 184 | + | |
| 185 | + handleClose() { | |
| 186 | + this.$refs.form.resetFields() | |
| 187 | + this.formData = { | |
| 188 | + boxName: '', | |
| 189 | + paId: '', | |
| 190 | + tempCarIn: '', | |
| 191 | + tempAuth: '', | |
| 192 | + fee: '', | |
| 193 | + blueCarIn: '', | |
| 194 | + yelowCarIn: '', | |
| 195 | + remark: '' | |
| 196 | + } | |
| 197 | + }, | |
| 198 | + | |
| 199 | + handleSubmit() { | |
| 200 | + this.$refs.form.validate(async valid => { | |
| 201 | + if (valid) { | |
| 202 | + try { | |
| 203 | + await addParkingBox(this.formData) | |
| 204 | + this.$message.success(this.$t('parkingBoxManage.addSuccess')) | |
| 205 | + this.visible = false | |
| 206 | + this.$emit('success') | |
| 207 | + } catch (error) { | |
| 208 | + console.error('添加岗亭失败:', error) | |
| 209 | + this.$message.error(this.$t('parkingBoxManage.addError')) | |
| 210 | + } | |
| 211 | + } | |
| 212 | + }) | |
| 213 | + } | |
| 214 | + } | |
| 215 | +} | |
| 216 | +</script> | |
| 0 | 217 | \ No newline at end of file | ... | ... |
src/components/car/deleteOwnerCar.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog | |
| 3 | + :title="$t('listOwnerCar.confirmDelete')" | |
| 4 | + :visible.sync="visible" | |
| 5 | + width="500px"> | |
| 6 | + <p>{{ $t('listOwnerCar.deleteCarConfirm') }}</p> | |
| 7 | + | |
| 8 | + <div slot="footer" class="dialog-footer"> | |
| 9 | + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button> | |
| 10 | + <el-button type="danger" @click="confirmDelete" :loading="loading"> | |
| 11 | + {{ $t('common.confirm') }} | |
| 12 | + </el-button> | |
| 13 | + </div> | |
| 14 | + </el-dialog> | |
| 15 | +</template> | |
| 16 | + | |
| 17 | +<script> | |
| 18 | +import { deleteOwnerCars } from '@/api/car/listOwnerCarApi' | |
| 19 | + | |
| 20 | +export default { | |
| 21 | + name: 'DeleteOwnerCar', | |
| 22 | + data() { | |
| 23 | + return { | |
| 24 | + visible: false, | |
| 25 | + loading: false, | |
| 26 | + carInfo: null | |
| 27 | + } | |
| 28 | + }, | |
| 29 | + methods: { | |
| 30 | + open(carInfo) { | |
| 31 | + this.carInfo = carInfo | |
| 32 | + this.visible = true | |
| 33 | + }, | |
| 34 | + | |
| 35 | + async confirmDelete() { | |
| 36 | + if (!this.carInfo || !this.carInfo.carId) return | |
| 37 | + | |
| 38 | + this.loading = true | |
| 39 | + try { | |
| 40 | + await deleteOwnerCars({ carId: this.carInfo.carId }) | |
| 41 | + this.$message.success(this.$t('listOwnerCar.deleteSuccess')) | |
| 42 | + this.$emit('success') | |
| 43 | + this.visible = false | |
| 44 | + } catch (error) { | |
| 45 | + console.error('删除车辆失败:', error) | |
| 46 | + this.$message.error(error.message || this.$t('listOwnerCar.deleteError')) | |
| 47 | + } finally { | |
| 48 | + this.loading = false | |
| 49 | + } | |
| 50 | + } | |
| 51 | + } | |
| 52 | +} | |
| 53 | +</script> | |
| 0 | 54 | \ No newline at end of file | ... | ... |
src/components/car/deleteParkingBox.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog | |
| 3 | + :title="$t('deleteParkingBox.title')" | |
| 4 | + :visible.sync="visible" | |
| 5 | + width="30%" | |
| 6 | + center | |
| 7 | + > | |
| 8 | + <p>{{ $t('deleteParkingBox.confirmDelete') }}</p> | |
| 9 | + | |
| 10 | + <div slot="footer" class="dialog-footer"> | |
| 11 | + <el-button @click="visible = false"> | |
| 12 | + {{ $t('deleteParkingBox.cancel') }} | |
| 13 | + </el-button> | |
| 14 | + <el-button type="danger" @click="handleConfirm"> | |
| 15 | + {{ $t('deleteParkingBox.confirm') }} | |
| 16 | + </el-button> | |
| 17 | + </div> | |
| 18 | + </el-dialog> | |
| 19 | +</template> | |
| 20 | + | |
| 21 | +<script> | |
| 22 | +import { deleteParkingBox } from '@/api/car/parkingBoxManageApi' | |
| 23 | + | |
| 24 | +export default { | |
| 25 | + name: 'DeleteParkingBox', | |
| 26 | + data() { | |
| 27 | + return { | |
| 28 | + visible: false, | |
| 29 | + boxId: '' | |
| 30 | + } | |
| 31 | + }, | |
| 32 | + methods: { | |
| 33 | + open(row) { | |
| 34 | + this.boxId = row.boxId | |
| 35 | + this.visible = true | |
| 36 | + }, | |
| 37 | + | |
| 38 | + async handleConfirm() { | |
| 39 | + try { | |
| 40 | + await deleteParkingBox({ boxId: this.boxId }) | |
| 41 | + this.$message.success(this.$t('parkingBoxManage.deleteSuccess')) | |
| 42 | + this.visible = false | |
| 43 | + this.$emit('success') | |
| 44 | + } catch (error) { | |
| 45 | + console.error('删除岗亭失败:', error) | |
| 46 | + this.$message.error(this.$t('parkingBoxManage.deleteError')) | |
| 47 | + } | |
| 48 | + } | |
| 49 | + } | |
| 50 | +} | |
| 51 | +</script> | |
| 0 | 52 | \ No newline at end of file | ... | ... |
src/components/car/editCar.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog | |
| 3 | + :title="$t('listOwnerCar.editCar')" | |
| 4 | + :visible.sync="visible" | |
| 5 | + width="600px" | |
| 6 | + @close="resetForm"> | |
| 7 | + <el-form :model="form" label-width="120px"> | |
| 8 | + <el-form-item :label="$t('listOwnerCar.carNum')" required> | |
| 9 | + <el-input | |
| 10 | + v-model="form.carNum" | |
| 11 | + :placeholder="$t('listOwnerCar.inputCarNumRequired')" /> | |
| 12 | + </el-form-item> | |
| 13 | + | |
| 14 | + <el-form-item :label="$t('listOwnerCar.carBrand')"> | |
| 15 | + <el-input | |
| 16 | + v-model="form.carBrand" | |
| 17 | + :placeholder="$t('listOwnerCar.inputCarBrand')" /> | |
| 18 | + </el-form-item> | |
| 19 | + | |
| 20 | + <el-form-item :label="$t('listOwnerCar.carType')" required> | |
| 21 | + <el-select | |
| 22 | + v-model="form.carType" | |
| 23 | + :placeholder="$t('listOwnerCar.selectType')" | |
| 24 | + style="width: 100%"> | |
| 25 | + <el-option | |
| 26 | + v-for="item in carTypes" | |
| 27 | + :key="item.statusCd" | |
| 28 | + :label="item.name" | |
| 29 | + :value="item.statusCd" /> | |
| 30 | + </el-select> | |
| 31 | + </el-form-item> | |
| 32 | + | |
| 33 | + <el-form-item :label="$t('listOwnerCar.color')"> | |
| 34 | + <el-input | |
| 35 | + v-model="form.carColor" | |
| 36 | + :placeholder="$t('listOwnerCar.inputCarColor')" /> | |
| 37 | + </el-form-item> | |
| 38 | + | |
| 39 | + <el-form-item :label="$t('listOwnerCar.licensePlateType')" required> | |
| 40 | + <el-select | |
| 41 | + v-model="form.leaseType" | |
| 42 | + :placeholder="$t('listOwnerCar.selectLicensePlateType')" | |
| 43 | + style="width: 100%"> | |
| 44 | + <el-option value="H" :label="$t('listOwnerCar.monthlyRentCar')"></el-option> | |
| 45 | + <el-option value="S" :label="$t('listOwnerCar.soldCar')"></el-option> | |
| 46 | + <el-option value="I" :label="$t('listOwnerCar.internalCar')"></el-option> | |
| 47 | + <el-option value="NM" :label="$t('listOwnerCar.freeCar')"></el-option> | |
| 48 | + </el-select> | |
| 49 | + </el-form-item> | |
| 50 | + | |
| 51 | + <template v-if="form.leaseType === 'H' || form.leaseType === 'S'"> | |
| 52 | + <el-form-item :label="$t('listOwnerCar.startRentTime')" required> | |
| 53 | + <el-date-picker | |
| 54 | + v-model="form.startTime" | |
| 55 | + type="datetime" | |
| 56 | + :placeholder="$t('listOwnerCar.inputStartRentTime')" | |
| 57 | + style="width: 100%" | |
| 58 | + value-format="yyyy-MM-dd HH:mm:ss" /> | |
| 59 | + </el-form-item> | |
| 60 | + | |
| 61 | + <el-form-item :label="$t('listOwnerCar.endRentTime')" required> | |
| 62 | + <el-date-picker | |
| 63 | + v-model="form.endTime" | |
| 64 | + type="datetime" | |
| 65 | + :placeholder="$t('listOwnerCar.inputEndRentTime')" | |
| 66 | + style="width: 100%" | |
| 67 | + value-format="yyyy-MM-dd HH:mm:ss" | |
| 68 | + :disabledDate="disabledEndDate" /> | |
| 69 | + </el-form-item> | |
| 70 | + </template> | |
| 71 | + | |
| 72 | + <el-form-item :label="$t('listOwnerCar.remark')"> | |
| 73 | + <el-input | |
| 74 | + v-model="form.remark" | |
| 75 | + type="textarea" | |
| 76 | + :rows="3" | |
| 77 | + :placeholder="$t('listOwnerCar.inputRemark')" /> | |
| 78 | + </el-form-item> | |
| 79 | + </el-form> | |
| 80 | + | |
| 81 | + <div slot="footer" class="dialog-footer"> | |
| 82 | + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button> | |
| 83 | + <el-button type="primary" @click="submitForm" :loading="loading"> | |
| 84 | + {{ $t('common.save') }} | |
| 85 | + </el-button> | |
| 86 | + </div> | |
| 87 | + </el-dialog> | |
| 88 | +</template> | |
| 89 | + | |
| 90 | +<script> | |
| 91 | +import { editOwnerCar } from '@/api/car/listOwnerCarApi' | |
| 92 | +import { getDict } from '@/api/community/communityApi' | |
| 93 | + | |
| 94 | +export default { | |
| 95 | + name: 'EditCar', | |
| 96 | + data() { | |
| 97 | + return { | |
| 98 | + visible: false, | |
| 99 | + loading: false, | |
| 100 | + carTypes: [], | |
| 101 | + form: { | |
| 102 | + carId: '', | |
| 103 | + memberId: '', | |
| 104 | + carNum: '', | |
| 105 | + carBrand: '', | |
| 106 | + carType: '', | |
| 107 | + carColor: '', | |
| 108 | + remark: '', | |
| 109 | + startTime: '', | |
| 110 | + endTime: '', | |
| 111 | + leaseType: '' | |
| 112 | + } | |
| 113 | + } | |
| 114 | + }, | |
| 115 | + mounted() { | |
| 116 | + this.getCarTypes() | |
| 117 | + }, | |
| 118 | + methods: { | |
| 119 | + open(carInfo) { | |
| 120 | + this.form = { ...carInfo } | |
| 121 | + this.visible = true | |
| 122 | + }, | |
| 123 | + | |
| 124 | + async getCarTypes() { | |
| 125 | + try { | |
| 126 | + this.carTypes = await getDict('owner_car', 'car_type') | |
| 127 | + } catch (error) { | |
| 128 | + console.error('获取车辆类型失败:', error) | |
| 129 | + } | |
| 130 | + }, | |
| 131 | + | |
| 132 | + disabledEndDate(endTime) { | |
| 133 | + if (!this.form.startTime) return false | |
| 134 | + const startTime = new Date(this.form.startTime) | |
| 135 | + return endTime.getTime() <= startTime.getTime() | |
| 136 | + }, | |
| 137 | + | |
| 138 | + async submitForm() { | |
| 139 | + if (!this.validateForm()) return | |
| 140 | + | |
| 141 | + this.loading = true | |
| 142 | + try { | |
| 143 | + await editOwnerCar(this.form) | |
| 144 | + this.$message.success(this.$t('listOwnerCar.updateSuccess')) | |
| 145 | + this.$emit('success') | |
| 146 | + this.visible = false | |
| 147 | + } catch (error) { | |
| 148 | + console.error('更新车辆信息失败:', error) | |
| 149 | + this.$message.error(error.message || this.$t('listOwnerCar.updateError')) | |
| 150 | + } finally { | |
| 151 | + this.loading = false | |
| 152 | + } | |
| 153 | + }, | |
| 154 | + | |
| 155 | + validateForm() { | |
| 156 | + if (!this.form.carNum) { | |
| 157 | + this.$message.warning(this.$t('listOwnerCar.inputCarNumRequired')) | |
| 158 | + return false | |
| 159 | + } | |
| 160 | + | |
| 161 | + if (!this.form.carType) { | |
| 162 | + this.$message.warning(this.$t('listOwnerCar.selectTypeRequired')) | |
| 163 | + return false | |
| 164 | + } | |
| 165 | + | |
| 166 | + if (!this.form.leaseType) { | |
| 167 | + this.$message.warning(this.$t('listOwnerCar.selectLicensePlateTypeRequired')) | |
| 168 | + return false | |
| 169 | + } | |
| 170 | + | |
| 171 | + if ((this.form.leaseType === 'H' || this.form.leaseType === 'S') && | |
| 172 | + (!this.form.startTime || !this.form.endTime)) { | |
| 173 | + this.$message.warning(this.$t('listOwnerCar.rentTimeRequired')) | |
| 174 | + return false | |
| 175 | + } | |
| 176 | + | |
| 177 | + if (this.form.startTime && this.form.endTime) { | |
| 178 | + const start = new Date(this.form.startTime) | |
| 179 | + const end = new Date(this.form.endTime) | |
| 180 | + if (start >= end) { | |
| 181 | + this.$message.warning(this.$t('listOwnerCar.endTimeAfterStart')) | |
| 182 | + return false | |
| 183 | + } | |
| 184 | + } | |
| 185 | + | |
| 186 | + return true | |
| 187 | + }, | |
| 188 | + | |
| 189 | + resetForm() { | |
| 190 | + this.form = { | |
| 191 | + carId: '', | |
| 192 | + memberId: '', | |
| 193 | + carNum: '', | |
| 194 | + carBrand: '', | |
| 195 | + carType: '', | |
| 196 | + carColor: '', | |
| 197 | + remark: '', | |
| 198 | + startTime: '', | |
| 199 | + endTime: '', | |
| 200 | + leaseType: '' | |
| 201 | + } | |
| 202 | + } | |
| 203 | + } | |
| 204 | +} | |
| 205 | +</script> | |
| 0 | 206 | \ No newline at end of file | ... | ... |
src/components/car/editParkingBox.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog | |
| 3 | + :title="$t('editParkingBox.title')" | |
| 4 | + :visible.sync="visible" | |
| 5 | + width="50%" | |
| 6 | + @close="handleClose" | |
| 7 | + > | |
| 8 | + <el-form ref="form" :model="formData" label-width="120px"> | |
| 9 | + <el-form-item | |
| 10 | + :label="$t('editParkingBox.boothName')" | |
| 11 | + prop="boxName" | |
| 12 | + :rules="[ | |
| 13 | + { required: true, message: $t('editParkingBox.required') + $t('editParkingBox.boothName'), trigger: 'blur' }, | |
| 14 | + { max: 64, message: $t('editParkingBox.maxLength'), trigger: 'blur' } | |
| 15 | + ]" | |
| 16 | + > | |
| 17 | + <el-input | |
| 18 | + v-model="formData.boxName" | |
| 19 | + :placeholder="$t('editParkingBox.required') + $t('editParkingBox.boothName')" | |
| 20 | + /> | |
| 21 | + </el-form-item> | |
| 22 | + | |
| 23 | + <el-form-item | |
| 24 | + :label="$t('editParkingBox.parkingLot')" | |
| 25 | + prop="paId" | |
| 26 | + :rules="[ | |
| 27 | + { required: true, message: $t('editParkingBox.required') + $t('editParkingBox.parkingLot'), trigger: 'change' } | |
| 28 | + ]" | |
| 29 | + > | |
| 30 | + <el-select | |
| 31 | + v-model="formData.paId" | |
| 32 | + :placeholder="$t('editParkingBox.required') + $t('editParkingBox.parkingLot')" | |
| 33 | + style="width:100%" | |
| 34 | + > | |
| 35 | + <el-option | |
| 36 | + v-for="item in parkingAreas" | |
| 37 | + :key="item.paId" | |
| 38 | + :label="item.num" | |
| 39 | + :value="item.paId" | |
| 40 | + /> | |
| 41 | + </el-select> | |
| 42 | + </el-form-item> | |
| 43 | + | |
| 44 | + <el-form-item | |
| 45 | + :label="$t('editParkingBox.tempCarIn')" | |
| 46 | + prop="tempCarIn" | |
| 47 | + :rules="[ | |
| 48 | + { required: true, message: $t('editParkingBox.required') + $t('editParkingBox.tempCarIn'), trigger: 'change' } | |
| 49 | + ]" | |
| 50 | + > | |
| 51 | + <el-select | |
| 52 | + v-model="formData.tempCarIn" | |
| 53 | + :placeholder="$t('editParkingBox.required') + $t('editParkingBox.tempCarIn')" | |
| 54 | + style="width:100%" | |
| 55 | + > | |
| 56 | + <el-option value="Y" :label="$t('parkingBoxManage.yes')" /> | |
| 57 | + <el-option value="N" :label="$t('parkingBoxManage.no')" /> | |
| 58 | + </el-select> | |
| 59 | + </el-form-item> | |
| 60 | + | |
| 61 | + <el-form-item | |
| 62 | + :label="$t('editParkingBox.tempAuth')" | |
| 63 | + prop="tempAuth" | |
| 64 | + :rules="[ | |
| 65 | + { required: true, message: $t('editParkingBox.required') + $t('editParkingBox.tempAuth'), trigger: 'change' } | |
| 66 | + ]" | |
| 67 | + > | |
| 68 | + <el-select | |
| 69 | + v-model="formData.tempAuth" | |
| 70 | + :placeholder="$t('editParkingBox.required') + $t('editParkingBox.tempAuth')" | |
| 71 | + style="width:100%" | |
| 72 | + > | |
| 73 | + <el-option value="Y" :label="$t('parkingBoxManage.yes')" /> | |
| 74 | + <el-option value="N" :label="$t('parkingBoxManage.no')" /> | |
| 75 | + </el-select> | |
| 76 | + </el-form-item> | |
| 77 | + | |
| 78 | + <el-form-item | |
| 79 | + :label="$t('editParkingBox.fee')" | |
| 80 | + prop="fee" | |
| 81 | + :rules="[ | |
| 82 | + { required: true, message: $t('editParkingBox.required') + $t('editParkingBox.fee'), trigger: 'change' } | |
| 83 | + ]" | |
| 84 | + > | |
| 85 | + <el-select | |
| 86 | + v-model="formData.fee" | |
| 87 | + :placeholder="$t('editParkingBox.required') + $t('editParkingBox.fee')" | |
| 88 | + style="width:100%" | |
| 89 | + > | |
| 90 | + <el-option value="Y" :label="$t('parkingBoxManage.yes')" /> | |
| 91 | + <el-option value="N" :label="$t('parkingBoxManage.no')" /> | |
| 92 | + </el-select> | |
| 93 | + </el-form-item> | |
| 94 | + | |
| 95 | + <el-form-item | |
| 96 | + :label="$t('editParkingBox.blueCarIn')" | |
| 97 | + prop="blueCarIn" | |
| 98 | + :rules="[ | |
| 99 | + { required: true, message: $t('editParkingBox.required') + $t('editParkingBox.blueCarIn'), trigger: 'change' } | |
| 100 | + ]" | |
| 101 | + > | |
| 102 | + <el-select | |
| 103 | + v-model="formData.blueCarIn" | |
| 104 | + :placeholder="$t('editParkingBox.required') + $t('editParkingBox.blueCarIn')" | |
| 105 | + style="width:100%" | |
| 106 | + > | |
| 107 | + <el-option value="Y" :label="$t('editParkingBox.canEnter')" /> | |
| 108 | + <el-option value="N" :label="$t('editParkingBox.cannotEnter')" /> | |
| 109 | + </el-select> | |
| 110 | + </el-form-item> | |
| 111 | + | |
| 112 | + <el-form-item | |
| 113 | + :label="$t('editParkingBox.yelowCarIn')" | |
| 114 | + prop="yelowCarIn" | |
| 115 | + :rules="[ | |
| 116 | + { required: true, message: $t('editParkingBox.required') + $t('editParkingBox.yelowCarIn'), trigger: 'change' } | |
| 117 | + ]" | |
| 118 | + > | |
| 119 | + <el-select | |
| 120 | + v-model="formData.yelowCarIn" | |
| 121 | + :placeholder="$t('editParkingBox.required') + $t('editParkingBox.yelowCarIn')" | |
| 122 | + style="width:100%" | |
| 123 | + > | |
| 124 | + <el-option value="Y" :label="$t('editParkingBox.canExit')" /> | |
| 125 | + <el-option value="N" :label="$t('editParkingBox.cannotExit')" /> | |
| 126 | + </el-select> | |
| 127 | + </el-form-item> | |
| 128 | + | |
| 129 | + <el-form-item :label="$t('editParkingBox.remark')"> | |
| 130 | + <el-input | |
| 131 | + v-model="formData.remark" | |
| 132 | + type="textarea" | |
| 133 | + :placeholder="$t('editParkingBox.optional') + $t('editParkingBox.remark')" | |
| 134 | + /> | |
| 135 | + </el-form-item> | |
| 136 | + </el-form> | |
| 137 | + | |
| 138 | + <div slot="footer" class="dialog-footer"> | |
| 139 | + <el-button @click="visible = false"> | |
| 140 | + {{ $t('editParkingBox.cancel') }} | |
| 141 | + </el-button> | |
| 142 | + <el-button type="primary" @click="handleSubmit"> | |
| 143 | + {{ $t('editParkingBox.save') }} | |
| 144 | + </el-button> | |
| 145 | + </div> | |
| 146 | + </el-dialog> | |
| 147 | +</template> | |
| 148 | + | |
| 149 | +<script> | |
| 150 | +import { updateParkingBox, getParkingAreaList } from '@/api/car/parkingBoxManageApi' | |
| 151 | + | |
| 152 | +export default { | |
| 153 | + name: 'EditParkingBox', | |
| 154 | + data() { | |
| 155 | + return { | |
| 156 | + visible: false, | |
| 157 | + formData: { | |
| 158 | + boxId: '', | |
| 159 | + boxName: '', | |
| 160 | + paId: '', | |
| 161 | + tempCarIn: '', | |
| 162 | + tempAuth: '', | |
| 163 | + fee: '', | |
| 164 | + blueCarIn: '', | |
| 165 | + yelowCarIn: '', | |
| 166 | + remark: '' | |
| 167 | + }, | |
| 168 | + parkingAreas: [] | |
| 169 | + } | |
| 170 | + }, | |
| 171 | + methods: { | |
| 172 | + open(row) { | |
| 173 | + this.formData = { ...row } | |
| 174 | + this.visible = true | |
| 175 | + this.loadParkingAreas() | |
| 176 | + }, | |
| 177 | + | |
| 178 | + async loadParkingAreas() { | |
| 179 | + try { | |
| 180 | + this.parkingAreas = await getParkingAreaList() | |
| 181 | + } catch (error) { | |
| 182 | + console.error('获取停车场列表失败:', error) | |
| 183 | + this.$message.error(this.$t('parkingBoxManage.fetchParkingAreaError')) | |
| 184 | + } | |
| 185 | + }, | |
| 186 | + | |
| 187 | + handleClose() { | |
| 188 | + this.$refs.form.resetFields() | |
| 189 | + }, | |
| 190 | + | |
| 191 | + handleSubmit() { | |
| 192 | + this.$refs.form.validate(async valid => { | |
| 193 | + if (valid) { | |
| 194 | + try { | |
| 195 | + await updateParkingBox(this.formData) | |
| 196 | + this.$message.success(this.$t('parkingBoxManage.updateSuccess')) | |
| 197 | + this.visible = false | |
| 198 | + this.$emit('success') | |
| 199 | + } catch (error) { | |
| 200 | + console.error('更新岗亭失败:', error) | |
| 201 | + this.$message.error(this.$t('parkingBoxManage.updateError')) | |
| 202 | + } | |
| 203 | + } | |
| 204 | + }) | |
| 205 | + } | |
| 206 | + } | |
| 207 | +} | |
| 208 | +</script> | |
| 0 | 209 | \ No newline at end of file | ... | ... |
src/components/car/importOwnerCar.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog :title="$t('listOwnerCar.importCarTitle')" :visible.sync="visible" width="600px" @close="resetForm"> | |
| 3 | + <el-form :model="form" label-width="120px"> | |
| 4 | + <el-form-item :label="$t('listOwnerCar.selectFile')"> | |
| 5 | + <el-upload class="upload-demo" action="" :on-change="handleFileChange" :auto-upload="false" | |
| 6 | + :show-file-list="false"> | |
| 7 | + <el-button size="small" type="primary">{{ $t('listOwnerCar.selectFile') }}</el-button> | |
| 8 | + <div slot="tip" class="el-upload__tip"> | |
| 9 | + {{ fileName || $t('listOwnerCar.fileRequired') }} | |
| 10 | + </div> | |
| 11 | + </el-upload> | |
| 12 | + </el-form-item> | |
| 13 | + | |
| 14 | + <el-form-item :label="$t('listOwnerCar.downloadTemplate')"> | |
| 15 | + <div> | |
| 16 | + {{ $t('listOwnerCar.downloadFirst') }} | |
| 17 | + <el-link type="primary" href="/import/importCar.xlsx" target="_blank"> | |
| 18 | + {{ $t('listOwnerCar.importTemplate') }} | |
| 19 | + </el-link> | |
| 20 | + <span>{{ $t('listOwnerCar.prepareData') }}</span> | |
| 21 | + </div> | |
| 22 | + </el-form-item> | |
| 23 | + </el-form> | |
| 24 | + | |
| 25 | + <div slot="footer" class="dialog-footer"> | |
| 26 | + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button> | |
| 27 | + <el-button type="primary" @click="importData" :loading="loading"> | |
| 28 | + {{ $t('listOwnerCar.import') }} | |
| 29 | + </el-button> | |
| 30 | + </div> | |
| 31 | + </el-dialog> | |
| 32 | +</template> | |
| 33 | + | |
| 34 | +<script> | |
| 35 | +import { importData } from '@/api/car/listOwnerCarApi' | |
| 36 | + | |
| 37 | +export default { | |
| 38 | + name: 'ImportOwnerCar', | |
| 39 | + data() { | |
| 40 | + return { | |
| 41 | + visible: false, | |
| 42 | + loading: false, | |
| 43 | + file: null, | |
| 44 | + fileName: '' | |
| 45 | + } | |
| 46 | + }, | |
| 47 | + methods: { | |
| 48 | + open() { | |
| 49 | + this.visible = true | |
| 50 | + }, | |
| 51 | + | |
| 52 | + handleFileChange(file) { | |
| 53 | + this.file = file.raw | |
| 54 | + this.fileName = file.name | |
| 55 | + }, | |
| 56 | + | |
| 57 | + async importData() { | |
| 58 | + if (!this.file) { | |
| 59 | + this.$message.warning(this.$t('listOwnerCar.fileRequired')) | |
| 60 | + return | |
| 61 | + } | |
| 62 | + | |
| 63 | + if (!this.checkFileType(this.fileName)) { | |
| 64 | + this.$message.warning(this.$t('listOwnerCar.invalidExcel')) | |
| 65 | + return | |
| 66 | + } | |
| 67 | + | |
| 68 | + if (!this.checkFileSize(this.file.size)) { | |
| 69 | + this.$message.warning(this.$t('listOwnerCar.fileSizeExceed')) | |
| 70 | + return | |
| 71 | + } | |
| 72 | + | |
| 73 | + this.loading = true | |
| 74 | + try { | |
| 75 | + const response = await importData({ | |
| 76 | + file: this.file, | |
| 77 | + importAdapt: 'importOwnerCar' | |
| 78 | + }) | |
| 79 | + | |
| 80 | + this.$message.success(this.$t('listOwnerCar.importSuccess')) | |
| 81 | + this.$emit('success') | |
| 82 | + this.visible = false | |
| 83 | + this.$router.push(`/pages/property/assetImportLogDetail?logId=${response.data.logId}&logType=importOwnerCar`) | |
| 84 | + } catch (error) { | |
| 85 | + console.error('导入失败:', error) | |
| 86 | + this.$message.error(error.message || this.$t('listOwnerCar.importError')) | |
| 87 | + } finally { | |
| 88 | + this.loading = false | |
| 89 | + } | |
| 90 | + }, | |
| 91 | + | |
| 92 | + checkFileType(fileName) { | |
| 93 | + const ext = fileName.split('.').pop().toLowerCase() | |
| 94 | + return ['xlsx', 'xls'].includes(ext) | |
| 95 | + }, | |
| 96 | + | |
| 97 | + checkFileSize(size) { | |
| 98 | + const maxSize = 2 * 1024 * 1024 // 2MB | |
| 99 | + return size <= maxSize | |
| 100 | + }, | |
| 101 | + | |
| 102 | + resetForm() { | |
| 103 | + this.file = null | |
| 104 | + this.fileName = '' | |
| 105 | + } | |
| 106 | + } | |
| 107 | +} | |
| 108 | +</script> | |
| 0 | 109 | \ No newline at end of file | ... | ... |
src/i18n/commonLang.js
| ... | ... | @@ -43,6 +43,7 @@ export const messages = { |
| 43 | 43 | remark: 'Remark', |
| 44 | 44 | hour:'hour', |
| 45 | 45 | more:'More', |
| 46 | + tip:'Tip', | |
| 46 | 47 | } |
| 47 | 48 | }, |
| 48 | 49 | zh: { |
| ... | ... | @@ -89,6 +90,8 @@ export const messages = { |
| 89 | 90 | remark: '备注', |
| 90 | 91 | hour:'时', |
| 91 | 92 | more:'更多', |
| 93 | + tip:'提示', | |
| 94 | + | |
| 92 | 95 | } |
| 93 | 96 | } |
| 94 | 97 | } |
| 95 | 98 | \ No newline at end of file | ... | ... |
src/i18n/index.js
| ... | ... | @@ -146,6 +146,11 @@ import { messages as invoiceApplyDetailMessages } from '../views/fee/invoiceAppl |
| 146 | 146 | import { messages as feeConfigDetailMessages } from '../views/fee/feeConfigDetailLang' |
| 147 | 147 | import { messages as parkingAreaManageMessages } from '../views/car/parkingAreaManageLang' |
| 148 | 148 | import { messages as listParkingSpaceMessages } from '../views/car/listParkingSpaceLang' |
| 149 | +import { messages as parkingBoxManageMessages } from '../views/car/parkingBoxManageLang' | |
| 150 | +import { messages as listOwnerCarMessages } from '../views/car/listOwnerCarLang' | |
| 151 | +import { messages as hireParkingSpaceMessages } from '../views/car/hireParkingSpaceLang' | |
| 152 | +import { messages as carAddParkingSpaceMessages } from '../views/car/carAddParkingSpaceLang' | |
| 153 | +import { messages as buyCarMonthCardMessages } from '../views/fee/buyCarMonthCardLang' | |
| 149 | 154 | |
| 150 | 155 | Vue.use(VueI18n) |
| 151 | 156 | |
| ... | ... | @@ -296,6 +301,11 @@ const messages = { |
| 296 | 301 | ...feeConfigDetailMessages.en, |
| 297 | 302 | ...parkingAreaManageMessages.en, |
| 298 | 303 | ...listParkingSpaceMessages.en, |
| 304 | + ...parkingBoxManageMessages.en, | |
| 305 | + ...listOwnerCarMessages.en, | |
| 306 | + ...hireParkingSpaceMessages.en, | |
| 307 | + ...carAddParkingSpaceMessages.en, | |
| 308 | + ...buyCarMonthCardMessages.en, | |
| 299 | 309 | }, |
| 300 | 310 | zh: { |
| 301 | 311 | ...loginMessages.zh, |
| ... | ... | @@ -442,6 +452,11 @@ const messages = { |
| 442 | 452 | ...feeConfigDetailMessages.zh, |
| 443 | 453 | ...parkingAreaManageMessages.zh, |
| 444 | 454 | ...listParkingSpaceMessages.zh, |
| 455 | + ...parkingBoxManageMessages.zh, | |
| 456 | + ...listOwnerCarMessages.zh, | |
| 457 | + ...hireParkingSpaceMessages.zh, | |
| 458 | + ...carAddParkingSpaceMessages.zh, | |
| 459 | + ...buyCarMonthCardMessages.zh, | |
| 445 | 460 | } |
| 446 | 461 | } |
| 447 | 462 | ... | ... |
src/router/index.js
| ... | ... | @@ -717,15 +717,40 @@ const routes = [ |
| 717 | 717 | component: () => import('@/views/fee/feeConfigDetailList.vue') |
| 718 | 718 | }, |
| 719 | 719 | { |
| 720 | - path:'/pages/property/parkingAreaManage', | |
| 721 | - name:'/pages/property/parkingAreaManage', | |
| 720 | + path: '/pages/property/parkingAreaManage', | |
| 721 | + name: '/pages/property/parkingAreaManage', | |
| 722 | 722 | component: () => import('@/views/car/parkingAreaManageList.vue') |
| 723 | - }, | |
| 724 | - { | |
| 725 | - path:'/pages/property/listParkingSpace', | |
| 726 | - name:'/pages/property/listParkingSpace', | |
| 727 | - component: () => import('@/views/car/listParkingSpaceList.vue') | |
| 728 | - }, | |
| 723 | + }, | |
| 724 | + { | |
| 725 | + path: '/pages/property/listParkingSpace', | |
| 726 | + name: '/pages/property/listParkingSpace', | |
| 727 | + component: () => import('@/views/car/listParkingSpaceList.vue') | |
| 728 | + }, | |
| 729 | + { | |
| 730 | + path: '/pages/property/parkingBoxManage', | |
| 731 | + name: '/pages/property/parkingBoxManage', | |
| 732 | + component: () => import('@/views/car/parkingBoxManageList.vue') | |
| 733 | + }, | |
| 734 | + { | |
| 735 | + path: '/pages/property/listOwnerCar', | |
| 736 | + name: '/pages/property/listOwnerCar', | |
| 737 | + component: () => import('@/views/car/listOwnerCarList.vue') | |
| 738 | + }, | |
| 739 | + { | |
| 740 | + path: '/views/car/hireParkingSpace', | |
| 741 | + name: '/views/car/hireParkingSpace', | |
| 742 | + component: () => import('@/views/car/hireParkingSpaceList.vue') | |
| 743 | + }, | |
| 744 | + { | |
| 745 | + path: '/views/car/carAddParkingSpace', | |
| 746 | + name: '/views/car/carAddParkingSpace', | |
| 747 | + component: () => import('@/views/car/carAddParkingSpaceList.vue') | |
| 748 | + }, | |
| 749 | + { | |
| 750 | + path: '/views/fee/buyCarMonthCard', | |
| 751 | + name: '/views/fee/buyCarMonthCard', | |
| 752 | + component: () => import('@/views/fee/buyCarMonthCardList.vue') | |
| 753 | + }, | |
| 729 | 754 | // 其他子路由可以在这里添加 |
| 730 | 755 | ] |
| 731 | 756 | }, | ... | ... |
src/views/car/carAddParkingSpaceLang.js
0 → 100644
| 1 | +export const messages = { | |
| 2 | + en: { | |
| 3 | + carAddParkingSpace: { | |
| 4 | + vehicleInfo: 'Vehicle Information', | |
| 5 | + licensePlate: 'License Plate', | |
| 6 | + requiredLicensePlate: 'Required, please fill in the license plate', | |
| 7 | + startTime: 'Start Time', | |
| 8 | + requiredStartTime: 'Required, please fill in the start time', | |
| 9 | + endTime: 'End Time', | |
| 10 | + requiredEndTime: 'Required, please fill in the end time', | |
| 11 | + remark: 'Remark', | |
| 12 | + remarkPlaceholder: 'Please fill in remarks', | |
| 13 | + submit: 'Submit', | |
| 14 | + parkingSpaceInfo: 'Parking Space Information', | |
| 15 | + parkingSpaceId: 'Parking Space ID', | |
| 16 | + number: 'Number', | |
| 17 | + parkingLot: 'Parking Lot', | |
| 18 | + parkingSpaceStatus: 'Parking Space Status', | |
| 19 | + area: 'Area', | |
| 20 | + squareMeters: 'square meters', | |
| 21 | + remarks: 'Remarks', | |
| 22 | + selectParkingSpace: 'Select Parking Space', | |
| 23 | + search: 'Search', | |
| 24 | + reset: 'Reset', | |
| 25 | + parkingLotCode: 'Parking Lot Code', | |
| 26 | + parkingSpaceCode: 'Parking Space Code', | |
| 27 | + parkingLotType: 'Parking Lot Type', | |
| 28 | + parkingSpaceType: 'Parking Space Type', | |
| 29 | + operation: 'Operation', | |
| 30 | + select: 'Select', | |
| 31 | + aboveGround: 'Above Ground', | |
| 32 | + underground: 'Underground', | |
| 33 | + free: 'Free', | |
| 34 | + sold: 'Sold', | |
| 35 | + rented: 'Rented', | |
| 36 | + unknown: 'Unknown' | |
| 37 | + } | |
| 38 | + }, | |
| 39 | + zh: { | |
| 40 | + carAddParkingSpace: { | |
| 41 | + vehicleInfo: '车辆信息', | |
| 42 | + licensePlate: '车牌号', | |
| 43 | + requiredLicensePlate: '必填,请填写车牌号', | |
| 44 | + startTime: '起租时间', | |
| 45 | + requiredStartTime: '必填,请填写起租时间', | |
| 46 | + endTime: '结租时间', | |
| 47 | + requiredEndTime: '必填,请填写结租时间', | |
| 48 | + remark: '备注', | |
| 49 | + remarkPlaceholder: '请填写备注信息', | |
| 50 | + submit: '提交', | |
| 51 | + parkingSpaceInfo: '停车位信息', | |
| 52 | + parkingSpaceId: '车位ID', | |
| 53 | + number: '编号', | |
| 54 | + parkingLot: '停车场', | |
| 55 | + parkingSpaceStatus: '车位状态', | |
| 56 | + area: '面积', | |
| 57 | + squareMeters: '平方米', | |
| 58 | + remarks: '备注', | |
| 59 | + selectParkingSpace: '选择车位', | |
| 60 | + search: '查询', | |
| 61 | + reset: '重置', | |
| 62 | + parkingLotCode: '停车场编码', | |
| 63 | + parkingSpaceCode: '停车位编码', | |
| 64 | + parkingLotType: '停车场类型', | |
| 65 | + parkingSpaceType: '车位类型', | |
| 66 | + operation: '操作', | |
| 67 | + select: '选择', | |
| 68 | + aboveGround: '地上停车位', | |
| 69 | + underground: '地下停车位', | |
| 70 | + free: '空闲', | |
| 71 | + sold: '已售卖', | |
| 72 | + rented: '已出租', | |
| 73 | + unknown: '未知' | |
| 74 | + } | |
| 75 | + } | |
| 76 | +} | |
| 0 | 77 | \ No newline at end of file | ... | ... |
src/views/car/carAddParkingSpaceList.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div class="app-container"> | |
| 3 | + <el-row :gutter="20"> | |
| 4 | + <el-col :span="24"> | |
| 5 | + <el-card> | |
| 6 | + <div slot="header"> | |
| 7 | + <span>{{ $t('carAddParkingSpace.vehicleInfo') }}</span> | |
| 8 | + </div> | |
| 9 | + <div> | |
| 10 | + <el-form label-width="120px"> | |
| 11 | + <el-row :gutter="20"> | |
| 12 | + <el-col :span="12"> | |
| 13 | + <el-form-item :label="$t('hireParkingSpace.parkingSpace')" prop="psName" required> | |
| 14 | + <el-input v-model="carAddParkingSpaceInfo.psName" disabled style="width: 80%;" | |
| 15 | + :placeholder="$t('hireParkingSpace.parkingSpacePlaceholder')" /> | |
| 16 | + <el-button type="primary" size="small" class="margin-left" @click="openSearchParkingSpaceModel"> | |
| 17 | + {{ $t('common.select') }} | |
| 18 | + </el-button> | |
| 19 | + </el-form-item> | |
| 20 | + </el-col> | |
| 21 | + <el-col :span="12"> | |
| 22 | + <el-form-item :label="$t('carAddParkingSpace.licensePlate')"> | |
| 23 | + <el-input v-model.trim="carAddParkingSpaceInfo.carNum" | |
| 24 | + :placeholder="$t('carAddParkingSpace.requiredLicensePlate')" disabled /> | |
| 25 | + </el-form-item> | |
| 26 | + </el-col> | |
| 27 | + </el-row> | |
| 28 | + | |
| 29 | + <el-row :gutter="20"> | |
| 30 | + <el-col :span="12"> | |
| 31 | + <el-form-item :label="$t('carAddParkingSpace.startTime')"> | |
| 32 | + <el-date-picker v-model="carAddParkingSpaceInfo.startTime" style="width: 100%;" type="date" | |
| 33 | + :placeholder="$t('carAddParkingSpace.requiredStartTime')" value-format="yyyy-MM-dd" /> | |
| 34 | + </el-form-item> | |
| 35 | + </el-col> | |
| 36 | + <el-col :span="12"> | |
| 37 | + <el-form-item :label="$t('carAddParkingSpace.endTime')"> | |
| 38 | + <el-date-picker v-model="carAddParkingSpaceInfo.endTime" style="width: 100%;" type="date" | |
| 39 | + :placeholder="$t('carAddParkingSpace.requiredEndTime')" value-format="yyyy-MM-dd" /> | |
| 40 | + </el-form-item> | |
| 41 | + </el-col> | |
| 42 | + </el-row> | |
| 43 | + | |
| 44 | + <el-row :gutter="20"> | |
| 45 | + <el-col :span="24"> | |
| 46 | + <el-form-item :label="$t('carAddParkingSpace.remark')"> | |
| 47 | + <el-input v-model.trim="carAddParkingSpaceInfo.remark" type="textarea" | |
| 48 | + :placeholder="$t('carAddParkingSpace.remarkPlaceholder')" rows="3" /> | |
| 49 | + </el-form-item> | |
| 50 | + </el-col> | |
| 51 | + </el-row> | |
| 52 | + </el-form> | |
| 53 | + </div> | |
| 54 | + </el-card> | |
| 55 | + </el-col> | |
| 56 | + </el-row> | |
| 57 | + | |
| 58 | + <el-row :gutter="20"> | |
| 59 | + <el-col :span="24" style="text-align: right; margin-top: 20px;"> | |
| 60 | + <el-button type="primary" @click="submitForm"> | |
| 61 | + {{ $t('carAddParkingSpace.submit') }} | |
| 62 | + </el-button> | |
| 63 | + </el-col> | |
| 64 | + </el-row> | |
| 65 | + <search-parking-space ref="searchParkingSpace" @choose-parking-space="handleChooseParkingSpace" /> | |
| 66 | + </div> | |
| 67 | +</template> | |
| 68 | + | |
| 69 | +<script> | |
| 70 | +import { getCarInfo, addCarParkingSpace } from '@/api/car/carAddParkingSpaceApi' | |
| 71 | +import SearchParkingSpace from '@/components/car/SearchParkingSpace' | |
| 72 | + | |
| 73 | +export default { | |
| 74 | + name: 'CarAddParkingSpaceList', | |
| 75 | + components: { | |
| 76 | + SearchParkingSpace | |
| 77 | + }, | |
| 78 | + data() { | |
| 79 | + return { | |
| 80 | + callBackComponent: 'carAddParkingSpace', | |
| 81 | + callBackFunction: 'notify', | |
| 82 | + carAddParkingSpaceInfo: { | |
| 83 | + carNum: '', | |
| 84 | + remark: '', | |
| 85 | + startTime: '', | |
| 86 | + endTime: '', | |
| 87 | + carId: '', | |
| 88 | + psId: '', | |
| 89 | + psName: '', | |
| 90 | + memberId: '' | |
| 91 | + } | |
| 92 | + } | |
| 93 | + }, | |
| 94 | + created() { | |
| 95 | + this.carAddParkingSpaceInfo.carId = this.$route.query.carId | |
| 96 | + this.loadCarInfo() | |
| 97 | + }, | |
| 98 | + methods: { | |
| 99 | + async loadCarInfo() { | |
| 100 | + try { | |
| 101 | + const params = { | |
| 102 | + page: 1, | |
| 103 | + row: 1, | |
| 104 | + carId: this.carAddParkingSpaceInfo.carId | |
| 105 | + } | |
| 106 | + | |
| 107 | + const res = await getCarInfo(params) | |
| 108 | + if (res.code === 0 && res.data.length > 0) { | |
| 109 | + const carData = res.data[0] | |
| 110 | + this.carAddParkingSpaceInfo = { | |
| 111 | + ...this.carAddParkingSpaceInfo, | |
| 112 | + carNum: carData.carNum || '', | |
| 113 | + psId: carData.psId || '' | |
| 114 | + } | |
| 115 | + this.$refs.viewSelectParkingSpace.handleShowParkingSpace(carData) | |
| 116 | + } | |
| 117 | + } catch (error) { | |
| 118 | + console.error('Failed to load car info:', error) | |
| 119 | + } | |
| 120 | + }, | |
| 121 | + handleParkingSpaceSelected(info) { | |
| 122 | + this.carAddParkingSpaceInfo.psId = info.psId | |
| 123 | + }, | |
| 124 | + validateForm() { | |
| 125 | + if (!this.carAddParkingSpaceInfo.carNum) { | |
| 126 | + this.$message.error(this.$t('carAddParkingSpace.requiredLicensePlate')) | |
| 127 | + return false | |
| 128 | + } | |
| 129 | + if (!this.carAddParkingSpaceInfo.startTime) { | |
| 130 | + this.$message.error(this.$t('carAddParkingSpace.requiredStartTime')) | |
| 131 | + return false | |
| 132 | + } | |
| 133 | + if (!this.carAddParkingSpaceInfo.endTime) { | |
| 134 | + this.$message.error(this.$t('carAddParkingSpace.requiredEndTime')) | |
| 135 | + return false | |
| 136 | + } | |
| 137 | + if (!this.carAddParkingSpaceInfo.psId) { | |
| 138 | + this.$message.error(this.$t('carAddParkingSpace.parkingSpaceRequired')) | |
| 139 | + return false | |
| 140 | + } | |
| 141 | + | |
| 142 | + const start = new Date(this.carAddParkingSpaceInfo.startTime) | |
| 143 | + const end = new Date(this.carAddParkingSpaceInfo.endTime) | |
| 144 | + if (start >= end) { | |
| 145 | + this.$message.error(this.$t('carAddParkingSpace.endTimeAfterStart')) | |
| 146 | + return false | |
| 147 | + } | |
| 148 | + | |
| 149 | + return true | |
| 150 | + }, | |
| 151 | + async submitForm() { | |
| 152 | + if (!this.validateForm()) return | |
| 153 | + | |
| 154 | + try { | |
| 155 | + const data = { | |
| 156 | + ...this.carAddParkingSpaceInfo, | |
| 157 | + memberId: this.carId | |
| 158 | + } | |
| 159 | + | |
| 160 | + const res = await addCarParkingSpace(data) | |
| 161 | + if (res.code === 0) { | |
| 162 | + this.$message.success(this.$t('carAddParkingSpace.submitSuccess')) | |
| 163 | + this.$router.go(-1) | |
| 164 | + } else { | |
| 165 | + this.$message.error(res.msg || this.$t('carAddParkingSpace.submitFailed')) | |
| 166 | + } | |
| 167 | + } catch (error) { | |
| 168 | + console.error('Submit failed:', error) | |
| 169 | + this.$message.error(this.$t('carAddParkingSpace.submitFailed')) | |
| 170 | + } | |
| 171 | + }, | |
| 172 | + openSearchParkingSpaceModel() { | |
| 173 | + this.$refs.searchParkingSpace.open() | |
| 174 | + }, | |
| 175 | + handleChooseParkingSpace(parkingSpace) { | |
| 176 | + this.carAddParkingSpaceInfo.psName = `${parkingSpace.areaNum}-${parkingSpace.num}` | |
| 177 | + this.carAddParkingSpaceInfo.psId = parkingSpace.psId | |
| 178 | + } | |
| 179 | + } | |
| 180 | +} | |
| 181 | +</script> | |
| 182 | + | |
| 183 | +<style scoped> | |
| 184 | +.app-container { | |
| 185 | + padding: 20px; | |
| 186 | +} | |
| 187 | + | |
| 188 | +.el-row { | |
| 189 | + margin-bottom: 20px; | |
| 190 | +} | |
| 191 | + | |
| 192 | +.margin-left { | |
| 193 | + margin-left: 10px; | |
| 194 | +} | |
| 195 | +</style> | |
| 0 | 196 | \ No newline at end of file | ... | ... |
src/views/car/hireParkingSpaceLang.js
0 → 100644
| 1 | +export const messages = { | |
| 2 | + en: { | |
| 3 | + hireParkingSpace: { | |
| 4 | + title: 'Add Vehicle', | |
| 5 | + carNum: 'License Plate', | |
| 6 | + carNumPlaceholder: 'Required, please enter license plate', | |
| 7 | + carBrand: 'Car Brand', | |
| 8 | + carBrandPlaceholder: 'Optional, please enter car brand', | |
| 9 | + carType: 'Vehicle Type', | |
| 10 | + carTypePlaceholder: 'Required, please select vehicle type', | |
| 11 | + carColor: 'Color', | |
| 12 | + carColorPlaceholder: 'Optional, please enter color', | |
| 13 | + licenseType: 'License Type', | |
| 14 | + licenseTypePlaceholder: 'Required, please select license type', | |
| 15 | + monthlyRent: 'Monthly Rent', | |
| 16 | + saleCar: 'For Sale', | |
| 17 | + internalCar: 'Internal Vehicle', | |
| 18 | + freeCar: 'Free Vehicle', | |
| 19 | + startTime: 'Start Time', | |
| 20 | + startTimePlaceholder: 'Required, please select start time', | |
| 21 | + endTime: 'End Time', | |
| 22 | + endTimePlaceholder: 'Required, please select end time', | |
| 23 | + owner: 'Owner', | |
| 24 | + ownerPlaceholder: 'Required, please select owner', | |
| 25 | + parkingSpace: 'Parking Space', | |
| 26 | + parkingSpacePlaceholder: 'Required, please select parking space', | |
| 27 | + remark: 'Remark', | |
| 28 | + remarkPlaceholder: 'Optional, please enter remark', | |
| 29 | + validate: { | |
| 30 | + carNum: 'License plate is required', | |
| 31 | + carType: 'Vehicle type is required', | |
| 32 | + licenseType: 'License type is required', | |
| 33 | + owner: 'Owner is required', | |
| 34 | + parkingSpace: 'Parking space is required', | |
| 35 | + dateRange: 'Date range is required' | |
| 36 | + }, | |
| 37 | + saveSuccess: 'Vehicle information saved successfully!', | |
| 38 | + saveError: 'Failed to save vehicle information' | |
| 39 | + }, | |
| 40 | + searchOwner: { | |
| 41 | + title: 'Select Owner', | |
| 42 | + roomPlaceholder: 'Enter room number (Building-Unit-Room)', | |
| 43 | + namePlaceholder: 'Enter owner name', | |
| 44 | + memberId: 'Owner ID', | |
| 45 | + name: 'Name', | |
| 46 | + personType: 'Person Type', | |
| 47 | + personRole: 'Person Role', | |
| 48 | + idCard: 'ID Card', | |
| 49 | + contact: 'Contact', | |
| 50 | + loadError: 'Failed to load owner information' | |
| 51 | + }, | |
| 52 | + searchParkingSpace: { | |
| 53 | + title: 'Select Parking Space', | |
| 54 | + parkingAreaPlaceholder: 'Select parking area', | |
| 55 | + numPlaceholder: 'Enter parking space number', | |
| 56 | + areaNum: 'Parking Area', | |
| 57 | + num: 'Parking Space', | |
| 58 | + type: 'Type', | |
| 59 | + ground: 'Ground', | |
| 60 | + underground: 'Underground', | |
| 61 | + parkingType: 'Parking Type', | |
| 62 | + state: 'State', | |
| 63 | + area: 'Area', | |
| 64 | + loadError: 'Failed to load parking space information' | |
| 65 | + } | |
| 66 | + }, | |
| 67 | + zh: { | |
| 68 | + hireParkingSpace: { | |
| 69 | + title: '添加车辆', | |
| 70 | + carNum: '车牌号', | |
| 71 | + carNumPlaceholder: '必填,请填写车牌号', | |
| 72 | + carBrand: '汽车品牌', | |
| 73 | + carBrandPlaceholder: '选填,请填写汽车品牌', | |
| 74 | + carType: '车类型', | |
| 75 | + carTypePlaceholder: '必填,请选择车辆类型', | |
| 76 | + carColor: '颜色', | |
| 77 | + carColorPlaceholder: '选填,请填写颜色', | |
| 78 | + licenseType: '车牌类型', | |
| 79 | + licenseTypePlaceholder: '必填,请选择车牌类型', | |
| 80 | + monthlyRent: '月租车', | |
| 81 | + saleCar: '出售车辆', | |
| 82 | + internalCar: '内部车', | |
| 83 | + freeCar: '免费车', | |
| 84 | + startTime: '开始时间', | |
| 85 | + startTimePlaceholder: '必填,请填写开始时间', | |
| 86 | + endTime: '结束时间', | |
| 87 | + endTimePlaceholder: '必填,请填写结束时间', | |
| 88 | + owner: '业主', | |
| 89 | + ownerPlaceholder: '必填,请选择业主', | |
| 90 | + parkingSpace: '车位', | |
| 91 | + parkingSpacePlaceholder: '必填,请选择车位', | |
| 92 | + remark: '备注', | |
| 93 | + remarkPlaceholder: '选填,请填写备注', | |
| 94 | + validate: { | |
| 95 | + carNum: '车牌号不能为空', | |
| 96 | + carType: '车类型不能为空', | |
| 97 | + licenseType: '车牌类型不能为空', | |
| 98 | + owner: '业主不能为空', | |
| 99 | + parkingSpace: '车位不能为空', | |
| 100 | + dateRange: '请选择日期范围' | |
| 101 | + }, | |
| 102 | + saveSuccess: '车辆信息保存成功!', | |
| 103 | + saveError: '车辆信息保存失败' | |
| 104 | + }, | |
| 105 | + searchOwner: { | |
| 106 | + title: '选择业主', | |
| 107 | + roomPlaceholder: '输入房屋编号楼栋-单元-房屋', | |
| 108 | + namePlaceholder: '输入业主名称', | |
| 109 | + memberId: '业主编号', | |
| 110 | + name: '名称', | |
| 111 | + personType: '人员类型', | |
| 112 | + personRole: '人员角色', | |
| 113 | + idCard: '证件号', | |
| 114 | + contact: '联系方式', | |
| 115 | + loadError: '加载业主信息失败' | |
| 116 | + }, | |
| 117 | + searchParkingSpace: { | |
| 118 | + title: '选择停车位', | |
| 119 | + parkingAreaPlaceholder: '请选择停车场', | |
| 120 | + numPlaceholder: '请输入停车位编号', | |
| 121 | + areaNum: '停车场编码', | |
| 122 | + num: '停车位编码', | |
| 123 | + type: '停车场类型', | |
| 124 | + ground: '地上停车位', | |
| 125 | + underground: '地下停车位', | |
| 126 | + parkingType: '车位类型', | |
| 127 | + state: '车位状态', | |
| 128 | + area: '面积', | |
| 129 | + loadError: '加载停车位信息失败' | |
| 130 | + } | |
| 131 | + } | |
| 132 | +} | |
| 0 | 133 | \ No newline at end of file | ... | ... |
src/views/car/hireParkingSpaceList.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div> | |
| 3 | + <el-card class="box-card margin"> | |
| 4 | + <div slot="header" class="flex justify-between"> | |
| 5 | + <span>{{ $t('hireParkingSpace.title') }}</span> | |
| 6 | + <div class=""> | |
| 7 | + <el-button type="primary" size="small" icon="el-icon-close" @click="goBack"> | |
| 8 | + {{ $t('common.back') }} | |
| 9 | + </el-button> | |
| 10 | + </div> | |
| 11 | + </div> | |
| 12 | + | |
| 13 | + <el-form ref="form" :model="hireParkingSpaceInfo" label-width="120px" label-position="right"> | |
| 14 | + <el-row :gutter="20"> | |
| 15 | + <el-col :span="12"> | |
| 16 | + <el-form-item :label="$t('hireParkingSpace.carNum')" prop="carNum" required> | |
| 17 | + <el-input v-model="hireParkingSpaceInfo.carNum" :placeholder="$t('hireParkingSpace.carNumPlaceholder')" /> | |
| 18 | + </el-form-item> | |
| 19 | + </el-col> | |
| 20 | + <el-col :span="12"> | |
| 21 | + <el-form-item :label="$t('hireParkingSpace.carBrand')"> | |
| 22 | + <el-input v-model="hireParkingSpaceInfo.carBrand" | |
| 23 | + :placeholder="$t('hireParkingSpace.carBrandPlaceholder')" /> | |
| 24 | + </el-form-item> | |
| 25 | + </el-col> | |
| 26 | + </el-row> | |
| 27 | + | |
| 28 | + <el-row :gutter="20"> | |
| 29 | + <el-col :span="12"> | |
| 30 | + <el-form-item :label="$t('hireParkingSpace.carType')" prop="carType" required> | |
| 31 | + <el-select v-model="hireParkingSpaceInfo.carType" class="w-full" | |
| 32 | + :placeholder="$t('hireParkingSpace.carTypePlaceholder')"> | |
| 33 | + <el-option v-for="carType in hireParkingSpaceInfo.carTypes" :key="carType.statusCd" :label="carType.name" | |
| 34 | + :value="carType.statusCd" /> | |
| 35 | + </el-select> | |
| 36 | + </el-form-item> | |
| 37 | + </el-col> | |
| 38 | + <el-col :span="12"> | |
| 39 | + <el-form-item :label="$t('hireParkingSpace.carColor')"> | |
| 40 | + <el-input v-model="hireParkingSpaceInfo.carColor" | |
| 41 | + :placeholder="$t('hireParkingSpace.carColorPlaceholder')" /> | |
| 42 | + </el-form-item> | |
| 43 | + </el-col> | |
| 44 | + </el-row> | |
| 45 | + | |
| 46 | + <el-row :gutter="20"> | |
| 47 | + <el-col :span="12"> | |
| 48 | + <el-form-item :label="$t('hireParkingSpace.licenseType')" prop="leaseType" required> | |
| 49 | + <el-select v-model="hireParkingSpaceInfo.leaseType" class="w-full" | |
| 50 | + :placeholder="$t('hireParkingSpace.licenseTypePlaceholder')" @change="changeLeaseType"> | |
| 51 | + <el-option :label="$t('hireParkingSpace.monthlyRent')" value="H" /> | |
| 52 | + <el-option :label="$t('hireParkingSpace.saleCar')" value="S" /> | |
| 53 | + <el-option :label="$t('hireParkingSpace.internalCar')" value="I" /> | |
| 54 | + <el-option :label="$t('hireParkingSpace.freeCar')" value="NM" /> | |
| 55 | + </el-select> | |
| 56 | + </el-form-item> | |
| 57 | + </el-col> | |
| 58 | + </el-row> | |
| 59 | + | |
| 60 | + <el-row v-if="showDateRange" :gutter="20"> | |
| 61 | + <el-col :span="12"> | |
| 62 | + <el-form-item :label="$t('hireParkingSpace.startTime')" prop="startTime" required> | |
| 63 | + <el-date-picker v-model="hireParkingSpaceInfo.startTime" type="date" value-format="yyyy-MM-dd" class="w-full" | |
| 64 | + :placeholder="$t('hireParkingSpace.startTimePlaceholder')" /> | |
| 65 | + </el-form-item> | |
| 66 | + </el-col> | |
| 67 | + <el-col :span="12"> | |
| 68 | + <el-form-item :label="$t('hireParkingSpace.endTime')" prop="endTime" required> | |
| 69 | + <el-date-picker v-model="hireParkingSpaceInfo.endTime" type="date" value-format="yyyy-MM-dd" class="w-full" | |
| 70 | + :placeholder="$t('hireParkingSpace.endTimePlaceholder')" /> | |
| 71 | + </el-form-item> | |
| 72 | + </el-col> | |
| 73 | + </el-row> | |
| 74 | + | |
| 75 | + <el-row :gutter="20"> | |
| 76 | + <el-col :span="8"> | |
| 77 | + <el-form-item :label="$t('hireParkingSpace.owner')" prop="ownerName" required> | |
| 78 | + <el-input v-model="hireParkingSpaceInfo.ownerName" disabled | |
| 79 | + :placeholder="$t('hireParkingSpace.ownerPlaceholder')" /> | |
| 80 | + </el-form-item> | |
| 81 | + </el-col> | |
| 82 | + <el-col :span="4"> | |
| 83 | + <div class=""> | |
| 84 | + <el-button type="primary" size="small" @click="openChooseOwner"> | |
| 85 | + {{ $t('common.select') }} | |
| 86 | + </el-button> | |
| 87 | + </div> | |
| 88 | + </el-col> | |
| 89 | + <el-col :span="8"> | |
| 90 | + <el-form-item :label="$t('hireParkingSpace.parkingSpace')" prop="psName" required> | |
| 91 | + <el-input v-model="hireParkingSpaceInfo.psName" disabled | |
| 92 | + :placeholder="$t('hireParkingSpace.parkingSpacePlaceholder')" /> | |
| 93 | + </el-form-item> | |
| 94 | + </el-col> | |
| 95 | + <el-col :span="4"> | |
| 96 | + <el-button type="primary" size="small" @click="openSearchParkingSpaceModel"> | |
| 97 | + {{ $t('common.select') }} | |
| 98 | + </el-button> | |
| 99 | + </el-col> | |
| 100 | + </el-row> | |
| 101 | + | |
| 102 | + <el-row v-for="(item, index) in hireParkingSpaceInfo.attrs" :key="index"> | |
| 103 | + <el-col :span="24"> | |
| 104 | + <el-form-item :label="item.specName"> | |
| 105 | + <el-input v-if="item.specType === '2233'" v-model="item.value" :placeholder="item.specHoldplace" /> | |
| 106 | + <el-select v-else-if="item.specType === '3344'" v-model="item.value" class="w-full" | |
| 107 | + :placeholder="item.specHoldplace"> | |
| 108 | + <el-option v-for="(val, idx) in item.values" :key="idx" :label="val.valueName" :value="val.value" /> | |
| 109 | + </el-select> | |
| 110 | + </el-form-item> | |
| 111 | + </el-col> | |
| 112 | + </el-row> | |
| 113 | + | |
| 114 | + <el-row> | |
| 115 | + <el-col :span="24"> | |
| 116 | + <el-form-item :label="$t('hireParkingSpace.remark')"> | |
| 117 | + <el-input v-model="hireParkingSpaceInfo.remark" type="textarea" :rows="3" | |
| 118 | + :placeholder="$t('hireParkingSpace.remarkPlaceholder')" /> | |
| 119 | + </el-form-item> | |
| 120 | + </el-col> | |
| 121 | + </el-row> | |
| 122 | + </el-form> | |
| 123 | + </el-card> | |
| 124 | + | |
| 125 | + <div class="mt-20 text-right"> | |
| 126 | + <el-button @click="goBack">{{ $t('common.back') }}</el-button> | |
| 127 | + <el-button type="primary" @click="saveAddCarInfo"> | |
| 128 | + {{ $t('common.submit') }} | |
| 129 | + </el-button> | |
| 130 | + </div> | |
| 131 | + | |
| 132 | + <search-owner ref="searchOwner" @chooseOwner="handleChooseOwner" /> | |
| 133 | + <search-parking-space ref="searchParkingSpace" @choose-parking-space="handleChooseParkingSpace" /> | |
| 134 | + </div> | |
| 135 | +</template> | |
| 136 | + | |
| 137 | +<script> | |
| 138 | +import { saveOwnerCar } from '@/api/car/hireParkingSpaceApi' | |
| 139 | +import { getCommunityId, getDict } from '@/api/community/communityApi' | |
| 140 | +import SearchOwner from '@/components/owner/SearchOwner' | |
| 141 | +import SearchParkingSpace from '@/components/car/SearchParkingSpace' | |
| 142 | +import { getSpecAttrList } from '@/api/dev/attrSpecApi' | |
| 143 | + | |
| 144 | +export default { | |
| 145 | + name: 'HireParkingSpaceList', | |
| 146 | + components: { | |
| 147 | + SearchOwner, | |
| 148 | + SearchParkingSpace | |
| 149 | + }, | |
| 150 | + data() { | |
| 151 | + return { | |
| 152 | + hireParkingSpaceInfo: { | |
| 153 | + carNum: '', | |
| 154 | + carBrand: '', | |
| 155 | + carType: '', | |
| 156 | + carColor: '', | |
| 157 | + remark: '', | |
| 158 | + startTime: '', | |
| 159 | + endTime: '', | |
| 160 | + leaseType: 'H', | |
| 161 | + ownerId: '', | |
| 162 | + ownerName: '', | |
| 163 | + psId: '', | |
| 164 | + psName: '', | |
| 165 | + attrs: [], | |
| 166 | + carTypes: [] | |
| 167 | + } | |
| 168 | + } | |
| 169 | + }, | |
| 170 | + computed: { | |
| 171 | + showDateRange() { | |
| 172 | + return ['H', 'S'].includes(this.hireParkingSpaceInfo.leaseType) | |
| 173 | + } | |
| 174 | + }, | |
| 175 | + async created() { | |
| 176 | + await this.initData() | |
| 177 | + }, | |
| 178 | + methods: { | |
| 179 | + async initData() { | |
| 180 | + this.communityId = getCommunityId() | |
| 181 | + | |
| 182 | + // 加载车辆类型字典 | |
| 183 | + try { | |
| 184 | + const carTypes = await getDict('owner_car', 'car_type') | |
| 185 | + this.hireParkingSpaceInfo.carTypes = carTypes | |
| 186 | + } catch (error) { | |
| 187 | + console.error('加载车辆类型失败:', error) | |
| 188 | + } | |
| 189 | + | |
| 190 | + // 加载车辆属性规格 | |
| 191 | + try { | |
| 192 | + await this.loadCarAttrSpec() | |
| 193 | + } catch (error) { | |
| 194 | + console.error('加载车辆属性失败:', error) | |
| 195 | + } | |
| 196 | + }, | |
| 197 | + | |
| 198 | + async loadCarAttrSpec() { | |
| 199 | + try { | |
| 200 | + const attrs = await getSpecAttrList('owner_car_attr') | |
| 201 | + this.hireParkingSpaceInfo.attrs = attrs.map(item => { | |
| 202 | + if (item.specShow === 'Y') { | |
| 203 | + return { | |
| 204 | + ...item, | |
| 205 | + value: '', | |
| 206 | + values: item.specType === '3344' ? [] : undefined | |
| 207 | + } | |
| 208 | + } | |
| 209 | + return null | |
| 210 | + }).filter(Boolean) | |
| 211 | + } catch (error) { | |
| 212 | + console.error('加载车辆属性规格失败:', error) | |
| 213 | + } | |
| 214 | + }, | |
| 215 | + | |
| 216 | + changeLeaseType() { | |
| 217 | + this.hireParkingSpaceInfo.startTime = '' | |
| 218 | + this.hireParkingSpaceInfo.endTime = '' | |
| 219 | + }, | |
| 220 | + | |
| 221 | + openChooseOwner() { | |
| 222 | + this.$refs.searchOwner.open() | |
| 223 | + }, | |
| 224 | + | |
| 225 | + handleChooseOwner(owner) { | |
| 226 | + this.hireParkingSpaceInfo.ownerName = owner.name | |
| 227 | + this.hireParkingSpaceInfo.ownerId = owner.memberId | |
| 228 | + }, | |
| 229 | + | |
| 230 | + openSearchParkingSpaceModel() { | |
| 231 | + this.$refs.searchParkingSpace.open() | |
| 232 | + }, | |
| 233 | + | |
| 234 | + handleChooseParkingSpace(parkingSpace) { | |
| 235 | + this.hireParkingSpaceInfo.psName = `${parkingSpace.areaNum}-${parkingSpace.num}` | |
| 236 | + this.hireParkingSpaceInfo.psId = parkingSpace.psId | |
| 237 | + }, | |
| 238 | + | |
| 239 | + validateForm() { | |
| 240 | + const requiredFields = [ | |
| 241 | + { field: 'carNum', message: this.$t('hireParkingSpace.validate.carNum') }, | |
| 242 | + { field: 'carType', message: this.$t('hireParkingSpace.validate.carType') }, | |
| 243 | + { field: 'leaseType', message: this.$t('hireParkingSpace.validate.licenseType') }, | |
| 244 | + { field: 'ownerId', message: this.$t('hireParkingSpace.validate.owner') }, | |
| 245 | + { field: 'psId', message: this.$t('hireParkingSpace.validate.parkingSpace') } | |
| 246 | + ] | |
| 247 | + | |
| 248 | + for (const { field, message } of requiredFields) { | |
| 249 | + if (!this.hireParkingSpaceInfo[field]) { | |
| 250 | + this.$message.error(message) | |
| 251 | + return false | |
| 252 | + } | |
| 253 | + } | |
| 254 | + | |
| 255 | + // 验证日期范围 | |
| 256 | + if (this.showDateRange) { | |
| 257 | + if (!this.hireParkingSpaceInfo.startTime || !this.hireParkingSpaceInfo.endTime) { | |
| 258 | + this.$message.error(this.$t('hireParkingSpace.validate.dateRange')) | |
| 259 | + return false | |
| 260 | + } | |
| 261 | + } | |
| 262 | + | |
| 263 | + // 验证自定义属性 | |
| 264 | + for (const attr of this.hireParkingSpaceInfo.attrs) { | |
| 265 | + if (attr.required === 'Y' && !attr.value) { | |
| 266 | + this.$message.error(attr.specHoldplace) | |
| 267 | + return false | |
| 268 | + } | |
| 269 | + } | |
| 270 | + | |
| 271 | + return true | |
| 272 | + }, | |
| 273 | + | |
| 274 | + async saveAddCarInfo() { | |
| 275 | + if (!this.validateForm()) return | |
| 276 | + | |
| 277 | + try { | |
| 278 | + const params = { | |
| 279 | + ...this.hireParkingSpaceInfo, | |
| 280 | + communityId: this.communityId | |
| 281 | + } | |
| 282 | + | |
| 283 | + await saveOwnerCar(params) | |
| 284 | + this.$message.success(this.$t('hireParkingSpace.saveSuccess')) | |
| 285 | + this.goBack() | |
| 286 | + } catch (error) { | |
| 287 | + console.error('保存失败:', error) | |
| 288 | + this.$message.error(this.$t('hireParkingSpace.saveError')) | |
| 289 | + } | |
| 290 | + }, | |
| 291 | + | |
| 292 | + goBack() { | |
| 293 | + this.$router.go(-1) | |
| 294 | + } | |
| 295 | + } | |
| 296 | +} | |
| 297 | +</script> | |
| 298 | + | |
| 299 | +<style scoped> | |
| 300 | +.card-header-actions { | |
| 301 | + position: absolute; | |
| 302 | + right: 20px; | |
| 303 | + top: 15px; | |
| 304 | +} | |
| 305 | + | |
| 306 | +.w-full { | |
| 307 | + width: 100%; | |
| 308 | +} | |
| 309 | + | |
| 310 | +.mt-10 { | |
| 311 | + margin-top: 10px; | |
| 312 | +} | |
| 313 | + | |
| 314 | +.mt-20 { | |
| 315 | + margin-top: 20px; | |
| 316 | +} | |
| 317 | +</style> | |
| 0 | 318 | \ No newline at end of file | ... | ... |
src/views/car/listOwnerCarLang.js
0 → 100644
| 1 | +export const messages = { | |
| 2 | + en: { | |
| 3 | + listOwnerCar: { | |
| 4 | + searchCondition: 'Search Condition', | |
| 5 | + inputCarNum: 'Please enter the license plate number', | |
| 6 | + inputParkingSpaceNum: 'Please fill in the parking space number', | |
| 7 | + selectParkingSpaceStatus: 'Required, please select the parking space status', | |
| 8 | + inputOwnerName: 'Please fill in the owner name', | |
| 9 | + inputContact: 'Please enter contact information', | |
| 10 | + inputMemberCarNum: 'Please enter member license plate number', | |
| 11 | + query: 'Query', | |
| 12 | + reset: 'Reset', | |
| 13 | + carInfo: 'Car Information', | |
| 14 | + importCar: 'Import Cars', | |
| 15 | + export: 'Export', | |
| 16 | + add: 'Add', | |
| 17 | + carNum: 'License Plate Number', | |
| 18 | + memberCar: 'Member Car', | |
| 19 | + roomNum: 'Room Number', | |
| 20 | + carPlateType: 'License Plate Type', | |
| 21 | + carType: 'Car Type', | |
| 22 | + color: 'Color', | |
| 23 | + owner: 'Owner', | |
| 24 | + parkingSpace: 'Parking Space', | |
| 25 | + validity: 'Validity', | |
| 26 | + status: 'Status', | |
| 27 | + remark: 'Remark', | |
| 28 | + operation: 'Operation', | |
| 29 | + temporaryCar: 'Temporary Car', | |
| 30 | + parkingSpaceReleased: 'Parking space released', | |
| 31 | + normal: 'Normal', | |
| 32 | + expired: 'Expired', | |
| 33 | + noParkingSpace: 'No Parking Space', | |
| 34 | + release: 'Release', | |
| 35 | + renew: 'Renew', | |
| 36 | + buyMonthlyCard: 'Buy Monthly Card', | |
| 37 | + modify: 'Modify', | |
| 38 | + delete: 'Delete', | |
| 39 | + confirmDelete: 'Are you sure to delete?', | |
| 40 | + cancel: 'Cancel', | |
| 41 | + confirm: 'Confirm', | |
| 42 | + importCarTitle: 'Car Import', | |
| 43 | + selectFile: 'Select File', | |
| 44 | + downloadTemplate: 'Download Template', | |
| 45 | + importTemplate: 'Import Template', | |
| 46 | + prepareData: 'Prepare data and upload', | |
| 47 | + import: 'Import', | |
| 48 | + editCar: 'Edit Car', | |
| 49 | + carBrand: 'Car Brand', | |
| 50 | + inputCarBrand: 'Optional, please fill in the car brand, e.g. BMW X6', | |
| 51 | + inputCarNumRequired: 'Required, please fill in the license plate number', | |
| 52 | + selectType: 'Required, please select type', | |
| 53 | + inputCarColor: 'Optional, please fill in the car color, e.g. white', | |
| 54 | + licensePlateType: 'License Plate Type', | |
| 55 | + selectLicensePlateType: 'Required, please select license plate type', | |
| 56 | + monthlyRentCar: 'Monthly Rent Car', | |
| 57 | + soldCar: 'Sold Car', | |
| 58 | + internalCar: 'Internal Car', | |
| 59 | + freeCar: 'Free Car', | |
| 60 | + startRentTime: 'Start Rent Time', | |
| 61 | + endRentTime: 'End Rent Time', | |
| 62 | + inputStartRentTime: 'Required, please fill in the start rent time', | |
| 63 | + inputEndRentTime: 'Required, please fill in the end rent time', | |
| 64 | + inputRemark: 'Please fill in remarks', | |
| 65 | + save: 'Save', | |
| 66 | + deleteCarConfirm: 'Confirm whether to delete', | |
| 67 | + fileRequired: 'Required, please select data file', | |
| 68 | + invalidExcel: 'Invalid Excel format', | |
| 69 | + fileSizeExceed: 'Excel file size cannot exceed 2M', | |
| 70 | + importSuccess: 'Import successful', | |
| 71 | + importError: 'Import failed', | |
| 72 | + updateSuccess: 'Update successful', | |
| 73 | + updateError: 'Update failed', | |
| 74 | + deleteSuccess: 'Delete successful', | |
| 75 | + deleteError: 'Delete failed', | |
| 76 | + releaseSuccess: 'Release successful', | |
| 77 | + releaseError: 'Release failed', | |
| 78 | + exportSuccess: 'Export successful', | |
| 79 | + exportError: 'Export failed', | |
| 80 | + fetchError: 'Failed to get data', | |
| 81 | + allCars: 'All Cars', | |
| 82 | + expiredCars: 'Expired Cars', | |
| 83 | + downloadFirst: 'Please download first ', | |
| 84 | + selectTypeRequired: 'Please select car type', | |
| 85 | + selectLicensePlateTypeRequired: 'Please select license plate type', | |
| 86 | + rentTimeRequired: 'Please fill in rent time', | |
| 87 | + endTimeAfterStart: 'End time must be after start time', | |
| 88 | + iotSyncDetail: 'IoT sync details', | |
| 89 | + confirmRelease: 'Are you sure to release the car?', | |
| 90 | + } | |
| 91 | + }, | |
| 92 | + zh: { | |
| 93 | + listOwnerCar: { | |
| 94 | + searchCondition: '查询条件', | |
| 95 | + inputCarNum: '请输入车牌号', | |
| 96 | + inputParkingSpaceNum: '请填写车位编号', | |
| 97 | + selectParkingSpaceStatus: '必填,请选择车位状态', | |
| 98 | + inputOwnerName: '请填写业主名称', | |
| 99 | + inputContact: '请输入联系方式', | |
| 100 | + inputMemberCarNum: '请输入成员车牌号', | |
| 101 | + query: '查询', | |
| 102 | + reset: '重置', | |
| 103 | + carInfo: '车辆信息', | |
| 104 | + importCar: '车辆导入', | |
| 105 | + export: '导出', | |
| 106 | + add: '添加', | |
| 107 | + carNum: '车牌号', | |
| 108 | + memberCar: '成员车辆', | |
| 109 | + roomNum: '房屋号', | |
| 110 | + carPlateType: '车牌类型', | |
| 111 | + carType: '车辆类型', | |
| 112 | + color: '颜色', | |
| 113 | + owner: '业主', | |
| 114 | + parkingSpace: '车位', | |
| 115 | + validity: '有效期', | |
| 116 | + status: '状态', | |
| 117 | + remark: '备注', | |
| 118 | + operation: '操作', | |
| 119 | + temporaryCar: '临时车', | |
| 120 | + parkingSpaceReleased: '车位已释放', | |
| 121 | + normal: '正常', | |
| 122 | + expired: '到期', | |
| 123 | + noParkingSpace: '无车位', | |
| 124 | + release: '释放', | |
| 125 | + renew: '续租', | |
| 126 | + buyMonthlyCard: '买月卡', | |
| 127 | + modify: '修改', | |
| 128 | + delete: '删除', | |
| 129 | + confirmDelete: '确认删除?', | |
| 130 | + cancel: '取消', | |
| 131 | + confirm: '确认', | |
| 132 | + importCarTitle: '车辆导入', | |
| 133 | + selectFile: '选择文件', | |
| 134 | + downloadTemplate: '下载模板', | |
| 135 | + importTemplate: '导入模板', | |
| 136 | + prepareData: '准备数据后,上传导入', | |
| 137 | + import: '导入', | |
| 138 | + editCar: '修改车辆', | |
| 139 | + carBrand: '车品牌', | |
| 140 | + inputCarBrand: '可选,请填写车品牌,如宝马X6', | |
| 141 | + inputCarNumRequired: '必填,请填写车牌号', | |
| 142 | + selectType: '必填,请选择类型', | |
| 143 | + inputCarColor: '可选,请填写车颜色,如白色', | |
| 144 | + licensePlateType: '车牌类型', | |
| 145 | + selectLicensePlateType: '必填,请选择车牌类型', | |
| 146 | + monthlyRentCar: '月租车', | |
| 147 | + soldCar: '出售车辆', | |
| 148 | + internalCar: '内部车', | |
| 149 | + freeCar: '免费车', | |
| 150 | + startRentTime: '起租时间', | |
| 151 | + endRentTime: '结租时间', | |
| 152 | + inputStartRentTime: '必填,请填写起租时间', | |
| 153 | + inputEndRentTime: '必填,请填写结租时间', | |
| 154 | + inputRemark: '请填写备注信息', | |
| 155 | + save: '保存', | |
| 156 | + deleteCarConfirm: '确认是否删除', | |
| 157 | + fileRequired: '必填,请选择数据文件', | |
| 158 | + invalidExcel: '不是有效的Excel格式', | |
| 159 | + fileSizeExceed: 'Excel文件大小不能超过2M', | |
| 160 | + importSuccess: '导入成功', | |
| 161 | + importError: '导入失败', | |
| 162 | + updateSuccess: '修改成功', | |
| 163 | + updateError: '修改失败', | |
| 164 | + deleteSuccess: '删除成功', | |
| 165 | + deleteError: '删除失败', | |
| 166 | + releaseSuccess: '释放成功', | |
| 167 | + releaseError: '释放失败', | |
| 168 | + exportSuccess: '导出成功', | |
| 169 | + exportError: '导出失败', | |
| 170 | + fetchError: '获取数据失败', | |
| 171 | + allCars: '全部车辆', | |
| 172 | + expiredCars: '到期车辆', | |
| 173 | + downloadFirst: '请先下载 ', | |
| 174 | + selectTypeRequired: '请选择车辆类型', | |
| 175 | + selectLicensePlateTypeRequired: '请选择车牌类型', | |
| 176 | + rentTimeRequired: '请填写起租时间和结租时间', | |
| 177 | + endTimeAfterStart: '结租时间必须大于起租时间', | |
| 178 | + iotSyncDetail: '同步物联网详情', | |
| 179 | + confirmRelease: '确认释放车辆?', | |
| 180 | + } | |
| 181 | + } | |
| 182 | +} | |
| 0 | 183 | \ No newline at end of file | ... | ... |
src/views/car/listOwnerCarList.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div class="list-owner-car-container"> | |
| 3 | + <el-row :gutter="20"> | |
| 4 | + <el-col :span="3"> | |
| 5 | + <el-card class="tree-card"> | |
| 6 | + <ul class="lease-type-list"> | |
| 7 | + <li v-for="(item, index) in leaseTypes" :key="index" @click="switchLeaseType(item)" | |
| 8 | + :class="{ 'selected': conditions.leaseType === item.statusCd }"> | |
| 9 | + {{ item.name }} | |
| 10 | + </li> | |
| 11 | + </ul> | |
| 12 | + </el-card> | |
| 13 | + </el-col> | |
| 14 | + <el-col :span="21"> | |
| 15 | + <el-card class="search-card"> | |
| 16 | + <div slot="header" class="flex justify-between"> | |
| 17 | + <span>{{ $t('listOwnerCar.searchCondition') }}</span> | |
| 18 | + </div> | |
| 19 | + <el-row :gutter="20"> | |
| 20 | + <el-col :span="6"> | |
| 21 | + <el-input v-model.trim="conditions.carNumLike" :placeholder="$t('listOwnerCar.inputCarNum')" clearable /> | |
| 22 | + </el-col> | |
| 23 | + <el-col :span="6"> | |
| 24 | + <el-input v-model.trim="conditions.num" :placeholder="$t('listOwnerCar.inputParkingSpaceNum')" clearable /> | |
| 25 | + </el-col> | |
| 26 | + <el-col :span="6"> | |
| 27 | + <el-select v-model="conditions.valid" :placeholder="$t('listOwnerCar.selectParkingSpaceStatus')" clearable> | |
| 28 | + <el-option value="1" :label="$t('listOwnerCar.normal')"></el-option> | |
| 29 | + <el-option value="3" :label="$t('listOwnerCar.expired')"></el-option> | |
| 30 | + <el-option value="2" :label="$t('listOwnerCar.noParkingSpace')"></el-option> | |
| 31 | + </el-select> | |
| 32 | + </el-col> | |
| 33 | + <el-col :span="6"> | |
| 34 | + <el-input v-model.trim="conditions.ownerName" :placeholder="$t('listOwnerCar.inputOwnerName')" clearable /> | |
| 35 | + </el-col> | |
| 36 | + </el-row> | |
| 37 | + <el-row :gutter="20" class="mt-10"> | |
| 38 | + <el-col :span="6"> | |
| 39 | + <el-input v-model.trim="conditions.link" :placeholder="$t('listOwnerCar.inputContact')" clearable /> | |
| 40 | + </el-col> | |
| 41 | + <el-col :span="6"> | |
| 42 | + <el-input v-model.trim="conditions.memberCarNumLike" :placeholder="$t('listOwnerCar.inputMemberCarNum')" | |
| 43 | + clearable /> | |
| 44 | + </el-col> | |
| 45 | + <el-col :span="12" class="text-right"> | |
| 46 | + <el-button type="primary" @click="queryMethod" icon="el-icon-search"> | |
| 47 | + {{ $t('listOwnerCar.query') }} | |
| 48 | + </el-button> | |
| 49 | + <el-button @click="resetMethod" icon="el-icon-refresh"> | |
| 50 | + {{ $t('listOwnerCar.reset') }} | |
| 51 | + </el-button> | |
| 52 | + </el-col> | |
| 53 | + </el-row> | |
| 54 | + </el-card> | |
| 55 | + | |
| 56 | + <el-card class="mt-20"> | |
| 57 | + <div slot="header" class="flex justify-between"> | |
| 58 | + <span>{{ $t('listOwnerCar.carInfo') }}</span> | |
| 59 | + <div class="header-buttons"> | |
| 60 | + <el-button v-if="hasPrivilege('502023032813991677')" type="primary" size="small" @click="addOwnerCar"> | |
| 61 | + {{ $t('listOwnerCar.add') }} | |
| 62 | + </el-button> | |
| 63 | + <el-button size="small" @click="openOwnerCarImport"> | |
| 64 | + <i class="el-icon-upload2"></i> {{ $t('listOwnerCar.importCar') }} | |
| 65 | + </el-button> | |
| 66 | + <el-button size="small" @click="exportExcel"> | |
| 67 | + <i class="el-icon-download"></i> {{ $t('listOwnerCar.export') }} | |
| 68 | + </el-button> | |
| 69 | + </div> | |
| 70 | + </div> | |
| 71 | + | |
| 72 | + <el-table :data="ownerCars" border v-loading="loading"> | |
| 73 | + <el-table-column prop="carNum" :label="$t('listOwnerCar.carNum')" align="center"> | |
| 74 | + <template slot-scope="scope"> | |
| 75 | + <router-link :to="`/pages/car/carDetail?memberId=${scope.row.memberId}`" target="_blank"> | |
| 76 | + {{ scope.row.carNum }} | |
| 77 | + </router-link> | |
| 78 | + </template> | |
| 79 | + </el-table-column> | |
| 80 | + <el-table-column prop="memberCarCount" :label="$t('listOwnerCar.memberCar')" align="center"> | |
| 81 | + <template slot-scope="scope"> | |
| 82 | + <a href="javascript:void(0)" @click="toCarMember(scope.row)"> | |
| 83 | + {{ scope.row.memberCarCount || 0 }} | |
| 84 | + </a> | |
| 85 | + </template> | |
| 86 | + </el-table-column> | |
| 87 | + <el-table-column prop="roomName" :label="$t('listOwnerCar.roomNum')" align="center" width="150" /> | |
| 88 | + <el-table-column :label="$t('listOwnerCar.carPlateType')" align="center"> | |
| 89 | + <template slot-scope="scope"> | |
| 90 | + <span v-if="scope.row.leaseType === 'T'"> | |
| 91 | + {{ $t('listOwnerCar.temporaryCar') }} | |
| 92 | + </span> | |
| 93 | + <span v-else>{{ scope.row.leaseTypeName }}</span> | |
| 94 | + </template> | |
| 95 | + </el-table-column> | |
| 96 | + <el-table-column prop="carTypeName" :label="$t('listOwnerCar.carType')" align="center" /> | |
| 97 | + <el-table-column prop="carColor" :label="$t('listOwnerCar.color')" align="center" /> | |
| 98 | + <el-table-column :label="$t('listOwnerCar.owner')" align="center"> | |
| 99 | + <template slot-scope="scope"> | |
| 100 | + <router-link :to="`/pages/owner/ownerDetail?ownerId=${scope.row.ownerId}`" target="_blank"> | |
| 101 | + {{ scope.row.ownerName }}({{ scope.row.link }}) | |
| 102 | + </router-link> | |
| 103 | + </template> | |
| 104 | + </el-table-column> | |
| 105 | + <el-table-column :label="$t('listOwnerCar.parkingSpace')" align="center"> | |
| 106 | + <template slot-scope="scope"> | |
| 107 | + <span v-if="scope.row.areaNum && scope.row.state === '1001'"> | |
| 108 | + {{ scope.row.areaNum }}-{{ scope.row.num }} | |
| 109 | + </span> | |
| 110 | + <span v-else>{{ $t('listOwnerCar.parkingSpaceReleased') }}</span> | |
| 111 | + </template> | |
| 112 | + </el-table-column> | |
| 113 | + <el-table-column :label="$t('listOwnerCar.validity')" align="center"> | |
| 114 | + <template slot-scope="scope"> | |
| 115 | + <div v-if="scope.row.leaseType === 'H' || scope.row.leaseType === 'S'"> | |
| 116 | + {{ scope.row.startTime }}<br>~{{ scope.row.endTime }} | |
| 117 | + </div> | |
| 118 | + <div v-else>--</div> | |
| 119 | + </template> | |
| 120 | + </el-table-column> | |
| 121 | + <el-table-column :label="$t('listOwnerCar.status')" align="center"> | |
| 122 | + <template slot-scope="scope"> | |
| 123 | + {{ getCarState(scope.row) }} | |
| 124 | + <span v-if="scope.row.iotStateName"> | |
| 125 | + (<a href="javascript:void(0)" @click="viewIotStateRemark(scope.row)">{{ scope.row.iotStateName }}</a>) | |
| 126 | + </span> | |
| 127 | + </template> | |
| 128 | + </el-table-column> | |
| 129 | + <el-table-column prop="remark" :label="$t('listOwnerCar.remark')" align="center" /> | |
| 130 | + <el-table-column :label="$t('listOwnerCar.operation')" align="center" width="280"> | |
| 131 | + <template slot-scope="scope"> | |
| 132 | + <el-button v-if="scope.row.state !== '3003' && hasPrivilege('502023032855861676')" size="mini" | |
| 133 | + @click="deleteCarParkingSpace(scope.row)"> | |
| 134 | + {{ $t('listOwnerCar.release') }} | |
| 135 | + </el-button> | |
| 136 | + <el-button v-else-if="hasPrivilege('502023032809021678')" size="mini" | |
| 137 | + @click="addCarParkingSpace(scope.row)"> | |
| 138 | + {{ $t('listOwnerCar.renew') }} | |
| 139 | + </el-button> | |
| 140 | + <el-button v-if="scope.row.leaseType === 'H'" size="mini" @click="toBuyCarMonthCard(scope.row)"> | |
| 141 | + {{ $t('listOwnerCar.buyMonthlyCard') }} | |
| 142 | + </el-button> | |
| 143 | + <el-button v-if="scope.row.carTypeCd !== '1003' && hasPrivilege('502023032804261679')" size="mini" | |
| 144 | + @click="openEditOwnerCar(scope.row)"> | |
| 145 | + {{ $t('listOwnerCar.modify') }} | |
| 146 | + </el-button> | |
| 147 | + <el-button v-if="hasPrivilege('502023032822121680')" size="mini" type="danger" | |
| 148 | + @click="openDelOwnerCarModel(scope.row)"> | |
| 149 | + {{ $t('listOwnerCar.delete') }} | |
| 150 | + </el-button> | |
| 151 | + </template> | |
| 152 | + </el-table-column> | |
| 153 | + </el-table> | |
| 154 | + | |
| 155 | + <el-pagination class="mt-20" :current-page="currentPage" :page-sizes="[10, 20, 30, 50]" :page-size="pageSize" | |
| 156 | + layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handleSizeChange" | |
| 157 | + @current-change="handleCurrentChange" /> | |
| 158 | + </el-card> | |
| 159 | + </el-col> | |
| 160 | + </el-row> | |
| 161 | + | |
| 162 | + <import-owner-car ref="importOwnerCar" @success="listOwnerCarData" /> | |
| 163 | + <edit-car ref="editCar" @success="listOwnerCarData" /> | |
| 164 | + <delete-owner-car ref="deleteOwnerCar" @success="listOwnerCarData" /> | |
| 165 | + </div> | |
| 166 | +</template> | |
| 167 | + | |
| 168 | +<script> | |
| 169 | +import { queryOwnerCars, exportData, deleteCarParkingSpace } from '@/api/car/listOwnerCarApi' | |
| 170 | +import ImportOwnerCar from '@/components/car/importOwnerCar' | |
| 171 | +import EditCar from '@/components/car/editCar' | |
| 172 | +import DeleteOwnerCar from '@/components/car/deleteOwnerCar' | |
| 173 | +import { getDict } from '@/api/community/communityApi' | |
| 174 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 175 | + | |
| 176 | + | |
| 177 | +export default { | |
| 178 | + name: 'ListOwnerCar', | |
| 179 | + components: { ImportOwnerCar, EditCar, DeleteOwnerCar }, | |
| 180 | + data() { | |
| 181 | + return { | |
| 182 | + loading: false, | |
| 183 | + ownerCars: [], | |
| 184 | + leaseTypes: [], | |
| 185 | + conditions: { | |
| 186 | + carNumLike: '', | |
| 187 | + num: '', | |
| 188 | + valid: '', | |
| 189 | + leaseType: 'H', | |
| 190 | + ownerName: '', | |
| 191 | + link: '', | |
| 192 | + memberCarNumLike: '' | |
| 193 | + }, | |
| 194 | + currentPage: 1, | |
| 195 | + pageSize: 10, | |
| 196 | + total: 0, | |
| 197 | + communityId: '' | |
| 198 | + } | |
| 199 | + }, | |
| 200 | + created() { | |
| 201 | + this.communityId = getCommunityId() | |
| 202 | + this.initData() | |
| 203 | + this.listOwnerCarData() | |
| 204 | + }, | |
| 205 | + methods: { | |
| 206 | + async initData() { | |
| 207 | + try { | |
| 208 | + const leaseTypes = await getDict('owner_car', 'lease_type') | |
| 209 | + this.leaseTypes = [{ statusCd: '', name: this.$t('listOwnerCar.allCars') }, ...leaseTypes, | |
| 210 | + { statusCd: 'expireCar', name: this.$t('listOwnerCar.expiredCars') }] | |
| 211 | + } catch (error) { | |
| 212 | + console.error('获取租赁类型失败:', error) | |
| 213 | + } | |
| 214 | + }, | |
| 215 | + | |
| 216 | + async listOwnerCarData() { | |
| 217 | + this.loading = true | |
| 218 | + try { | |
| 219 | + const params = { | |
| 220 | + ...this.conditions, | |
| 221 | + page: this.currentPage, | |
| 222 | + row: this.pageSize, | |
| 223 | + communityId: this.communityId | |
| 224 | + } | |
| 225 | + | |
| 226 | + if (this.conditions.leaseType === 'expireCar') { | |
| 227 | + params.leaseType = '' | |
| 228 | + params.valid = 3 | |
| 229 | + } | |
| 230 | + | |
| 231 | + const response = await queryOwnerCars(params) | |
| 232 | + this.ownerCars = response.data | |
| 233 | + this.total = response.total | |
| 234 | + } catch (error) { | |
| 235 | + console.error('获取车辆列表失败:', error) | |
| 236 | + this.$message.error(this.$t('listOwnerCar.fetchError')) | |
| 237 | + } finally { | |
| 238 | + this.loading = false | |
| 239 | + } | |
| 240 | + }, | |
| 241 | + | |
| 242 | + switchLeaseType(item) { | |
| 243 | + this.conditions.leaseType = item.statusCd | |
| 244 | + this.currentPage = 1 | |
| 245 | + this.listOwnerCarData() | |
| 246 | + }, | |
| 247 | + | |
| 248 | + queryMethod() { | |
| 249 | + this.currentPage = 1 | |
| 250 | + this.listOwnerCarData() | |
| 251 | + }, | |
| 252 | + | |
| 253 | + resetMethod() { | |
| 254 | + this.conditions = { | |
| 255 | + carNumLike: '', | |
| 256 | + num: '', | |
| 257 | + valid: '', | |
| 258 | + leaseType: 'H', | |
| 259 | + ownerName: '', | |
| 260 | + link: '', | |
| 261 | + memberCarNumLike: '' | |
| 262 | + } | |
| 263 | + this.currentPage = 1 | |
| 264 | + this.listOwnerCarData() | |
| 265 | + }, | |
| 266 | + | |
| 267 | + handleSizeChange(val) { | |
| 268 | + this.pageSize = val | |
| 269 | + this.listOwnerCarData() | |
| 270 | + }, | |
| 271 | + | |
| 272 | + handleCurrentChange(val) { | |
| 273 | + this.currentPage = val | |
| 274 | + this.listOwnerCarData() | |
| 275 | + }, | |
| 276 | + | |
| 277 | + addOwnerCar() { | |
| 278 | + this.$router.push('/views/car/hireParkingSpace') | |
| 279 | + }, | |
| 280 | + | |
| 281 | + openEditOwnerCar(car) { | |
| 282 | + this.$refs.editCar.open(car) | |
| 283 | + }, | |
| 284 | + | |
| 285 | + openDelOwnerCarModel(car) { | |
| 286 | + this.$refs.deleteOwnerCar.open(car) | |
| 287 | + }, | |
| 288 | + | |
| 289 | + deleteCarParkingSpace(car) { | |
| 290 | + this.$confirm(this.$t('listOwnerCar.confirmRelease'), this.$t('common.tip'), { | |
| 291 | + confirmButtonText: this.$t('common.confirm'), | |
| 292 | + cancelButtonText: this.$t('common.cancel'), | |
| 293 | + type: 'warning' | |
| 294 | + }).then(async () => { | |
| 295 | + try { | |
| 296 | + await deleteCarParkingSpace(car) | |
| 297 | + this.$message.success(this.$t('listOwnerCar.releaseSuccess')) | |
| 298 | + this.listOwnerCarData() | |
| 299 | + } catch (error) { | |
| 300 | + console.error('释放车位失败:', error) | |
| 301 | + this.$message.error(error.message || this.$t('listOwnerCar.releaseError')) | |
| 302 | + } | |
| 303 | + }) | |
| 304 | + }, | |
| 305 | + | |
| 306 | + addCarParkingSpace(car) { | |
| 307 | + this.$router.push(`/views/car/carAddParkingSpace?carId=${car.carId}`) | |
| 308 | + }, | |
| 309 | + | |
| 310 | + toBuyCarMonthCard(car) { | |
| 311 | + this.$router.push(`/views/fee/buyCarMonthCard?carNum=${car.carNum}`) | |
| 312 | + }, | |
| 313 | + | |
| 314 | + toCarMember(car) { | |
| 315 | + this.$router.push(`/pages/property/listOwnerCarMember?carId=${car.carId}&carNum=${car.carNum}`) | |
| 316 | + }, | |
| 317 | + | |
| 318 | + getCarState(car) { | |
| 319 | + if (car.state === '3003') { | |
| 320 | + return this.$t('listOwnerCar.expired') | |
| 321 | + } | |
| 322 | + const endTime = new Date(car.endTime) | |
| 323 | + if (endTime > new Date()) { | |
| 324 | + return this.$t('listOwnerCar.normal') | |
| 325 | + } | |
| 326 | + return this.$t('listOwnerCar.expired') | |
| 327 | + }, | |
| 328 | + | |
| 329 | + openOwnerCarImport() { | |
| 330 | + this.$refs.importOwnerCar.open() | |
| 331 | + }, | |
| 332 | + | |
| 333 | + async exportExcel() { | |
| 334 | + try { | |
| 335 | + const params = { | |
| 336 | + ...this.conditions, | |
| 337 | + communityId: this.communityId, | |
| 338 | + pagePath: 'exportOwnerCar' | |
| 339 | + } | |
| 340 | + await exportData(params) | |
| 341 | + this.$message.success(this.$t('listOwnerCar.exportSuccess')) | |
| 342 | + this.$router.push('/pages/property/downloadTempFile?tab=下载中心') | |
| 343 | + } catch (error) { | |
| 344 | + console.error('导出失败:', error) | |
| 345 | + this.$message.error(error.message || this.$t('listOwnerCar.exportError')) | |
| 346 | + } | |
| 347 | + }, | |
| 348 | + | |
| 349 | + viewIotStateRemark(car) { | |
| 350 | + this.$alert(car.iotRemark, `${car.carNum} ${this.$t('listOwnerCar.iotSyncDetail')}`, { | |
| 351 | + confirmButtonText: this.$t('common.confirm') | |
| 352 | + }) | |
| 353 | + }, | |
| 354 | + | |
| 355 | + } | |
| 356 | +} | |
| 357 | +</script> | |
| 358 | + | |
| 359 | +<style lang="scss" scoped> | |
| 360 | +.list-owner-car-container { | |
| 361 | + padding: 20px; | |
| 362 | + | |
| 363 | + .tree-card { | |
| 364 | + height: 100%; | |
| 365 | + | |
| 366 | + .lease-type-list { | |
| 367 | + list-style: none; | |
| 368 | + padding: 0; | |
| 369 | + margin: 0; | |
| 370 | + | |
| 371 | + li { | |
| 372 | + padding: 10px 15px; | |
| 373 | + text-align: center; | |
| 374 | + cursor: pointer; | |
| 375 | + border-bottom: 1px solid #eee; | |
| 376 | + transition: all 0.3s; | |
| 377 | + | |
| 378 | + &:hover { | |
| 379 | + background-color: #f5f7fa; | |
| 380 | + } | |
| 381 | + | |
| 382 | + &.selected { | |
| 383 | + background-color: #409EFF; | |
| 384 | + color: white; | |
| 385 | + } | |
| 386 | + } | |
| 387 | + } | |
| 388 | + } | |
| 389 | + | |
| 390 | + .search-card { | |
| 391 | + margin-bottom: 20px; | |
| 392 | + } | |
| 393 | + | |
| 394 | + .header-buttons { | |
| 395 | + float: right; | |
| 396 | + } | |
| 397 | + | |
| 398 | + .mt-10 { | |
| 399 | + margin-top: 10px; | |
| 400 | + } | |
| 401 | + | |
| 402 | + .mt-20 { | |
| 403 | + margin-top: 20px; | |
| 404 | + } | |
| 405 | + | |
| 406 | + .text-right { | |
| 407 | + text-align: right; | |
| 408 | + } | |
| 409 | + | |
| 410 | + .el-table .expired-row { | |
| 411 | + background-color: #fef0f0; | |
| 412 | + } | |
| 413 | +} | |
| 414 | +</style> | |
| 0 | 415 | \ No newline at end of file | ... | ... |
src/views/car/parkingBoxManageLang.js
0 → 100644
| 1 | +export const messages = { | |
| 2 | + en: { | |
| 3 | + parkingBoxManage: { | |
| 4 | + searchTitle: 'Search Conditions', | |
| 5 | + boxIdPlaceholder: 'Please enter booth number', | |
| 6 | + boxNamePlaceholder: 'Please enter booth name', | |
| 7 | + tempCarInPlaceholder: 'Please select temporary car entry', | |
| 8 | + yes: 'Yes', | |
| 9 | + no: 'No', | |
| 10 | + searchBtn: 'Search', | |
| 11 | + resetBtn: 'Reset', | |
| 12 | + listTitle: 'Booth Information', | |
| 13 | + boxId: 'Booth Number', | |
| 14 | + boxName: 'Booth Name', | |
| 15 | + parkingLot: 'Parking Lot', | |
| 16 | + tempCarIn: 'Temporary Car Entry', | |
| 17 | + tempAuth: 'Temporary Car Audit', | |
| 18 | + fee: 'Chargeable', | |
| 19 | + blueCarIn: 'Already Present', | |
| 20 | + yelowCarIn: 'Not Present', | |
| 21 | + remark: 'Remark', | |
| 22 | + operation: 'Operation', | |
| 23 | + console: 'Console', | |
| 24 | + dataSource: 'Data comes from IoT system', | |
| 25 | + pagination: 'Pagination' | |
| 26 | + }, | |
| 27 | + addParkingBox: { | |
| 28 | + title: 'Add Booth', | |
| 29 | + boothName: 'Booth Name', | |
| 30 | + parkingLot: 'Parking Lot', | |
| 31 | + tempCarIn: 'Temporary Car Entry', | |
| 32 | + tempAuth: 'Temporary Car Audit', | |
| 33 | + fee: 'Chargeable', | |
| 34 | + blueCarIn: 'Already Present', | |
| 35 | + yelowCarIn: 'Not Present', | |
| 36 | + remark: 'Remark', | |
| 37 | + required: 'Required', | |
| 38 | + optional: 'Optional', | |
| 39 | + save: 'Save', | |
| 40 | + cancel: 'Cancel' | |
| 41 | + }, | |
| 42 | + editParkingBox: { | |
| 43 | + title: 'Edit Booth', | |
| 44 | + boothName: 'Booth Name', | |
| 45 | + parkingLot: 'Parking Lot', | |
| 46 | + tempCarIn: 'Temporary Car Entry', | |
| 47 | + tempAuth: 'Temporary Car Audit', | |
| 48 | + fee: 'Chargeable', | |
| 49 | + blueCarIn: 'Already Present', | |
| 50 | + yelowCarIn: 'Not Present', | |
| 51 | + remark: 'Remark', | |
| 52 | + save: 'Save', | |
| 53 | + cancel: 'Cancel' | |
| 54 | + }, | |
| 55 | + deleteParkingBox: { | |
| 56 | + title: 'Confirm Operation', | |
| 57 | + confirmDelete: 'Confirm delete booth?', | |
| 58 | + cancel: 'Cancel', | |
| 59 | + confirm: 'Confirm Delete' | |
| 60 | + } | |
| 61 | + }, | |
| 62 | + zh: { | |
| 63 | + parkingBoxManage: { | |
| 64 | + searchTitle: '查询条件', | |
| 65 | + boxIdPlaceholder: '请输入岗亭编号', | |
| 66 | + boxNamePlaceholder: '请输入岗亭名称', | |
| 67 | + tempCarInPlaceholder: '请选择临时车进场', | |
| 68 | + yes: '是', | |
| 69 | + no: '否', | |
| 70 | + searchBtn: '查询', | |
| 71 | + resetBtn: '重置', | |
| 72 | + listTitle: '岗亭信息', | |
| 73 | + boxId: '岗亭编号', | |
| 74 | + boxName: '岗亭名称', | |
| 75 | + parkingLot: '停车场', | |
| 76 | + tempCarIn: '临时车进场', | |
| 77 | + tempAuth: '临时车审核', | |
| 78 | + fee: '是否收费', | |
| 79 | + blueCarIn: '已在场', | |
| 80 | + yelowCarIn: '未在场', | |
| 81 | + remark: '备注', | |
| 82 | + operation: '操作', | |
| 83 | + console: '控制台', | |
| 84 | + dataSource: '数据来源于物联网系统,请到物联网系统管理数据', | |
| 85 | + pagination: '分页' | |
| 86 | + }, | |
| 87 | + addParkingBox: { | |
| 88 | + title: '添加岗亭', | |
| 89 | + boothName: '岗亭名称', | |
| 90 | + parkingLot: '停车场', | |
| 91 | + tempCarIn: '临时车进场', | |
| 92 | + tempAuth: '临时车审核', | |
| 93 | + fee: '是否收费', | |
| 94 | + blueCarIn: '已在场', | |
| 95 | + yelowCarIn: '未在场', | |
| 96 | + remark: '备注', | |
| 97 | + required: '必填', | |
| 98 | + optional: '选填', | |
| 99 | + save: '保存', | |
| 100 | + cancel: '取消' | |
| 101 | + }, | |
| 102 | + editParkingBox: { | |
| 103 | + title: '修改岗亭', | |
| 104 | + boothName: '岗亭名称', | |
| 105 | + parkingLot: '停车场', | |
| 106 | + tempCarIn: '临时车进场', | |
| 107 | + tempAuth: '临时车审核', | |
| 108 | + fee: '是否收费', | |
| 109 | + blueCarIn: '已在场', | |
| 110 | + yelowCarIn: '未在场', | |
| 111 | + remark: '备注', | |
| 112 | + save: '保存', | |
| 113 | + cancel: '取消' | |
| 114 | + }, | |
| 115 | + deleteParkingBox: { | |
| 116 | + title: '请确认您的操作', | |
| 117 | + confirmDelete: '确定删除岗亭?', | |
| 118 | + cancel: '点错了', | |
| 119 | + confirm: '确认删除' | |
| 120 | + } | |
| 121 | + } | |
| 122 | +} | |
| 0 | 123 | \ No newline at end of file | ... | ... |
src/views/car/parkingBoxManageList.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div class="parking-box-manage-container"> | |
| 3 | + <el-card class="search-card"> | |
| 4 | + <div slot="header" class="flex justify-between"> | |
| 5 | + <span>{{ $t('parkingBoxManage.searchTitle') }}</span> | |
| 6 | + </div> | |
| 7 | + <el-row :gutter="20"> | |
| 8 | + <el-col :span="6"> | |
| 9 | + <el-input v-model.trim="searchForm.boxId" :placeholder="$t('parkingBoxManage.boxIdPlaceholder')" clearable /> | |
| 10 | + </el-col> | |
| 11 | + <el-col :span="6"> | |
| 12 | + <el-input v-model.trim="searchForm.boxName" :placeholder="$t('parkingBoxManage.boxNamePlaceholder')" | |
| 13 | + clearable /> | |
| 14 | + </el-col> | |
| 15 | + <el-col :span="6"> | |
| 16 | + <el-select v-model="searchForm.tempCarIn" :placeholder="$t('parkingBoxManage.tempCarInPlaceholder')" clearable | |
| 17 | + style="width:100%"> | |
| 18 | + <el-option value="" :label="$t('parkingBoxManage.tempCarInPlaceholder')" /> | |
| 19 | + <el-option value="Y" :label="$t('parkingBoxManage.yes')" /> | |
| 20 | + <el-option value="N" :label="$t('parkingBoxManage.no')" /> | |
| 21 | + </el-select> | |
| 22 | + </el-col> | |
| 23 | + <el-col :span="6"> | |
| 24 | + <el-button type="primary" @click="handleSearch"> | |
| 25 | + {{ $t('parkingBoxManage.searchBtn') }} | |
| 26 | + </el-button> | |
| 27 | + <el-button @click="handleReset"> | |
| 28 | + {{ $t('parkingBoxManage.resetBtn') }} | |
| 29 | + </el-button> | |
| 30 | + </el-col> | |
| 31 | + </el-row> | |
| 32 | + </el-card> | |
| 33 | + | |
| 34 | + <el-card class="list-card"> | |
| 35 | + <div slot="header" class="flex justify-between"> | |
| 36 | + <span>{{ $t('parkingBoxManage.listTitle') }}</span> | |
| 37 | + </div> | |
| 38 | + | |
| 39 | + <el-table v-loading="loading" :data="tableData" border style="width: 100%"> | |
| 40 | + <el-table-column prop="boxId" :label="$t('parkingBoxManage.boxId')" align="center" /> | |
| 41 | + <el-table-column prop="boxName" :label="$t('parkingBoxManage.boxName')" align="center" /> | |
| 42 | + <el-table-column prop="paNum" :label="$t('parkingBoxManage.parkingLot')" align="center" /> | |
| 43 | + <el-table-column prop="tempCarIn" :label="$t('parkingBoxManage.tempCarIn')" align="center"> | |
| 44 | + <template slot-scope="scope"> | |
| 45 | + {{ scope.row.tempCarIn === 'Y' ? $t('parkingBoxManage.yes') : $t('parkingBoxManage.no') }} | |
| 46 | + </template> | |
| 47 | + </el-table-column> | |
| 48 | + <el-table-column prop="tempAuth" :label="$t('parkingBoxManage.tempAuth')" align="center"> | |
| 49 | + <template slot-scope="scope"> | |
| 50 | + {{ scope.row.tempAuth === 'Y' ? $t('parkingBoxManage.yes') : $t('parkingBoxManage.no') }} | |
| 51 | + </template> | |
| 52 | + </el-table-column> | |
| 53 | + <el-table-column prop="fee" :label="$t('parkingBoxManage.fee')" align="center"> | |
| 54 | + <template slot-scope="scope"> | |
| 55 | + {{ scope.row.fee === 'Y' ? $t('parkingBoxManage.yes') : $t('parkingBoxManage.no') }} | |
| 56 | + </template> | |
| 57 | + </el-table-column> | |
| 58 | + <el-table-column prop="blueCarIn" :label="$t('parkingBoxManage.blueCarIn')" align="center"> | |
| 59 | + <template slot-scope="scope"> | |
| 60 | + {{ scope.row.blueCarIn === 'Y' ? $t('parkingBoxManage.yes') : $t('parkingBoxManage.no') }} | |
| 61 | + </template> | |
| 62 | + </el-table-column> | |
| 63 | + <el-table-column prop="yelowCarIn" :label="$t('parkingBoxManage.yelowCarIn')" align="center"> | |
| 64 | + <template slot-scope="scope"> | |
| 65 | + {{ scope.row.yelowCarIn === 'Y' ? $t('parkingBoxManage.yes') : $t('parkingBoxManage.no') }} | |
| 66 | + </template> | |
| 67 | + </el-table-column> | |
| 68 | + <el-table-column prop="remark" :label="$t('parkingBoxManage.remark')" align="center" /> | |
| 69 | + <el-table-column :label="$t('parkingBoxManage.operation')" align="center" width="120"> | |
| 70 | + <template slot-scope="scope"> | |
| 71 | + <el-button v-if="hasPrivilege('502022090904120022')" type="text" size="small" | |
| 72 | + @click="handleOpenConsole(scope.row)"> | |
| 73 | + {{ $t('parkingBoxManage.console') }} | |
| 74 | + </el-button> | |
| 75 | + </template> | |
| 76 | + </el-table-column> | |
| 77 | + </el-table> | |
| 78 | + | |
| 79 | + <el-row class="pagination-row"> | |
| 80 | + <el-col :span="12" class="data-source"> | |
| 81 | + {{ $t('parkingBoxManage.dataSource') }} | |
| 82 | + </el-col> | |
| 83 | + <el-col :span="12"> | |
| 84 | + <el-pagination :current-page="pagination.current" :page-sizes="[10, 20, 30, 50]" :page-size="pagination.size" | |
| 85 | + layout="total, sizes, prev, pager, next, jumper" :total="pagination.total" @size-change="handleSizeChange" | |
| 86 | + @current-change="handleCurrentChange" /> | |
| 87 | + </el-col> | |
| 88 | + </el-row> | |
| 89 | + </el-card> | |
| 90 | + | |
| 91 | + </div> | |
| 92 | +</template> | |
| 93 | + | |
| 94 | +<script> | |
| 95 | +import { getParkingBoxList } from '@/api/car/parkingBoxManageApi' | |
| 96 | + | |
| 97 | +export default { | |
| 98 | + name: 'ParkingBoxManageList', | |
| 99 | + components: { | |
| 100 | + }, | |
| 101 | + data() { | |
| 102 | + return { | |
| 103 | + loading: false, | |
| 104 | + searchForm: { | |
| 105 | + boxId: '', | |
| 106 | + boxName: '', | |
| 107 | + tempCarIn: '' | |
| 108 | + }, | |
| 109 | + tableData: [], | |
| 110 | + pagination: { | |
| 111 | + current: 1, | |
| 112 | + size: 10, | |
| 113 | + total: 0 | |
| 114 | + } | |
| 115 | + } | |
| 116 | + }, | |
| 117 | + created() { | |
| 118 | + this.fetchData() | |
| 119 | + }, | |
| 120 | + methods: { | |
| 121 | + | |
| 122 | + async fetchData() { | |
| 123 | + this.loading = true | |
| 124 | + try { | |
| 125 | + const params = { | |
| 126 | + page: this.pagination.current, | |
| 127 | + row: this.pagination.size, | |
| 128 | + ...this.searchForm | |
| 129 | + } | |
| 130 | + | |
| 131 | + const res = await getParkingBoxList(params) | |
| 132 | + this.tableData = res.data | |
| 133 | + this.pagination.total = res.total || 0 | |
| 134 | + this.pagination.current = res.page || 1 | |
| 135 | + } catch (error) { | |
| 136 | + console.error('获取岗亭列表失败:', error) | |
| 137 | + this.$message.error(this.$t('parkingBoxManage.fetchError')) | |
| 138 | + } finally { | |
| 139 | + this.loading = false | |
| 140 | + } | |
| 141 | + }, | |
| 142 | + | |
| 143 | + handleSearch() { | |
| 144 | + this.pagination.current = 1 | |
| 145 | + this.fetchData() | |
| 146 | + }, | |
| 147 | + | |
| 148 | + handleReset() { | |
| 149 | + this.searchForm = { | |
| 150 | + boxId: '', | |
| 151 | + boxName: '', | |
| 152 | + tempCarIn: '' | |
| 153 | + } | |
| 154 | + this.handleSearch() | |
| 155 | + }, | |
| 156 | + | |
| 157 | + handleSizeChange(size) { | |
| 158 | + this.pagination.size = size | |
| 159 | + this.fetchData() | |
| 160 | + }, | |
| 161 | + | |
| 162 | + handleCurrentChange(current) { | |
| 163 | + this.pagination.current = current | |
| 164 | + this.fetchData() | |
| 165 | + }, | |
| 166 | + | |
| 167 | + handleSuccess() { | |
| 168 | + this.fetchData() | |
| 169 | + }, | |
| 170 | + | |
| 171 | + handleOpenAdd() { | |
| 172 | + this.$refs.addDialog.open() | |
| 173 | + }, | |
| 174 | + | |
| 175 | + handleOpenEdit(row) { | |
| 176 | + this.$refs.editDialog.open(row) | |
| 177 | + }, | |
| 178 | + | |
| 179 | + handleOpenDelete(row) { | |
| 180 | + this.$refs.deleteDialog.open(row) | |
| 181 | + }, | |
| 182 | + | |
| 183 | + handleOpenConsole(row) { | |
| 184 | + // 跳转到控制台页面 | |
| 185 | + this.$router.push({ | |
| 186 | + path: '/car/parkingAreaControl', | |
| 187 | + query: { | |
| 188 | + boxId: row.boxId, | |
| 189 | + paId: row.paId | |
| 190 | + } | |
| 191 | + }) | |
| 192 | + } | |
| 193 | + } | |
| 194 | +} | |
| 195 | +</script> | |
| 196 | + | |
| 197 | +<style lang="scss" scoped> | |
| 198 | +.parking-box-manage-container { | |
| 199 | + padding: 20px; | |
| 200 | + | |
| 201 | + .search-card { | |
| 202 | + margin-bottom: 20px; | |
| 203 | + } | |
| 204 | + | |
| 205 | + .list-card { | |
| 206 | + margin-bottom: 20px; | |
| 207 | + } | |
| 208 | + | |
| 209 | + .pagination-row { | |
| 210 | + margin-top: 20px; | |
| 211 | + display: flex; | |
| 212 | + align-items: center; | |
| 213 | + | |
| 214 | + .data-source { | |
| 215 | + display: flex; | |
| 216 | + align-items: center; | |
| 217 | + color: #999; | |
| 218 | + font-size: 14px; | |
| 219 | + } | |
| 220 | + } | |
| 221 | +} | |
| 222 | +</style> | |
| 0 | 223 | \ No newline at end of file | ... | ... |
src/views/fee/buyCarMonthCardLang.js
0 → 100644
| 1 | +export const messages = { | |
| 2 | + en: { | |
| 3 | + buyCarMonthCard: { | |
| 4 | + title: 'Buy Monthly Card', | |
| 5 | + carNum: 'License Plate', | |
| 6 | + card: 'Monthly Card', | |
| 7 | + paymentMethod: 'Payment Method', | |
| 8 | + receivableAmount: 'Receivable Amount', | |
| 9 | + receivedAmount: 'Received Amount', | |
| 10 | + remark: 'Remark', | |
| 11 | + tip: 'Monthly cards need to be added in the IoT system and must be added to the parking lot where the vehicle is located', | |
| 12 | + placeholders: { | |
| 13 | + carNum: 'Required, please enter license plate number', | |
| 14 | + card: 'Required, please select monthly card', | |
| 15 | + paymentMethod: 'Required, please select payment method', | |
| 16 | + receivableAmount: 'Required, receivable amount', | |
| 17 | + receivedAmount: 'Required, received amount', | |
| 18 | + remark: 'Optional, please enter remark' | |
| 19 | + }, | |
| 20 | + rules: { | |
| 21 | + carNumRequired: 'License plate number is required', | |
| 22 | + cardRequired: 'Monthly card is required', | |
| 23 | + paymentMethodRequired: 'Payment method is required', | |
| 24 | + receivedAmountRequired: 'Received amount is required' | |
| 25 | + }, | |
| 26 | + warnings: { | |
| 27 | + carNotExist: 'Monthly rental car does not exist, please add it first', | |
| 28 | + carNoParkingSpace: 'Monthly rental car is not bound to a parking space' | |
| 29 | + }, | |
| 30 | + errors: { | |
| 31 | + getDictFailed: 'Failed to get payment methods', | |
| 32 | + queryCarFailed: 'Failed to query vehicle information', | |
| 33 | + getCardsFailed: 'Failed to get monthly card list', | |
| 34 | + saveFailed: 'Failed to save monthly card order' | |
| 35 | + }, | |
| 36 | + success: { | |
| 37 | + saveSuccess: 'Monthly card purchased successfully' | |
| 38 | + } | |
| 39 | + } | |
| 40 | + }, | |
| 41 | + zh: { | |
| 42 | + buyCarMonthCard: { | |
| 43 | + title: '购买月卡', | |
| 44 | + carNum: '车牌号', | |
| 45 | + card: '月卡', | |
| 46 | + paymentMethod: '支付方式', | |
| 47 | + receivableAmount: '应收金额', | |
| 48 | + receivedAmount: '实收金额', | |
| 49 | + remark: '备注', | |
| 50 | + tip: '月卡请到物联网系统添加,需要添加到车辆所在的停车场', | |
| 51 | + placeholders: { | |
| 52 | + carNum: '必填,请填写车牌号', | |
| 53 | + card: '必填,请选择月卡', | |
| 54 | + paymentMethod: '必填,请选择支付方式', | |
| 55 | + receivableAmount: '必填,应收金额', | |
| 56 | + receivedAmount: '必填,实收金额', | |
| 57 | + remark: '选填,请填写备注' | |
| 58 | + }, | |
| 59 | + rules: { | |
| 60 | + carNumRequired: '车牌号不能为空', | |
| 61 | + cardRequired: '月卡不能为空', | |
| 62 | + paymentMethodRequired: '支付方式不能为空', | |
| 63 | + receivedAmountRequired: '实收金额不能为空' | |
| 64 | + }, | |
| 65 | + warnings: { | |
| 66 | + carNotExist: '月租车不存在,请先添加为月租车', | |
| 67 | + carNoParkingSpace: '月租车没有绑定车位' | |
| 68 | + }, | |
| 69 | + errors: { | |
| 70 | + getDictFailed: '获取支付方式失败', | |
| 71 | + queryCarFailed: '查询车辆信息失败', | |
| 72 | + getCardsFailed: '获取月卡列表失败', | |
| 73 | + saveFailed: '保存月卡订单失败' | |
| 74 | + }, | |
| 75 | + success: { | |
| 76 | + saveSuccess: '月卡购买成功' | |
| 77 | + } | |
| 78 | + } | |
| 79 | + } | |
| 80 | +} | |
| 0 | 81 | \ No newline at end of file | ... | ... |
src/views/fee/buyCarMonthCardList.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-card class="buy-car-month-card-container"> | |
| 3 | + <div slot="header"> | |
| 4 | + <h5>{{ $t('buyCarMonthCard.title') }}</h5> | |
| 5 | + </div> | |
| 6 | + | |
| 7 | + <el-form ref="form" :model="buyCarMonthCardInfo" label-width="120px"> | |
| 8 | + <el-form-item :label="$t('buyCarMonthCard.carNum')" prop="carNum" | |
| 9 | + :rules="[{ required: true, message: $t('buyCarMonthCard.rules.carNumRequired'), trigger: 'blur' }]"> | |
| 10 | + <el-input v-model="buyCarMonthCardInfo.carNum" :placeholder="$t('buyCarMonthCard.placeholders.carNum')" | |
| 11 | + @blur="_queryOwnerCar" clearable> | |
| 12 | + </el-input> | |
| 13 | + </el-form-item> | |
| 14 | + | |
| 15 | + <el-form-item :label="$t('buyCarMonthCard.card')" prop="cardId" | |
| 16 | + :rules="[{ required: true, message: $t('buyCarMonthCard.rules.cardRequired'), trigger: 'change' }]"> | |
| 17 | + <el-select v-model="buyCarMonthCardInfo.cardId" :placeholder="$t('buyCarMonthCard.placeholders.card')" | |
| 18 | + @change="_changeCard" style="width:100%"> | |
| 19 | + <el-option v-for="(item, index) in buyCarMonthCardInfo.cards" :key="index" | |
| 20 | + :label="`${item.cardName}(${item.cardMonth}${$t('common.month')})`" :value="item.cardId"> | |
| 21 | + </el-option> | |
| 22 | + </el-select> | |
| 23 | + <div class="tip">{{ $t('buyCarMonthCard.tip') }}</div> | |
| 24 | + </el-form-item> | |
| 25 | + | |
| 26 | + <el-form-item :label="$t('buyCarMonthCard.paymentMethod')" prop="primeRate" | |
| 27 | + :rules="[{ required: true, message: $t('buyCarMonthCard.rules.paymentMethodRequired'), trigger: 'change' }]"> | |
| 28 | + <el-select v-model="buyCarMonthCardInfo.primeRate" :placeholder="$t('buyCarMonthCard.placeholders.paymentMethod')" | |
| 29 | + style="width:100%"> | |
| 30 | + <el-option v-for="(item, index) in filteredPrimeRates" :key="index" :label="item.name" :value="item.statusCd"> | |
| 31 | + </el-option> | |
| 32 | + </el-select> | |
| 33 | + </el-form-item> | |
| 34 | + | |
| 35 | + <el-form-item :label="$t('buyCarMonthCard.receivableAmount')"> | |
| 36 | + <el-input v-model="buyCarMonthCardInfo.receivableAmount" | |
| 37 | + :placeholder="$t('buyCarMonthCard.placeholders.receivableAmount')" disabled> | |
| 38 | + </el-input> | |
| 39 | + </el-form-item> | |
| 40 | + | |
| 41 | + <el-form-item :label="$t('buyCarMonthCard.receivedAmount')" prop="receivedAmount" | |
| 42 | + :rules="[{ required: true, message: $t('buyCarMonthCard.rules.receivedAmountRequired'), trigger: 'blur' }]"> | |
| 43 | + <el-input v-model="buyCarMonthCardInfo.receivedAmount" type="number" | |
| 44 | + :placeholder="$t('buyCarMonthCard.placeholders.receivedAmount')"> | |
| 45 | + </el-input> | |
| 46 | + </el-form-item> | |
| 47 | + | |
| 48 | + <el-form-item :label="$t('buyCarMonthCard.remark')"> | |
| 49 | + <el-input v-model="buyCarMonthCardInfo.remark" type="textarea" | |
| 50 | + :placeholder="$t('buyCarMonthCard.placeholders.remark')"> | |
| 51 | + </el-input> | |
| 52 | + </el-form-item> | |
| 53 | + | |
| 54 | + <el-form-item> | |
| 55 | + <el-button type="primary" @click="saveCarMonthOrderInfo"> | |
| 56 | + <i class="el-icon-check"></i>{{ $t('common.submit') }} | |
| 57 | + </el-button> | |
| 58 | + <el-button type="warning" @click="goBack" style="margin-left:20px;"> | |
| 59 | + {{ $t('common.back') }} | |
| 60 | + </el-button> | |
| 61 | + </el-form-item> | |
| 62 | + </el-form> | |
| 63 | + </el-card> | |
| 64 | +</template> | |
| 65 | + | |
| 66 | +<script> | |
| 67 | +import { buyCarMonthOrder, queryOwnerCars, getOpenApi } from '@/api/fee/buyCarMonthCardApi' | |
| 68 | +import { getDict } from '@/api/community/communityApi' | |
| 69 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 70 | + | |
| 71 | +export default { | |
| 72 | + name: 'BuyCarMonthCardList', | |
| 73 | + data() { | |
| 74 | + return { | |
| 75 | + buyCarMonthCardInfo: { | |
| 76 | + orderId: '', | |
| 77 | + cardId: '', | |
| 78 | + carNum: '', | |
| 79 | + carId: '', | |
| 80 | + primeRate: '', | |
| 81 | + receivableAmount: '', | |
| 82 | + receivedAmount: '', | |
| 83 | + remark: '', | |
| 84 | + cards: [], | |
| 85 | + primeRates: [], | |
| 86 | + areaNum: '' | |
| 87 | + }, | |
| 88 | + communityId: '' | |
| 89 | + } | |
| 90 | + }, | |
| 91 | + computed: { | |
| 92 | + filteredPrimeRates() { | |
| 93 | + return this.buyCarMonthCardInfo.primeRates.filter( | |
| 94 | + item => item.statusCd !== '5' && item.statusCd !== '6' && item.statusCd !== '8' | |
| 95 | + ) | |
| 96 | + } | |
| 97 | + }, | |
| 98 | + mounted() { | |
| 99 | + this.communityId = getCommunityId() | |
| 100 | + | |
| 101 | + // 从路由参数获取车牌号 | |
| 102 | + if (this.$route.query.carNum) { | |
| 103 | + this.buyCarMonthCardInfo.carNum = this.$route.query.carNum | |
| 104 | + this._queryOwnerCar() | |
| 105 | + } | |
| 106 | + | |
| 107 | + // 获取支付方式字典 | |
| 108 | + this.getPrimeRateDict() | |
| 109 | + }, | |
| 110 | + methods: { | |
| 111 | + async getPrimeRateDict() { | |
| 112 | + try { | |
| 113 | + const data = await getDict('pay_fee_detail', 'prime_rate') | |
| 114 | + this.buyCarMonthCardInfo.primeRates = data | |
| 115 | + } catch (error) { | |
| 116 | + console.error('获取支付方式字典失败:', error) | |
| 117 | + this.$message.error(this.$t('buyCarMonthCard.errors.getDictFailed')) | |
| 118 | + } | |
| 119 | + }, | |
| 120 | + | |
| 121 | + async _queryOwnerCar() { | |
| 122 | + if (!this.buyCarMonthCardInfo.carNum) return | |
| 123 | + | |
| 124 | + try { | |
| 125 | + const params = { | |
| 126 | + page: 1, | |
| 127 | + row: 1, | |
| 128 | + communityId: this.communityId, | |
| 129 | + carNum: this.buyCarMonthCardInfo.carNum, | |
| 130 | + carTypeCd: '1001' | |
| 131 | + } | |
| 132 | + | |
| 133 | + const res = await queryOwnerCars(params) | |
| 134 | + if (res.total < 1) { | |
| 135 | + this.$message.warning(this.$t('buyCarMonthCard.warnings.carNotExist')) | |
| 136 | + return | |
| 137 | + } | |
| 138 | + | |
| 139 | + const carData = res.data[0] | |
| 140 | + if (!carData.paId) { | |
| 141 | + this.$message.warning(this.$t('buyCarMonthCard.warnings.carNoParkingSpace')) | |
| 142 | + return | |
| 143 | + } | |
| 144 | + | |
| 145 | + this.buyCarMonthCardInfo.carId = carData.carId | |
| 146 | + this.buyCarMonthCardInfo.areaNum = carData.areaNum | |
| 147 | + this._listBuyMonthCards() | |
| 148 | + } catch (error) { | |
| 149 | + console.error('查询车主车辆失败:', error) | |
| 150 | + this.$message.error(this.$t('buyCarMonthCard.errors.queryCarFailed')) | |
| 151 | + } | |
| 152 | + }, | |
| 153 | + | |
| 154 | + async _listBuyMonthCards() { | |
| 155 | + if (!this.buyCarMonthCardInfo.areaNum) return | |
| 156 | + | |
| 157 | + try { | |
| 158 | + const params = { | |
| 159 | + page: 1, | |
| 160 | + row: 100, | |
| 161 | + communityId: this.communityId, | |
| 162 | + paNum: this.buyCarMonthCardInfo.areaNum, | |
| 163 | + iotApiCode: 'queryCarMonthCardBmoImpl' | |
| 164 | + } | |
| 165 | + | |
| 166 | + const res = await getOpenApi(params) | |
| 167 | + this.buyCarMonthCardInfo.cards = res.data.data || [] | |
| 168 | + } catch (error) { | |
| 169 | + console.error('获取月卡列表失败:', error) | |
| 170 | + this.$message.error(this.$t('buyCarMonthCard.errors.getCardsFailed')) | |
| 171 | + } | |
| 172 | + }, | |
| 173 | + | |
| 174 | + _changeCard() { | |
| 175 | + const cardId = this.buyCarMonthCardInfo.cardId | |
| 176 | + const selectedCard = this.buyCarMonthCardInfo.cards.find(item => item.cardId === cardId) | |
| 177 | + | |
| 178 | + if (selectedCard) { | |
| 179 | + this.buyCarMonthCardInfo.receivableAmount = selectedCard.cardPrice | |
| 180 | + this.buyCarMonthCardInfo.receivedAmount = selectedCard.cardPrice | |
| 181 | + } | |
| 182 | + }, | |
| 183 | + | |
| 184 | + async saveCarMonthOrderInfo() { | |
| 185 | + try { | |
| 186 | + // 表单验证 | |
| 187 | + await this.$refs.form.validate() | |
| 188 | + | |
| 189 | + const params = { | |
| 190 | + ...this.buyCarMonthCardInfo, | |
| 191 | + communityId: this.communityId | |
| 192 | + } | |
| 193 | + | |
| 194 | + const res = await buyCarMonthOrder(params) | |
| 195 | + if (res.code === 0) { | |
| 196 | + this.$message.success(this.$t('buyCarMonthCard.success.saveSuccess')) | |
| 197 | + this.goBack() | |
| 198 | + } else { | |
| 199 | + this.$message.error(res.msg || this.$t('buyCarMonthCard.errors.saveFailed')) | |
| 200 | + } | |
| 201 | + } catch (error) { | |
| 202 | + if (error instanceof Error) { | |
| 203 | + console.error('保存月卡订单失败:', error) | |
| 204 | + this.$message.error(error.message) | |
| 205 | + } | |
| 206 | + // 验证失败不显示错误 | |
| 207 | + } | |
| 208 | + }, | |
| 209 | + | |
| 210 | + clearBuyCarMonthCardInfo() { | |
| 211 | + this.$refs.form.resetFields() | |
| 212 | + this.buyCarMonthCardInfo.cards = [] | |
| 213 | + this.buyCarMonthCardInfo.areaNum = '' | |
| 214 | + this.getPrimeRateDict() | |
| 215 | + }, | |
| 216 | + | |
| 217 | + goBack() { | |
| 218 | + this.$router.go(-1) | |
| 219 | + } | |
| 220 | + } | |
| 221 | +} | |
| 222 | +</script> | |
| 223 | + | |
| 224 | +<style scoped> | |
| 225 | +.buy-car-month-card-container { | |
| 226 | + margin: 20px; | |
| 227 | +} | |
| 228 | + | |
| 229 | +.tip { | |
| 230 | + font-size: 12px; | |
| 231 | + color: #909399; | |
| 232 | + margin-top: 5px; | |
| 233 | +} | |
| 234 | +</style> | |
| 0 | 235 | \ No newline at end of file | ... | ... |