Commit 15981f1e0b2f31eb232e8a524299551175ca1afc

Authored by wuxw
1 parent 84aec3bc

商铺开发完成

src/api/room/shopsApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +import { getCommunityId } from '@/api/community/communityApi'
  3 +
  4 +// 查询商铺列表
  5 +export function queryShops(params) {
  6 + return new Promise((resolve, reject) => {
  7 + const communityId = getCommunityId()
  8 + request({
  9 + url: '/room.queryRooms',
  10 + method: 'get',
  11 + params: {
  12 + ...params,
  13 + communityId,
  14 + roomType: '2020602'
  15 + }
  16 + }).then(response => {
  17 + const res = response.data
  18 + resolve(res)
  19 + }).catch(error => {
  20 + reject(error)
  21 + })
  22 + })
  23 +}
  24 +
  25 +// 添加商铺
  26 +export function saveShops(data) {
  27 + return new Promise((resolve, reject) => {
  28 + data.communityId = getCommunityId()
  29 + request({
  30 + url: '/room.saveShops',
  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 || 'Failed to add shop'))
  39 + }
  40 + }).catch(error => {
  41 + reject(error)
  42 + })
  43 + })
  44 +}
  45 +
  46 +// 更新商铺
  47 +export function updateShops(data) {
  48 + return new Promise((resolve, reject) => {
  49 + data.communityId = getCommunityId()
  50 + request({
  51 + url: '/room.updateRoom',
  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 || 'Failed to update shop'))
  60 + }
  61 + }).catch(error => {
  62 + reject(error)
  63 + })
  64 + })
  65 +}
  66 +
  67 +// 绑定业主商铺
  68 +export function saveOwnerShops(data) {
  69 + return new Promise((resolve, reject) => {
  70 + data.communityId = getCommunityId()
  71 + request({
  72 + url: '/room.saveOwnerShops',
  73 + method: 'post',
  74 + data
  75 + }).then(response => {
  76 + const res = response.data
  77 + if (res.code === 0) {
  78 + resolve(res)
  79 + } else {
  80 + reject(new Error(res.msg || 'Failed to bind owner'))
  81 + }
  82 + }).catch(error => {
  83 + reject(error)
  84 + })
  85 + })
  86 +}
  87 +
  88 +// 删除商铺
  89 +export function deleteShops(roomId) {
  90 + return new Promise((resolve, reject) => {
  91 + request({
  92 + url: '/room.deleteRoom',
  93 + method: 'post',
  94 + data: {
  95 + roomId,
  96 + communityId: getCommunityId()
  97 + }
  98 + }).then(response => {
  99 + const res = response.data
  100 + if (res.code === 0) {
  101 + resolve(res)
  102 + } else {
  103 + reject(new Error(res.msg || 'Failed to delete shop'))
  104 + }
  105 + }).catch(error => {
  106 + reject(error)
  107 + })
  108 + })
  109 +}
