Commit 2c760b978dd3fcc8f758ef3f5b063cb7017f74f1

Authored by wuxw
1 parent a3057712

完成停车功能

src/api/car/addParkingSpaceApplyApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 查询业主列表
  4 +export function queryOwners(params) {
  5 + return new Promise((resolve, reject) => {
  6 + request({
  7 + url: '/owner.queryOwners',
  8 + method: 'get',
  9 + params
  10 + }).then(response => {
  11 + const res = response.data
  12 + if (res.code === 0) {
  13 + resolve({
  14 + data: res.data,
  15 + total: res.records,
  16 + currentPage: params.page,
  17 + pageSize: params.row
  18 + })
  19 + } else {
  20 + reject(new Error(res.msg || 'Failed to query owners'))
  21 + }
  22 + }).catch(error => {
  23 + reject(error)
  24 + })
  25 + })
  26 +}
  27 +
  28 +// 保存车位申请
  29 +export function saveParkingSpaceApply(data) {
  30 + return new Promise((resolve, reject) => {
  31 + request({
  32 + url: '/parkingSpaceApply.saveParkingSpaceApply',
  33 + method: 'post',
  34 + data
  35 + }).then(response => {
  36 + const res = response.data
  37 + if (res.code === 0) {
  38 + resolve(res)
  39 + } else {
  40 + reject(new Error(res.msg || 'Failed to save parking space apply'))
  41 + }
  42 + }).catch(error => {
  43 + reject(error)
  44 + })
  45 + })
  46 +}
0 \ No newline at end of file 47 \ No newline at end of file
src/api/car/auditParkingSpaceApplyApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 查询停车位申请详情
  4 +export function getParkingSpaceApplyDetail(params) {
  5 + return new Promise((resolve, reject) => {
  6 + request({
  7 + url: '/parkingSpaceApply.listParkingSpaceApply',
  8 + method: 'get',
  9 + params
  10 + }).then(response => {
  11 + const res = response.data
  12 + if (res.code == 0) {
  13 + resolve(res)
  14 + } else {
  15 + reject(new Error(res.msg || '获取申请详情失败'))
  16 + }
  17 + }).catch(error => {
  18 + reject(error)
  19 + })
  20 + })
  21 +}
  22 +
  23 +// 审核停车位申请
  24 +export function auditParkingSpaceApply(data) {
  25 + return new Promise((resolve, reject) => {
  26 + request({
  27 + url: '/parkingSpaceApply.auditParkingSpaceApply',
  28 + method: 'post',
  29 + data
  30 + }).then(response => {
  31 + const res = response.data
  32 + if (res.code == 0) {
  33 + resolve(res)
  34 + } else {
  35 + reject(new Error(res.msg || '审核失败'))
  36 + }
  37 + }).catch(error => {
  38 + reject(error)
  39 + })
  40 + })
  41 +}
  42 +
  43 +// 查询停车位列表
  44 +export function queryParkingSpaces(params) {
  45 + return new Promise((resolve, reject) => {
  46 + request({
  47 + url: '/parkingSpace.queryParkingSpaces',
  48 + method: 'get',
  49 + params
  50 + }).then(response => {
  51 + const res = response.data
  52 + if (res.code == 0) {
  53 + resolve(res)
  54 + } else {
  55 + reject(new Error(res.msg || '查询停车位失败'))
  56 + }
  57 + }).catch(error => {
  58 + reject(error)
  59 + })
  60 + })
  61 +}
  62 +
  63 +// 查询停车场列表
  64 +export function listParkingAreas(params) {
  65 + return new Promise((resolve, reject) => {
  66 + request({
  67 + url: '/parkingArea.listParkingAreas',
  68 + method: 'get',
  69 + params
  70 + }).then(response => {
  71 + const res = response.data
  72 + if (res.code == 0) {
  73 + resolve(res)
  74 + } else {
  75 + reject(new Error(res.msg || '查询停车场失败'))
  76 + }
  77 + }).catch(error => {
  78 + reject(error)
  79 + })
  80 + })
  81 +}
0 \ No newline at end of file 82 \ No newline at end of file
src/api/car/parkingSpaceApplyManageApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 获取车位申请列表
  5 +export function listParkingSpaceApply(params) {
  6 + return new Promise((resolve, reject) => {
  7 + params.communityId = getCommunityId()
  8 + request({
  9 + url: '/parkingSpaceApply.listParkingSpaceApply',
  10 + method: 'get',
  11 + params
  12 + }).then(response => {
  13 + const res = response.data
  14 + if (res.code === 0) {
  15 + resolve(res)
  16 + } else {
  17 + reject(new Error(res.msg || '获取车位申请列表失败'))
  18 + }
  19 + }).catch(error => {
  20 + reject(error)
  21 + })
  22 + })
  23 +}
  24 +
  25 +// 更新车位申请
  26 +export function updateParkingSpaceApply(data) {
  27 + return new Promise((resolve, reject) => {
  28 + data.communityId = getCommunityId()
  29 + request({
  30 + url: '/parkingSpaceApply.updateParkingSpaceApply',
  31 + method: 'post',
  32 + data
  33 + }).then(response => {
  34 + const res = response.data
  35 + if (res.code === 0) {
  36 + resolve(res)
  37 + } else {
  38 + reject(new Error(res.msg || '更新车位申请失败'))
  39 + }
  40 + }).catch(error => {
  41 + reject(error)
  42 + })
  43 + })
  44 +}
  45 +
  46 +// 删除车位申请
  47 +export function deleteParkingSpaceApply(data) {
  48 + return new Promise((resolve, reject) => {
  49 + data.communityId = getCommunityId()
  50 + request({
  51 + url: '/parkingSpaceApply.deleteParkingSpaceApply',
  52 + method: 'post',
  53 + data
  54 + }).then(response => {
  55 + const res = response.data
  56 + if (res.code === 0) {
  57 + resolve(res)
  58 + } else {
  59 + reject(new Error(res.msg || '删除车位申请失败'))
  60 + }
  61 + }).catch(error => {
  62 + reject(error)
  63 + })
  64 + })
  65 +}
0 \ No newline at end of file 66 \ No newline at end of file
src/api/car/remainingParkingSpaceApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +/**
  4 + * 获取剩余车位信息
  5 + * @param {Object} params 请求参数
  6 + * @returns {Promise} Promise对象
  7 + */
  8 +export function getRemainingParkingSpace(params) {
  9 + return new Promise((resolve, reject) => {
  10 + request({
  11 + url: '/iot.getOpenApi',
  12 + method: 'get',
  13 + params
  14 + }).then(response => {
  15 + const res = response.data
  16 + if (res.code === 0) {
  17 + resolve(res)
  18 + } else {
  19 + reject(new Error(res.msg || 'Failed to get remaining parking space'))
  20 + }
  21 + }).catch(error => {
  22 + reject(error)
  23 + })
  24 + })
  25 +}
0 \ No newline at end of file 26 \ No newline at end of file
src/api/car/tempCarPaymentApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 获取停车区域列表
  4 +export function listParkingAreas(params) {
  5 + return new Promise((resolve, reject) => {
  6 + request({
  7 + url: '/parkingArea.listParkingAreas',
  8 + method: 'get',
  9 + params
  10 + }).then(response => {
  11 + const res = response.data
  12 + resolve(res)
  13 + }).catch(error => {
  14 + reject(error)
  15 + })
  16 + })
  17 +}
  18 +
  19 +// 获取车辆进出支付列表
  20 +export function getCarInoutPaymentList(params) {
  21 + return new Promise((resolve, reject) => {
  22 + request({
  23 + url: '/iot.getOpenApi',
  24 + method: 'get',
  25 + params
  26 + }).then(response => {
  27 + const res = response.data
  28 + if (res.code === 0) {
  29 + resolve({
  30 + data: res.data,
  31 + total: res.total,
  32 + records: res.records
  33 + })
  34 + } else {
  35 + reject(new Error(res.msg || '获取车辆进出支付列表失败'))
  36 + }
  37 + }).catch(error => {
  38 + reject(error)
  39 + })
  40 + })
  41 +}
0 \ No newline at end of file 42 \ No newline at end of file
src/components/car/chooseParkingSpace.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="$t('auditParkingSpaceApply.selectParkingSpace')" :visible.sync="visible" width="80%"
  3 + @close="handleClose">
  4 + <el-card>
  5 + <el-row :gutter="20">
  6 + <el-col :span="18"></el-col>
  7 + <el-col :span="6">
  8 + <el-input-group>
  9 + <el-input v-model="searchParams.areaNum" :placeholder="$t('auditParkingSpaceApply.inputParkingLot')" />
  10 + <el-button type="primary" @click="queryParkingSpaces">
  11 + {{ $t('common.search') }}
  12 + </el-button>
  13 + </el-input-group>
  14 + </el-col>
  15 + </el-row>
  16 +
  17 + <el-table :data="parkingSpaces" style="width: 100%" border>
  18 + <el-table-column prop="areaNum" :label="$t('auditParkingSpaceApply.parkingLot')" align="center">
  19 + <template slot-scope="scope">
  20 + {{ scope.row.areaNum }}{{ $t('auditParkingSpaceApply.parkingLotUnit') }}
  21 + </template>
  22 + </el-table-column>
  23 + <el-table-column prop="num" :label="$t('auditParkingSpaceApply.parkingSpace')" align="center">
  24 + <template slot-scope="scope">
  25 + {{ scope.row.num }}{{ $t('auditParkingSpaceApply.parkingSpaceUnit') }}
  26 + </template>
  27 + </el-table-column>
  28 + <el-table-column prop="state" :label="$t('auditParkingSpaceApply.parkingStatus')" align="center">
  29 + <template slot-scope="scope">
  30 + {{ viewParkingSpaceState(scope.row.state) }}
  31 + </template>
  32 + </el-table-column>
  33 + <el-table-column prop="parkingTypeName" :label="$t('auditParkingSpaceApply.parkingType')" align="center" />
  34 + <el-table-column prop="area" :label="$t('auditParkingSpaceApply.area')" align="center" />
  35 + <el-table-column prop="psId" :label="$t('auditParkingSpaceApply.parkingSpace') + 'ID'" align="center" />
  36 + <el-table-column :label="$t('auditParkingSpaceApply.operation')" align="center">
  37 + <template slot-scope="scope">
  38 + <el-button size="mini" type="primary" @click="chooseParkingSpace(scope.row)">
  39 + {{ $t('auditParkingSpaceApply.choose') }}
  40 + </el-button>
  41 + </template>
  42 + </el-table-column>
  43 + </el-table>
  44 +
  45 + <el-pagination :current-page="pagination.currentPage" :page-sizes="[10, 20, 30, 50]"
  46 + :page-size="pagination.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="pagination.total"
  47 + @size-change="handleSizeChange" @current-change="handleCurrentChange" />
  48 + </el-card>
  49 + </el-dialog>
  50 +</template>
  51 +
  52 +<script>
  53 +import { queryParkingSpaces } from '@/api/car/auditParkingSpaceApplyApi'
  54 +import { getCommunityId } from '@/api/community/communityApi'
  55 +
  56 +export default {
  57 + name: 'ChooseParkingSpace',
  58 + props: {
  59 + visible: {
  60 + type: Boolean,
  61 + default: false
  62 + },
  63 + paId: {
  64 + type: String,
  65 + default: ''
  66 + }
  67 + },
  68 + data() {
  69 + return {
  70 + searchParams: {
  71 + areaNum: '',
  72 + state: 'F' // 默认查询空闲车位
  73 + },
  74 + parkingSpaces: [],
  75 + pagination: {
  76 + currentPage: 1,
  77 + pageSize: 10,
  78 + total: 0
  79 + },
  80 + communityId: getCommunityId()
  81 + }
  82 + },
  83 + methods: {
  84 + open() {
  85 + this.visible = true
  86 + this.queryParkingSpaces()
  87 + },
  88 + handleClose() {
  89 + this.$emit('update:visible', false)
  90 + },
  91 + async queryParkingSpaces() {
  92 + try {
  93 + const params = {
  94 + page: this.pagination.currentPage,
  95 + row: this.pagination.pageSize,
  96 + communityId: this.communityId,
  97 + ...this.searchParams,
  98 + paId: this.paId
  99 + }
  100 +
  101 + const res = await queryParkingSpaces(params)
  102 + this.parkingSpaces = res.data.parkingSpaces
  103 + this.pagination.total = res.data.total
  104 + } catch (error) {
  105 + this.$message.error(this.$t('common.queryFailed'))
  106 + }
  107 + },
  108 + chooseParkingSpace(parkingSpace) {
  109 + this.$emit('choose', parkingSpace)
  110 + this.handleClose()
  111 + },
  112 + viewParkingSpaceState(state) {
  113 + const states = {
  114 + 'F': this.$t('auditParkingSpaceApply.free'),
  115 + 'S': this.$t('auditParkingSpaceApply.sold'),
  116 + 'H': this.$t('auditParkingSpaceApply.rented'),
  117 + }
  118 + return states[state] || this.$t('auditParkingSpaceApply.unknown')
  119 + },
  120 + handleSizeChange(val) {
  121 + this.pagination.pageSize = val
  122 + this.queryParkingSpaces()
  123 + },
  124 + handleCurrentChange(val) {
  125 + this.pagination.currentPage = val
  126 + this.queryParkingSpaces()
  127 + }
  128 + }
  129 +}
  130 +</script>
  131 +
  132 +<style scoped>
  133 +.el-input-group {
  134 + display: flex;
  135 +}
  136 +</style>
