master
yaoxin 2024-03-06 12:44:42 +08:00
parent 4c18a3f47b
commit fb98814aec
9 changed files with 469 additions and 134 deletions

38
src/api/house.js 100644
View File

@ -0,0 +1,38 @@
import request from '@/utils/request'
export function houseList(data) {
return request({
url: '/house/house/HouseList',
method: 'post',
data
})
}
export function typeList() {
return request({
url: '/house/house/TypeList',
method: 'get'
})
}
export function addRent(data) {
return request({
url: '/house/house/AddRent',
method: 'post',
data
})
}
export function rentList() {
return request({
url: '/house/house/RentList',
method: 'get'
})
}
export function removeRent(rid) {
return request({
url: '/house/house/RemoveRent?rid=' + rid,
method: 'get'
})
}

View File

@ -2,7 +2,7 @@ import request from '@/utils/request'
export function login(data) { export function login(data) {
return request({ return request({
url: '/vue-admin-template/user/login', url: '/auth/auth/Login',
method: 'post', method: 'post',
data data
}) })
@ -10,15 +10,14 @@ export function login(data) {
export function getInfo(token) { export function getInfo(token) {
return request({ return request({
url: '/vue-admin-template/user/info', url: '/auth/auth/info',
method: 'get', method: 'get'
params: { token }
}) })
} }
export function logout() { export function logout() {
return request({ return request({
url: '/vue-admin-template/user/logout', url: '/auth/auth/logout',
method: 'post' method: 'post'
}) })
} }

View File

@ -4,7 +4,7 @@ import 'normalize.css/normalize.css' // A modern alternative to CSS resets
import ElementUI from 'element-ui' import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css' import 'element-ui/lib/theme-chalk/index.css'
import locale from 'element-ui/lib/locale/lang/en' // lang i18n import locale from 'element-ui/lib/locale/lang/zh-CN' // lang i18n
import '@/styles/index.scss' // global css import '@/styles/index.scss' // global css

View File

@ -54,111 +54,123 @@ export const constantRoutes = [
meta: { title: 'Dashboard', icon: 'dashboard' } meta: { title: 'Dashboard', icon: 'dashboard' }
}] }]
}, },
{ {
path: '/example', path: '/house',
component: Layout,
redirect: '/example/table',
name: 'Example',
meta: { title: 'Example', icon: 'el-icon-s-help' },
children: [
{
path: 'table',
name: 'Table',
component: () => import('@/views/table/index'),
meta: { title: 'Table', icon: 'table' }
},
{
path: 'tree',
name: 'Tree',
component: () => import('@/views/tree/index'),
meta: { title: 'Tree', icon: 'tree' }
}
]
},
{
path: '/form',
component: Layout, component: Layout,
children: [ children: [
{ {
path: 'index', path: 'index',
name: 'Form', name: 'House',
component: () => import('@/views/form/index'), component: () => import('@/views/house/index'),
meta: { title: 'Form', icon: 'form' } meta: { title: '房屋管理', icon: 'form' }
} }
] ]
}, },
{ // {
path: '/nested', // path: '/example',
component: Layout, // component: Layout,
redirect: '/nested/menu1', // redirect: '/example/table',
name: 'Nested', // name: 'Example',
meta: { // meta: { title: 'Example', icon: 'el-icon-s-help' },
title: 'Nested', // children: [
icon: 'nested' // {
}, // path: 'table',
children: [ // name: 'Table',
{ // component: () => import('@/views/table/index'),
path: 'menu1', // meta: { title: 'Table', icon: 'table' }
component: () => import('@/views/nested/menu1/index'), // Parent router-view // },
name: 'Menu1', // {
meta: { title: 'Menu1' }, // path: 'tree',
children: [ // name: 'Tree',
{ // component: () => import('@/views/tree/index'),
path: 'menu1-1', // meta: { title: 'Tree', icon: 'tree' }
component: () => import('@/views/nested/menu1/menu1-1'), // }
name: 'Menu1-1', // ]
meta: { title: 'Menu1-1' } // },
}, //
{ // {
path: 'menu1-2', // path: '/form',
component: () => import('@/views/nested/menu1/menu1-2'), // component: Layout,
name: 'Menu1-2', // children: [
meta: { title: 'Menu1-2' }, // {
children: [ // path: 'index',
{ // name: 'Form',
path: 'menu1-2-1', // component: () => import('@/views/form/index'),
component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1'), // meta: { title: 'Form', icon: 'form' }
name: 'Menu1-2-1', // }
meta: { title: 'Menu1-2-1' } // ]
}, // },
{ //
path: 'menu1-2-2', // {
component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2'), // path: '/nested',
name: 'Menu1-2-2', // component: Layout,
meta: { title: 'Menu1-2-2' } // redirect: '/nested/menu1',
} // name: 'Nested',
] // meta: {
}, // title: 'Nested',
{ // icon: 'nested'
path: 'menu1-3', // },
component: () => import('@/views/nested/menu1/menu1-3'), // children: [
name: 'Menu1-3', // {
meta: { title: 'Menu1-3' } // path: 'menu1',
} // component: () => import('@/views/nested/menu1/index'), // Parent router-view
] // name: 'Menu1',
}, // meta: { title: 'Menu1' },
{ // children: [
path: 'menu2', // {
component: () => import('@/views/nested/menu2/index'), // path: 'menu1-1',
name: 'Menu2', // component: () => import('@/views/nested/menu1/menu1-1'),
meta: { title: 'menu2' } // name: 'Menu1-1',
} // meta: { title: 'Menu1-1' }
] // },
}, // {
// path: 'menu1-2',
{ // component: () => import('@/views/nested/menu1/menu1-2'),
path: 'external-link', // name: 'Menu1-2',
component: Layout, // meta: { title: 'Menu1-2' },
children: [ // children: [
{ // {
path: 'https://panjiachen.github.io/vue-element-admin-site/#/', // path: 'menu1-2-1',
meta: { title: 'External Link', icon: 'link' } // component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1'),
} // name: 'Menu1-2-1',
] // meta: { title: 'Menu1-2-1' }
}, // },
// {
// path: 'menu1-2-2',
// component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2'),
// name: 'Menu1-2-2',
// meta: { title: 'Menu1-2-2' }
// }
// ]
// },
// {
// path: 'menu1-3',
// component: () => import('@/views/nested/menu1/menu1-3'),
// name: 'Menu1-3',
// meta: { title: 'Menu1-3' }
// }
// ]
// },
// {
// path: 'menu2',
// component: () => import('@/views/nested/menu2/index'),
// name: 'Menu2',
// meta: { title: 'menu2' }
// }
// ]
// },
//
// {
// path: 'external-link',
// component: Layout,
// children: [
// {
// path: 'https://panjiachen.github.io/vue-element-admin-site/#/',
// meta: { title: 'External Link', icon: 'link' }
// }
// ]
// },
// 404 page must be placed at the end !!! // 404 page must be placed at the end !!!
{ path: '*', redirect: '/404', hidden: true } { path: '*', redirect: '/404', hidden: true }