0 \ No newline at end of file 110 \ No newline at end of file
src/components/room/addShops.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="$t('shops.addShop')" :visible.sync="dialogVisible" width="50%">
  3 + <el-form ref="form" :model="formData" :rules="rules" label-width="120px">
  4 + <el-form-item :label="$t('shops.shopNumber')" prop="roomNum">
  5 + <el-input v-model="formData.roomNum" :placeholder="$t('shops.shopNumberPlaceholder')"></el-input>
  6 + </el-form-item>
  7 + <el-form-item :label="$t('shops.shopFloor')" prop="layer">
  8 + <el-input v-model="formData.layer" :placeholder="$t('shops.floorRequired')"></el-input>
  9 + </el-form-item>
  10 + <el-form-item :label="$t('shops.building')" prop="floorId">
  11 + <el-select v-model="formData.floorId"
  12 + :placeholder="$t('shops.building')" style="width: 100%">
  13 + <el-option v-for="item in floors" :key="item.floorId" :label="item.floorNum + $t('shops.building')"
  14 + :value="item.floorId"></el-option>
  15 + </el-select>
  16 + </el-form-item>
  17 + <el-form-item :label="$t('shops.rent')" prop="roomRent">
  18 + <el-input v-model="formData.roomRent" :placeholder="$t('shops.rentPlaceholder')" type="number"></el-input>
  19 + </el-form-item>
  20 + <el-form-item :label="$t('shops.builtUpArea')" prop="builtUpArea">
  21 + <el-input v-model="formData.builtUpArea" :placeholder="$t('shops.builtUpAreaPlaceholder')"
  22 + type="number"></el-input>
  23 + </el-form-item>
  24 + <el-form-item :label="$t('shops.roomArea')" prop="roomArea">
  25 + <el-input v-model="formData.roomArea" :placeholder="$t('shops.roomAreaPlaceholder')" type="number"></el-input>
  26 + </el-form-item>
  27 + <el-form-item :label="$t('shops.feeCoefficient')" prop="feeCoefficient">
  28 + <el-input v-model="formData.feeCoefficient" :placeholder="$t('shops.feeCoefficientPlaceholder')"
  29 + type="number"></el-input>
  30 + </el-form-item>
  31 + <el-form-item :label="$t('shops.remark')">
  32 + <el-input type="textarea" v-model="formData.remark" :placeholder="$t('shops.remark')"></el-input>
  33 + </el-form-item>
  34 + </el-form>
  35 + <div slot="footer">
  36 + <el-button @click="dialogVisible = false">{{ $t('common.cancel') }}</el-button>
  37 + <el-button type="primary" @click="handleSubmit">{{ $t('common.save') }}</el-button>
  38 + </div>
  39 + </el-dialog>
  40 +</template>
  41 +
  42 +<script>
  43 +import { saveShops } from '@/api/room/shopsApi'
  44 +import { getFloors } from '@/api/room/roomApi'
  45 +import {getCommunityId} from '@/api/community/communityApi'
  46 +
  47 +export default {
  48 + name: 'AddShops',
  49 + components: {
  50 + },
  51 + data() {
  52 + return {
  53 + dialogVisible: false,
  54 + formData: {
  55 + roomNum: '',
  56 + layer: '',
  57 + floorId: '',
  58 + roomRent: '',
  59 + builtUpArea: '',
  60 + roomArea: '',
  61 + feeCoefficient: '1.00',
  62 + remark: '',
  63 + roomSubType: '120'
  64 + },
  65 + rules: {
  66 + roomNum: [
  67 + { required: true, message: this.$t('shops.shopNumberRequired'), trigger: 'blur' }
  68 + ],
  69 + layer: [
  70 + { required: true, message: this.$t('shops.floorRequired'), trigger: 'blur' }
  71 + ],
  72 + floorId: [
  73 + { required: true, message: this.$t('shops.buildingRequired'), trigger: 'change' }
  74 + ],
  75 + roomRent: [
  76 + { required: true, message: this.$t('shops.rentRequired'), trigger: 'blur' }
  77 + ],
  78 + builtUpArea: [
  79 + { required: true, message: this.$t('shops.builtUpAreaRequired'), trigger: 'blur' }
  80 + ],
  81 + roomArea: [
  82 + { required: true, message: this.$t('shops.roomAreaRequired'), trigger: 'blur' }
  83 + ],
  84 + feeCoefficient: [
  85 + { required: true, message: this.$t('shops.feeCoefficientRequired'), trigger: 'blur' }
  86 + ]
  87 + }
  88 + }
  89 + },
  90 + methods: {
  91 + open() {
  92 + this.dialogVisible = true
  93 + this.resetForm()
  94 + this.searchFloors()
  95 + },
  96 + resetForm() {
  97 + this.formData = {
  98 + roomNum: '',
  99 + layer: '',
  100 + floorId: '',
  101 + roomRent: '',
  102 + builtUpArea: '',
  103 + roomArea: '',
  104 + feeCoefficient: '1.00',
  105 + remark: '',
  106 + roomSubType: '120'
  107 + }
  108 + if (this.$refs.form) {
  109 + this.$refs.form.resetFields()
  110 + }
  111 + },
  112 + handleFloorChange(floor) {
  113 + this.formData.floorId = floor.floorId
  114 + this.$refs.form.validateField('floorId')
  115 + },
  116 + handleSubmit() {
  117 + this.$refs.form.validate(valid => {
  118 + if (valid) {
  119 + this.saveData()
  120 + }
  121 + })
  122 + },
  123 + saveData() {
  124 + saveShops(this.formData)
  125 + .then(res => {
  126 + if (res.code == 0) {
  127 + this.$message.success(this.$t('common.saveSuccess'))
  128 + this.dialogVisible = false
  129 + this.$emit('success')
  130 + } else {
  131 + this.$message.error(res.msg)
  132 + }
  133 + })
  134 + .catch(error => {
  135 + console.error(error)
  136 + this.$message.error(this.$t('common.saveFailed'))
  137 + })
  138 + },
  139 + async searchFloors() {
  140 + const {apiFloorDataVoList} = await getFloors({
  141 + communityId: getCommunityId(),
  142 + page:1,
  143 + row:100
  144 + })
  145 + this.floors = apiFloorDataVoList
  146 + },
  147 + }
  148 +}
  149 +</script>