0 \ No newline at end of file 137 \ No newline at end of file
src/components/car/deleteParkingSpaceApply.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('deleteParkingSpaceApply.confirmOperation')"
  4 + :visible.sync="visible"
  5 + width="500px"
  6 + >
  7 + <div class="text-center">
  8 + <p style="font-size: 16px; margin-bottom: 20px;">
  9 + {{ $t('deleteParkingSpaceApply.deletePrompt') }}
  10 + </p>
  11 + </div>
  12 +
  13 + <div slot="footer" class="dialog-footer">
  14 + <el-button @click="visible = false">
  15 + {{ $t('deleteParkingSpaceApply.cancel') }}
  16 + </el-button>
  17 + <el-button type="danger" @click="confirmDelete">
  18 + {{ $t('deleteParkingSpaceApply.confirmDeleteAction') }}
  19 + </el-button>
  20 + </div>
  21 + </el-dialog>
  22 +</template>
  23 +
  24 +<script>
  25 +import { deleteParkingSpaceApply } from '@/api/car/parkingSpaceApplyManageApi'
  26 +
  27 +export default {
  28 + name: 'DeleteParkingSpaceApply',
  29 + data() {
  30 + return {
  31 + visible: false,
  32 + currentApply: {}
  33 + }
  34 + },
  35 + methods: {
  36 + open(apply) {
  37 + this.currentApply = { ...apply }
  38 + this.visible = true
  39 + },
  40 +
  41 + async confirmDelete() {
  42 + try {
  43 + const response = await deleteParkingSpaceApply({
  44 + applyId: this.currentApply.applyId
  45 + })
  46 +
  47 + if (response.code === 0) {
  48 + this.$message.success(this.$t('common.deleteSuccess'))
  49 + this.visible = false
  50 + this.$emit('success')
  51 + } else {
  52 + this.$message.error(response.msg || this.$t('common.deleteFailed'))
  53 + }
  54 + } catch (error) {
  55 + console.error('Error deleting parking space application:', error)
  56 + this.$message.error(this.$t('common.requestError'))
  57 + }
  58 + }
  59 + }
  60 +}
  61 +</script>
0 \ No newline at end of file 62 \ No newline at end of file
src/components/car/editParkingSpaceApply.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('editParkingSpaceApply.editApplication')"
  4 + :visible.sync="visible"
  5 + width="800px"
  6 + @close="closeDialog"
  7 + >
  8 + <el-form
  9 + ref="form"
  10 + :model="formData"
  11 + :rules="rules"
  12 + label-width="150px"
  13 + >
  14 + <el-form-item
  15 + :label="$t('editParkingSpaceApply.licensePlate')"
  16 + prop="carNum"
  17 + >
  18 + <el-input
  19 + v-model="formData.carNum"
  20 + :placeholder="$t('editParkingSpaceApply.fillLicensePlate')"
  21 + />
  22 + </el-form-item>
  23 +
  24 + <el-form-item
  25 + :label="$t('editParkingSpaceApply.carBrand')"
  26 + prop="carBrand"
  27 + >
  28 + <el-input
  29 + v-model="formData.carBrand"
  30 + :placeholder="$t('editParkingSpaceApply.fillCarBrand')"
  31 + />
  32 + </el-form-item>
  33 +
  34 + <el-form-item
  35 + :label="$t('editParkingSpaceApply.vehicleType')"
  36 + prop="carType"
  37 + >
  38 + <el-select
  39 + v-model="formData.carType"
  40 + :placeholder="$t('editParkingSpaceApply.selectVehicleType')"
  41 + style="width: 100%"
  42 + >
  43 + <el-option
  44 + :label="$t('parkingSpaceApplyManage.homeCar')"
  45 + value="9901"
  46 + />
  47 + <el-option
  48 + :label="$t('parkingSpaceApplyManage.bus')"
  49 + value="9902"
  50 + />
  51 + <el-option
  52 + :label="$t('parkingSpaceApplyManage.truck')"
  53 + value="9903"
  54 + />
  55 + </el-select>
  56 + </el-form-item>
  57 +
  58 + <el-form-item
  59 + :label="$t('editParkingSpaceApply.color')"
  60 + prop="carColor"
  61 + >
  62 + <el-input
  63 + v-model="formData.carColor"
  64 + :placeholder="$t('editParkingSpaceApply.fillColor')"
  65 + />
  66 + </el-form-item>
  67 +
  68 + <el-form-item
  69 + :label="$t('editParkingSpaceApply.startTime')"
  70 + prop="startTime"
  71 + >
  72 + <el-date-picker
  73 + v-model="formData.startTime"
  74 + type="datetime"
  75 + :placeholder="$t('editParkingSpaceApply.fillStartTime')"
  76 + value-format="yyyy-MM-dd HH:mm:ss"
  77 + style="width: 100%"
  78 + />
  79 + </el-form-item>
  80 +
  81 + <el-form-item
  82 + :label="$t('editParkingSpaceApply.endTime')"
  83 + prop="endTime"
  84 + >
  85 + <el-date-picker
  86 + v-model="formData.endTime"
  87 + type="datetime"
  88 + :placeholder="$t('editParkingSpaceApply.fillEndTime')"
  89 + value-format="yyyy-MM-dd HH:mm:ss"
  90 + style="width: 100%"
  91 + />
  92 + </el-form-item>
  93 +
  94 + <el-form-item :label="$t('editParkingSpaceApply.applicant')">
  95 + <el-input
  96 + v-model="formData.applyPersonName"
  97 + disabled
  98 + :placeholder="$t('editParkingSpaceApply.fillApplicant')"
  99 + />
  100 + </el-form-item>
  101 +
  102 + <el-form-item :label="$t('editParkingSpaceApply.applicantPhone')">
  103 + <el-input
  104 + v-model="formData.applyPersonLink"
  105 + disabled
  106 + :placeholder="$t('editParkingSpaceApply.fillApplicantPhone')"
  107 + />
  108 + </el-form-item>
  109 +
  110 + <el-form-item :label="$t('editParkingSpaceApply.remarks')">
  111 + <el-input
  112 + v-model="formData.remark"
  113 + type="textarea"
  114 + :rows="3"
  115 + :placeholder="$t('editParkingSpaceApply.optional')"
  116 + />
  117 + </el-form-item>
  118 + </el-form>
  119 +
  120 + <div slot="footer" class="dialog-footer">
  121 + <el-button @click="visible = false">
  122 + {{ $t('editParkingSpaceApply.cancel') }}
  123 + </el-button>
  124 + <el-button type="primary" @click="submitForm">
  125 + {{ $t('editParkingSpaceApply.save') }}
  126 + </el-button>
  127 + </div>
  128 + </el-dialog>
  129 +</template>
  130 +
  131 +<script>
  132 +import { updateParkingSpaceApply } from '@/api/car/parkingSpaceApplyManageApi'
  133 +
  134 +export default {
  135 + name: 'EditParkingSpaceApply',
  136 + data() {
  137 + return {
  138 + visible: false,
  139 + formData: {
  140 + applyId: '',
  141 + carNum: '',
  142 + carBrand: '',
  143 + carType: '',
  144 + carColor: '',
  145 + startTime: '',
  146 + endTime: '',
  147 + applyPersonName: '',
  148 + applyPersonLink: '',
  149 + applyPersonId: '',
  150 + state: '1001',
  151 + remark: ''
  152 + },
  153 + rules: {
  154 + carNum: [
  155 + { required: true, message: this.$t('editParkingSpaceApply.fillLicensePlate'), trigger: 'blur' }
  156 + ],
  157 + carBrand: [
  158 + { required: true, message: this.$t('editParkingSpaceApply.fillCarBrand'), trigger: 'blur' }
  159 + ],
  160 + carType: [
  161 + { required: true, message: this.$t('editParkingSpaceApply.selectVehicleType'), trigger: 'change' }
  162 + ],
  163 + carColor: [
  164 + { required: true, message: this.$t('editParkingSpaceApply.fillColor'), trigger: 'blur' }
  165 + ],
  166 + startTime: [
  167 + { required: true, message: this.$t('editParkingSpaceApply.fillStartTime'), trigger: 'change' }
  168 + ],
  169 + endTime: [
  170 + { required: true, message: this.$t('editParkingSpaceApply.fillEndTime'), trigger: 'change' }
  171 + ]
  172 + }
  173 + }
  174 + },
  175 + methods: {
  176 + open(data) {
  177 + this.formData = { ...data }
  178 + this.visible = true
  179 + },
  180 +
  181 + closeDialog() {
  182 + this.$refs.form.resetFields()
  183 + },
  184 +
  185 + submitForm() {
  186 + this.$refs.form.validate(async valid => {
  187 + if (valid) {
  188 + try {
  189 + const response = await updateParkingSpaceApply(this.formData)
  190 + if (response.code === 0) {
  191 + this.$message.success(this.$t('common.updateSuccess'))
  192 + this.visible = false
  193 + this.$emit('success')
  194 + } else {
  195 + this.$message.error(response.msg || this.$t('common.updateFailed'))
  196 + }
  197 + } catch (error) {
  198 + console.error('Error updating parking space application:', error)
  199 + this.$message.error(this.$t('common.requestError'))
  200 + }
  201 + }
  202 + })
  203 + }
  204 + }
  205 +}
  206 +</script>
