mirror of
https://gitee.com/java110/MicroCommunityWeb.git
synced 2026-02-24 05:46:03 +08:00
完成物业首页功能
This commit is contained in:
parent
0e3df9ef62
commit
6d9d3e2776
101
src/api/index/propertyIndexApi.js
Normal file
101
src/api/index/propertyIndexApi.js
Normal file
@ -0,0 +1,101 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询物业资产指标
|
||||
export function getPropertyAssetsIndex(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
request({
|
||||
url: '/propertyIndex.queryPropertyAssetsIndex',
|
||||
method: 'get',
|
||||
params
|
||||
}).then(response => {
|
||||
const res = response.data
|
||||
if (res.code === 0) {
|
||||
resolve(res)
|
||||
} else {
|
||||
reject(new Error(res.msg || '查询物业资产指标失败'))
|
||||
}
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 查询记事本列表
|
||||
export function getNotepadList(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
request({
|
||||
url: '/notepad.listNotepad',
|
||||
method: 'get',
|
||||
params
|
||||
}).then(response => {
|
||||
const res = response.data
|
||||
if (res.code === 0) {
|
||||
resolve(res)
|
||||
} else {
|
||||
reject(new Error(res.msg || '查询记事本列表失败'))
|
||||
}
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 查询报修指标
|
||||
export function getRepairIndex(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
request({
|
||||
url: '/propertyIndex.queryRepairIndex',
|
||||
method: 'get',
|
||||
params
|
||||
}).then(response => {
|
||||
const res = response.data
|
||||
if (res.code === 0) {
|
||||
resolve(res)
|
||||
} else {
|
||||
reject(new Error(res.msg || '查询报修指标失败'))
|
||||
}
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 查询投诉指标
|
||||
export function getComplaintIndex(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
request({
|
||||
url: '/propertyIndex.queryComplaintIndex',
|
||||
method: 'get',
|
||||
params
|
||||
}).then(response => {
|
||||
const res = response.data
|
||||
if (res.code === 0) {
|
||||
resolve(res)
|
||||
} else {
|
||||
reject(new Error(res.msg || '查询投诉指标失败'))
|
||||
}
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 查询业主注册指标
|
||||
export function getOwnerRegisterIndex(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
request({
|
||||
url: '/propertyIndex.queryOwnerRegisterIndex',
|
||||
method: 'get',
|
||||
params
|
||||
}).then(response => {
|
||||
const res = response.data
|
||||
if (res.code === 0) {
|
||||
resolve(res)
|
||||
} else {
|
||||
reject(new Error(res.msg || '查询业主注册指标失败'))
|
||||
}
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
92
src/components/index/index-property.vue
Normal file
92
src/components/index/index-property.vue
Normal file
@ -0,0 +1,92 @@
|
||||
<template>
|
||||
<div class="property-index-container">
|
||||
<div class="vc-index-nav">
|
||||
<span><i class="el-icon-s-home margin-right-sm"></i>{{ $t('propertyIndex.home') }}</span>
|
||||
<span class="margin-left-sm margin-right-sm">/</span>
|
||||
<span>{{ $t('propertyIndex.dashboard') }}</span>
|
||||
</div>
|
||||
|
||||
<el-row class="vc-index-1" :gutter="20">
|
||||
<el-col :span="15">
|
||||
<index-community ref="indexCommunity" />
|
||||
</el-col>
|
||||
<el-col :span="9">
|
||||
<index-notice ref="indexNotice" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row class="vc-index-1" :gutter="20">
|
||||
<el-col :span="15">
|
||||
<index-repair-complaint ref="indexRepairComplaint" />
|
||||
</el-col>
|
||||
<el-col :span="9">
|
||||
<index-owner-room ref="indexOwnerRoom" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import IndexCommunity from '@/components/index/indexCommunity'
|
||||
import IndexNotice from '@/components/index/indexNotice'
|
||||
import IndexRepairComplaint from '@/components/index/indexRepairComplaint'
|
||||
import IndexOwnerRoom from '@/components/index/indexOwnerRoom'
|
||||
|
||||
export default {
|
||||
name: 'PropertyIndexList',
|
||||
components: {
|
||||
IndexCommunity,
|
||||
IndexNotice,
|
||||
IndexRepairComplaint,
|
||||
IndexOwnerRoom
|
||||
},
|
||||
mounted() {
|
||||
this.initData()
|
||||
},
|
||||
methods: {
|
||||
initData() {
|
||||
this.$refs.indexCommunity._loadPropertyIndexAssets()
|
||||
this.$refs.indexNotice._loadPropertyIndexNotices()
|
||||
this.$refs.indexRepairComplaint.initData()
|
||||
this.$refs.indexOwnerRoom._loadIndexOwnerRegisterData()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.property-index-container {
|
||||
|
||||
|
||||
.vc-index-nav {
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.margin-right-sm {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.margin-left-sm {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.margin-top-lg {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.margin-bottom {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.vc-index-1 {
|
||||
margin-bottom: 20px;
|
||||
|
||||
.index-1-left,
|
||||
.index-1-right {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
217
src/components/index/indexCommunity.vue
Normal file
217
src/components/index/indexCommunity.vue
Normal file
@ -0,0 +1,217 @@
|
||||
<template>
|
||||
<div class="index-1-left-1">
|
||||
<div class="index-title">
|
||||
<span>{{ $t('propertyIndex.communityInfo') }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between border-bottom index-1-left-1-content">
|
||||
<div v-for="(item, index) in stats" :key="index" class="flex justify-center" >
|
||||
<div class="index-1-left-img">
|
||||
<i :class="item.icon"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="index-number">{{ indexCommunityViewInfo[item.key] }}</div>
|
||||
<div class="index-number-describe">{{ $t(`propertyIndex.${item.label}`) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between index-1-left-1-bottom">
|
||||
<div class="flex justify-between index-1-left-1-bottom-item">
|
||||
<div class="text-center">
|
||||
<div class="index-name">{{ $t('propertyIndex.residentReg') }}</div>
|
||||
<div class="index-name-ico">
|
||||
<i class="el-icon-user"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div class="index-number">{{ indexCommunityViewInfo.ownerCount }}
|
||||
<span class="index-number-unit">{{ $t('propertyIndex.unit') }}</span>
|
||||
</div>
|
||||
<div class="index-number-describe margin-top-sm" @click="_toOwner">
|
||||
{{ $t('propertyIndex.registerResident') }} >
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between index-1-left-1-bottom-item">
|
||||
<div class="text-center">
|
||||
<div class="index-name">{{ $t('propertyIndex.vehicle') }}</div>
|
||||
<div class="index-name-ico">
|
||||
<i class="el-icon-truck"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div class="index-number">{{ indexCommunityViewInfo.carCount }}
|
||||
<span class="index-number-unit">{{ $t('propertyIndex.unit') }}</span>
|
||||
</div>
|
||||
<div class="index-number-describe margin-top-sm" @click="_toCar">
|
||||
{{ $t('propertyIndex.viewVehicle') }} >
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getPropertyAssetsIndex } from '@/api/index/propertyIndexApi'
|
||||
|
||||
export default {
|
||||
name: 'IndexCommunity',
|
||||
data() {
|
||||
return {
|
||||
indexCommunityViewInfo: {
|
||||
floorCount: 0,
|
||||
roomCount: 0,
|
||||
shopCount: 0,
|
||||
ownerCount: 0,
|
||||
spaceCount: 0,
|
||||
carCount: 0,
|
||||
},
|
||||
stats: [
|
||||
{ key: 'floorCount', label: 'building', icon: 'el-icon-office-building' },
|
||||
{ key: 'roomCount', label: 'house', icon: 'el-icon-house' },
|
||||
{ key: 'shopCount', label: 'shop', icon: 'el-icon-shopping-bag-2' },
|
||||
{ key: 'spaceCount', label: 'parkingSpace', icon: 'el-icon-truck' }
|
||||
]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
},
|
||||
methods: {
|
||||
_loadPropertyIndexAssets() {
|
||||
const param = {
|
||||
page: 1,
|
||||
row: 10,
|
||||
communityId: this.getCommunityId()
|
||||
}
|
||||
|
||||
getPropertyAssetsIndex(param)
|
||||
.then(res => {
|
||||
if (res.code === 0) {
|
||||
Object.assign(this.indexCommunityViewInfo, res.data)
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('请求失败处理', err)
|
||||
})
|
||||
},
|
||||
_toOwner() {
|
||||
this.$router.push('/property/listOwner?tab=ownerInfo')
|
||||
},
|
||||
_toCar() {
|
||||
this.$router.push('/property/listOwnerCar?tab=ownerCar')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.index-1-left-1 {
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
padding: 15px;
|
||||
|
||||
.index-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 15px;
|
||||
text-align: left;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.index-1-left-1-content {
|
||||
padding: 50px 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
|
||||
> div {
|
||||
width: 25%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.index-1-left-img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: #f0f7ff;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 10px;
|
||||
|
||||
i {
|
||||
font-size: 20px;
|
||||
color: #409EFF;
|
||||
}
|
||||
}
|
||||
|
||||
.index-number {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.index-number-describe {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.index-1-left-1-bottom {
|
||||
padding: 28px 40px;
|
||||
|
||||
.index-1-left-1-bottom-item {
|
||||
width: 40%;
|
||||
border-radius: 4px;
|
||||
padding: 10px;
|
||||
padding-left:30px;
|
||||
padding-right:30px;
|
||||
|
||||
.index-name {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.index-name-ico {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: #e6f7ff;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 10px auto;
|
||||
|
||||
i {
|
||||
font-size: 20px;
|
||||
color: #1890ff;
|
||||
}
|
||||
}
|
||||
|
||||
.index-number {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
|
||||
.index-number-unit {
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.index-number-describe {
|
||||
font-size: 12px;
|
||||
color: #1890ff;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.margin-top-sm {
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
174
src/components/index/indexNotice.vue
Normal file
174
src/components/index/indexNotice.vue
Normal file
@ -0,0 +1,174 @@
|
||||
<template>
|
||||
<div class="index-1-right-1">
|
||||
<div class="index-title text-left">
|
||||
<span>{{ $t('propertyIndex.ownerFeedback') }}</span>
|
||||
</div>
|
||||
<ul id="pool" class="notice-list">
|
||||
<li v-if="!indexNoticeInfo.notices || indexNoticeInfo.notices.length < 1"
|
||||
class="flex justify-between padding-top-sm no-data">
|
||||
<div class="vc-index-notice-title">
|
||||
{{ $t('propertyIndex.noFeedback') }}
|
||||
</div>
|
||||
</li>
|
||||
<li v-else v-for="(item, index) in indexNoticeInfo.notices" :key="index"
|
||||
class="flex justify-between padding-top-sm notice-item">
|
||||
<div class="vc-index-notice-title">
|
||||
{{ item.objName }}({{ item.roomName }}){{ $t('propertyIndex.feedback') }}{{ item.title }}
|
||||
({{ item.state === 'F' ? $t('propertyIndex.completed') : $t('propertyIndex.followingUp') }}<span v-if="item.thridId">-{{ $t('propertyIndex.transferRepair') }}</span>)
|
||||
</div>
|
||||
<div class="vc-index-notice-time">
|
||||
{{ item.createTime }}
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getNotepadList } from '@/api/index/propertyIndexApi'
|
||||
|
||||
export default {
|
||||
name: 'IndexNotice',
|
||||
data() {
|
||||
return {
|
||||
indexNoticeInfo: {
|
||||
notices: [],
|
||||
scrollInterval: null,
|
||||
scrollTopValue: 0,
|
||||
scrollDirection: true,
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
window.addEventListener('resize', this.checkPoolScroll)
|
||||
})
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.indexNoticeInfo.scrollInterval) {
|
||||
clearInterval(this.indexNoticeInfo.scrollInterval)
|
||||
}
|
||||
window.removeEventListener('resize', this.checkPoolScroll)
|
||||
},
|
||||
methods: {
|
||||
async _loadPropertyIndexNotices() {
|
||||
const param = {
|
||||
page: 1,
|
||||
row: 10,
|
||||
communityId: this.getCommunityId()
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await getNotepadList(param)
|
||||
this.indexNoticeInfo.notices = res.data
|
||||
this.$nextTick(() => {
|
||||
this.checkPoolScroll()
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('请求失败处理', error)
|
||||
}
|
||||
},
|
||||
checkPoolScroll() {
|
||||
const element = document.getElementById('pool')
|
||||
if (!element) return
|
||||
|
||||
const clientHeight = element.clientHeight
|
||||
const scrollHeight = element.scrollHeight
|
||||
|
||||
if (scrollHeight > clientHeight) {
|
||||
if (!this.indexNoticeInfo.scrollInterval) {
|
||||
this.indexNoticeInfo.scrollInterval = setInterval(this.poolScroll, 5000)
|
||||
}
|
||||
} else {
|
||||
clearInterval(this.indexNoticeInfo.scrollInterval)
|
||||
this.indexNoticeInfo.scrollInterval = null
|
||||
}
|
||||
},
|
||||
poolScroll() {
|
||||
const element = document.getElementById('pool')
|
||||
if (!element) return
|
||||
|
||||
const clientHeight = element.clientHeight
|
||||
const scrollHeight = element.scrollHeight
|
||||
const canScrollHeight = scrollHeight - clientHeight
|
||||
|
||||
if (this.indexNoticeInfo.scrollTopValue <= 0) {
|
||||
this.indexNoticeInfo.scrollDirection = true
|
||||
}
|
||||
|
||||
if (this.indexNoticeInfo.scrollDirection) {
|
||||
this.indexNoticeInfo.scrollTopValue += canScrollHeight / 1200
|
||||
} else {
|
||||
this.indexNoticeInfo.scrollTopValue -= canScrollHeight / 1200
|
||||
}
|
||||
|
||||
if (canScrollHeight <= this.indexNoticeInfo.scrollTopValue) {
|
||||
this.indexNoticeInfo.scrollDirection = !this.indexNoticeInfo.scrollDirection
|
||||
}
|
||||
|
||||
element.scrollTop = this.indexNoticeInfo.scrollTopValue
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.index-1-right-1 {
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
padding: 15px;
|
||||
height: 100%;
|
||||
|
||||
.index-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 15px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.notice-list {
|
||||
height: 300px;
|
||||
overflow-y: auto;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
|
||||
.no-data {
|
||||
color: #999;
|
||||
text-align: center;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.notice-item {
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.vc-index-notice-title {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
width: 70%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.vc-index-notice-time {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
width: 30%;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.padding-top-sm {
|
||||
padding-top: 5px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
179
src/components/index/indexOwnerRoom.vue
Normal file
179
src/components/index/indexOwnerRoom.vue
Normal file
@ -0,0 +1,179 @@
|
||||
<template>
|
||||
<div class="owner-room-container">
|
||||
<div class="bg-white index-1-right-item">
|
||||
<div class="index-title"><span>{{ $t('propertyIndex.residentRegStats') }}</span></div>
|
||||
<div id="ownerRoomCount" style="height:250px"></div>
|
||||
<div class="flex justify-between text-center stats-container">
|
||||
<div v-for="(item, index) in stats" :key="index">
|
||||
<div class="index-bottom-number">{{ item.value }}</div>
|
||||
<div class="index-bottom-number-desc">{{ $t(`propertyIndex.${item.label}`) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from 'echarts'
|
||||
import { getOwnerRegisterIndex } from '@/api/index/propertyIndexApi'
|
||||
|
||||
export default {
|
||||
name: 'IndexOwnerRoom',
|
||||
data() {
|
||||
return {
|
||||
indexOwnerRoomInfo: {
|
||||
unbindCount: 0,
|
||||
bindCount: 0,
|
||||
unbindRoomCount: 0,
|
||||
bindRoomCount: 0,
|
||||
},
|
||||
ownerRoomChart: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
stats() {
|
||||
return [
|
||||
{ label: 'unregistered', value: this.indexOwnerRoomInfo.unbindCount },
|
||||
{ label: 'registered', value: this.indexOwnerRoomInfo.bindCount },
|
||||
{ label: 'unboundRoom', value: this.indexOwnerRoomInfo.unbindRoomCount },
|
||||
{ label: 'boundRoom', value: this.indexOwnerRoomInfo.bindRoomCount }
|
||||
]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
},
|
||||
mounted() {
|
||||
window.addEventListener('resize', this.handleResize)
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', this.handleResize)
|
||||
if (this.ownerRoomChart) {
|
||||
this.ownerRoomChart.dispose()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleResize() {
|
||||
if (this.ownerRoomChart) {
|
||||
this.ownerRoomChart.resize()
|
||||
}
|
||||
},
|
||||
async _loadIndexOwnerRegisterData() {
|
||||
const param = {
|
||||
page: 1,
|
||||
row: 10,
|
||||
communityId: this.getCommunityId()
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await getOwnerRegisterIndex(param)
|
||||
Object.assign(this.indexOwnerRoomInfo, res.data)
|
||||
|
||||
this.$nextTick(() => {
|
||||
const dom = document.getElementById('ownerRoomCount')
|
||||
if (!dom) return
|
||||
|
||||
if (this.ownerRoomChart) {
|
||||
this.ownerRoomChart.dispose()
|
||||
}
|
||||
this.ownerRoomChart = echarts.init(dom)
|
||||
this._initOwnerEcharts(
|
||||
this.ownerRoomChart,
|
||||
this.indexOwnerRoomInfo.bindCount,
|
||||
this.indexOwnerRoomInfo.unbindCount,
|
||||
this.$t('propertyIndex.residentInfo'),
|
||||
this.$t('propertyIndex.registered'),
|
||||
this.$t('propertyIndex.unregistered'),
|
||||
'#4B7AF0',
|
||||
'#E2EDF6'
|
||||
)
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('请求失败处理', error)
|
||||
}
|
||||
},
|
||||
_initOwnerEcharts(chart, userCount, freeCount, _title, _userCountName, _freeCountName, userColor, freeColor) {
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b}: {c} ({d}%)'
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
right: 10,
|
||||
top: 'center',
|
||||
textStyle: {
|
||||
color: '#606266'
|
||||
},
|
||||
data: [_userCountName, _freeCountName]
|
||||
},
|
||||
color: [userColor, freeColor],
|
||||
series: [{
|
||||
name: _title,
|
||||
type: 'pie',
|
||||
radius: ['40%', '65%'],
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
show: false,
|
||||
position: 'center'
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: true,
|
||||
fontSize: '16',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
},
|
||||
labelLine: {
|
||||
show: false
|
||||
},
|
||||
data: [
|
||||
{ value: userCount, name: _userCountName },
|
||||
{ value: freeCount, name: _freeCountName }
|
||||
]
|
||||
}]
|
||||
}
|
||||
|
||||
chart.setOption(option)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.owner-room-container {
|
||||
.index-1-right-item {
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
padding: 15px;
|
||||
height: 100%;
|
||||
|
||||
.index-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 15px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.stats-container {
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #eee;
|
||||
|
||||
> div {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.index-bottom-number {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.index-bottom-number-desc {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
253
src/components/index/indexRepairComplaint.vue
Normal file
253
src/components/index/indexRepairComplaint.vue
Normal file
@ -0,0 +1,253 @@
|
||||
<template>
|
||||
<div class="repair-complaint-container">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<div class="bg-white index-1-left-item">
|
||||
<div class="index-title"><span>{{ $t('propertyIndex.repairStats') }}</span></div>
|
||||
<div id="repairCount" style="height:250px"></div>
|
||||
<div class="flex justify-between text-center stats-container">
|
||||
<div v-for="(item, index) in repairStats" :key="index">
|
||||
<div class="index-bottom-number">{{ item.value }}</div>
|
||||
<div class="index-bottom-number-desc">{{ $t(`propertyIndex.${item.label}`) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="bg-white index-1-left-item">
|
||||
<div class="index-title"><span>{{ $t('propertyIndex.complaintStats') }}</span></div>
|
||||
<div id="complaintCount" style="height:250px"></div>
|
||||
<div class="flex justify-around text-center stats-container">
|
||||
<div v-for="(item, index) in complaintStats" :key="index">
|
||||
<div class="index-bottom-number">{{ item.value }}</div>
|
||||
<div class="index-bottom-number-desc">{{ $t(`propertyIndex.${item.label}`) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from 'echarts'
|
||||
import { getRepairIndex, getComplaintIndex } from '@/api/index/propertyIndexApi'
|
||||
|
||||
export default {
|
||||
name: 'IndexRepairComplaint',
|
||||
data() {
|
||||
return {
|
||||
indexRepairComplaintInfo: {
|
||||
allCount: 0,
|
||||
waitCount: 0,
|
||||
doingCount: 0,
|
||||
finishCount: 0,
|
||||
allComplaintCount: 0,
|
||||
waitComplaintCount: 0,
|
||||
finishComplaintCount: 0,
|
||||
},
|
||||
repairChart: null,
|
||||
complaintChart: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
repairStats() {
|
||||
return [
|
||||
{ label: 'allRepair', value: this.indexRepairComplaintInfo.allCount },
|
||||
{ label: 'toBeDispatched', value: this.indexRepairComplaintInfo.waitCount },
|
||||
{ label: 'processing', value: this.indexRepairComplaintInfo.doingCount },
|
||||
{ label: 'processed', value: this.indexRepairComplaintInfo.finishCount }
|
||||
]
|
||||
},
|
||||
complaintStats() {
|
||||
return [
|
||||
{ label: 'allComplaint', value: this.indexRepairComplaintInfo.allComplaintCount },
|
||||
{ label: 'processing', value: this.indexRepairComplaintInfo.waitComplaintCount },
|
||||
{ label: 'processed', value: this.indexRepairComplaintInfo.finishComplaintCount }
|
||||
]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
},
|
||||
mounted() {
|
||||
window.addEventListener('resize', this.handleResize)
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', this.handleResize)
|
||||
if (this.repairChart) {
|
||||
this.repairChart.dispose()
|
||||
}
|
||||
if (this.complaintChart) {
|
||||
this.complaintChart.dispose()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initData() {
|
||||
this._loadIndexRepairData()
|
||||
this._loadIndexComplaintData()
|
||||
},
|
||||
handleResize() {
|
||||
if (this.repairChart) {
|
||||
this.repairChart.resize()
|
||||
}
|
||||
if (this.complaintChart) {
|
||||
this.complaintChart.resize()
|
||||
}
|
||||
},
|
||||
async _loadIndexRepairData() {
|
||||
const param = {
|
||||
page: 1,
|
||||
row: 10,
|
||||
communityId: this.getCommunityId()
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await getRepairIndex(param)
|
||||
Object.assign(this.indexRepairComplaintInfo, res.data)
|
||||
|
||||
this.$nextTick(() => {
|
||||
const dom = document.getElementById('repairCount')
|
||||
if (!dom) return
|
||||
|
||||
if (this.repairChart) {
|
||||
this.repairChart.dispose()
|
||||
}
|
||||
this.repairChart = echarts.init(dom)
|
||||
this._initEcharts(
|
||||
this.repairChart,
|
||||
this.indexRepairComplaintInfo.finishCount,
|
||||
this.indexRepairComplaintInfo.allCount - this.indexRepairComplaintInfo.finishCount,
|
||||
this.$t('propertyIndex.repairInfo'),
|
||||
this.$t('propertyIndex.processed'),
|
||||
this.$t('propertyIndex.unprocessed'),
|
||||
'#4B7AF0',
|
||||
'#E2EDF6'
|
||||
)
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('请求失败处理', error)
|
||||
}
|
||||
},
|
||||
async _loadIndexComplaintData() {
|
||||
const param = {
|
||||
page: 1,
|
||||
row: 10,
|
||||
communityId: this.getCommunityId()
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await getComplaintIndex(param)
|
||||
Object.assign(this.indexRepairComplaintInfo, res.data)
|
||||
|
||||
this.$nextTick(() => {
|
||||
const dom = document.getElementById('complaintCount')
|
||||
if (!dom) return
|
||||
|
||||
if (this.complaintChart) {
|
||||
this.complaintChart.dispose()
|
||||
}
|
||||
this.complaintChart = echarts.init(dom)
|
||||
this._initEcharts(
|
||||
this.complaintChart,
|
||||
this.indexRepairComplaintInfo.finishComplaintCount,
|
||||
this.indexRepairComplaintInfo.allComplaintCount - this.indexRepairComplaintInfo.finishComplaintCount,
|
||||
this.$t('propertyIndex.complaintStats'),
|
||||
this.$t('propertyIndex.processed'),
|
||||
this.$t('propertyIndex.unprocessed'),
|
||||
'#01C36D',
|
||||
'#E2EDF6'
|
||||
)
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('请求失败处理', error)
|
||||
}
|
||||
},
|
||||
_initEcharts(chart, userCount, freeCount, _title, _userCountName, _freeCountName, userColor, freeColor) {
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b}: {c} ({d}%)'
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
right: 10,
|
||||
top: 'center',
|
||||
textStyle: {
|
||||
color: '#606266'
|
||||
},
|
||||
data: [_userCountName, _freeCountName]
|
||||
},
|
||||
color: [userColor, freeColor],
|
||||
series: [{
|
||||
name: _title,
|
||||
type: 'pie',
|
||||
radius: ['40%', '65%'],
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
show: false,
|
||||
position: 'center'
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: true,
|
||||
fontSize: '16',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
},
|
||||
labelLine: {
|
||||
show: false
|
||||
},
|
||||
data: [
|
||||
{ value: userCount, name: _userCountName },
|
||||
{ value: freeCount, name: _freeCountName }
|
||||
]
|
||||
}]
|
||||
}
|
||||
|
||||
chart.setOption(option)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.repair-complaint-container {
|
||||
|
||||
}
|
||||
|
||||
.index-1-left-item {
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
padding: 15px;
|
||||
|
||||
.index-title {
|
||||
text-align: left;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 15px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.stats-container {
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #eee;
|
||||
|
||||
>div {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.index-bottom-number {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.index-bottom-number-desc {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -7,6 +7,9 @@
|
||||
<div v-if="storeInfo.storeTypeCd == '800900000001'">
|
||||
<index-admin></index-admin>
|
||||
</div>
|
||||
<div v-if="storeInfo.storeTypeCd == '800900000003'">
|
||||
<index-property></index-property>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -15,12 +18,14 @@
|
||||
import {deepCopy} from "@/utils/vc"
|
||||
import indexDev from "@/components/index/index-dev.vue"
|
||||
import indexAdmin from "@/components/index/index-admin.vue"
|
||||
import indexProperty from '@/components/index/index-property.vue'
|
||||
|
||||
export default {
|
||||
name: 'index',
|
||||
components: {
|
||||
indexDev,
|
||||
indexAdmin
|
||||
indexAdmin,
|
||||
indexProperty
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
@ -8,6 +8,41 @@ export const messages = {
|
||||
repairCount: 'Repair Count',
|
||||
communityFeeStats: 'Community Fee Statistics',
|
||||
communityRepairStats: 'Community Repair Statistics'
|
||||
},
|
||||
propertyIndex: {
|
||||
home: 'Home',
|
||||
dashboard: 'Dashboard',
|
||||
communityInfo: 'Community Information',
|
||||
building: 'Building',
|
||||
house: 'House',
|
||||
shop: 'Shop',
|
||||
parkingSpace: 'Parking Space',
|
||||
residentReg: 'Resident Registration',
|
||||
registerResident: 'Register Resident',
|
||||
vehicle: 'Vehicle',
|
||||
viewVehicle: 'View Vehicles',
|
||||
unit: 'unit',
|
||||
ownerFeedback: 'Owner Feedback',
|
||||
noFeedback: 'No feedback content currently',
|
||||
feedback: 'feedback',
|
||||
completed: 'Completed',
|
||||
followingUp: 'Following up',
|
||||
transferRepair: 'Transferred to repair order',
|
||||
repairStats: 'Repair Statistics',
|
||||
allRepair: 'All Repairs',
|
||||
toBeDispatched: 'To be dispatched',
|
||||
processing: 'Processing',
|
||||
processed: 'Processed',
|
||||
complaintStats: 'Complaint Statistics',
|
||||
allComplaint: 'All Complaints',
|
||||
repairInfo: 'Repair Info',
|
||||
unprocessed: 'Unprocessed',
|
||||
residentRegStats: 'Resident Registration Statistics',
|
||||
unregistered: 'Unregistered',
|
||||
registered: 'Registered',
|
||||
unboundRoom: 'Unbound Room',
|
||||
boundRoom: 'Bound Room',
|
||||
residentInfo: 'Resident Info'
|
||||
}
|
||||
},
|
||||
zh: {
|
||||
@ -19,6 +54,41 @@ export const messages = {
|
||||
repairCount: '报修单数',
|
||||
communityFeeStats: '小区缴费统计',
|
||||
communityRepairStats: '小区报修统计'
|
||||
},
|
||||
propertyIndex: {
|
||||
home: '首页',
|
||||
dashboard: '控制台',
|
||||
communityInfo: '小区信息',
|
||||
building: '楼宇',
|
||||
house: '房屋',
|
||||
shop: '商铺',
|
||||
parkingSpace: '车位',
|
||||
residentReg: '住户登记',
|
||||
registerResident: '登记住户',
|
||||
vehicle: '车辆',
|
||||
viewVehicle: '查看车辆',
|
||||
unit: '个',
|
||||
ownerFeedback: '业主反馈',
|
||||
noFeedback: '当前没有业主反馈内容',
|
||||
feedback: '反馈',
|
||||
completed: '完成',
|
||||
followingUp: '跟进中',
|
||||
transferRepair: '已转报修单',
|
||||
repairStats: '报修统计',
|
||||
allRepair: '全部报修',
|
||||
toBeDispatched: '待派单',
|
||||
processing: '处理中',
|
||||
processed: '已处理',
|
||||
complaintStats: '投诉统计',
|
||||
allComplaint: '全部投诉',
|
||||
repairInfo: '报修信息',
|
||||
unprocessed: '未处理',
|
||||
residentRegStats: '住户注册统计',
|
||||
unregistered: '未注册',
|
||||
registered: '已注册',
|
||||
unboundRoom: '未绑定房屋',
|
||||
boundRoom: '已绑定房屋',
|
||||
residentInfo: '住户信息'
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user