0 \ No newline at end of file 150 \ No newline at end of file
src/components/room/bindOwnerShops.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="formTitle" :visible.sync="dialogVisible" width="50%">
  3 + <el-form ref="form" :model="formData" :rules="rules" label-width="120px">
  4 + <el-form-item :label="$t('shops.shopNumber')">
  5 + <el-input v-model="formData.shopsName" disabled></el-input>
  6 + </el-form-item>
  7 + <el-form-item :label="$t('shops.tenantPhone')" prop="tel">
  8 + <el-input v-model="formData.tel" :placeholder="$t('shops.tenantPhoneRequired')" @blur="loadOwnerInfo"></el-input>
  9 + </el-form-item>
  10 + <el-form-item :label="$t('shops.tenantName')" prop="ownerName">
  11 + <el-input v-model="formData.ownerName" :placeholder="$t('shops.tenantNameRequired')"></el-input>
  12 + </el-form-item>
  13 + <el-form-item v-if="formData.shopsState === '2006'" :label="$t('shops.leaseStart')" prop="startTime">
  14 + <el-date-picker v-model="formData.startTime" type="date" :placeholder="$t('shops.leaseStartRequired')"
  15 + value-format="yyyy-MM-dd" style="width: 100%"></el-date-picker>
  16 + </el-form-item>
  17 + <el-form-item v-if="formData.shopsState === '2006'" :label="$t('shops.leaseEnd')" prop="endTime">
  18 + <el-date-picker v-model="formData.endTime" type="date" :placeholder="$t('shops.leaseEndRequired')"
  19 + value-format="yyyy-MM-dd" :picker-options="endDateOptions" style="width: 100%"></el-date-picker>
  20 + </el-form-item>
  21 + <el-form-item :label="$t('shops.remark')">
  22 + <el-input type="textarea" v-model="formData.remark" :placeholder="$t('shops.remark')"></el-input>
  23 + </el-form-item>
  24 + </el-form>
  25 + <div slot="footer">
  26 + <el-button @click="dialogVisible = false">{{ $t('common.cancel') }}</el-button>
  27 + <el-button type="primary" @click="handleSubmit">{{ $t('common.save') }}</el-button>
  28 + </div>
  29 + </el-dialog>
  30 +</template>
  31 +
  32 +<script>
  33 +import { saveOwnerShops } from '@/api/room/shopsApi'
  34 +import {queryOwners} from '@/api/owner/roomBindOwnerApi'
  35 +import {getCommunityId} from '@/api/community/communityApi'
  36 +import {getDateYYYYMMDD} from '@/utils/dateUtil'
  37 +
  38 +export default {
  39 + name: 'BindOwnerShops',
  40 + data() {
  41 + const validatePhone = (rule, value, callback) => {
  42 + if (!value) {
  43 + callback(new Error(this.$t('shops.tenantPhoneRequired')))
  44 + } else if (!/^1[3-9]\d{9}$/.test(value)) {
  45 + callback(new Error(this.$t('shops.phoneFormatError')))
  46 + } else {
  47 + callback()
  48 + }
  49 + }
  50 +
  51 + const validateEndDate = (rule, value, callback) => {
  52 + if (!value) {
  53 + callback(new Error(this.$t('shops.leaseEndRequired')))
  54 + } else if (new Date(value) <= new Date(this.formData.startTime)) {
  55 + callback(new Error(this.$t('shops.leaseEndRequired')))
  56 + } else {
  57 + callback()
  58 + }
  59 + }
  60 +
  61 + return {
  62 + dialogVisible: false,
  63 + formData: {
  64 + roomId: '',
  65 + shopsName: '',
  66 + ownerId: '',
  67 + ownerName: '',
  68 + tel: '',
  69 + startTime: '',
  70 + endTime: '',
  71 + remark: '',
  72 + shopsState: '2006'
  73 + },
  74 + rules: {
  75 + tel: [
  76 + { validator: validatePhone, trigger: 'blur' }
  77 + ],
  78 + ownerName: [
  79 + { required: true, message: this.$t('shops.tenantNameRequired'), trigger: 'blur' }
  80 + ],
  81 + startTime: [
  82 + { required: true, message: this.$t('shops.leaseStartRequired'), trigger: 'change' }
  83 + ],
  84 + endTime: [
  85 + { validator: validateEndDate, trigger: 'change' }
  86 + ]
  87 + },
  88 + endDateOptions: {
  89 + disabledDate: (time) => {
  90 + if (this.formData.startTime) {
  91 + return time.getTime() <= new Date(this.formData.startTime).getTime()
  92 + }
  93 + return false
  94 + }
  95 + }
  96 + }
  97 + },
  98 + computed: {
  99 + formTitle() {
  100 + return this.formData.shopsState === '2007'
  101 + ? this.$t('shops.sell') + this.$t('shops.shopInfo')
  102 + : this.$t('shops.rent') + this.$t('shops.shopInfo')
  103 + }
  104 + },
  105 + methods: {
  106 + open(row, state) {
  107 + this.dialogVisible = true
  108 + this.resetForm()
  109 + this.formData = {
  110 + roomId: row.roomId,
  111 + shopsName: `${row.floorNum}-${row.roomNum}`,
  112 + ownerId: '',
  113 + ownerName: '',
  114 + tel: '',
  115 + startTime: state === '2007' ? getDateYYYYMMDD() : '',
  116 + endTime: state === '2007' ? '2050-01-01' : '',
  117 + remark: '',
  118 + shopsState: state
  119 + }
  120 + },
  121 + resetForm() {
  122 + this.formData = {
  123 + roomId: '',
  124 + shopsName: '',
  125 + ownerId: '',
  126 + ownerName: '',
  127 + tel: '',
  128 + startTime: '',
  129 + endTime: '',
  130 + remark: '',
  131 + shopsState: '2006'
  132 + }
  133 + if (this.$refs.form) {
  134 + this.$refs.form.resetFields()
  135 + }
  136 + },
  137 + async loadOwnerInfo() {
  138 + if (!this.formData.tel) return
  139 +
  140 + const {data,total} = await queryOwners({page:1,row:1,communityId:getCommunityId(),tel: this.formData.tel});
  141 + if(total>0){
  142 + this.formData.ownerName = data[0].name
  143 + this.formData.ownerId = data[0].ownerId
  144 + }else{
  145 + this.formData.ownerName = ''
  146 + this.formData.ownerId = ''
  147 + }
  148 + },
  149 + handleSubmit() {
  150 + this.$refs.form.validate(valid => {
  151 + if (valid) {
  152 + this.saveData()
  153 + }
  154 + })
  155 + },
  156 + saveData() {
  157 + saveOwnerShops(this.formData)
  158 + .then(res => {
  159 + if (res.code == 0) {
  160 + this.$message.success(this.$t('common.saveSuccess'))
  161 + this.dialogVisible = false
  162 + this.$emit('success')
  163 + } else {
  164 + this.$message.error(res.msg)
  165 + }
  166 + })
  167 + .catch(error => {
  168 + console.error(error)
  169 + this.$message.error(this.$t('common.saveFailed'))
  170 + })
  171 + }
  172 + }
  173 +}
  174 +</script>