0 \ No newline at end of file 207 \ No newline at end of file
src/components/car/searchOwner.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('searchOwner.title')"
  4 + :visible.sync="visible"
  5 + width="80%"
  6 + @close="handleClose"
  7 + >
  8 + <el-card>
  9 + <el-row :gutter="20">
  10 + <el-col :span="8">
  11 + <el-input
  12 + v-model="searchInfo.roomName"
  13 + :placeholder="$t('searchOwner.placeholderRoom')"
  14 + clearable
  15 + />
  16 + </el-col>
  17 + <el-col :span="8">
  18 + <el-input
  19 + v-model="searchInfo._currentOwnerName"
  20 + :placeholder="$t('searchOwner.placeholderOwner')"
  21 + clearable
  22 + />
  23 + </el-col>
  24 + <el-col :span="8" style="text-align: right">
  25 + <el-button
  26 + type="primary"
  27 + @click="searchOwners"
  28 + >
  29 + <i class="el-icon-search"></i>
  30 + {{ $t('common.search') }}
  31 + </el-button>
  32 + <el-button
  33 + type="primary"
  34 + @click="resetOwners"
  35 + >
  36 + {{ $t('common.reset') }}
  37 + </el-button>
  38 + </el-col>
  39 + </el-row>
  40 +
  41 + <el-table
  42 + :data="owners"
  43 + style="width: 100%; margin-top: 20px"
  44 + border
  45 + >
  46 + <el-table-column
  47 + prop="memberId"
  48 + :label="$t('searchOwner.memberId')"
  49 + align="center"
  50 + />
  51 + <el-table-column
  52 + prop="name"
  53 + :label="$t('searchOwner.name')"
  54 + align="center"
  55 + />
  56 + <el-table-column
  57 + prop="personTypeName"
  58 + :label="$t('searchOwner.personType')"
  59 + align="center"
  60 + />
  61 + <el-table-column
  62 + prop="personRoleName"
  63 + :label="$t('searchOwner.personRole')"
  64 + align="center"
  65 + />
  66 + <el-table-column
  67 + prop="idCard"
  68 + :label="$t('searchOwner.idCard')"
  69 + align="center"
  70 + />
  71 + <el-table-column
  72 + prop="link"
  73 + :label="$t('searchOwner.link')"
  74 + align="center"
  75 + />
  76 + <el-table-column
  77 + :label="$t('common.operation')"
  78 + align="center"
  79 + >
  80 + <template slot-scope="scope">
  81 + <el-button
  82 + type="primary"
  83 + size="small"
  84 + @click="chooseOwner(scope.row)"
  85 + >
  86 + {{ $t('common.select') }}
  87 + </el-button>
  88 + </template>
  89 + </el-table-column>
  90 + </el-table>
  91 +
  92 + <el-pagination
  93 + :current-page="page.current"
  94 + :page-sizes="[10, 20, 30, 50]"
  95 + :page-size="page.size"
  96 + :total="page.total"
  97 + layout="total, sizes, prev, pager, next, jumper"
  98 + style="margin-top: 20px"
  99 + @size-change="handleSizeChange"
  100 + @current-change="handleCurrentChange"
  101 + />
  102 + </el-card>
  103 + </el-dialog>
  104 +</template>
  105 +
  106 +<script>
  107 +import { queryOwners } from '@/api/car/addParkingSpaceApplyApi'
  108 +
  109 +export default {
  110 + name: 'SearchOwner',
  111 + data() {
  112 + return {
  113 + visible: false,
  114 + searchInfo: {
  115 + owners: [],
  116 + _currentOwnerName: '',
  117 + roomName: '',
  118 + ownerTypeCd: '1001'
  119 + },
  120 + owners: [],
  121 + page: {
  122 + current: 1,
  123 + size: 10,
  124 + total: 0
  125 + }
  126 + }
  127 + },
  128 + methods: {
  129 + open() {
  130 + this.visible = true
  131 + this.resetOwners()
  132 + this._loadAllOwnerInfo(1, 10)
  133 + },
  134 + handleClose() {
  135 + this.visible = false
  136 + },
  137 + async _loadAllOwnerInfo(page, size) {
  138 + try {
  139 + const params = {
  140 + page: page,
  141 + row: size,
  142 + communityId: this.$store.getters.communityId,
  143 + name: this.searchInfo._currentOwnerName.trim(),
  144 + roomName: this.searchInfo.roomName.trim(),
  145 + ownerTypeCd: this.searchInfo.ownerTypeCd
  146 + }
  147 +
  148 + const res = await queryOwners(params)
  149 + this.owners = res.data
  150 + this.page.total = res.total
  151 + this.page.current = page
  152 + this.page.size = size
  153 + } catch (error) {
  154 + console.error('获取业主列表失败:', error)
  155 + }
  156 + },
  157 + chooseOwner(owner) {
  158 + this.$emit('choose-owner', owner)
  159 + this.visible = false
  160 + },
  161 + searchOwners() {
  162 + this._loadAllOwnerInfo(1, this.page.size)
  163 + },
  164 + resetOwners() {
  165 + this.searchInfo = {
  166 + owners: [],
  167 + _currentOwnerName: '',
  168 + roomName: '',
  169 + ownerTypeCd: '1001'
  170 + }
  171 + this._loadAllOwnerInfo(1, this.page.size)
  172 + },
  173 + handleSizeChange(size) {
  174 + this._loadAllOwnerInfo(this.page.current, size)
  175 + },
  176 + handleCurrentChange(page) {
  177 + this._loadAllOwnerInfo(page, this.page.size)
  178 + }
  179 + }
  180 +}
  181 +</script>
0 \ No newline at end of file 182 \ No newline at end of file
src/components/car/searchOwnerLang.js 0 → 100644
  1 +export default {
  2 + en: {
  3 + searchOwner: {
  4 + title: 'Select Owner',
  5 + placeholderRoom: 'Enter room number (building-unit-room)',
  6 + placeholderOwner: 'Enter owner name',
  7 + memberId: 'Owner ID',
  8 + name: 'Name',
  9 + personType: 'Person Type',
  10 + personRole: 'Person Role',
  11 + idCard: 'ID Card',
  12 + link: 'Contact'
  13 + }
  14 + },
  15 + zh: {
  16 + searchOwner: {
  17 + title: '选择业主',
  18 + placeholderRoom: '输入房屋编号楼栋-单元-房屋',
  19 + placeholderOwner: '输入业主名称',
  20 + memberId: '业主编号',
  21 + name: '名称',
  22 + personType: '人员类型',
  23 + personRole: '人员角色',
  24 + idCard: '证件号',
  25 + link: '联系方式'
  26 + }
  27 + }
  28 +}
0 \ No newline at end of file 29 \ No newline at end of file
src/i18n/index.js
@@ -153,6 +153,11 @@ import { messages as carAddParkingSpaceMessages } from &#39;../views/car/carAddParki @@ -153,6 +153,11 @@ import { messages as carAddParkingSpaceMessages } from &#39;../views/car/carAddParki
153 import { messages as buyCarMonthCardMessages } from '../views/fee/buyCarMonthCardLang' 153 import { messages as buyCarMonthCardMessages } from '../views/fee/buyCarMonthCardLang'
154 import { messages as carInoutManageMessages } from '../views/car/carInoutManageLang' 154 import { messages as carInoutManageMessages } from '../views/car/carInoutManageLang'
155 import { messages as carInManageMessages } from '../views/car/carInManageLang' 155 import { messages as carInManageMessages } from '../views/car/carInManageLang'
  156 +import { messages as remainingParkingSpaceMessages } from '../views/car/remainingParkingSpaceLang'
  157 +import { messages as tempCarPaymentMessages } from '../views/car/tempCarPaymentLang'
  158 +import { messages as parkingSpaceApplyManageMessages } from '../views/car/parkingSpaceApplyManageLang'
  159 +import { messages as addParkingSpaceApplyMessages } from '../views/car/addParkingSpaceApplyLang'
  160 +import { messages as auditParkingSpaceApplyMessages } from '../views/car/auditParkingSpaceApplyLang'
156 161
157 Vue.use(VueI18n) 162 Vue.use(VueI18n)
158 163
@@ -310,6 +315,11 @@ const messages = { @@ -310,6 +315,11 @@ const messages = {
310 ...buyCarMonthCardMessages.en, 315 ...buyCarMonthCardMessages.en,
311 ...carInoutManageMessages.en, 316 ...carInoutManageMessages.en,
312 ...carInManageMessages.en, 317 ...carInManageMessages.en,
  318 + ...remainingParkingSpaceMessages.en,
  319 + ...tempCarPaymentMessages.en,
  320 + ...parkingSpaceApplyManageMessages.en,
  321 + ...addParkingSpaceApplyMessages.en,
  322 + ...auditParkingSpaceApplyMessages.en,
313 }, 323 },
314 zh: { 324 zh: {
315 ...loginMessages.zh, 325 ...loginMessages.zh,
@@ -463,6 +473,11 @@ const messages = { @@ -463,6 +473,11 @@ const messages = {
463 ...buyCarMonthCardMessages.zh, 473 ...buyCarMonthCardMessages.zh,
464 ...carInoutManageMessages.zh, 474 ...carInoutManageMessages.zh,
465 ...carInManageMessages.zh, 475 ...carInManageMessages.zh,
  476 + ...remainingParkingSpaceMessages.zh,
  477 + ...tempCarPaymentMessages.zh,
  478 + ...parkingSpaceApplyManageMessages.zh,
  479 + ...addParkingSpaceApplyMessages.zh,
  480 + ...auditParkingSpaceApplyMessages.zh,
466 } 481 }
467 } 482 }
468 483
src/router/index.js
@@ -752,15 +752,40 @@ const routes = [ @@ -752,15 +752,40 @@ const routes = [
752 component: () => import('@/views/fee/buyCarMonthCardList.vue') 752 component: () => import('@/views/fee/buyCarMonthCardList.vue')
753 }, 753 },
754 { 754 {
755 - path:'/pages/property/carInoutManage',  
756 - name:'/pages/property/carInoutManage', 755 + path: '/pages/property/carInoutManage',
  756 + name: '/pages/property/carInoutManage',
757 component: () => import('@/views/car/carInoutManageList.vue') 757 component: () => import('@/views/car/carInoutManageList.vue')
  758 + },
  759 + {
  760 + path: '/pages/property/carInManage',
  761 + name: '/pages/property/carInManage',
  762 + component: () => import('@/views/car/carInManageList.vue')
  763 + },
  764 + {
  765 + path: '/pages/property/remainingParkingSpace',
  766 + name: '/pages/property/remainingParkingSpace',
  767 + component: () => import('@/views/car/remainingParkingSpaceList.vue')
  768 + },
  769 + {
  770 + path:'/pages/car/tempCarPayment',
  771 + name:'/pages/car/tempCarPayment',
  772 + component: () => import('@/views/car/tempCarPaymentList.vue')
758 }, 773 },
759 { 774 {
760 - path:'/pages/property/carInManage',  
761 - name:'/pages/property/carInManage',  
762 - component: () => import('@/views/car/carInManageList.vue') 775 + path:'/pages/property/parkingSpaceApplyManage',
  776 + name:'/pages/property/parkingSpaceApplyManage',
  777 + component: () => import('@/views/car/parkingSpaceApplyManageList.vue')
763 }, 778 },
  779 + {
  780 + path:'/views/car/addParkingSpaceApply',
  781 + name:'/views/car/addParkingSpaceApply',
  782 + component: () => import('@/views/car/addParkingSpaceApply.vue')
  783 + },
  784 + {
  785 + path:'/views/car/auditParkingSpaceApply',
  786 + name:'/views/car/auditParkingSpaceApply',
  787 + component: () => import('@/views/car/auditParkingSpaceApply.vue')
  788 + },