View File

@ -30,9 +30,9 @@ const mutations = {
const actions = { const actions = {
// user login // user login
login({ commit }, userInfo) { login({ commit }, userInfo) {
const { username, password } = userInfo const { tel, password } = userInfo
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
login({ username: username.trim(), password: password }).then(response => { login({ tel: tel.trim(), password: password }).then(response => {
const { data } = response const { data } = response
commit('SET_TOKEN', data.token) commit('SET_TOKEN', data.token)
setToken(data.token) setToken(data.token)

View File

@ -19,7 +19,7 @@ service.interceptors.request.use(
// let each request carry token // let each request carry token
// ['X-Token'] is a custom headers key // ['X-Token'] is a custom headers key
// please modify it according to the actual situation // please modify it according to the actual situation
config.headers['X-Token'] = getToken() config.headers['token'] = getToken()
} }
return config return config
}, },
@ -46,9 +46,9 @@ service.interceptors.response.use(
const res = response.data const res = response.data
// if the custom code is not 20000, it is judged as an error. // if the custom code is not 20000, it is judged as an error.
if (res.code !== 20000) { if (res.code !== 200) {
Message({ Message({
message: res.message || 'Error', message: res.msg || 'Error',
type: 'error', type: 'error',
duration: 5 * 1000 duration: 5 * 1000
}) })
@ -66,7 +66,7 @@ service.interceptors.response.use(
}) })
}) })
} }
return Promise.reject(new Error(res.message || 'Error')) return Promise.reject(new Error(res.msg || 'Error'))
} else { } else {
return res return res
} }
@ -74,7 +74,7 @@ service.interceptors.response.use(
error => { error => {
console.log('err' + error) // for debug console.log('err' + error) // for debug
Message({ Message({
message: error.message, message: error.msg,
type: 'error', type: 'error',
duration: 5 * 1000 duration: 5 * 1000
}) })

View File

@ -0,0 +1,293 @@
<template>
<div>
<h1>房屋列表</h1>
<el-form :inline="true" :model="houseRequest" class="demo-form-inline">
<el-form-item label="户型">
<el-select v-model="houseRequest.tid" placeholder="请选择户型" clearable>
<el-option v-for="type in typeAttr" :label="type.typeName" :key="type.tid" :value="type.tid"></el-option>
</el-select>
</el-form-item>
<el-form-item label="价格">
<el-input v-model="houseRequest.staPrice" style="width: 80px" clearable></el-input>-
<el-input v-model="houseRequest.endPrice" style="width: 80px" clearable></el-input>
</el-form-item>
<el-form-item label="地铁房">
<el-select v-model="houseRequest.isSubway" placeholder="请选择" clearable>
<el-option label="仅展示地铁房" value="0"></el-option>
<el-option label="全部" value="1"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="houseList"></el-button>
</el-form-item>
</el-form>
<el-button @click="rent"></el-button>
<el-table :data="houseAttr">
<el-table-column label="房屋编号">
<template v-slot="house">
<span>{{ house.row.hid }}</span>
</template>
</el-table-column>
<el-table-column label="户型">
<template v-slot="house">
{{ house.row.typeName }}
</template>
</el-table-column>
<el-table-column label="房屋面积">
<template v-slot="house">
{{ house.row.area }}
</template>
</el-table-column>
<el-table-column label="房屋价格">
<template v-slot="house">
{{ house.row.price }}
</template>
</el-table-column>
<el-table-column label="地铁房">
<template v-slot="house">
<span v-if="house.row.isSubway == 0"></span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="操作">
<template v-slot="house">
<el-button @click="rentHouse(house.row)"></el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="houseRequest.pageNum"
:page-sizes="[3, 5, 7]"
:page-size="houseRequest.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
<!-- 租房弹窗-->
<el-dialog title="租房" :visible.sync="dialogFormVisible">
<el-form :model="houseInfo">
<el-form-item label="房屋编号" :label-width="formLabelWidth">
<el-input v-model="houseInfo.hid" autocomplete="off" readonly></el-input>
</el-form-item>
<el-form-item label="房屋编号" :label-width="formLabelWidth">
<el-input v-model="houseInfo.price" autocomplete="off" readonly></el-input>
</el-form-item>
<el-form-item label="付款方式" :label-width="formLabelWidth">
<el-radio-group v-model="houseInfo.radio">
<el-radio :label="1">季付</el-radio>
<el-radio :label="2">半年付</el-radio>
<el-radio :label="3">年付</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="总计" :label-width="formLabelWidth">
<el-input v-model="houseInfo.amount" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="支付卡" :label-width="formLabelWidth">
<el-select placeholder="请选择银行卡">
<el-option label="请选择银行卡"></el-option>
<el-option label="中国银行"></el-option>
<el-option label="工商银行"></el-option>
</el-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogF"> </el-button>
<el-button type="primary" @click="addRent"> </el-button>
</div>
</el-dialog>
<el-dialog title="我的房屋" :visible.sync="dialogForm" width="1000px">
<el-table :data="rentAttr">
<el-table-column label="房屋编号">
<template v-slot="rent">
{{ rent.row.rid }}
</template>
</el-table-column>
<el-table-column label="户型">
<template v-slot="rent">
{{ rent.row.typeName }}
</template>
</el-table-column>
<el-table-column label="房屋面积">
<template v-slot="rent">
{{ rent.row.area }}
</template>
</el-table-column>
<el-table-column label="房屋价格">
<template v-slot="rent">
{{ rent.row.price }}
</template>
</el-table-column>
<el-table-column label="地铁房">
<template v-slot="rent">
<span v-if="rent.row.isSubway == 0"></span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="入住时间">
<template v-slot="rent">
{{ rent.row.checkTime }}
</template>
</el-table-column>
<el-table-column label="到期时间">
<template v-slot="rent">
{{ rent.row.degroupingTime }}
</template>
</el-table-column>
<el-table-column label="支付金额">
<template v-slot="rent">
{{ rent.row.amount }}
</template>
</el-table-column>
<el-table-column label="操作">
<template v-slot="rent">
<el-button @click="removeHouse(rent.row)">退</el-button>
</template>
</el-table-column>
</el-table>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="dialogForm = false"> </el-button>
</div>
</el-dialog>
<el-dialog title="退租" :visible.sync="dialog">
<el-form :model="removeInfo">
<el-form-item label="入住时间" :label-width="formLabelWidth">
<el-input v-model="removeInfo.checkTime" autocomplete="off" readonly></el-input>
</el-form-item>
<el-form-item label="退租时间" :label-width="formLabelWidth">
<el-input v-model="date" value-format="yyyy-MM-dd" autocomplete="off" readonly></el-input>
</el-form-item>
<el-form-item label="剩余租金" :label-width="formLabelWidth">
<el-input v-model="remaining" autocomplete="off" readonly></el-input>
</el-form-item>
<el-form-item label="违约金" :label-width="formLabelWidth">
<el-input v-model="removeInfo.price" autocomplete="off" readonly></el-input>
</el-form-item>
<el-form-item label="应退金额" :label-width="formLabelWidth">
<el-input v-model="refundPrice" autocomplete="off" readonly></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialog = false"> </el-button>
<el-button type="primary" @click="removeRent"> 退 </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {addRent, houseList, removeRent, rentList, typeList} from '@/api/house'
export default {
watch: {
'houseInfo.radio': {
handler(val) {
if (val === 0) {
this.houseInfo.amount = undefined
}
if (val === 1) {
let sum = parseInt(this.houseInfo.price) * 3 + parseInt(this.houseInfo.price)
this.houseInfo.amount = sum
}
if (val === 2) {
let sum = parseInt(this.houseInfo.price) * 6 + parseInt(this.houseInfo.price)
this.houseInfo.amount = sum
}
if (val === 3) {
let sum = parseInt(this.houseInfo.price) * 12 * 0.95 + parseInt(this.houseInfo.price)
this.houseInfo.amount = sum
}
}
}
},
data() {
return {
houseRequest: {
pageNum: 1,
pageSize: 3
},
houseAttr: [],
total: 0,
typeAttr: [],
dialogFormVisible: false,
houseInfo: {},
formLabelWidth: '120px',
rentAttr: [],
dialogForm: false,
dialog: false,
removeInfo: {},
date: undefined,
refundPrice: undefined,
remaining: undefined
}
},
methods: {
removeRent() {
removeRent(this.removeInfo.rid).then(res => {
this.$message.success('退租成功')
this.removeInfo = {}
this.dialog = false
})
},
removeHouse(row) {
this.dialogForm = false
this.removeInfo = row
this.date = new Date().toISOString().slice(0, 10)
this.remaining = parseInt(this.removeInfo.amount) - parseInt(this.removeInfo.price)
this.refundPrice = parseInt(this.remaining) - parseInt(this.removeInfo.price)
this.dialog = true
},
rent() {
rentList().then(res => {
this.rentAttr = res.data
this.dialogForm = true
})
},
dialogF() {
this.houseInfo.radio = 0
this.dialogFormVisible = false
},
addRent() {
addRent(this.houseInfo).then(res => {
this.$message.success('租房成功')
this.houseInfo.radio = 0
this.dialogFormVisible = false
})
},
rentHouse(row) {
this.houseInfo = row
this.dialogFormVisible = true
},
handleSizeChange(val) {
this.houseRequest.pageSize = val
this.houseList()
},
handleCurrentChange(val) {
this.houseRequest.pageNum = val
this.houseList()
},
houseList() {
houseList(this.houseRequest).then(res => {
console.log(res)
this.houseAttr = res.data.list
this.total = res.data.total
})
},
typeList() {
typeList().then(res => {
this.typeAttr = res.data
})
}
},
created() {
this.houseList()
this.typeList()
}
}
</script>
<style scoped>
</style>

View File

@ -6,15 +6,15 @@
<h3 class="title">Login Form</h3> <h3 class="title">Login Form</h3>
</div> </div>
<el-form-item prop="username"> <el-form-item prop="tel">
<span class="svg-container"> <span class="svg-container">
<svg-icon icon-class="user" /> <svg-icon icon-class="user" />
</span> </span>
<el-input <el-input
ref="username" ref="tel"
v-model="loginForm.username" v-model="loginForm.tel"
placeholder="Username" placeholder="Tel"
name="username" name="tel"
type="text" type="text"
tabindex="1" tabindex="1"
auto-complete="on" auto-complete="on"
@ -53,33 +53,18 @@
</template> </template>
<script> <script>
import { validUsername } from '@/utils/validate'
export default { export default {
name: 'Login', name: 'Login',
data() { data() {
const validateUsername = (rule, value, callback) => {
if (!validUsername(value)) {
callback(new Error('Please enter the correct user name'))
} else {
callback()
}
}
const validatePassword = (rule, value, callback) => {
if (value.length < 6) {
callback(new Error('The password can not be less than 6 digits'))
} else {
callback()
}
}
return { return {
loginForm: { loginForm: {
username: 'admin', tel: '18037613093',
password: '111111' password: ''
}, },
loginRules: { loginRules: {
username: [{ required: true, trigger: 'blur', validator: validateUsername }], tel: [{ required: true, trigger: 'blur' }],
password: [{ required: true, trigger: 'blur', validator: validatePassword }] password: [{ required: true, trigger: 'blur' }]
}, },
loading: false, loading: false,
passwordType: 'password', passwordType: 'password',

View File

@ -36,7 +36,15 @@ module.exports = {
warnings: false, warnings: false,
errors: true errors: true
}, },
before: require('./mock/mock-server.js') proxy: {
[process.env.VUE_APP_BASE_API]: {
target: 'http://127.0.0.1:18080',
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_BASE_API]: ''
}
}
}
}, },
configureWebpack: { configureWebpack: {
// provide the app's title in webpack's name field, so that // provide the app's title in webpack's name field, so that