0 \ No newline at end of file 175 \ No newline at end of file
src/components/room/editShops.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="$t('shops.edit') + $t('shops.shopInfo')" :visible.sync="dialogVisible" width="50%">
  3 + <el-form ref="form" :model="formData" :rules="rules" label-width="120px">
  4 + <el-form-item :label="$t('shops.shopId')">
  5 + <el-input v-model="formData.roomId" disabled></el-input>
  6 + </el-form-item>
  7 + <el-form-item :label="$t('shops.shopNumber')" prop="roomNum">
  8 + <el-input v-model="formData.roomNum" :placeholder="$t('shops.shopNumberRequired')"></el-input>
  9 + </el-form-item>
  10 + <el-form-item :label="$t('shops.shopFloor')" prop="layer">
  11 + <el-input v-model="formData.layer" :placeholder="$t('shops.floorRequired')"></el-input>
  12 + </el-form-item>
  13 + <el-form-item v-if="formData.state === '2006'" :label="$t('shops.leaseStart')" prop="startTime">
  14 + <el-date-picker v-model="formData.startTime" type="date" :placeholder="$t('shops.leaseStartRequired')"
  15 + value-format="yyyy-MM-dd" style="width: 100%"></el-date-picker>
  16 + </el-form-item>
  17 + <el-form-item v-if="formData.state === '2006'" :label="$t('shops.leaseEnd')" prop="endTime">
  18 + <el-date-picker v-model="formData.endTime" type="date" :placeholder="$t('shops.leaseEndRequired')"
  19 + value-format="yyyy-MM-dd" :picker-options="endDateOptions" style="width: 100%"></el-date-picker>
  20 + </el-form-item>
  21 + <el-form-item :label="$t('shops.rent')" prop="roomRent">
  22 + <el-input v-model="formData.roomRent" :placeholder="$t('shops.rentPlaceholder')" type="number"></el-input>
  23 + </el-form-item>
  24 + <el-form-item :label="$t('shops.builtUpArea')" prop="builtUpArea">
  25 + <el-input v-model="formData.builtUpArea" :placeholder="$t('shops.builtUpAreaPlaceholder')"
  26 + type="number"></el-input>
  27 + </el-form-item>
  28 + <el-form-item :label="$t('shops.roomArea')" prop="roomArea">
  29 + <el-input v-model="formData.roomArea" :placeholder="$t('shops.roomAreaPlaceholder')" type="number"></el-input>
  30 + </el-form-item>
  31 + <el-form-item :label="$t('shops.feeCoefficient')" prop="feeCoefficient">
  32 + <el-input v-model="formData.feeCoefficient" :placeholder="$t('shops.feeCoefficientPlaceholder')"
  33 + type="number"></el-input>
  34 + </el-form-item>
  35 +
  36 + <!-- 动态属性 -->
  37 + <div v-for="(item, index) in formData.attrs" :key="index">
  38 + <el-form-item v-if="item.specType === '2233'" :label="item.specName">
  39 + <el-input v-model="item.value" :placeholder="item.specHoldplace"></el-input>
  40 + </el-form-item>
  41 + <el-form-item v-if="item.specType === '3344'" :label="item.specName">
  42 + <el-select v-model="item.value" :placeholder="item.specHoldplace" style="width: 100%">
  43 + <el-option v-for="option in item.values" :key="option.value" :label="option.valueName"
  44 + :value="option.value"></el-option>
  45 + </el-select>
  46 + </el-form-item>
  47 + </div>
  48 +
  49 + <el-form-item :label="$t('shops.remark')">
  50 + <el-input type="textarea" v-model="formData.remark" :placeholder="$t('shops.remark')"></el-input>
  51 + </el-form-item>
  52 + </el-form>
  53 + <div slot="footer">
  54 + <el-button @click="dialogVisible = false">{{ $t('common.cancel') }}</el-button>
  55 + <el-button type="primary" @click="handleSubmit">{{ $t('common.save') }}</el-button>
  56 + </div>
  57 + </el-dialog>
  58 +</template>
  59 +
  60 +<script>
  61 +import { updateShops } from '@/api/room/shopsApi'
  62 +
  63 +export default {
  64 + name: 'EditShops',
  65 + data() {
  66 + const validateEndDate = (rule, value, callback) => {
  67 + if (!value) {
  68 + callback(new Error(this.$t('shops.leaseEndRequired')))
  69 + } else if (new Date(value) <= new Date(this.formData.startTime)) {
  70 + callback(new Error(this.$t('shops.leaseEndRequired')))
  71 + } else {
  72 + callback()
  73 + }
  74 + }
  75 +
  76 + return {
  77 + dialogVisible: false,
  78 + formData: {
  79 + roomId: '',
  80 + roomNum: '',
  81 + layer: '',
  82 + builtUpArea: '',
  83 + feeCoefficient: '',
  84 + remark: '',
  85 + roomRent: '',
  86 + roomArea: '',
  87 + startTime: '',
  88 + endTime: '',
  89 + state: '',
  90 + attrs: []
  91 + },
  92 + rules: {
  93 + roomNum: [
  94 + { required: true, message: this.$t('shops.shopNumberRequired'), trigger: 'blur' }
  95 + ],
  96 + layer: [
  97 + { required: true, message: this.$t('shops.floorRequired'), trigger: 'blur' }
  98 + ],
  99 + roomRent: [
  100 + { required: true, message: this.$t('shops.rentRequired'), trigger: 'blur' }
  101 + ],
  102 + builtUpArea: [
  103 + { required: true, message: this.$t('shops.builtUpAreaRequired'), trigger: 'blur' }
  104 + ],
  105 + roomArea: [
  106 + { required: true, message: this.$t('shops.roomAreaRequired'), trigger: 'blur' }
  107 + ],
  108 + feeCoefficient: [
  109 + { required: true, message: this.$t('shops.feeCoefficientRequired'), trigger: 'blur' }
  110 + ],
  111 + startTime: [
  112 + { required: true, message: this.$t('shops.leaseStartRequired'), trigger: 'change' }
  113 + ],
  114 + endTime: [
  115 + { validator: validateEndDate, trigger: 'change' }
  116 + ]
  117 + },
  118 + endDateOptions: {
  119 + disabledDate: (time) => {
  120 + if (this.formData.startTime) {
  121 + return time.getTime() <= new Date(this.formData.startTime).getTime()
  122 + }
  123 + return false
  124 + }
  125 + }
  126 + }
  127 + },
  128 + methods: {
  129 + open(row) {
  130 + this.dialogVisible = true
  131 + this.resetForm()
  132 + this.formData = { ...row }
  133 +
  134 + // 处理日期格式
  135 + if (this.formData.startTime) {
  136 + this.formData.startTime = this.formData.startTime.split(' ')[0]
  137 + }
  138 + if (this.formData.endTime) {
  139 + this.formData.endTime = this.formData.endTime.split(' ')[0]
  140 + }
  141 +
  142 + // 加载属性数据
  143 + this.loadAttributes()
  144 + },
  145 + resetForm() {
  146 + this.formData = {
  147 + roomId: '',
  148 + roomNum: '',
  149 + layer: '',
  150 + builtUpArea: '',
  151 + feeCoefficient: '',
  152 + remark: '',
  153 + roomRent: '',
  154 + roomArea: '',
  155 + startTime: '',
  156 + endTime: '',
  157 + state: '',
  158 + attrs: []
  159 + }
  160 + if (this.$refs.form) {
  161 + this.$refs.form.resetFields()
  162 + }
  163 + },
  164 + loadAttributes() {
  165 + // 模拟加载属性数据
  166 + this.formData.attrs = [
  167 + ]
  168 + },
  169 + handleSubmit() {
  170 + this.$refs.form.validate(valid => {
  171 + if (valid) {
  172 + this.saveData()
  173 + }
  174 + })
  175 + },
  176 + saveData() {
  177 + updateShops(this.formData)
  178 + .then(res => {
  179 + if (res.code == 0) {
  180 + this.$message.success(this.$t('common.saveSuccess'))
  181 + this.dialogVisible = false
  182 + this.$emit('success')
  183 + } else {
  184 + this.$message.error(res.msg)
  185 + }
  186 + })
  187 + .catch(error => {
  188 + console.error(error)
  189 + this.$message.error(this.$t('common.saveFailed'))
  190 + })
  191 + }
  192 + }
  193 +}
  194 +</script>