764 // 其他子路由可以在这里添加 789 // 其他子路由可以在这里添加
765 ] 790 ]
766 }, 791 },
src/views/car/addParkingSpaceApply.vue 0 → 100644
  1 +<template>
  2 + <el-card class="box-card">
  3 + <div slot="header" class=" flex justify-between">
  4 + <div>{{ $t('addParkingSpaceApply.title') }}</div>
  5 + <div>
  6 + <el-button type="primary" size="small" icon="el-icon-close" @click="_goBack">
  7 + {{ $t('common.back') }}
  8 + </el-button>
  9 + </div>
  10 + </div>
  11 +
  12 + <el-form ref="form" :model="addParkingSpaceApplyInfo" label-width="120px">
  13 + <el-row :gutter="20">
  14 + <el-col :span="12">
  15 + <el-form-item :label="$t('addParkingSpaceApply.carNum')" prop="carNum" :rules="[
  16 + { required: true, message: $t('addParkingSpaceApply.requiredCarNum') },
  17 + { pattern: /^[\u4e00-\u9fa5A-Za-z0-9]{6,12}$/, message: $t('addParkingSpaceApply.invalidCarNum') }
  18 + ]">
  19 + <el-input v-model="addParkingSpaceApplyInfo.carNum"
  20 + :placeholder="$t('addParkingSpaceApply.placeholderCarNum')" />
  21 + </el-form-item>
  22 + </el-col>
  23 + <el-col :span="12">
  24 + <el-form-item :label="$t('addParkingSpaceApply.carBrand')" prop="carBrand" :rules="[
  25 + { required: true, message: $t('addParkingSpaceApply.requiredCarBrand') },
  26 + { max: 50, message: $t('addParkingSpaceApply.maxCarBrand') }
  27 + ]">
  28 + <el-input v-model="addParkingSpaceApplyInfo.carBrand"
  29 + :placeholder="$t('addParkingSpaceApply.placeholderCarBrand')" />
  30 + </el-form-item>
  31 + </el-col>
  32 + </el-row>
  33 +
  34 + <el-row :gutter="20">
  35 + <el-col :span="12">
  36 + <el-form-item :label="$t('addParkingSpaceApply.carType')" prop="carType"
  37 + :rules="[{ required: true, message: $t('addParkingSpaceApply.requiredCarType') }]">
  38 + <el-select v-model="addParkingSpaceApplyInfo.carType" style="width: 100%"
  39 + :placeholder="$t('addParkingSpaceApply.placeholderCarType')">
  40 + <el-option v-for="item in carTypes" :key="item.statusCd" :label="item.name" :value="item.statusCd" />
  41 + </el-select>
  42 + </el-form-item>
  43 + </el-col>
  44 + <el-col :span="12">
  45 + <el-form-item :label="$t('addParkingSpaceApply.carColor')" prop="carColor" :rules="[
  46 + { required: true, message: $t('addParkingSpaceApply.requiredCarColor') },
  47 + { max: 12, message: $t('addParkingSpaceApply.maxCarColor') }
  48 + ]">
  49 + <el-input v-model="addParkingSpaceApplyInfo.carColor"
  50 + :placeholder="$t('addParkingSpaceApply.placeholderCarColor')" />
  51 + </el-form-item>
  52 + </el-col>
  53 + </el-row>
  54 +
  55 + <el-row :gutter="20">
  56 + <el-col :span="8">
  57 + <el-form-item :label="$t('addParkingSpaceApply.applyPersonName')" prop="applyPersonName" :rules="[
  58 + { required: true, message: $t('addParkingSpaceApply.requiredApplyPersonName') },
  59 + { max: 64, message: $t('addParkingSpaceApply.maxApplyPersonName') }
  60 + ]">
  61 + <el-input v-model="addParkingSpaceApplyInfo.applyPersonName"
  62 + :placeholder="$t('addParkingSpaceApply.placeholderApplyPersonName')"
  63 + style="width: calc(100% - 70px); margin-right: 10px" />
  64 +
  65 + </el-form-item>
  66 + </el-col>
  67 + <el-col :span="4">
  68 + <el-button type="primary" size="small" @click="_openChooseOwner">
  69 + {{ $t('addParkingSpaceApply.selectOwner') }}
  70 + </el-button>
  71 + </el-col>
  72 + <el-col :span="12">
  73 + <el-form-item :label="$t('addParkingSpaceApply.applyPersonLink')" prop="applyPersonLink" :rules="[
  74 + { required: true, message: $t('addParkingSpaceApply.requiredApplyPersonLink') },
  75 + { max: 11, message: $t('addParkingSpaceApply.maxApplyPersonLink') }
  76 + ]">
  77 + <el-input v-model="addParkingSpaceApplyInfo.applyPersonLink"
  78 + :placeholder="$t('addParkingSpaceApply.placeholderApplyPersonLink')" />
  79 + </el-form-item>
  80 + </el-col>
  81 + </el-row>
  82 +
  83 + <el-row>
  84 + <el-col :span="24">
  85 + <el-form-item :label="$t('addParkingSpaceApply.remark')" prop="remark"
  86 + :rules="[{ max: 300, message: $t('addParkingSpaceApply.maxRemark') }]">
  87 + <el-input v-model="addParkingSpaceApplyInfo.remark" type="textarea"
  88 + :placeholder="$t('addParkingSpaceApply.placeholderRemark')" />
  89 + </el-form-item>
  90 + </el-col>
  91 + </el-row>
  92 +
  93 + <el-row>
  94 + <el-col :span="24" style="text-align: right">
  95 + <el-button type="warning" style="margin-right: 20px" @click="_goBack">
  96 + {{ $t('common.back') }}
  97 + </el-button>
  98 + <el-button type="primary" @click="saveParkingSpaceApplyInfo">
  99 + <i class="el-icon-check"></i>
  100 + {{ $t('common.submit') }}
  101 + </el-button>
  102 + </el-col>
  103 + </el-row>
  104 + </el-form>
  105 +
  106 + <search-owner ref="searchOwner" @chooseOwner="handleChooseOwner" />
  107 + </el-card>
  108 +</template>
  109 +
  110 +<script>
  111 +import { saveParkingSpaceApply } from '@/api/car/addParkingSpaceApplyApi'
  112 +import { getDict } from '@/api/community/communityApi'
  113 +import SearchOwner from '@/components/owner/SearchOwner'
  114 +
  115 +export default {
  116 + name: 'AddParkingSpaceApply',
  117 + components: {
  118 + SearchOwner
  119 + },
  120 + data() {
  121 + return {
  122 + addParkingSpaceApplyInfo: {
  123 + paName: '',
  124 + paId: '',
  125 + psId: '',
  126 + psName: '',
  127 + applyId: '',
  128 + carNum: '',
  129 + carBrand: '',
  130 + carType: '',
  131 + carColor: '',
  132 + applyPersonName: '',
  133 + applyPersonLink: '',
  134 + applyPersonId: '',
  135 + state: '1001',
  136 + remark: ''
  137 + },
  138 + carTypes: []
  139 + }
  140 + },
  141 + async created() {
  142 + await this.getCarTypeDict()
  143 + },
  144 + methods: {
  145 + async getCarTypeDict() {
  146 + try {
  147 + const data = await getDict('owner_car', 'car_type')
  148 + this.carTypes = data
  149 + } catch (error) {
  150 + console.error('获取车辆类型字典失败:', error)
  151 + }
  152 + },
  153 + handleChooseOwner(owner) {
  154 + this.addParkingSpaceApplyInfo.applyPersonName = owner.name
  155 + this.addParkingSpaceApplyInfo.applyPersonLink = owner.link
  156 + this.addParkingSpaceApplyInfo.applyPersonId = owner.ownerId
  157 + },
  158 + _openChooseOwner() {
  159 + this.$refs.searchOwner.open()
  160 + },
  161 + async saveParkingSpaceApplyInfo() {
  162 + try {
  163 + await this.$refs.form.validate()
  164 +
  165 + const data = {
  166 + ...this.addParkingSpaceApplyInfo,
  167 + communityId: this.getCommunityId()
  168 + }
  169 +
  170 + await saveParkingSpaceApply(data)
  171 + this.$message.success(this.$t('common.submitSuccess'))
  172 + this.clearAddParkingSpaceApplyInfo()
  173 + this._goBack()
  174 + } catch (error) {
  175 + if (error.errors) {
  176 + this.$message.error(Object.values(error.errors).join('; '))
  177 + } else {
  178 + console.error('保存失败:', error)
  179 + }
  180 + }
  181 + },
  182 + clearAddParkingSpaceApplyInfo() {
  183 + this.addParkingSpaceApplyInfo = {
  184 + paName: '',
  185 + paId: '',
  186 + psId: '',
  187 + psName: '',
  188 + applyId: '',
  189 + carNum: '',
  190 + carBrand: '',
  191 + carType: '',
  192 + carColor: '',
  193 + applyPersonName: '',
  194 + applyPersonLink: '',
  195 + applyPersonId: '',
  196 + state: '1001',
  197 + remark: ''
  198 + }
  199 + },
  200 + _goBack() {
  201 + this.$router.go(-1)
  202 + }
  203 + }
  204 +}
  205 +</script>
  206 +
  207 +<style scoped>
  208 +.box-card {
  209 + margin: 20px;
  210 +}
  211 +
  212 +.el-form-item {
  213 + margin-bottom: 22px;
  214 +}
  215 +</style>
0 \ No newline at end of file 216 \ No newline at end of file
src/views/car/addParkingSpaceApplyLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + addParkingSpaceApply: {
  4 + title: 'Parking Space Application',
  5 + carNum: 'License Plate',
  6 + carBrand: 'Car Brand',
  7 + carType: 'Vehicle Type',
  8 + carColor: 'Color',
  9 + applyPersonName: 'Applicant',
  10 + applyPersonLink: 'Applicant Phone',
  11 + remark: 'Remarks',
  12 + requiredCarNum: 'License plate is required',
  13 + invalidCarNum: 'Invalid license plate format',
  14 + requiredCarBrand: 'Car brand is required',
  15 + maxCarBrand: 'Car brand max 50 characters',
  16 + requiredCarType: 'Vehicle type is required',
  17 + requiredCarColor: 'Color is required',
  18 + maxCarColor: 'Color max 12 characters',
  19 + requiredApplyPersonName: 'Applicant name is required',
  20 + maxApplyPersonName: 'Applicant name max 64 characters',
  21 + requiredApplyPersonLink: 'Applicant phone is required',
  22 + maxApplyPersonLink: 'Applicant phone max 11 characters',
  23 + maxRemark: 'Remarks max 300 characters',
  24 + placeholderCarNum: 'Required, please enter license plate',
  25 + placeholderCarBrand: 'Required, please enter car brand',
  26 + placeholderCarType: 'Required, please select vehicle type',
  27 + placeholderCarColor: 'Required, please enter color',
  28 + placeholderApplyPersonName: 'Required, please enter applicant',
  29 + placeholderApplyPersonLink: 'Required, please enter applicant phone',
  30 + placeholderRemark: 'Optional, please enter remarks',
  31 + selectOwner: 'Select Owner',
  32 + }
  33 + },
  34 + zh: {
  35 + addParkingSpaceApply: {
  36 + title: '车位申请',
  37 + carNum: '车牌号',
  38 + carBrand: '汽车品牌',
  39 + carType: '车辆类型',
  40 + carColor: '颜色',
  41 + applyPersonName: '申请人',
  42 + applyPersonLink: '申请人电话',
  43 + remark: '备注',
  44 + requiredCarNum: '车牌号不能为空',
  45 + invalidCarNum: '车牌号格式错误',
  46 + requiredCarBrand: '汽车品牌不能为空',
  47 + maxCarBrand: '汽车品牌不能超过50位',
  48 + requiredCarType: '车辆类型不能为空',
  49 + requiredCarColor: '颜色不能为空',
  50 + maxCarColor: '颜色不能超过12位',
  51 + requiredApplyPersonName: '申请人不能为空',
  52 + maxApplyPersonName: '申请人名称不能超过64位',
  53 + requiredApplyPersonLink: '申请人电话不能为空',
  54 + maxApplyPersonLink: '申请人电话不能超过11位',
  55 + maxRemark: '备注不能超过300位',
  56 + placeholderCarNum: '必填,请填写车牌号',
  57 + placeholderCarBrand: '必填,请填写汽车品牌',
  58 + placeholderCarType: '必填,请选择车辆类型',
  59 + placeholderCarColor: '必填,请填写颜色',
  60 + placeholderApplyPersonName: '必填,请填写申请人',
  61 + placeholderApplyPersonLink: '必填,请填写申请人电话',
  62 + placeholderRemark: '选填,请填写备注',
  63 + selectOwner: '选择车主',
  64 + }
  65 + }
  66 +}
