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) {
return request({
url: '/vue-admin-template/user/login',
url: '/auth/auth/Login',
method: 'post',
data
})
@ -10,15 +10,14 @@ export function login(data) {
export function getInfo(token) {
return request({
url: '/vue-admin-template/user/info',
method: 'get',
params: { token }
url: '/auth/auth/info',
method: 'get'
})
}
export function logout() {
return request({
url: '/vue-admin-template/user/logout',
url: '/auth/auth/logout',
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 '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

View File

@ -54,111 +54,123 @@ export const constantRoutes = [
meta: { title: 'Dashboard', icon: 'dashboard' }
}]
},
{
path: '/example',
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',
path: '/house',
component: Layout,
children: [
{
path: 'index',
name: 'Form',
component: () => import('@/views/form/index'),
meta: { title: 'Form', icon: 'form' }
name: 'House',
component: () => import('@/views/house/index'),
meta: { title: '房屋管理', icon: 'form' }
}
]
},
{
path: '/nested',
component: Layout,
redirect: '/nested/menu1',
name: 'Nested',
meta: {
title: 'Nested',
icon: 'nested'
},
children: [
{
path: 'menu1',
component: () => import('@/views/nested/menu1/index'), // Parent router-view
name: 'Menu1',
meta: { title: 'Menu1' },
children: [
{
path: 'menu1-1',
component: () => import('@/views/nested/menu1/menu1-1'),
name: 'Menu1-1',
meta: { title: 'Menu1-1' }
},
{
path: 'menu1-2',
component: () => import('@/views/nested/menu1/menu1-2'),
name: 'Menu1-2',
meta: { title: 'Menu1-2' },
children: [
{
path: 'menu1-2-1',
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' }
}
]
},
// {
// path: '/example',
// 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,
// children: [
// {
// path: 'index',
// name: 'Form',
// component: () => import('@/views/form/index'),
// meta: { title: 'Form', icon: 'form' }
// }
// ]
// },
//
// {
// path: '/nested',
// component: Layout,
// redirect: '/nested/menu1',
// name: 'Nested',
// meta: {
// title: 'Nested',
// icon: 'nested'
// },
// children: [
// {
// path: 'menu1',
// component: () => import('@/views/nested/menu1/index'), // Parent router-view
// name: 'Menu1',
// meta: { title: 'Menu1' },
// children: [
// {
// path: 'menu1-1',
// component: () => import('@/views/nested/menu1/menu1-1'),
// name: 'Menu1-1',
// meta: { title: 'Menu1-1' }
// },
// {
// path: 'menu1-2',
// component: () => import('@/views/nested/menu1/menu1-2'),
// name: 'Menu1-2',
// meta: { title: 'Menu1-2' },
// children: [
// {
// path: 'menu1-2-1',
// 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 !!!
{ path: '*', redirect: '/404', hidden: true }

View File

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

View File

@ -19,7 +19,7 @@ service.interceptors.request.use(
// let each request carry token
// ['X-Token'] is a custom headers key
// please modify it according to the actual situation
config.headers['X-Token'] = getToken()
config.headers['token'] = getToken()
}
return config
},
@ -46,9 +46,9 @@ service.interceptors.response.use(
const res = response.data
// if the custom code is not 20000, it is judged as an error.
if (res.code !== 20000) {
if (res.code !== 200) {
Message({
message: res.message || 'Error',
message: res.msg || 'Error',
type: 'error',
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 {
return res
}
@ -74,7 +74,7 @@ service.interceptors.response.use(
error => {
console.log('err' + error) // for debug
Message({
message: error.message,
message: error.msg,
type: 'error',
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>
</div>
<el-form-item prop="username">
<el-form-item prop="tel">
<span class="svg-container">
<svg-icon icon-class="user" />
</span>
<el-input
ref="username"
v-model="loginForm.username"
placeholder="Username"
name="username"
ref="tel"
v-model="loginForm.tel"
placeholder="Tel"
name="tel"
type="text"
tabindex="1"
auto-complete="on"
@ -53,33 +53,18 @@
</template>
<script>
import { validUsername } from '@/utils/validate'
export default {
name: 'Login',
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 {
loginForm: {
username: 'admin',
password: '111111'
tel: '18037613093',
password: ''
},
loginRules: {
username: [{ required: true, trigger: 'blur', validator: validateUsername }],
password: [{ required: true, trigger: 'blur', validator: validatePassword }]
tel: [{ required: true, trigger: 'blur' }],
password: [{ required: true, trigger: 'blur' }]
},
loading: false,
passwordType: 'password',

View File

@ -36,7 +36,15 @@ module.exports = {
warnings: false,
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: {
// provide the app's title in webpack's name field, so that