0 \ No newline at end of file 195 \ No newline at end of file
src/components/room/floorSelect2.vue 0 → 100644
  1 +<template>
  2 + <el-select v-model="selectedFloor" filterable remote :remote-method="searchFloors" :loading="loading"
  3 + :placeholder="$t('shops.buildingPlaceholder')" style="width: 100%" @change="handleChange">
  4 + <el-option v-for="item in floors" :key="item.floorId" :label="item.floorNum + $t('shops.building')"
  5 + :value="item"></el-option>
  6 + </el-select>
  7 +</template>
  8 +
  9 +<script>
  10 +import { getCommunityId } from '@/api/community/communityApi'
  11 +
  12 +import { getFloors } from '@/api/room/roomApi'
  13 +
  14 +export default {
  15 + name: 'FloorSelect2',
  16 + data() {
  17 + return {
  18 + selectedFloor: null,
  19 + floors: [],
  20 + loading: false
  21 + }
  22 + },
  23 + methods: {
  24 + open() {
  25 + this.searchFloors()
  26 + },
  27 + async searchFloors() {
  28 + const {apiFloorDataVoList} = await getFloors({
  29 + communityId: getCommunityId(),
  30 + page:1,
  31 + row:100
  32 + })
  33 + this.floors = apiFloorDataVoList
  34 + },
  35 + handleChange(value) {
  36 + this.$emit('change', value)
  37 + },
  38 + clear() {
  39 + this.selectedFloor = null
  40 + this.floors = []
  41 + }
  42 + }
  43 +}
  44 +</script>
0 \ No newline at end of file 45 \ No newline at end of file
src/i18n/index.js
@@ -126,6 +126,7 @@ import { messages as roomMessages } from &#39;../views/room/roomLang.js&#39; @@ -126,6 +126,7 @@ import { messages as roomMessages } from &#39;../views/room/roomLang.js&#39;
126 import { messages as addRoomViewMessages } from '../views/room/addRoomViewLang' 126 import { messages as addRoomViewMessages } from '../views/room/addRoomViewLang'
127 import { messages as roomBindOwnerMessages } from '../views/owner/roomBindOwnerLang' 127 import { messages as roomBindOwnerMessages } from '../views/owner/roomBindOwnerLang'
128 import { messages as deleteOwnerRoomMessages } from '../views/owner/deleteOwnerRoomLang' 128 import { messages as deleteOwnerRoomMessages } from '../views/owner/deleteOwnerRoomLang'
  129 +import { messages as shopsMessages } from '../views/room/shopsLang'
129 130
130 Vue.use(VueI18n) 131 Vue.use(VueI18n)
131 132
@@ -256,6 +257,7 @@ const messages = { @@ -256,6 +257,7 @@ const messages = {
256 ...addRoomViewMessages.en, 257 ...addRoomViewMessages.en,
257 ...roomBindOwnerMessages.en, 258 ...roomBindOwnerMessages.en,
258 ...deleteOwnerRoomMessages.en, 259 ...deleteOwnerRoomMessages.en,
  260 + ...shopsMessages.en,
259 }, 261 },
260 zh: { 262 zh: {
261 ...loginMessages.zh, 263 ...loginMessages.zh,
@@ -382,6 +384,7 @@ const messages = { @@ -382,6 +384,7 @@ const messages = {
382 ...addRoomViewMessages.zh, 384 ...addRoomViewMessages.zh,
383 ...roomBindOwnerMessages.zh, 385 ...roomBindOwnerMessages.zh,
384 ...deleteOwnerRoomMessages.zh, 386 ...deleteOwnerRoomMessages.zh,
  387 + ...shopsMessages.zh,
385 } 388 }
386 } 389 }
387 390
src/router/index.js
@@ -607,15 +607,20 @@ const routes = [ @@ -607,15 +607,20 @@ const routes = [
607 component: () => import('@/views/room/addRoomViewList.vue') 607 component: () => import('@/views/room/addRoomViewList.vue')
608 }, 608 },
609 { 609 {
610 - path:'/views/owner/roomBindOwner',  
611 - name:'/views/owner/roomBindOwner', 610 + path: '/views/owner/roomBindOwner',
  611 + name: '/views/owner/roomBindOwner',
612 component: () => import('@/views/owner/roomBindOwnerList.vue') 612 component: () => import('@/views/owner/roomBindOwnerList.vue')
613 - },  
614 - {  
615 - path:'/views/owner/deleteOwnerRoom',  
616 - name:'/views/owner/deleteOwnerRoom',  
617 - component: () => import('@/views/owner/deleteOwnerRoomList.vue')  
618 - }, 613 + },
  614 + {
  615 + path: '/views/owner/deleteOwnerRoom',
  616 + name: '/views/owner/deleteOwnerRoom',
  617 + component: () => import('@/views/owner/deleteOwnerRoomList.vue')
  618 + },
  619 + {
  620 + path: '/pages/property/shops',
  621 + name: '/pages/property/shops',
  622 + component: () => import('@/views/room/shopsList.vue')
  623 + },