0 \ No newline at end of file 67 \ No newline at end of file
src/views/car/auditParkingSpaceApply.vue 0 → 100644
  1 +<template>
  2 + <div class="audit-container">
  3 + <el-card class="box-card">
  4 + <div slot="header" class=" flex justify-between">
  5 + <span>{{ $t('auditParkingSpaceApply.applyInfo') }}</span>
  6 + <el-button style="float: right; padding: 3px 0" type="text" @click="goBack">
  7 + {{ $t('auditParkingSpaceApply.back') }}
  8 + </el-button>
  9 + </div>
  10 + <el-form ref="viewForm" :model="formData" label-width="120px" class="text-left">
  11 + <el-row :gutter="20">
  12 + <el-col :span="6">
  13 + <el-form-item :label="$t('auditParkingSpaceApply.licensePlate') + ':'">
  14 + <span>{{ formData.carNum }}</span>
  15 + </el-form-item>
  16 + </el-col>
  17 + <el-col :span="6">
  18 + <el-form-item :label="$t('auditParkingSpaceApply.carBrand') + ':'">
  19 + <span>{{ formData.carBrand }}</span>
  20 + </el-form-item>
  21 + </el-col>
  22 + <el-col :span="6">
  23 + <el-form-item :label="$t('auditParkingSpaceApply.carType') + ':'">
  24 + <span>{{ formData.carType }}</span>
  25 + </el-form-item>
  26 + </el-col>
  27 + <el-col :span="6">
  28 + <el-form-item :label="$t('auditParkingSpaceApply.color') + ':'">
  29 + <span>{{ formData.carColor }}</span>
  30 + </el-form-item>
  31 + </el-col>
  32 + <el-col :span="6">
  33 + <el-form-item :label="$t('auditParkingSpaceApply.startRentTime') + ':'">
  34 + <span>{{ formData.startTime }}</span>
  35 + </el-form-item>
  36 + </el-col>
  37 + <el-col :span="6">
  38 + <el-form-item :label="$t('auditParkingSpaceApply.endRentTime') + ':'">
  39 + <span>{{ formData.endTime }}</span>
  40 + </el-form-item>
  41 + </el-col>
  42 +
  43 + <el-col :span="6">
  44 + <el-form-item :label="$t('auditParkingSpaceApply.applicant') + ':'">
  45 + <span>{{ formData.applyPersonName }}</span>
  46 + </el-form-item>
  47 + </el-col>
  48 + <el-col :span="6">
  49 + <el-form-item :label="$t('auditParkingSpaceApply.applicantPhone') + ':'">
  50 + <span>{{ formData.applyPersonLink }}</span>
  51 + </el-form-item>
  52 + </el-col>
  53 + <el-col :span="6">
  54 + <el-form-item :label="$t('auditParkingSpaceApply.applicantId') + ':'">
  55 + <span>{{ formData.applyPersonId }}</span>
  56 + </el-form-item>
  57 + </el-col>
  58 + <el-col :span="16">
  59 + <el-form-item :label="$t('auditParkingSpaceApply.remark') + ':'">
  60 + <span>{{ formData.remark }}</span>
  61 + </el-form-item>
  62 + </el-col>
  63 + </el-row>
  64 + </el-form>
  65 + </el-card>
  66 +
  67 + <el-card class="box-card" style="margin-top: 20px;">
  68 + <div slot="header" class="clearfix">
  69 + <span>{{ $t('auditParkingSpaceApply.auditInfo') }}</span>
  70 + </div>
  71 +
  72 + <el-form ref="form" :model="formData" label-width="120px">
  73 + <el-form-item :label="$t('auditParkingSpaceApply.startRentTime')" required>
  74 + <el-date-picker v-model="formData.startTime" type="datetime"
  75 + :placeholder="$t('auditParkingSpaceApply.requiredField')" value-format="yyyy-MM-dd HH:mm:ss"
  76 + style="width: 100%;" />
  77 + </el-form-item>
  78 +
  79 + <el-form-item :label="$t('auditParkingSpaceApply.endRentTime')" required>
  80 + <el-date-picker v-model="formData.endTime" type="datetime"
  81 + :placeholder="$t('auditParkingSpaceApply.requiredField')" value-format="yyyy-MM-dd HH:mm:ss"
  82 + style="width: 100%;" />
  83 + </el-form-item>
  84 +
  85 + <el-form-item :label="$t('auditParkingSpaceApply.auditResult')" required>
  86 + <el-select v-model="formData.state" :placeholder="$t('auditParkingSpaceApply.selectResult')" style="width:100%">
  87 + <el-option :label="$t('auditParkingSpaceApply.pass')" value="3003" />
  88 + <el-option :label="$t('auditParkingSpaceApply.reject')" value="4004" />
  89 + </el-select>
  90 + </el-form-item>
  91 +
  92 + <el-form-item v-if="formData.state === '3003'" :label="$t('auditParkingSpaceApply.selectParkingSpace')">
  93 + <el-input v-model="formData.psName" :placeholder="$t('auditParkingSpaceApply.selectParkingSpace')" readonly
  94 + style="width: 80%;" />
  95 + <el-button type="primary" @click="openChooseParkingSpace" style="margin-left: 10px;">
  96 + <i class="el-icon-search"></i>
  97 + {{ $t('auditParkingSpaceApply.select') }}
  98 + </el-button>
  99 + </el-form-item>
  100 +
  101 + <el-form-item :label="$t('auditParkingSpaceApply.auditOpinion')">
  102 + <el-input v-model="formData.remark2" type="textarea" :placeholder="$t('auditParkingSpaceApply.optional')"
  103 + :rows="3" />
  104 + </el-form-item>
  105 +
  106 + <el-form-item>
  107 + <el-button @click="goBack">
  108 + {{ $t('auditParkingSpaceApply.back') }}
  109 + </el-button>
  110 + <el-button type="primary" @click="doAudit">
  111 + {{ $t('auditParkingSpaceApply.submit') }}
  112 + </el-button>
  113 + </el-form-item>
  114 + </el-form>
  115 + </el-card>
  116 +
  117 +
  118 + <!-- 搜索车位组件 -->
  119 + <search-parking-space
  120 + ref="searchParkingSpace"
  121 + :ps-flag="formData.parkingSpaceFlag"
  122 + @choose-parking-space="handleChooseParkingSpace"
  123 + />
  124 + </div>
  125 +</template>
  126 +
  127 +<script>
  128 +import { getParkingSpaceApplyDetail, auditParkingSpaceApply } from '@/api/car/auditParkingSpaceApplyApi'
  129 +import SearchParkingSpace from '@/components/car/SearchParkingSpace'
  130 +
  131 +import { getCommunityId } from '@/api/community/communityApi'
  132 +
  133 +export default {
  134 + name: 'AuditParkingSpaceApply',
  135 + components: {
  136 + SearchParkingSpace
  137 + },
  138 + data() {
  139 + return {
  140 + formData: {
  141 + applyId: '',
  142 + communityId: getCommunityId(),
  143 + psId: '',
  144 + psName: '',
  145 + carNum: '',
  146 + carBrand: '',
  147 + carType: '',
  148 + carColor: '',
  149 + startTime: '',
  150 + endTime: '',
  151 + applyPersonName: '',
  152 + applyPersonLink: '',
  153 + applyPersonId: '',
  154 + state: '',
  155 + remark: '',
  156 + remark2: '',
  157 + parkingSpaceFlag: 'F'
  158 + }
  159 + }
  160 + },
  161 + created() {
  162 + this.formData.applyId = this.$route.query.applyId
  163 + this.getApplyDetail()
  164 + },
  165 + methods: {
  166 + async getApplyDetail() {
  167 + try {
  168 + const params = {
  169 + page: 1,
  170 + row: 1,
  171 + applyId: this.formData.applyId
  172 + }
  173 +
  174 + const res = await getParkingSpaceApplyDetail(params)
  175 + if (res.data && res.data.length > 0) {
  176 + Object.assign(this.formData, res.data[0])
  177 + }
  178 + } catch (error) {
  179 + this.$message.error(this.$t('common.queryFailed'))
  180 + }
  181 + },
  182 + openChooseParkingSpace() {
  183 + this.$refs.searchParkingSpace.open()
  184 + },
  185 + handleChooseParkingSpace(parkingSpace) {
  186 + console.log('选择车位', parkingSpace)
  187 + this.formData.psId = parkingSpace.psId
  188 + this.formData.psName = parkingSpace.num
  189 + },
  190 + async doAudit() {
  191 + // 验证逻辑
  192 + if (!this.formData.state) {
  193 + this.$message.warning(this.$t('auditParkingSpaceApply.selectResult'))
  194 + return
  195 + }
  196 +
  197 + if (this.formData.state === '3003' && !this.formData.psId) {
  198 + this.$message.warning(this.$t('auditParkingSpaceApply.selectParkingSpace'))
  199 + return
  200 + }
  201 +
  202 + if (this.formData.state === '4004' && !this.formData.remark2) {
  203 + this.$message.warning(this.$t('auditParkingSpaceApply.auditOpinionRequired'))
  204 + return
  205 + }
  206 +
  207 + try {
  208 + // 合并备注信息
  209 + const remark = `${this.formData.remark}\n审核意见:${this.formData.remark2}`
  210 +
  211 + const data = {
  212 + ...this.formData,
  213 + remark
  214 + }
  215 +
  216 + await auditParkingSpaceApply(data)
  217 + this.$message.success(this.$t('common.submitSuccess'))
  218 + this.goBack()
  219 + } catch (error) {
  220 + this.$message.error(this.$t('common.submitFailed'))
  221 + }
  222 + },
  223 + goBack() {
  224 + this.$router.go(-1)
  225 + }
  226 + }
  227 +}
  228 +</script>
  229 +
  230 +<style scoped>
  231 +.audit-container {
  232 + padding: 20px;
  233 +}
  234 +
  235 +.box-card {
  236 + margin-bottom: 20px;
  237 +}
  238 +
  239 +.clearfix:before,
  240 +.clearfix:after {
  241 + display: table;
  242 + content: "";
  243 +}
  244 +
  245 +.clearfix:after {
  246 + clear: both;
  247 +}
  248 +</style>
0 \ No newline at end of file 249 \ No newline at end of file
src/views/car/auditParkingSpaceApplyLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + auditParkingSpaceApply: {
  4 + applyInfo: 'Application Information',
  5 + back: 'Back',
  6 + licensePlate: 'License Plate',
  7 + carBrand: 'Car Brand',
  8 + carType: 'Car Type',
  9 + color: 'Color',
  10 + startRentTime: 'Start Rent Time',
  11 + endRentTime: 'End Rent Time',
  12 + applicant: 'Applicant',
  13 + applicantPhone: 'Applicant Phone',
  14 + applicantId: 'Applicant ID',
  15 + remark: 'Remark',
  16 + auditInfo: 'Audit Information',
  17 + auditResult: 'Audit Result',
  18 + selectResult: 'Please select audit result',
  19 + pass: 'Pass',
  20 + reject: 'Reject',
  21 + selectParkingSpace: 'Select Parking Space',
  22 + select: 'Select',
  23 + auditOpinion: 'Audit Opinion',
  24 + optional: 'Optional',
  25 + submit: 'Submit',
  26 + requiredField: 'Required field',
  27 + parkingLot: 'Parking Lot',
  28 + parkingSpace: 'Parking Space',
  29 + parkingStatus: 'Parking Status',
  30 + parkingType: 'Parking Type',
  31 + area: 'Area',
  32 + operation: 'Operation',
  33 + choose: 'Choose',
  34 + parkingLotCode: 'Parking Lot Code',
  35 + parkingSpaceCode: 'Parking Space Code',
  36 + parkingLotType: 'Parking Lot Type',
  37 + groundParking: 'Ground Parking',
  38 + undergroundParking: 'Underground Parking',
  39 + free: 'Free',
  40 + sold: 'Sold',
  41 + rented: 'Rented',
  42 + unknown: 'Unknown'
  43 + }
  44 + },
  45 + zh: {
  46 + auditParkingSpaceApply: {
  47 + applyInfo: '申请信息',
  48 + back: '返回',
  49 + licensePlate: '车牌号',
  50 + carBrand: '汽车品牌',
  51 + carType: '车辆类型',
  52 + color: '颜色',
  53 + startRentTime: '起租时间',
  54 + endRentTime: '结租时间',
  55 + applicant: '申请人',
  56 + applicantPhone: '申请人电话',
  57 + applicantId: '申请人ID',
  58 + remark: '备注',
  59 + auditInfo: '审核信息',
  60 + auditResult: '审核结果',
  61 + selectResult: '请选择审核结果',
  62 + pass: '通过',
  63 + reject: '不通过',
  64 + selectParkingSpace: '选择车位',
  65 + select: '选择',
  66 + auditOpinion: '审核意见',
  67 + optional: '选填',
  68 + submit: '提交',
  69 + requiredField: '必填',
  70 + parkingLot: '停车场',
  71 + parkingSpace: '车位',
  72 + parkingStatus: '车位状态',
  73 + parkingType: '车位类型',
  74 + area: '面积',
  75 + operation: '操作',
  76 + choose: '选择',
  77 + parkingLotCode: '停车场编码',
  78 + parkingSpaceCode: '停车位编码',
  79 + parkingLotType: '停车场类型',
  80 + groundParking: '地上停车位',
  81 + undergroundParking: '地下停车位',
  82 + free: '空闲',
  83 + sold: '已售卖',
  84 + rented: '已出租',
  85 + unknown: '未知'
  86 + }
  87 + }
  88 +}
0 \ No newline at end of file 89 \ No newline at end of file
src/views/car/parkingSpaceApplyManageLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + parkingSpaceApplyManage: {
  4 + searchCondition: 'Search Condition',
  5 + licensePlate: 'License Plate',
  6 + carBrand: 'Car Brand',
  7 + applicantName: 'Applicant Name',
  8 + applicantPhone: 'Applicant Phone',
  9 + status: 'Status',
  10 + selectStatus: 'Select Status',
  11 + pendingReview: 'Pending Review',
  12 + pendingPayment: 'Pending Payment',
  13 + completed: 'Completed',
  14 + applicationFailed: 'Application Failed',
  15 + search: 'Search',
  16 + reset: 'Reset',
  17 + parkingSpaceApplication: 'Parking Space Application',
  18 + applyForSpace: 'Apply for Space',
  19 + applicationId: 'Application ID',
  20 + parkingSpace: 'Parking Space',
  21 + vehicleType: 'Vehicle Type',
  22 + color: 'Color',
  23 + startTime: 'Start Time',
  24 + endTime: 'End Time',
  25 + applicant: 'Applicant',
  26 + phoneNumber: 'Phone Number',
  27 + reviewResult: 'Review Result',
  28 + operation: 'Operation',
  29 + audit: 'Audit',
  30 + edit: 'Edit',
  31 + delete: 'Delete',
  32 + homeCar: 'Home Car',
  33 + bus: 'Bus',
  34 + truck: 'Truck',
  35 + abnormalVehicle: 'Abnormal Vehicle',
  36 + statusAbnormal: 'Status Abnormal'
  37 + },
  38 + editParkingSpaceApply: {
  39 + editApplication: 'Edit Parking Space Application',
  40 + licensePlate: 'License Plate',
  41 + carBrand: 'Car Brand',
  42 + vehicleType: 'Vehicle Type',
  43 + color: 'Color',
  44 + startTime: 'Start Time',
  45 + endTime: 'End Time',
  46 + applicant: 'Applicant',
  47 + applicantPhone: 'Applicant Phone',
  48 + remarks: 'Remarks',
  49 + required: 'Required',
  50 + optional: 'Optional',
  51 + save: 'Save',
  52 + cancel: 'Cancel',
  53 + fillLicensePlate: 'Please fill in license plate',
  54 + fillCarBrand: 'Please fill in car brand',
  55 + selectVehicleType: 'Please select vehicle type',
  56 + fillColor: 'Please fill in color',
  57 + fillStartTime: 'Please fill in start time',
  58 + fillEndTime: 'Please fill in end time',
  59 + fillApplicant: 'Please fill in applicant',
  60 + fillApplicantPhone: 'Please fill in applicant phone'
  61 + },
  62 + deleteParkingSpaceApply: {
  63 + confirmOperation: 'Please confirm your operation',
  64 + confirmDelete: 'Confirm delete parking space application',
  65 + cancel: 'Cancel',
  66 + confirmDeleteAction: 'Confirm Delete',
  67 + deletePrompt: 'Are you sure you want to delete this parking space application?'
  68 + }
  69 + },
  70 + zh: {
  71 + parkingSpaceApplyManage: {
  72 + searchCondition: '查询条件',
  73 + licensePlate: '车牌号',
  74 + carBrand: '车辆品牌',
  75 + applicantName: '申请人名称',
  76 + applicantPhone: '申请人电话',
  77 + status: '状态',
  78 + selectStatus: '请选择状态',
  79 + pendingReview: '待审核',
  80 + pendingPayment: '待缴费',
  81 + completed: '完成',
  82 + applicationFailed: '申请失败',
  83 + search: '查询',
  84 + reset: '重置',
  85 + parkingSpaceApplication: '车位申请',
  86 + applyForSpace: '申请车位',
  87 + applicationId: '申请ID',
  88 + parkingSpace: '停车位',
  89 + vehicleType: '车辆类型',
  90 + color: '颜色',
  91 + startTime: '起租时间',
  92 + endTime: '结租时间',
  93 + applicant: '申请人',
  94 + phoneNumber: '手机号',
  95 + reviewResult: '审核结果',
  96 + operation: '操作',
  97 + audit: '审核',
  98 + edit: '修改',
  99 + delete: '删除',
  100 + homeCar: '家用小汽车',
  101 + bus: '客车',
  102 + truck: '货车',
  103 + abnormalVehicle: '异常车辆',
  104 + statusAbnormal: '状态异常'
  105 + },
  106 + editParkingSpaceApply: {
  107 + editApplication: '修改车位申请',
  108 + licensePlate: '车牌号',
  109 + carBrand: '汽车品牌',
  110 + vehicleType: '车辆类型',
  111 + color: '颜色',
  112 + startTime: '起租时间',
  113 + endTime: '结租时间',
  114 + applicant: '申请人',
  115 + applicantPhone: '申请人电话',
  116 + remarks: '备注',
  117 + required: '必填',
  118 + optional: '选填',
  119 + save: '保存',
  120 + cancel: '取消',
  121 + fillLicensePlate: '请填写车牌号',
  122 + fillCarBrand: '请填写汽车品牌',
  123 + selectVehicleType: '请选择车辆类型',
  124 + fillColor: '请填写颜色',
  125 + fillStartTime: '请填写起租时间',
  126 + fillEndTime: '请填写结租时间',
  127 + fillApplicant: '请填写申请人',
  128 + fillApplicantPhone: '请填写申请人电话'
  129 + },
  130 + deleteParkingSpaceApply: {
  131 + confirmOperation: '请确认您的操作',
  132 + confirmDelete: '确定删除车位申请',
  133 + cancel: '点错了',
  134 + confirmDeleteAction: '确认删除',
  135 + deletePrompt: '确定删除车位申请吗?'
  136 + }
  137 + }
  138 +}