619 // 其他子路由可以在这里添加 624 // 其他子路由可以在这里添加
620 ] 625 ]
621 }, 626 },
src/views/room/shopsLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + shops: {
  4 + queryCondition: 'Query Conditions',
  5 + shopInfo: 'Shop Information',
  6 + shopId: 'Shop ID',
  7 + shopIdPlaceholder: 'Please enter shop ID',
  8 + shopNumber: 'Shop Number',
  9 + shopNumberPlaceholder: 'Please enter shop number (format: Building-Shop)',
  10 + state: 'Status',
  11 + statePlaceholder: 'Please select status',
  12 + rented: 'Rented',
  13 + sold: 'Sold',
  14 + idle: 'Vacant',
  15 + addShop: 'Add Shop',
  16 + floor: 'Floor',
  17 + owner: 'Owner/Tenant',
  18 + contactNumber: 'Contact Number',
  19 + builtUpArea: 'Built-up Area',
  20 + roomArea: 'Indoor Area',
  21 + startTime: 'Start Lease Time',
  22 + endTime: 'End Lease Time',
  23 + rent: 'Rent',
  24 + feeCoefficient: 'Fee Coefficient',
  25 + operation: 'Operation',
  26 + rentAction: 'Rent',
  27 + sellAction: 'Sell',
  28 + unbind: 'Unbind',
  29 + edit: 'Edit',
  30 + delete: 'Delete',
  31 + squareMeter: 'm²',
  32 + layerUnit: 'F',
  33 + confirmDelete: 'Confirm Delete',
  34 + deleteTip: 'Deleting the shop will delete associated fees and payment records, and automatically unbind the owner!',
  35 + cancel: 'Cancel',
  36 + confirm: 'Confirm',
  37 + save: 'Save',
  38 + building: 'Building',
  39 + tenantPhone: 'Tenant Phone',
  40 + tenantName: 'Tenant Name',
  41 + leaseStart: 'Lease Start Date',
  42 + leaseEnd: 'Lease End Date',
  43 + remark: 'Remark',
  44 + shopFloor: 'Shop Floor',
  45 + feeCoefficientPlaceholder: 'Please enter fee coefficient',
  46 + builtUpAreaPlaceholder: 'Please enter built-up area',
  47 + roomAreaPlaceholder: 'Please enter indoor area',
  48 + rentPlaceholder: 'Please enter rent amount',
  49 + shopNumberRequired: 'Shop number is required',
  50 + floorRequired: 'Shop floor is required',
  51 + buildingRequired: 'Building is required',
  52 + rentRequired: 'Rent is required',
  53 + builtUpAreaRequired: 'Built-up area is required',
  54 + roomAreaRequired: 'Indoor area is required',
  55 + feeCoefficientRequired: 'Fee coefficient is required',
  56 + tenantPhoneRequired: 'Tenant phone is required',
  57 + tenantNameRequired: 'Tenant name is required',
  58 + leaseStartRequired: 'Lease start date is required',
  59 + leaseEndRequired: 'Lease end date is required',
  60 + phoneFormatError: 'Invalid phone format'
  61 + }
  62 + },
  63 + zh: {
  64 + shops: {
  65 + queryCondition: '查询条件',
  66 + shopInfo: '商铺信息',
  67 + shopId: '商铺ID',
  68 + shopIdPlaceholder: '请填写商铺ID',
  69 + shopNumber: '商铺编号',
  70 + shopNumberPlaceholder: '请填写商铺编号(格式:楼栋-商铺)',
  71 + state: '状态',
  72 + statePlaceholder: '请选择状态',
  73 + rented: '已出租',
  74 + sold: '已出售',
  75 + idle: '空闲',
  76 + addShop: '添加商铺',
  77 + floor: '楼层',
  78 + owner: '业主/租方',
  79 + contactNumber: '联系电话',
  80 + builtUpArea: '建筑面积',
  81 + roomArea: '室内面积',
  82 + startTime: '起租时间',
  83 + endTime: '截租时间',
  84 + rent: '租金',
  85 + feeCoefficient: '算费系数',
  86 + operation: '操作',
  87 + rentAction: '出租',
  88 + sellAction: '出售',
  89 + unbind: '解绑',
  90 + edit: '修改',
  91 + delete: '删除',
  92 + squareMeter: '平方米',
  93 + layerUnit: '层',
  94 + confirmDelete: '确认删除',
  95 + deleteTip: '确认是否删除!删除房屋会关联删除房屋下的费用以及缴费记录,并且自动解绑业主!',
  96 + cancel: '取消',
  97 + confirm: '确认',
  98 + save: '保存',
  99 + building: '楼栋',
  100 + tenantPhone: '租户手机号',
  101 + tenantName: '租户姓名',
  102 + leaseStart: '起租时间',
  103 + leaseEnd: '截租时间',
  104 + remark: '备注',
  105 + shopFloor: '商铺楼层',
  106 + feeCoefficientPlaceholder: '请填写算费系数',
  107 + builtUpAreaPlaceholder: '请填写建筑面积',
  108 + roomAreaPlaceholder: '请填写室内面积',
  109 + rentPlaceholder: '请填写租金',
  110 + shopNumberRequired: '商铺编号不能为空',
  111 + floorRequired: '商铺楼层不能为空',
  112 + buildingRequired: '楼栋不能为空',
  113 + rentRequired: '租金不能为空',
  114 + builtUpAreaRequired: '建筑面积不能为空',
  115 + roomAreaRequired: '室内面积不能为空',
  116 + feeCoefficientRequired: '算费系数不能为空',
  117 + tenantPhoneRequired: '租户手机号不能为空',
  118 + tenantNameRequired: '租户名称不能为空',
  119 + leaseStartRequired: '起租时间不能为空',
  120 + leaseEndRequired: '截租时间不能为空',
  121 + phoneFormatError: '手机号格式错误'
  122 + }
  123 + }
  124 +}