0 \ No newline at end of file 139 \ No newline at end of file
src/views/car/parkingSpaceApplyManageList.vue 0 → 100644
  1 +<template>
  2 + <div class="parking-space-apply-manage">
  3 + <el-card class="search-card">
  4 + <div slot="header" class="clearfix flex justify-between">
  5 + <span>{{ $t('parkingSpaceApplyManage.searchCondition') }}</span>
  6 + </div>
  7 + <el-form :model="conditions" label-width="0">
  8 + <el-row :gutter="20">
  9 + <el-col :span="4">
  10 + <el-form-item>
  11 + <el-input v-model="conditions.carNum" :placeholder="$t('parkingSpaceApplyManage.licensePlate')" clearable />
  12 + </el-form-item>
  13 + </el-col>
  14 + <el-col :span="4">
  15 + <el-form-item>
  16 + <el-input v-model="conditions.carBrand" :placeholder="$t('parkingSpaceApplyManage.carBrand')" clearable />
  17 + </el-form-item>
  18 + </el-col>
  19 + <el-col :span="4">
  20 + <el-form-item>
  21 + <el-input v-model="conditions.applyPersonName" :placeholder="$t('parkingSpaceApplyManage.applicantName')"
  22 + clearable />
  23 + </el-form-item>
  24 + </el-col>
  25 + <el-col :span="4">
  26 + <el-form-item>
  27 + <el-input v-model="conditions.applyPersonLink" :placeholder="$t('parkingSpaceApplyManage.applicantPhone')"
  28 + clearable />
  29 + </el-form-item>
  30 + </el-col>
  31 + <el-col :span="4">
  32 + <el-form-item>
  33 + <el-select v-model="conditions.state" :placeholder="$t('parkingSpaceApplyManage.selectStatus')"
  34 + style="width: 100%">
  35 + <el-option :label="$t('parkingSpaceApplyManage.selectStatus')" value="" />
  36 + <el-option :label="$t('parkingSpaceApplyManage.pendingReview')" value="1001" />
  37 + <el-option :label="$t('parkingSpaceApplyManage.pendingPayment')" value="2002" />
  38 + <el-option :label="$t('parkingSpaceApplyManage.completed')" value="3003" />
  39 + <el-option :label="$t('parkingSpaceApplyManage.applicationFailed')" value="4004" />
  40 + </el-select>
  41 + </el-form-item>
  42 + </el-col>
  43 + <el-col :span="4">
  44 + <el-button type="primary" @click="_queryParkingSpaceApplyMethod">
  45 + {{ $t('parkingSpaceApplyManage.search') }}
  46 + </el-button>
  47 + <el-button @click="_resetParkingSpaceApplyMethod">
  48 + {{ $t('parkingSpaceApplyManage.reset') }}
  49 + </el-button>
  50 + </el-col>
  51 + </el-row>
  52 + </el-form>
  53 + </el-card>
  54 +
  55 + <el-card class="list-card">
  56 + <div slot="header" class="flex justify-between">
  57 + <span>{{ $t('parkingSpaceApplyManage.parkingSpaceApplication') }}</span>
  58 + <el-button type="primary" size="small" style="float: right;" @click="_openAddParkingSpaceApplyModal">
  59 + {{ $t('parkingSpaceApplyManage.applyForSpace') }}
  60 + </el-button>
  61 + </div>
  62 +
  63 + <el-table :data="parkingSpaceApplys" border v-loading="loading">
  64 + <el-table-column prop="applyId" :label="$t('parkingSpaceApplyManage.applicationId')" align="center" />
  65 + <el-table-column prop="carNum" :label="$t('parkingSpaceApplyManage.licensePlate')" align="center" />
  66 + <el-table-column :label="$t('parkingSpaceApplyManage.parkingSpace')" align="center">
  67 + <template slot-scope="scope">
  68 + <span v-if="scope.row.psId">
  69 + {{ scope.row.areaNum }} - {{ scope.row.num }}
  70 + </span>
  71 + <span v-else>-</span>
  72 + </template>
  73 + </el-table-column>
  74 + <el-table-column prop="carBrand" :label="$t('parkingSpaceApplyManage.carBrand')" align="center" />
  75 + <el-table-column :label="$t('parkingSpaceApplyManage.vehicleType')" align="center">
  76 + <template slot-scope="scope">
  77 + {{ _getCatType(scope.row.carType) }}
  78 + </template>
  79 + </el-table-column>
  80 + <el-table-column prop="carColor" :label="$t('parkingSpaceApplyManage.color')" align="center" />
  81 + <el-table-column prop="startTime" :label="$t('parkingSpaceApplyManage.startTime')" align="center" />
  82 + <el-table-column prop="endTime" :label="$t('parkingSpaceApplyManage.endTime')" align="center" />
  83 + <el-table-column prop="applyPersonName" :label="$t('parkingSpaceApplyManage.applicant')" align="center" />
  84 + <el-table-column prop="applyPersonLink" :label="$t('parkingSpaceApplyManage.phoneNumber')" align="center" />
  85 + <el-table-column :label="$t('parkingSpaceApplyManage.reviewResult')" align="center">
  86 + <template slot-scope="scope">
  87 + <el-tag :type="getStatusTagType(scope.row.state)" size="small">
  88 + {{ _getState(scope.row.state) }}
  89 + </el-tag>
  90 + </template>
  91 + </el-table-column>
  92 + <el-table-column :label="$t('parkingSpaceApplyManage.operation')" align="center" width="250">
  93 + <template slot-scope="scope">
  94 + <el-button v-if="scope.row.state === '1001'" size="mini" type="primary"
  95 + @click="_openAuditParkingSpaceApplyModal(scope.row)">
  96 + {{ $t('parkingSpaceApplyManage.audit') }}
  97 + </el-button>
  98 + <el-button v-if="scope.row.state === '1001'" size="mini" type="warning"
  99 + @click="_openEditParkingSpaceApplyModel(scope.row)">
  100 + {{ $t('parkingSpaceApplyManage.edit') }}
  101 + </el-button>
  102 + <el-button size="mini" type="danger" @click="_openDeleteParkingSpaceApplyModel(scope.row)">
  103 + {{ $t('parkingSpaceApplyManage.delete') }}
  104 + </el-button>
  105 + </template>
  106 + </el-table-column>
  107 + </el-table>
  108 +
  109 + <el-pagination :current-page="page.current" :page-sizes="[10, 20, 30, 50]" :page-size="page.size"
  110 + :total="page.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  111 + @current-change="handleCurrentChange" style="margin-top: 20px;" />
  112 + </el-card>
  113 +
  114 + <edit-parking-space-apply ref="editComponent" @success="handleSuccess" />
  115 + <delete-parking-space-apply ref="deleteComponent" @success="handleSuccess" />
  116 + </div>
  117 +</template>
  118 +
  119 +<script>
  120 +import { listParkingSpaceApply } from '@/api/car/parkingSpaceApplyManageApi'
  121 +import EditParkingSpaceApply from '@/components/car/editParkingSpaceApply'
  122 +import DeleteParkingSpaceApply from '@/components/car/deleteParkingSpaceApply'
  123 +
  124 +export default {
  125 + name: 'ParkingSpaceApplyManageList',
  126 + components: {
  127 + EditParkingSpaceApply,
  128 + DeleteParkingSpaceApply
  129 + },
  130 + data() {
  131 + return {
  132 + loading: false,
  133 + page: {
  134 + current: 1,
  135 + size: 10,
  136 + total: 0
  137 + },
  138 + conditions: {
  139 + state: '',
  140 + carNum: '',
  141 + carBrand: '',
  142 + applyPersonName: '',
  143 + applyPersonLink: '',
  144 + communityId: ''
  145 + },
  146 + parkingSpaceApplys: []
  147 + }
  148 + },
  149 + created() {
  150 + this._listParkingSpaceApplys(1, this.page.size)
  151 + },
  152 + methods: {
  153 + async _listParkingSpaceApplys(page, size) {
  154 + this.loading = true
  155 + try {
  156 + const params = {
  157 + ...this.conditions,
  158 + page: page,
  159 + row: size
  160 + }
  161 + const response = await listParkingSpaceApply(params)
  162 + if (response.code === 0) {
  163 + this.parkingSpaceApplys = response.data
  164 + this.page.total = response.total
  165 + this.page.current = page
  166 + } else {
  167 + this.$message.error(response.msg || this.$t('common.requestFailed'))
  168 + }
  169 + } catch (error) {
  170 + console.error('Error fetching parking space applications:', error)
  171 + this.$message.error(this.$t('common.requestError'))
  172 + } finally {
  173 + this.loading = false
  174 + }
  175 + },
  176 +
  177 + _queryParkingSpaceApplyMethod() {
  178 + this._listParkingSpaceApplys(1, this.page.size)
  179 + },
  180 +
  181 + _resetParkingSpaceApplyMethod() {
  182 + this.conditions = {
  183 + state: '',
  184 + carNum: '',
  185 + carBrand: '',
  186 + applyPersonName: '',
  187 + applyPersonLink: '',
  188 + communityId: ''
  189 + }
  190 + this._listParkingSpaceApplys(1, this.page.size)
  191 + },
  192 +
  193 + _openAddParkingSpaceApplyModal() {
  194 + // 跳转到申请页面
  195 + this.$router.push('/views/car/addParkingSpaceApply')
  196 + },
  197 +
  198 + _openAuditParkingSpaceApplyModal(apply) {
  199 + // 跳转到审核页面
  200 + this.$router.push(`/views/car/auditParkingSpaceApply?applyId=${apply.applyId}`)
  201 + },
  202 +
  203 + _openEditParkingSpaceApplyModel(apply) {
  204 + this.$refs.editComponent.open(apply)
  205 + },
  206 +
  207 + _openDeleteParkingSpaceApplyModel(apply) {
  208 + this.$refs.deleteComponent.open(apply)
  209 + },
  210 +
  211 + handleSizeChange(size) {
  212 + this.page.size = size
  213 + this._listParkingSpaceApplys(1, size)
  214 + },
  215 +
  216 + handleCurrentChange(page) {
  217 + this._listParkingSpaceApplys(page, this.page.size)
  218 + },
  219 +
  220 + handleSuccess() {
  221 + this._listParkingSpaceApplys(this.page.current, this.page.size)
  222 + },
  223 +
  224 + getStatusTagType(state) {
  225 + switch (state) {
  226 + case '1001': return 'warning'
  227 + case '2002': return 'primary'
  228 + case '3003': return 'success'
  229 + case '4004': return 'danger'
  230 + default: return 'info'
  231 + }
  232 + },
  233 +
  234 + _getState(state) {
  235 + switch (state) {
  236 + case '1001': return this.$t('parkingSpaceApplyManage.pendingReview')
  237 + case '2002': return this.$t('parkingSpaceApplyManage.pendingPayment')
  238 + case '3003': return this.$t('parkingSpaceApplyManage.completed')
  239 + case '4004': return this.$t('parkingSpaceApplyManage.applicationFailed')
  240 + default: return this.$t('parkingSpaceApplyManage.statusAbnormal')
  241 + }
  242 + },
  243 +
  244 + _getCatType(type) {
  245 + switch (type) {
  246 + case '9901': return this.$t('parkingSpaceApplyManage.homeCar')
  247 + case '9902': return this.$t('parkingSpaceApplyManage.bus')
  248 + case '9903': return this.$t('parkingSpaceApplyManage.truck')
  249 + default: return this.$t('parkingSpaceApplyManage.abnormalVehicle')
  250 + }
  251 + }
  252 + }
  253 +}
  254 +</script>
  255 +
  256 +<style scoped>
  257 +.search-card {
  258 + margin-bottom: 20px;
  259 +}
  260 +
  261 +.list-card {
  262 + margin-top: 20px;
  263 +}
  264 +</style>
0 \ No newline at end of file 265 \ No newline at end of file
src/views/car/remainingParkingSpaceLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + remainingParkingSpace: {
  4 + title: 'Remaining Parking Space',
  5 + total: 'Total Parking Spaces',
  6 + freeCount: 'Remaining Spaces',
  7 + createTime: 'Collection Time',
  8 + operation: 'Operation',
  9 + refresh: 'Refresh',
  10 + unit: 'units',
  11 + fetchError: 'Failed to fetch parking space data'
  12 + }
  13 + },
  14 + zh: {
  15 + remainingParkingSpace: {
  16 + title: '剩余车位',
  17 + total: '总车位数',
  18 + freeCount: '剩余车位数',
  19 + createTime: '采集时间',
  20 + operation: '操作',
  21 + refresh: '刷新',
  22 + unit: '位',
  23 + fetchError: '获取车位数据失败'
  24 + }
  25 + }
  26 +}
0 \ No newline at end of file 27 \ No newline at end of file
src/views/car/remainingParkingSpaceList.vue 0 → 100644
  1 +<template>
  2 + <div class="remaining-parking-space-container">
  3 + <el-card class="box-card">
  4 + <div slot="header" class="flex justify-between">
  5 + <div>{{ $t('remainingParkingSpace.title') }}</div>
  6 + </div>
  7 + <div class="card-content">
  8 + <el-row>
  9 + <el-col :span="24">
  10 + <el-table
  11 + v-loading="loading"
  12 + :data="tableData"
  13 + style="width: 100%"
  14 + border
  15 + stripe
  16 + >
  17 + <el-table-column
  18 + prop="total"
  19 + :label="$t('remainingParkingSpace.total')"
  20 + align="center"
  21 + >
  22 + <template slot-scope="scope">
  23 + {{ scope.row.total }} {{ $t('remainingParkingSpace.unit') }}
  24 + </template>
  25 + </el-table-column>
  26 + <el-table-column
  27 + prop="freeCount"
  28 + :label="$t('remainingParkingSpace.freeCount')"
  29 + align="center"
  30 + >
  31 + <template slot-scope="scope">
  32 + {{ scope.row.freeCount }} {{ $t('remainingParkingSpace.unit') }}
  33 + </template>
  34 + </el-table-column>
  35 + <el-table-column
  36 + prop="createTime"
  37 + :label="$t('remainingParkingSpace.createTime')"
  38 + align="center"
  39 + />
  40 + <el-table-column
  41 + :label="$t('remainingParkingSpace.operation')"
  42 + align="center"
  43 + width="150"
  44 + >
  45 + <template slot-scope="scope">
  46 + <el-button
  47 + size="mini"
  48 + type="primary"
  49 + @click="handleRefresh(scope.row)"
  50 + >
  51 + {{ $t('remainingParkingSpace.refresh') }}
  52 + </el-button>
  53 + </template>
  54 + </el-table-column>
  55 + </el-table>
  56 + </el-col>
  57 + </el-row>
  58 + </div>
  59 + </el-card>
  60 + </div>
  61 +</template>
  62 +
  63 +<script>
  64 +import { getRemainingParkingSpace } from '@/api/car/remainingParkingSpaceApi'
  65 +import { getCommunityId } from '@/api/community/communityApi'
  66 +
  67 +export default {
  68 + name: 'RemainingParkingSpaceList',
  69 + data() {
  70 + return {
  71 + loading: false,
  72 + tableData: [
  73 + {
  74 + total: 0,
  75 + freeCount: 0,
  76 + createTime: this.formatDateTime(new Date().getTime())
  77 + }
  78 + ],
  79 + communityId: ''
  80 + }
  81 + },
  82 + created() {
  83 + this.communityId = getCommunityId()
  84 + this.getData()
  85 + },
  86 + methods: {
  87 + formatDateTime(timestamp) {
  88 + const date = new Date(timestamp)
  89 + return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')} ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}:${date.getSeconds().toString().padStart(2, '0')}`
  90 + },
  91 + async getData() {
  92 + try {
  93 + this.loading = true
  94 + const params = {
  95 + communityId: this.communityId,
  96 + iotApiCode: 'getFreeParkingSpaceBmoImpl'
  97 + }
  98 +
  99 + const res = await getRemainingParkingSpace(params)
  100 + if (res.code === 0) {
  101 + this.tableData = [{
  102 + total: res.data.total,
  103 + freeCount: res.data.freeCount,
  104 + createTime: this.formatDateTime(new Date().getTime())
  105 + }]
  106 + } else {
  107 + this.$message.error(res.msg || this.$t('remainingParkingSpace.fetchError'))
  108 + }
  109 + } catch (error) {
  110 + this.$message.error(this.$t('remainingParkingSpace.fetchError'))
  111 + console.error('Error fetching remaining parking space:', error)
  112 + } finally {
  113 + this.loading = false
  114 + }
  115 + },
  116 + handleRefresh() {
  117 + this.getData()
  118 + }
  119 + }
  120 +}
  121 +</script>
  122 +
  123 +<style lang="scss" scoped>
  124 +.remaining-parking-space-container {
  125 + padding: 20px;
  126 +
  127 + .box-card {
  128 + margin-bottom: 20px;
  129 +
  130 + .clearfix {
  131 + display: flex;
  132 + justify-content: space-between;
  133 + align-items: center;
  134 + }
  135 + }
  136 +
  137 + .card-content {
  138 + padding: 20px;
  139 + }
  140 +}
  141 +</style>
0 \ No newline at end of file 142 \ No newline at end of file
src/views/car/tempCarPaymentLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + tempCarPayment: {
  4 + searchTitle: 'Search Conditions',
  5 + inParkingTitle: 'Parking Vehicles',
  6 + carNumPlaceholder: 'Please enter license plate number',
  7 + carStatusPlaceholder: 'Please select vehicle status',
  8 + selectCarStatus: 'Select vehicle status',
  9 + inStatus: 'Entry Status',
  10 + paidStatus: 'Payment Completed',
  11 + outStatus: 'Exit Status',
  12 + repayStatus: 'Re-payment due to timeout',
  13 + entryStartTime: 'Entry start time',
  14 + entryEndTime: 'Entry end time',
  15 + search: 'Search',
  16 + reset: 'Reset',
  17 + inoutId: 'In/Out ID',
  18 + carStatus: 'Vehicle Status',
  19 + carNum: 'License Plate',
  20 + inTime: 'Entry Time',
  21 + payType: 'Payment Type',
  22 + payableAmount: 'Payable Amount',
  23 + paidAmount: 'Paid Amount',
  24 + payTime: 'Payment Time',
  25 + loadParkingAreaError: 'Failed to load parking areas',
  26 + queryError: 'Query failed'
  27 + }
  28 + },
  29 + zh: {
  30 + tempCarPayment: {
  31 + searchTitle: '查询条件',
  32 + inParkingTitle: '在场车辆',
  33 + carNumPlaceholder: '请输入车牌号',
  34 + carStatusPlaceholder: '请选择车辆状态',
  35 + selectCarStatus: '请选择车辆状态',
  36 + inStatus: '进场状态',
  37 + paidStatus: '支付完成',
  38 + outStatus: '离场状态',
  39 + repayStatus: '支付超时重新支付',
  40 + entryStartTime: '进场开始时间',
  41 + entryEndTime: '进场结束时间',
  42 + search: '查询',
  43 + reset: '重置',
  44 + inoutId: '进出场编号',
  45 + carStatus: '车辆状态',
  46 + carNum: '车牌号',
  47 + inTime: '进场时间',
  48 + payType: '收费类型',
  49 + payableAmount: '应收金额',
  50 + paidAmount: '实收金额',
  51 + payTime: '支付时间',
  52 + loadParkingAreaError: '加载停车区域失败',
  53 + queryError: '查询失败'
  54 + }
  55 + }
  56 +}
0 \ No newline at end of file 57 \ No newline at end of file
src/views/car/tempCarPaymentList.vue 0 → 100644
  1 +<template>
  2 + <div class="animated fadeInRight">
  3 + <el-row :gutter="20">
  4 + <el-col :span="3" class="left-panel">
  5 + <el-card class="box-card">
  6 + <div class="treeview">
  7 + <ul class="list-group">
  8 + <li v-for="(item, index) in parkingAreas" :key="index" class="list-group-item"
  9 + :class="{ 'vc-node-selected': conditions.paId === item.paId }" @click="handleSwitchParkingArea(item)">
  10 + {{ item.num }}
  11 + </li>
  12 + </ul>
  13 + </div>
  14 + </el-card>
  15 + </el-col>
  16 +
  17 + <el-col :span="21" class="right-panel">
  18 + <el-card class="box-card" >
  19 + <div slot="header" class="flex justify-between">
  20 + <span>{{ $t('tempCarPayment.searchTitle') }}</span>
  21 + </div>
  22 + <el-form :inline="true" :model="conditions" class="demo-form-inline">
  23 + <el-row :gutter="20">
  24 + <el-col :span="4">
  25 + <el-form-item>
  26 + <el-input v-model="conditions.carNum" :placeholder="$t('tempCarPayment.carNumPlaceholder')" />
  27 + </el-form-item>
  28 + </el-col>
  29 +
  30 + <el-col :span="4">
  31 + <el-form-item>
  32 + <el-select v-model="conditions.state" :placeholder="$t('tempCarPayment.carStatusPlaceholder')"
  33 + style="width:100%">
  34 + <el-option label="" :value="null">{{ $t('tempCarPayment.selectCarStatus') }}</el-option>
  35 + <el-option value="100300" :label="$t('tempCarPayment.inStatus')" />
  36 + <el-option value="100400" :label="$t('tempCarPayment.paidStatus')" />
  37 + <el-option value="100500" :label="$t('tempCarPayment.outStatus')" />
  38 + <el-option value="100600" :label="$t('tempCarPayment.repayStatus')" />
  39 + </el-select>
  40 + </el-form-item>
  41 + </el-col>
  42 +
  43 + <el-col :span="4">
  44 + <el-form-item>
  45 + <el-date-picker v-model="conditions.startTime" type="datetime"
  46 + :placeholder="$t('tempCarPayment.entryStartTime')" style="width:100%" />
  47 + </el-form-item>
  48 + </el-col>
  49 +
  50 + <el-col :span="4">
  51 + <el-form-item>
  52 + <el-date-picker v-model="conditions.endTime" type="datetime"
  53 + :placeholder="$t('tempCarPayment.entryEndTime')" style="width:100%" />
  54 + </el-form-item>
  55 + </el-col>
  56 +
  57 + <el-col :span="4" >
  58 + <el-button type="primary" @click="queryCarInoutMethod">{{ $t('tempCarPayment.search') }}</el-button>
  59 + <el-button @click="resetCarInoutMethod">{{ $t('tempCarPayment.reset') }}</el-button>
  60 + </el-col>
  61 + </el-row>
  62 + </el-form>
  63 + </el-card>
  64 +
  65 + <el-card class="box-card" style="margin-top:20px">
  66 + <div slot="header" class="flex justify-between">
  67 + <span>{{ $t('tempCarPayment.inParkingTitle') }}</span>
  68 + </div>
  69 + <el-table :data="payments" border style="width:100%">
  70 + <el-table-column prop="inoutId" :label="$t('tempCarPayment.inoutId')" align="center" />
  71 + <el-table-column :label="$t('tempCarPayment.carStatus')" align="center">
  72 + <template slot-scope="scope">
  73 + {{ getCarStatusText(scope.row.carInout) }}
  74 + </template>
  75 + </el-table-column>
  76 + <el-table-column prop="carNum" :label="$t('tempCarPayment.carNum')" align="center" />
  77 + <el-table-column prop="inTime" :label="$t('tempCarPayment.inTime')" align="center" />
  78 + <el-table-column prop="payTypeName" :label="$t('tempCarPayment.payType')" align="center" />
  79 + <el-table-column prop="payCharge" :label="$t('tempCarPayment.payableAmount')" align="center" />
  80 + <el-table-column prop="realCharge" :label="$t('tempCarPayment.paidAmount')" align="center" />
  81 + <el-table-column prop="createTime" :label="$t('tempCarPayment.payTime')" align="center" />
  82 + </el-table>
  83 +
  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" style="margin-top:20px" />
  87 + </el-card>
  88 + </el-col>
  89 + </el-row>
  90 + </div>
  91 +</template>
  92 +
  93 +<script>
  94 +import { listParkingAreas, getCarInoutPaymentList } from '@/api/car/tempCarPaymentApi'
  95 +import { getCommunityId } from '@/api/community/communityApi'
  96 +
  97 +export default {
  98 + name: 'TempCarPaymentList',
  99 + data() {
  100 + return {
  101 + parkingAreas: [],
  102 + payments: [],
  103 + pagination: {
  104 + current: 1,
  105 + size: 10,
  106 + total: 0
  107 + },
  108 + conditions: {
  109 + paId: '',
  110 + state: null,
  111 + carNum: '',
  112 + startTime: null,
  113 + endTime: null,
  114 + iotApiCode: 'listCarInoutPaymentBmoImpl'
  115 + }
  116 + }
  117 + },
  118 + created() {
  119 + this.communityId = getCommunityId()
  120 + this.loadParkingAreas()
  121 + },
  122 + methods: {
  123 + async loadParkingAreas() {
  124 + try {
  125 + const params = {
  126 + page: 1,
  127 + row: 100,
  128 + communityId: this.communityId
  129 + }
  130 + const res = await listParkingAreas(params)
  131 + this.parkingAreas = res.parkingAreas
  132 + if (this.parkingAreas.length > 0) {
  133 + this.handleSwitchParkingArea(this.parkingAreas[0])
  134 + }
  135 + } catch (error) {
  136 + console.error('加载停车区域失败:', error)
  137 + this.$message.error(this.$t('tempCarPayment.loadParkingAreaError'))
  138 + }
  139 + },
  140 +
  141 + handleSwitchParkingArea(parkingArea) {
  142 + this.conditions.paId = parkingArea.paId
  143 + this.queryCarInoutMethod()
  144 + },
  145 +
  146 + async queryCarInoutMethod() {
  147 + try {
  148 + const params = {
  149 + ...this.conditions,
  150 + page: this.pagination.current,
  151 + row: this.pagination.size,
  152 + communityId: this.communityId
  153 + }
  154 +
  155 + // 清理参数
  156 + if (params.carNum) params.carNum = params.carNum.trim()
  157 + if (params.startTime) params.startTime = this.formatDate(params.startTime)
  158 + if (params.endTime) params.endTime = this.formatDate(params.endTime)
  159 +
  160 + const res = await getCarInoutPaymentList(params)
  161 + this.payments = res.data
  162 + this.pagination.total = res.total
  163 + } catch (error) {
  164 + console.error('查询失败:', error)
  165 + this.$message.error(this.$t('tempCarPayment.queryError'))
  166 + }
  167 + },
  168 +
  169 + resetCarInoutMethod() {
  170 + this.conditions = {
  171 + ...this.conditions,
  172 + state: null,
  173 + carNum: '',
  174 + startTime: null,
  175 + endTime: null
  176 + }
  177 + this.queryCarInoutMethod()
  178 + },
  179 +
  180 + handleSizeChange(size) {
  181 + this.pagination.size = size
  182 + this.queryCarInoutMethod()
  183 + },
  184 +
  185 + handleCurrentChange(current) {
  186 + this.pagination.current = current
  187 + this.queryCarInoutMethod()
  188 + },
  189 +
  190 + formatDate(date) {
  191 + if (!date) return null
  192 + const d = new Date(date)
  193 + return `${d.getFullYear()}-${(d.getMonth() + 1).toString().padStart(2, '0')}-${d.getDate().toString().padStart(2, '0')} ${d.getHours().toString().padStart(2, '0')}:${d.getMinutes().toString().padStart(2, '0')}:${d.getSeconds().toString().padStart(2, '0')}`
  194 + },
  195 +
  196 + getCarStatusText(status) {
  197 + const statusMap = {
  198 + '3306': this.$t('tempCarPayment.inStatus'),
  199 + '100400': this.$t('tempCarPayment.paidStatus'),
  200 + '100500': this.$t('tempCarPayment.outStatus'),
  201 + '100600': this.$t('tempCarPayment.repayStatus')
  202 + }
  203 + return statusMap[status] || status
  204 + }
  205 + }
  206 +}
  207 +</script>
  208 +
  209 +<style scoped>
  210 +.left-panel {
  211 + padding-right: 0;
  212 +}
  213 +
  214 +.treeview {
  215 + overflow-y: auto;
  216 +}
  217 +
  218 +.list-group {
  219 + list-style: none;
  220 + padding: 0;
  221 + margin: 0;
  222 +}
  223 +
  224 +.list-group-item {
  225 + padding: 10px 15px;
  226 + margin-bottom: 5px;
  227 + border-radius: 4px;
  228 + text-align: center;
  229 + cursor: pointer;
  230 + transition: all 0.3s;
  231 +}
  232 +
  233 +.list-group-item:hover {
  234 + background-color: #f5f7fa;
  235 +}
  236 +
  237 +.vc-node-selected {
  238 + background-color: #409EFF;
  239 + color: white;
  240 +}
  241 +
  242 +.button-group {
  243 + margin-top: 10px;
  244 + text-align: center;
  245 +}
  246 +
  247 +.box-card {
  248 + margin-bottom: 20px;
  249 +}
  250 +</style>
0 \ No newline at end of file 251 \ No newline at end of file