0 \ No newline at end of file 125 \ No newline at end of file
src/views/room/shopsList.vue 0 → 100644
  1 +<template>
  2 + <div class="shops-container">
  3 + <el-row :gutter="20">
  4 + <el-col :span="24">
  5 + <el-card>
  6 + <div slot="header" class="flex justify-between">
  7 + <span>{{ $t('shops.queryCondition') }}</span>
  8 + </div>
  9 + <el-form :inline="true" :model="queryParams" class="demo-form-inline text-left">
  10 + <el-form-item :label="$t('shops.shopId')">
  11 + <el-input v-model.trim="queryParams.roomId" :placeholder="$t('shops.shopIdPlaceholder')"
  12 + clearable></el-input>
  13 + </el-form-item>
  14 + <el-form-item :label="$t('shops.shopNumber')">
  15 + <el-input v-model.trim="queryParams.roomNum" :placeholder="$t('shops.shopNumberPlaceholder')"
  16 + clearable></el-input>
  17 + </el-form-item>
  18 + <el-form-item :label="$t('shops.state')">
  19 + <el-select v-model="queryParams.state" :placeholder="$t('shops.statePlaceholder')" clearable
  20 + style="width: 100%">
  21 + <el-option :label="$t('shops.rented')" value="2006"></el-option>
  22 + <el-option :label="$t('shops.sold')" value="2007"></el-option>
  23 + <el-option :label="$t('shops.idle')" value="2008"></el-option>
  24 + </el-select>
  25 + </el-form-item>
  26 + <el-form-item>
  27 + <el-button type="primary" @click="handleQuery">{{ $t('common.search') }}</el-button>
  28 + <el-button @click="handleReset">{{ $t('common.reset') }}</el-button>
  29 + </el-form-item>
  30 + </el-form>
  31 + </el-card>
  32 + </el-col>
  33 + </el-row>
  34 +
  35 + <el-row :gutter="20" style="margin-top: 20px">
  36 + <el-col :span="24">
  37 + <el-card>
  38 + <div slot="header" class="flex justify-between">
  39 + <span>{{ $t('shops.shopInfo') }}</span>
  40 + <el-button v-if="hasPrivilege('502020082453087940')" type="primary" size="small" style="float: right"
  41 + @click="openAddDialog">
  42 + {{ $t('shops.addShop') }}
  43 + </el-button>
  44 + </div>
  45 +
  46 + <el-table :data="shopsData" border style="width: 100%" v-loading="loading">
  47 + <el-table-column prop="roomId" :label="$t('shops.shopId')" align="center" />
  48 + <el-table-column :label="$t('shops.shopNumber')" align="center">
  49 + <template slot-scope="scope">
  50 + {{ scope.row.floorNum }}-{{ scope.row.roomNum }}
  51 + </template>
  52 + </el-table-column>
  53 + <el-table-column :label="$t('shops.floor')" align="center">
  54 + <template slot-scope="scope">
  55 + {{ scope.row.layer }}{{ $t('shops.layerUnit') }}
  56 + </template>
  57 + </el-table-column>
  58 + <el-table-column :label="$t('shops.owner')" align="center">
  59 + <template slot-scope="scope">
  60 + <router-link v-if="scope.row.ownerName" :to="`/pages/owner/ownerDetail?ownerId=${scope.row.ownerId}`"
  61 + target="_blank">
  62 + {{ scope.row.ownerName }}
  63 + </router-link>
  64 + <span v-else>--</span>
  65 + </template>
  66 + </el-table-column>
  67 + <el-table-column prop="link" :label="$t('shops.contactNumber')" align="center">
  68 + <template slot-scope="scope">
  69 + {{ scope.row.link || '-' }}
  70 + </template>
  71 + </el-table-column>
  72 + <el-table-column :label="$t('shops.builtUpArea')" align="center">
  73 + <template slot-scope="scope">
  74 + {{ scope.row.builtUpArea }}{{ $t('shops.squareMeter') }}
  75 + </template>
  76 + </el-table-column>
  77 + <el-table-column :label="$t('shops.roomArea')" align="center">
  78 + <template slot-scope="scope">
  79 + {{ scope.row.roomArea }}{{ $t('shops.squareMeter') }}
  80 + </template>
  81 + </el-table-column>
  82 + <el-table-column prop="startTime" :label="$t('shops.startTime')" align="center" />
  83 + <el-table-column prop="endTime" :label="$t('shops.endTime')" align="center" />
  84 + <el-table-column prop="roomRent" :label="$t('shops.rent')" align="center" />
  85 + <el-table-column prop="feeCoefficient" :label="$t('shops.feeCoefficient')" align="center" />
  86 + <el-table-column prop="stateName" :label="$t('shops.state')" align="center" />
  87 + <el-table-column v-for="(item, index) in listColumns" :key="index" :label="item" align="center">
  88 + <template slot-scope="scope">
  89 + {{ scope.row.listValues[index] }}
  90 + </template>
  91 + </el-table-column>
  92 + <el-table-column :label="$t('shops.operation')" align="center" fixed="right" width="250">
  93 + <template slot-scope="scope">
  94 + <el-button-group>
  95 + <el-button v-if="hasPrivilege('502020082493857941') && scope.row.state === '2008'" size="mini"
  96 + @click="openRentDialog(scope.row)">
  97 + {{ $t('shops.rentAction') }}
  98 + </el-button>
  99 + <el-button v-if="hasPrivilege('502020082493857941') && scope.row.state === '2008'" size="mini"
  100 + @click="openSellDialog(scope.row)">
  101 + {{ $t('shops.sellAction') }}
  102 + </el-button>
  103 + <el-button v-if="hasPrivilege('502020082493857941') && scope.row.state !== '2008'" size="mini"
  104 + @click="openUnbind(scope.row)">
  105 + {{ $t('shops.unbind') }}
  106 + </el-button>
  107 + <el-button v-if="hasPrivilege('502020082493857941')" size="mini" type="primary"
  108 + @click="openEditDialog(scope.row)">
  109 + {{ $t('shops.edit') }}
  110 + </el-button>
  111 + <el-button v-if="hasPrivilege('502020082417457942')" size="mini" type="danger"
  112 + @click="openDeleteDialog(scope.row)">
  113 + {{ $t('shops.delete') }}
  114 + </el-button>
  115 + </el-button-group>
  116 + </template>
  117 + </el-table-column>
  118 + </el-table>
  119 +
  120 + <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange"
  121 + :current-page="pagination.current" :page-sizes="[10, 20, 30, 50]" :page-size="pagination.size"
  122 + layout="total, sizes, prev, pager, next, jumper" :total="pagination.total" style="margin-top: 20px">
  123 + </el-pagination>
  124 + </el-card>
  125 + </el-col>
  126 + </el-row>
  127 +
  128 + <!-- 子组件 -->
  129 + <add-shops ref="addDialog" @success="loadData"></add-shops>
  130 + <bind-owner-shops ref="bindDialog" @success="loadData"></bind-owner-shops>
  131 + <edit-shops ref="editDialog" @success="loadData"></edit-shops>
  132 + <delete-room ref="deleteDialog" @success="loadData"></delete-room>
  133 + </div>
  134 +</template>
  135 +
  136 +<script>
  137 +import { queryShops } from '@/api/room/shopsApi'
  138 +import AddShops from '@/components/room/addShops'
  139 +import BindOwnerShops from '@/components/room/bindOwnerShops'
  140 +import EditShops from '@/components/room/editShops'
  141 +import DeleteRoom from '@/components/room/deleteRoom'
  142 +
  143 +export default {
  144 + name: 'ShopsList',
  145 + components: {
  146 + AddShops,
  147 + BindOwnerShops,
  148 + EditShops,
  149 + DeleteRoom
  150 + },
  151 + data() {
  152 + return {
  153 + loading: false,
  154 + queryParams: {
  155 + roomId: '',
  156 + roomNum: '',
  157 + state: '',
  158 + roomType: '2020602',
  159 + page: 1,
  160 + row: 10
  161 + },
  162 + shopsData: [],
  163 + listColumns: [],
  164 + pagination: {
  165 + current: 1,
  166 + size: 10,
  167 + total: 0
  168 + }
  169 + }
  170 + },
  171 + created() {
  172 + this.loadData()
  173 + },
  174 + methods: {
  175 + loadData() {
  176 + this.loading = true
  177 + queryShops(this.queryParams)
  178 + .then(res => {
  179 + this.shopsData = res.rooms
  180 + this.pagination.total = res.total
  181 + this.dealShopsAttr(res.rooms)
  182 + })
  183 + .catch(error => {
  184 + console.error(error)
  185 + this.$message.error(this.$t('common.requestError'))
  186 + })
  187 + .finally(() => {
  188 + this.loading = false
  189 + })
  190 + },
  191 + handleQuery() {
  192 + this.queryParams.page = 1
  193 + this.loadData()
  194 + },
  195 + handleReset() {
  196 + this.queryParams = {
  197 + roomId: '',
  198 + roomNum: '',
  199 + state: '',
  200 + roomType: '2020602',
  201 + page: 1,
  202 + row: 10
  203 + }
  204 + this.loadData()
  205 + },
  206 + handleSizeChange(size) {
  207 + this.queryParams.row = size
  208 + this.loadData()
  209 + },
  210 + handleCurrentChange(page) {
  211 + this.queryParams.page = page
  212 + this.loadData()
  213 + },
  214 + openAddDialog() {
  215 + this.$refs.addDialog.open()
  216 + },
  217 + openRentDialog(row) {
  218 + this.$refs.bindDialog.open(row, '2006')
  219 + },
  220 + openSellDialog(row) {
  221 + this.$refs.bindDialog.open(row, '2007')
  222 + },
  223 + openEditDialog(row) {
  224 + this.$refs.editDialog.open(row)
  225 + },
  226 + openDeleteDialog(row) {
  227 + this.$refs.deleteDialog.open(row)
  228 + },
  229 + openUnbind(row) {
  230 + this.$router.push(`/views/owner/deleteOwnerRoom?ownerId=${row.ownerId}`)
  231 + },
  232 + dealShopsAttr(shopss) {
  233 + // 处理商铺属性列
  234 + // this.listColumns = ['Attr1', 'Attr2'] // 实际应从API获取
  235 + shopss.forEach(shop => {
  236 + shop.listValues = [] // 实际应从API获取
  237 + })
  238 + },
  239 + }
  240 +}
  241 +</script>
  242 +
  243 +<style scoped>
  244 +.shops-container {
  245 + padding: 20px;
  246 +}
  247 +
  248 +.clearfix:after {
  249 + content: "";
  250 + display: table;
  251 + clear: both;
  252 +}
  253 +</style>
0 \ No newline at end of file 254 \ No newline at end of file