Commit 6d9d3e277658eacd7b61e339652c8f4e6ce513da

Authored by wuxw
1 parent 0e3df9ef

完成物业首页功能

src/api/index/propertyIndexApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 查询物业资产指标
  4 +export function getPropertyAssetsIndex(params) {
  5 + return new Promise((resolve, reject) => {
  6 + request({
  7 + url: '/propertyIndex.queryPropertyAssetsIndex',
  8 + method: 'get',
  9 + params
  10 + }).then(response => {
  11 + const res = response.data
  12 + if (res.code === 0) {
  13 + resolve(res)
  14 + } else {
  15 + reject(new Error(res.msg || '查询物业资产指标失败'))
  16 + }
  17 + }).catch(error => {
  18 + reject(error)
  19 + })
  20 + })
  21 +}
  22 +
  23 +// 查询记事本列表
  24 +export function getNotepadList(params) {
  25 + return new Promise((resolve, reject) => {
  26 + request({
  27 + url: '/notepad.listNotepad',
  28 + method: 'get',
  29 + params
  30 + }).then(response => {
  31 + const res = response.data
  32 + if (res.code === 0) {
  33 + resolve(res)
  34 + } else {
  35 + reject(new Error(res.msg || '查询记事本列表失败'))
  36 + }
  37 + }).catch(error => {
  38 + reject(error)
  39 + })
  40 + })
  41 +}
  42 +
  43 +// 查询报修指标
  44 +export function getRepairIndex(params) {
  45 + return new Promise((resolve, reject) => {
  46 + request({
  47 + url: '/propertyIndex.queryRepairIndex',
  48 + method: 'get',
  49 + params
  50 + }).then(response => {
  51 + const res = response.data
  52 + if (res.code === 0) {
  53 + resolve(res)
  54 + } else {
  55 + reject(new Error(res.msg || '查询报修指标失败'))
  56 + }
  57 + }).catch(error => {
  58 + reject(error)
  59 + })
  60 + })
  61 +}
  62 +
  63 +// 查询投诉指标
  64 +export function getComplaintIndex(params) {
  65 + return new Promise((resolve, reject) => {
  66 + request({
  67 + url: '/propertyIndex.queryComplaintIndex',
  68 + method: 'get',
  69 + params
  70 + }).then(response => {
  71 + const res = response.data
  72 + if (res.code === 0) {
  73 + resolve(res)
  74 + } else {
  75 + reject(new Error(res.msg || '查询投诉指标失败'))
  76 + }
  77 + }).catch(error => {
  78 + reject(error)
  79 + })
  80 + })
  81 +}
  82 +
  83 +// 查询业主注册指标
  84 +export function getOwnerRegisterIndex(params) {
  85 + return new Promise((resolve, reject) => {
  86 + request({
  87 + url: '/propertyIndex.queryOwnerRegisterIndex',
  88 + method: 'get',
  89 + params
  90 + }).then(response => {
  91 + const res = response.data
  92 + if (res.code === 0) {
  93 + resolve(res)
  94 + } else {
  95 + reject(new Error(res.msg || '查询业主注册指标失败'))
  96 + }
  97 + }).catch(error => {
  98 + reject(error)
  99 + })
  100 + })
  101 +}
0 102 \ No newline at end of file
... ...
src/components/index/index-property.vue 0 → 100644
  1 +<template>
  2 + <div class="property-index-container">
  3 + <div class="vc-index-nav">
  4 + <span><i class="el-icon-s-home margin-right-sm"></i>{{ $t('propertyIndex.home') }}</span>
  5 + <span class="margin-left-sm margin-right-sm">/</span>
  6 + <span>{{ $t('propertyIndex.dashboard') }}</span>
  7 + </div>
  8 +
  9 + <el-row class="vc-index-1" :gutter="20">
  10 + <el-col :span="15">
  11 + <index-community ref="indexCommunity" />
  12 + </el-col>
  13 + <el-col :span="9">
  14 + <index-notice ref="indexNotice" />
  15 + </el-col>
  16 + </el-row>
  17 +
  18 + <el-row class="vc-index-1" :gutter="20">
  19 + <el-col :span="15">
  20 + <index-repair-complaint ref="indexRepairComplaint" />
  21 + </el-col>
  22 + <el-col :span="9">
  23 + <index-owner-room ref="indexOwnerRoom" />
  24 + </el-col>
  25 + </el-row>
  26 + </div>
  27 +</template>
  28 +
  29 +<script>
  30 +import IndexCommunity from '@/components/index/indexCommunity'
  31 +import IndexNotice from '@/components/index/indexNotice'
  32 +import IndexRepairComplaint from '@/components/index/indexRepairComplaint'
  33 +import IndexOwnerRoom from '@/components/index/indexOwnerRoom'
  34 +
  35 +export default {
  36 + name: 'PropertyIndexList',
  37 + components: {
  38 + IndexCommunity,
  39 + IndexNotice,
  40 + IndexRepairComplaint,
  41 + IndexOwnerRoom
  42 + },
  43 + mounted() {
  44 + this.initData()
  45 + },
  46 + methods: {
  47 + initData() {
  48 + this.$refs.indexCommunity._loadPropertyIndexAssets()
  49 + this.$refs.indexNotice._loadPropertyIndexNotices()
  50 + this.$refs.indexRepairComplaint.initData()
  51 + this.$refs.indexOwnerRoom._loadIndexOwnerRegisterData()
  52 + }
  53 + }
  54 +}
  55 +</script>
  56 +
  57 +<style lang="scss" scoped>
  58 +.property-index-container {
  59 +
  60 +
  61 + .vc-index-nav {
  62 + padding: 10px;
  63 + font-size: 16px;
  64 + text-align: left;
  65 + }
  66 +
  67 + .margin-right-sm {
  68 + margin-right: 5px;
  69 + }
  70 +
  71 + .margin-left-sm {
  72 + margin-left: 5px;
  73 + }
  74 +
  75 + .margin-top-lg {
  76 + margin-top: 15px;
  77 + }
  78 +
  79 + .margin-bottom {
  80 + margin-bottom: 20px;
  81 + }
  82 +
  83 + .vc-index-1 {
  84 + margin-bottom: 20px;
  85 +
  86 + .index-1-left,
  87 + .index-1-right {
  88 + height: 100%;
  89 + }
  90 + }
  91 +}
  92 +</style>
0 93 \ No newline at end of file
... ...
src/components/index/indexCommunity.vue 0 → 100644
  1 +<template>
  2 + <div class="index-1-left-1">
  3 + <div class="index-title">
  4 + <span>{{ $t('propertyIndex.communityInfo') }}</span>
  5 + </div>
  6 + <div class="flex justify-between border-bottom index-1-left-1-content">
  7 + <div v-for="(item, index) in stats" :key="index" class="flex justify-center" >
  8 + <div class="index-1-left-img">
  9 + <i :class="item.icon"></i>
  10 + </div>
  11 + <div>
  12 + <div class="index-number">{{ indexCommunityViewInfo[item.key] }}</div>
  13 + <div class="index-number-describe">{{ $t(`propertyIndex.${item.label}`) }}</div>
  14 + </div>
  15 + </div>
  16 + </div>
  17 + <div class="flex justify-between index-1-left-1-bottom">
  18 + <div class="flex justify-between index-1-left-1-bottom-item">
  19 + <div class="text-center">
  20 + <div class="index-name">{{ $t('propertyIndex.residentReg') }}</div>
  21 + <div class="index-name-ico">
  22 + <i class="el-icon-user"></i>
  23 + </div>
  24 + </div>
  25 + <div class="text-center">
  26 + <div class="index-number">{{ indexCommunityViewInfo.ownerCount }}
  27 + <span class="index-number-unit">{{ $t('propertyIndex.unit') }}</span>
  28 + </div>
  29 + <div class="index-number-describe margin-top-sm" @click="_toOwner">
  30 + {{ $t('propertyIndex.registerResident') }} >
  31 + </div>
  32 + </div>
  33 + </div>
  34 + <div class="flex justify-between index-1-left-1-bottom-item">
  35 + <div class="text-center">
  36 + <div class="index-name">{{ $t('propertyIndex.vehicle') }}</div>
  37 + <div class="index-name-ico">
  38 + <i class="el-icon-truck"></i>
  39 + </div>
  40 + </div>
  41 + <div class="text-center">
  42 + <div class="index-number">{{ indexCommunityViewInfo.carCount }}
  43 + <span class="index-number-unit">{{ $t('propertyIndex.unit') }}</span>
  44 + </div>
  45 + <div class="index-number-describe margin-top-sm" @click="_toCar">
  46 + {{ $t('propertyIndex.viewVehicle') }} >
  47 + </div>
  48 + </div>
  49 + </div>
  50 + </div>
  51 + </div>
  52 +</template>
  53 +
  54 +<script>
  55 +import { getPropertyAssetsIndex } from '@/api/index/propertyIndexApi'
  56 +
  57 +export default {
  58 + name: 'IndexCommunity',
  59 + data() {
  60 + return {
  61 + indexCommunityViewInfo: {
  62 + floorCount: 0,
  63 + roomCount: 0,
  64 + shopCount: 0,
  65 + ownerCount: 0,
  66 + spaceCount: 0,
  67 + carCount: 0,
  68 + },
  69 + stats: [
  70 + { key: 'floorCount', label: 'building', icon: 'el-icon-office-building' },
  71 + { key: 'roomCount', label: 'house', icon: 'el-icon-house' },
  72 + { key: 'shopCount', label: 'shop', icon: 'el-icon-shopping-bag-2' },
  73 + { key: 'spaceCount', label: 'parkingSpace', icon: 'el-icon-truck' }
  74 + ]
  75 + }
  76 + },
  77 + created() {
  78 + },
  79 + methods: {
  80 + _loadPropertyIndexAssets() {
  81 + const param = {
  82 + page: 1,
  83 + row: 10,
  84 + communityId: this.getCommunityId()
  85 + }
  86 +
  87 + getPropertyAssetsIndex(param)
  88 + .then(res => {
  89 + if (res.code === 0) {
  90 + Object.assign(this.indexCommunityViewInfo, res.data)
  91 + }
  92 + })
  93 + .catch(err => {
  94 + console.error('请求失败处理', err)
  95 + })
  96 + },
  97 + _toOwner() {
  98 + this.$router.push('/property/listOwner?tab=ownerInfo')
  99 + },
  100 + _toCar() {
  101 + this.$router.push('/property/listOwnerCar?tab=ownerCar')
  102 + }
  103 + }
  104 +}
  105 +</script>
  106 +
  107 +<style lang="scss" scoped>
  108 +.index-1-left-1 {
  109 + background: #fff;
  110 + border-radius: 4px;
  111 + padding: 15px;
  112 +
  113 + .index-title {
  114 + font-size: 16px;
  115 + font-weight: bold;
  116 + margin-bottom: 15px;
  117 + text-align: left;
  118 + color: #333;
  119 + }
  120 +
  121 + .index-1-left-1-content {
  122 + padding: 50px 0;
  123 + border-bottom: 1px solid #eee;
  124 +
  125 + > div {
  126 + width: 25%;
  127 + text-align: center;
  128 + }
  129 +
  130 + .index-1-left-img {
  131 + width: 40px;
  132 + height: 40px;
  133 + background: #f0f7ff;
  134 + border-radius: 50%;
  135 + display: flex;
  136 + align-items: center;
  137 + justify-content: center;
  138 + margin-right: 10px;
  139 +
  140 + i {
  141 + font-size: 20px;
  142 + color: #409EFF;
  143 + }
  144 + }
  145 +
  146 + .index-number {
  147 + font-size: 24px;
  148 + font-weight: bold;
  149 + color: #333;
  150 + }
  151 +
  152 + .index-number-describe {
  153 + font-size: 12px;
  154 + color: #999;
  155 + }
  156 + }
  157 +
  158 + .index-1-left-1-bottom {
  159 + padding: 28px 40px;
  160 +
  161 + .index-1-left-1-bottom-item {
  162 + width: 40%;
  163 + border-radius: 4px;
  164 + padding: 10px;
  165 + padding-left:30px;
  166 + padding-right:30px;
  167 +
  168 + .index-name {
  169 + font-size: 16px;
  170 + font-weight: bold;
  171 + color: #333;
  172 + }
  173 +
  174 + .index-name-ico {
  175 + width: 40px;
  176 + height: 40px;
  177 + background: #e6f7ff;
  178 + border-radius: 50%;
  179 + display: flex;
  180 + align-items: center;
  181 + justify-content: center;
  182 + margin: 10px auto;
  183 +
  184 + i {
  185 + font-size: 20px;
  186 + color: #1890ff;
  187 + }
  188 + }
  189 +
  190 + .index-number {
  191 + font-size: 24px;
  192 + font-weight: bold;
  193 + color: #333;
  194 +
  195 + .index-number-unit {
  196 + font-size: 14px;
  197 + color: #999;
  198 + }
  199 + }
  200 +
  201 + .index-number-describe {
  202 + font-size: 12px;
  203 + color: #1890ff;
  204 + cursor: pointer;
  205 +
  206 + &:hover {
  207 + text-decoration: underline;
  208 + }
  209 + }
  210 + }
  211 + }
  212 +
  213 + .margin-top-sm {
  214 + margin-top: 5px;
  215 + }
  216 +}
  217 +</style>
0 218 \ No newline at end of file
... ...
src/components/index/indexNotice.vue 0 → 100644
  1 +<template>
  2 + <div class="index-1-right-1">
  3 + <div class="index-title text-left">
  4 + <span>{{ $t('propertyIndex.ownerFeedback') }}</span>
  5 + </div>
  6 + <ul id="pool" class="notice-list">
  7 + <li v-if="!indexNoticeInfo.notices || indexNoticeInfo.notices.length < 1"
  8 + class="flex justify-between padding-top-sm no-data">
  9 + <div class="vc-index-notice-title">
  10 + {{ $t('propertyIndex.noFeedback') }}
  11 + </div>
  12 + </li>
  13 + <li v-else v-for="(item, index) in indexNoticeInfo.notices" :key="index"
  14 + class="flex justify-between padding-top-sm notice-item">
  15 + <div class="vc-index-notice-title">
  16 + {{ item.objName }}({{ item.roomName }}){{ $t('propertyIndex.feedback') }}{{ item.title }}
  17 + ({{ item.state === 'F' ? $t('propertyIndex.completed') : $t('propertyIndex.followingUp') }}<span v-if="item.thridId">-{{ $t('propertyIndex.transferRepair') }}</span>)
  18 + </div>
  19 + <div class="vc-index-notice-time">
  20 + {{ item.createTime }}
  21 + </div>
  22 + </li>
  23 + </ul>
  24 + </div>
  25 +</template>
  26 +
  27 +<script>
  28 +import { getNotepadList } from '@/api/index/propertyIndexApi'
  29 +
  30 +export default {
  31 + name: 'IndexNotice',
  32 + data() {
  33 + return {
  34 + indexNoticeInfo: {
  35 + notices: [],
  36 + scrollInterval: null,
  37 + scrollTopValue: 0,
  38 + scrollDirection: true,
  39 + }
  40 + }
  41 + },
  42 + created() {
  43 + },
  44 + mounted() {
  45 + this.$nextTick(() => {
  46 + window.addEventListener('resize', this.checkPoolScroll)
  47 + })
  48 + },
  49 + beforeDestroy() {
  50 + if (this.indexNoticeInfo.scrollInterval) {
  51 + clearInterval(this.indexNoticeInfo.scrollInterval)
  52 + }
  53 + window.removeEventListener('resize', this.checkPoolScroll)
  54 + },
  55 + methods: {
  56 + async _loadPropertyIndexNotices() {
  57 + const param = {
  58 + page: 1,
  59 + row: 10,
  60 + communityId: this.getCommunityId()
  61 + }
  62 +
  63 + try {
  64 + const res = await getNotepadList(param)
  65 + this.indexNoticeInfo.notices = res.data
  66 + this.$nextTick(() => {
  67 + this.checkPoolScroll()
  68 + })
  69 + } catch (error) {
  70 + console.error('请求失败处理', error)
  71 + }
  72 + },
  73 + checkPoolScroll() {
  74 + const element = document.getElementById('pool')
  75 + if (!element) return
  76 +
  77 + const clientHeight = element.clientHeight
  78 + const scrollHeight = element.scrollHeight
  79 +
  80 + if (scrollHeight > clientHeight) {
  81 + if (!this.indexNoticeInfo.scrollInterval) {
  82 + this.indexNoticeInfo.scrollInterval = setInterval(this.poolScroll, 5000)
  83 + }
  84 + } else {
  85 + clearInterval(this.indexNoticeInfo.scrollInterval)
  86 + this.indexNoticeInfo.scrollInterval = null
  87 + }
  88 + },
  89 + poolScroll() {
  90 + const element = document.getElementById('pool')
  91 + if (!element) return
  92 +
  93 + const clientHeight = element.clientHeight
  94 + const scrollHeight = element.scrollHeight
  95 + const canScrollHeight = scrollHeight - clientHeight
  96 +
  97 + if (this.indexNoticeInfo.scrollTopValue <= 0) {
  98 + this.indexNoticeInfo.scrollDirection = true
  99 + }
  100 +
  101 + if (this.indexNoticeInfo.scrollDirection) {
  102 + this.indexNoticeInfo.scrollTopValue += canScrollHeight / 1200
  103 + } else {
  104 + this.indexNoticeInfo.scrollTopValue -= canScrollHeight / 1200
  105 + }
  106 +
  107 + if (canScrollHeight <= this.indexNoticeInfo.scrollTopValue) {
  108 + this.indexNoticeInfo.scrollDirection = !this.indexNoticeInfo.scrollDirection
  109 + }
  110 +
  111 + element.scrollTop = this.indexNoticeInfo.scrollTopValue
  112 + }
  113 + }
  114 +}
  115 +</script>
  116 +
  117 +<style lang="scss" scoped>
  118 +.index-1-right-1 {
  119 + background: #fff;
  120 + border-radius: 4px;
  121 + padding: 15px;
  122 + height: 100%;
  123 +
  124 + .index-title {
  125 + font-size: 16px;
  126 + font-weight: bold;
  127 + margin-bottom: 15px;
  128 + color: #333;
  129 + }
  130 +
  131 + .notice-list {
  132 + height: 300px;
  133 + overflow-y: auto;
  134 + padding: 0;
  135 + margin: 0;
  136 + list-style: none;
  137 +
  138 + .no-data {
  139 + color: #999;
  140 + text-align: center;
  141 + padding: 20px 0;
  142 + }
  143 +
  144 + .notice-item {
  145 + padding: 8px 0;
  146 + border-bottom: 1px solid #eee;
  147 +
  148 + &:last-child {
  149 + border-bottom: none;
  150 + }
  151 +
  152 + .vc-index-notice-title {
  153 + font-size: 14px;
  154 + color: #333;
  155 + width: 70%;
  156 + overflow: hidden;
  157 + text-overflow: ellipsis;
  158 + white-space: nowrap;
  159 + }
  160 +
  161 + .vc-index-notice-time {
  162 + font-size: 12px;
  163 + color: #999;
  164 + width: 30%;
  165 + text-align: right;
  166 + }
  167 + }
  168 + }
  169 +
  170 + .padding-top-sm {
  171 + padding-top: 5px;
  172 + }
  173 +}
  174 +</style>
0 175 \ No newline at end of file
... ...
src/components/index/indexOwnerRoom.vue 0 → 100644
  1 +<template>
  2 + <div class="owner-room-container">
  3 + <div class="bg-white index-1-right-item">
  4 + <div class="index-title"><span>{{ $t('propertyIndex.residentRegStats') }}</span></div>
  5 + <div id="ownerRoomCount" style="height:250px"></div>
  6 + <div class="flex justify-between text-center stats-container">
  7 + <div v-for="(item, index) in stats" :key="index">
  8 + <div class="index-bottom-number">{{ item.value }}</div>
  9 + <div class="index-bottom-number-desc">{{ $t(`propertyIndex.${item.label}`) }}</div>
  10 + </div>
  11 + </div>
  12 + </div>
  13 + </div>
  14 +</template>
  15 +
  16 +<script>
  17 +import * as echarts from 'echarts'
  18 +import { getOwnerRegisterIndex } from '@/api/index/propertyIndexApi'
  19 +
  20 +export default {
  21 + name: 'IndexOwnerRoom',
  22 + data() {
  23 + return {
  24 + indexOwnerRoomInfo: {
  25 + unbindCount: 0,
  26 + bindCount: 0,
  27 + unbindRoomCount: 0,
  28 + bindRoomCount: 0,
  29 + },
  30 + ownerRoomChart: null
  31 + }
  32 + },
  33 + computed: {
  34 + stats() {
  35 + return [
  36 + { label: 'unregistered', value: this.indexOwnerRoomInfo.unbindCount },
  37 + { label: 'registered', value: this.indexOwnerRoomInfo.bindCount },
  38 + { label: 'unboundRoom', value: this.indexOwnerRoomInfo.unbindRoomCount },
  39 + { label: 'boundRoom', value: this.indexOwnerRoomInfo.bindRoomCount }
  40 + ]
  41 + }
  42 + },
  43 + created() {
  44 + },
  45 + mounted() {
  46 + window.addEventListener('resize', this.handleResize)
  47 + },
  48 + beforeDestroy() {
  49 + window.removeEventListener('resize', this.handleResize)
  50 + if (this.ownerRoomChart) {
  51 + this.ownerRoomChart.dispose()
  52 + }
  53 + },
  54 + methods: {
  55 + handleResize() {
  56 + if (this.ownerRoomChart) {
  57 + this.ownerRoomChart.resize()
  58 + }
  59 + },
  60 + async _loadIndexOwnerRegisterData() {
  61 + const param = {
  62 + page: 1,
  63 + row: 10,
  64 + communityId: this.getCommunityId()
  65 + }
  66 +
  67 + try {
  68 + const res = await getOwnerRegisterIndex(param)
  69 + Object.assign(this.indexOwnerRoomInfo, res.data)
  70 +
  71 + this.$nextTick(() => {
  72 + const dom = document.getElementById('ownerRoomCount')
  73 + if (!dom) return
  74 +
  75 + if (this.ownerRoomChart) {
  76 + this.ownerRoomChart.dispose()
  77 + }
  78 + this.ownerRoomChart = echarts.init(dom)
  79 + this._initOwnerEcharts(
  80 + this.ownerRoomChart,
  81 + this.indexOwnerRoomInfo.bindCount,
  82 + this.indexOwnerRoomInfo.unbindCount,
  83 + this.$t('propertyIndex.residentInfo'),
  84 + this.$t('propertyIndex.registered'),
  85 + this.$t('propertyIndex.unregistered'),
  86 + '#4B7AF0',
  87 + '#E2EDF6'
  88 + )
  89 + })
  90 + } catch (error) {
  91 + console.error('请求失败处理', error)
  92 + }
  93 + },
  94 + _initOwnerEcharts(chart, userCount, freeCount, _title, _userCountName, _freeCountName, userColor, freeColor) {
  95 + const option = {
  96 + tooltip: {
  97 + trigger: 'item',
  98 + formatter: '{a} <br/>{b}: {c} ({d}%)'
  99 + },
  100 + legend: {
  101 + orient: 'vertical',
  102 + right: 10,
  103 + top: 'center',
  104 + textStyle: {
  105 + color: '#606266'
  106 + },
  107 + data: [_userCountName, _freeCountName]
  108 + },
  109 + color: [userColor, freeColor],
  110 + series: [{
  111 + name: _title,
  112 + type: 'pie',
  113 + radius: ['40%', '65%'],
  114 + avoidLabelOverlap: false,
  115 + label: {
  116 + show: false,
  117 + position: 'center'
  118 + },
  119 + emphasis: {
  120 + label: {
  121 + show: true,
  122 + fontSize: '16',
  123 + fontWeight: 'bold'
  124 + }
  125 + },
  126 + labelLine: {
  127 + show: false
  128 + },
  129 + data: [
  130 + { value: userCount, name: _userCountName },
  131 + { value: freeCount, name: _freeCountName }
  132 + ]
  133 + }]
  134 + }
  135 +
  136 + chart.setOption(option)
  137 + }
  138 + }
  139 +}
  140 +</script>
  141 +
  142 +<style lang="scss" scoped>
  143 +.owner-room-container {
  144 + .index-1-right-item {
  145 + background: #fff;
  146 + border-radius: 4px;
  147 + padding: 15px;
  148 + height: 100%;
  149 +
  150 + .index-title {
  151 + font-size: 16px;
  152 + font-weight: bold;
  153 + margin-bottom: 15px;
  154 + color: #333;
  155 + }
  156 +
  157 + .stats-container {
  158 + padding-top: 15px;
  159 + border-top: 1px solid #eee;
  160 +
  161 + > div {
  162 + flex: 1;
  163 + }
  164 +
  165 + .index-bottom-number {
  166 + font-size: 20px;
  167 + font-weight: bold;
  168 + color: #333;
  169 + }
  170 +
  171 + .index-bottom-number-desc {
  172 + font-size: 12px;
  173 + color: #999;
  174 + margin-top: 5px;
  175 + }
  176 + }
  177 + }
  178 +}
  179 +</style>
0 180 \ No newline at end of file
... ...
src/components/index/indexRepairComplaint.vue 0 → 100644
  1 +<template>
  2 + <div class="repair-complaint-container">
  3 + <el-row :gutter="20">
  4 + <el-col :span="12">
  5 + <div class="bg-white index-1-left-item">
  6 + <div class="index-title"><span>{{ $t('propertyIndex.repairStats') }}</span></div>
  7 + <div id="repairCount" style="height:250px"></div>
  8 + <div class="flex justify-between text-center stats-container">
  9 + <div v-for="(item, index) in repairStats" :key="index">
  10 + <div class="index-bottom-number">{{ item.value }}</div>
  11 + <div class="index-bottom-number-desc">{{ $t(`propertyIndex.${item.label}`) }}</div>
  12 + </div>
  13 + </div>
  14 + </div>
  15 + </el-col>
  16 + <el-col :span="12">
  17 + <div class="bg-white index-1-left-item">
  18 + <div class="index-title"><span>{{ $t('propertyIndex.complaintStats') }}</span></div>
  19 + <div id="complaintCount" style="height:250px"></div>
  20 + <div class="flex justify-around text-center stats-container">
  21 + <div v-for="(item, index) in complaintStats" :key="index">
  22 + <div class="index-bottom-number">{{ item.value }}</div>
  23 + <div class="index-bottom-number-desc">{{ $t(`propertyIndex.${item.label}`) }}</div>
  24 + </div>
  25 + </div>
  26 + </div>
  27 + </el-col>
  28 + </el-row>
  29 + </div>
  30 +</template>
  31 +
  32 +<script>
  33 +import * as echarts from 'echarts'
  34 +import { getRepairIndex, getComplaintIndex } from '@/api/index/propertyIndexApi'
  35 +
  36 +export default {
  37 + name: 'IndexRepairComplaint',
  38 + data() {
  39 + return {
  40 + indexRepairComplaintInfo: {
  41 + allCount: 0,
  42 + waitCount: 0,
  43 + doingCount: 0,
  44 + finishCount: 0,
  45 + allComplaintCount: 0,
  46 + waitComplaintCount: 0,
  47 + finishComplaintCount: 0,
  48 + },
  49 + repairChart: null,
  50 + complaintChart: null
  51 + }
  52 + },
  53 + computed: {
  54 + repairStats() {
  55 + return [
  56 + { label: 'allRepair', value: this.indexRepairComplaintInfo.allCount },
  57 + { label: 'toBeDispatched', value: this.indexRepairComplaintInfo.waitCount },
  58 + { label: 'processing', value: this.indexRepairComplaintInfo.doingCount },
  59 + { label: 'processed', value: this.indexRepairComplaintInfo.finishCount }
  60 + ]
  61 + },
  62 + complaintStats() {
  63 + return [
  64 + { label: 'allComplaint', value: this.indexRepairComplaintInfo.allComplaintCount },
  65 + { label: 'processing', value: this.indexRepairComplaintInfo.waitComplaintCount },
  66 + { label: 'processed', value: this.indexRepairComplaintInfo.finishComplaintCount }
  67 + ]
  68 + }
  69 + },
  70 + created() {
  71 +
  72 + },
  73 + mounted() {
  74 + window.addEventListener('resize', this.handleResize)
  75 + },
  76 + beforeDestroy() {
  77 + window.removeEventListener('resize', this.handleResize)
  78 + if (this.repairChart) {
  79 + this.repairChart.dispose()
  80 + }
  81 + if (this.complaintChart) {
  82 + this.complaintChart.dispose()
  83 + }
  84 + },
  85 + methods: {
  86 + initData() {
  87 + this._loadIndexRepairData()
  88 + this._loadIndexComplaintData()
  89 + },
  90 + handleResize() {
  91 + if (this.repairChart) {
  92 + this.repairChart.resize()
  93 + }
  94 + if (this.complaintChart) {
  95 + this.complaintChart.resize()
  96 + }
  97 + },
  98 + async _loadIndexRepairData() {
  99 + const param = {
  100 + page: 1,
  101 + row: 10,
  102 + communityId: this.getCommunityId()
  103 + }
  104 +
  105 + try {
  106 + const res = await getRepairIndex(param)
  107 + Object.assign(this.indexRepairComplaintInfo, res.data)
  108 +
  109 + this.$nextTick(() => {
  110 + const dom = document.getElementById('repairCount')
  111 + if (!dom) return
  112 +
  113 + if (this.repairChart) {
  114 + this.repairChart.dispose()
  115 + }
  116 + this.repairChart = echarts.init(dom)
  117 + this._initEcharts(
  118 + this.repairChart,
  119 + this.indexRepairComplaintInfo.finishCount,
  120 + this.indexRepairComplaintInfo.allCount - this.indexRepairComplaintInfo.finishCount,
  121 + this.$t('propertyIndex.repairInfo'),
  122 + this.$t('propertyIndex.processed'),
  123 + this.$t('propertyIndex.unprocessed'),
  124 + '#4B7AF0',
  125 + '#E2EDF6'
  126 + )
  127 + })
  128 + } catch (error) {
  129 + console.error('请求失败处理', error)
  130 + }
  131 + },
  132 + async _loadIndexComplaintData() {
  133 + const param = {
  134 + page: 1,
  135 + row: 10,
  136 + communityId: this.getCommunityId()
  137 + }
  138 +
  139 + try {
  140 + const res = await getComplaintIndex(param)
  141 + Object.assign(this.indexRepairComplaintInfo, res.data)
  142 +
  143 + this.$nextTick(() => {
  144 + const dom = document.getElementById('complaintCount')
  145 + if (!dom) return
  146 +
  147 + if (this.complaintChart) {
  148 + this.complaintChart.dispose()
  149 + }
  150 + this.complaintChart = echarts.init(dom)
  151 + this._initEcharts(
  152 + this.complaintChart,
  153 + this.indexRepairComplaintInfo.finishComplaintCount,
  154 + this.indexRepairComplaintInfo.allComplaintCount - this.indexRepairComplaintInfo.finishComplaintCount,
  155 + this.$t('propertyIndex.complaintStats'),
  156 + this.$t('propertyIndex.processed'),
  157 + this.$t('propertyIndex.unprocessed'),
  158 + '#01C36D',
  159 + '#E2EDF6'
  160 + )
  161 + })
  162 + } catch (error) {
  163 + console.error('请求失败处理', error)
  164 + }
  165 + },
  166 + _initEcharts(chart, userCount, freeCount, _title, _userCountName, _freeCountName, userColor, freeColor) {
  167 + const option = {
  168 + tooltip: {
  169 + trigger: 'item',
  170 + formatter: '{a} <br/>{b}: {c} ({d}%)'
  171 + },
  172 + legend: {
  173 + orient: 'vertical',
  174 + right: 10,
  175 + top: 'center',
  176 + textStyle: {
  177 + color: '#606266'
  178 + },
  179 + data: [_userCountName, _freeCountName]
  180 + },
  181 + color: [userColor, freeColor],
  182 + series: [{
  183 + name: _title,
  184 + type: 'pie',
  185 + radius: ['40%', '65%'],
  186 + avoidLabelOverlap: false,
  187 + label: {
  188 + show: false,
  189 + position: 'center'
  190 + },
  191 + emphasis: {
  192 + label: {
  193 + show: true,
  194 + fontSize: '16',
  195 + fontWeight: 'bold'
  196 + }
  197 + },
  198 + labelLine: {
  199 + show: false
  200 + },
  201 + data: [
  202 + { value: userCount, name: _userCountName },
  203 + { value: freeCount, name: _freeCountName }
  204 + ]
  205 + }]
  206 + }
  207 +
  208 + chart.setOption(option)
  209 + }
  210 + }
  211 +}
  212 +</script>
  213 +
  214 +<style lang="scss" scoped>
  215 +.repair-complaint-container {
  216 +
  217 +}
  218 +
  219 +.index-1-left-item {
  220 + background: #fff;
  221 + border-radius: 4px;
  222 + padding: 15px;
  223 +
  224 + .index-title {
  225 + text-align: left;
  226 + font-size: 16px;
  227 + font-weight: bold;
  228 + margin-bottom: 15px;
  229 + color: #333;
  230 + }
  231 +
  232 + .stats-container {
  233 + padding-top: 15px;
  234 + border-top: 1px solid #eee;
  235 +
  236 + >div {
  237 + flex: 1;
  238 + }
  239 +
  240 + .index-bottom-number {
  241 + font-size: 20px;
  242 + font-weight: bold;
  243 + color: #333;
  244 + }
  245 +
  246 + .index-bottom-number-desc {
  247 + font-size: 12px;
  248 + color: #999;
  249 + margin-top: 5px;
  250 + }
  251 + }
  252 +}
  253 +</style>
0 254 \ No newline at end of file
... ...
src/views/index/index.vue
... ... @@ -7,6 +7,9 @@
7 7 <div v-if="storeInfo.storeTypeCd == '800900000001'">
8 8 <index-admin></index-admin>
9 9 </div>
  10 + <div v-if="storeInfo.storeTypeCd == '800900000003'">
  11 + <index-property></index-property>
  12 + </div>
10 13 </div>
11 14 </template>
12 15  
... ... @@ -15,12 +18,14 @@
15 18 import {deepCopy} from "@/utils/vc"
16 19 import indexDev from "@/components/index/index-dev.vue"
17 20 import indexAdmin from "@/components/index/index-admin.vue"
  21 + import indexProperty from '@/components/index/index-property.vue'
18 22  
19 23 export default {
20 24 name: 'index',
21 25 components: {
22 26 indexDev,
23   - indexAdmin
  27 + indexAdmin,
  28 + indexProperty
24 29 },
25 30 data() {
26 31 return {
... ...
src/views/index/indexLang.js
... ... @@ -8,6 +8,41 @@ export const messages = {
8 8 repairCount: 'Repair Count',
9 9 communityFeeStats: 'Community Fee Statistics',
10 10 communityRepairStats: 'Community Repair Statistics'
  11 + },
  12 + propertyIndex: {
  13 + home: 'Home',
  14 + dashboard: 'Dashboard',
  15 + communityInfo: 'Community Information',
  16 + building: 'Building',
  17 + house: 'House',
  18 + shop: 'Shop',
  19 + parkingSpace: 'Parking Space',
  20 + residentReg: 'Resident Registration',
  21 + registerResident: 'Register Resident',
  22 + vehicle: 'Vehicle',
  23 + viewVehicle: 'View Vehicles',
  24 + unit: 'unit',
  25 + ownerFeedback: 'Owner Feedback',
  26 + noFeedback: 'No feedback content currently',
  27 + feedback: 'feedback',
  28 + completed: 'Completed',
  29 + followingUp: 'Following up',
  30 + transferRepair: 'Transferred to repair order',
  31 + repairStats: 'Repair Statistics',
  32 + allRepair: 'All Repairs',
  33 + toBeDispatched: 'To be dispatched',
  34 + processing: 'Processing',
  35 + processed: 'Processed',
  36 + complaintStats: 'Complaint Statistics',
  37 + allComplaint: 'All Complaints',
  38 + repairInfo: 'Repair Info',
  39 + unprocessed: 'Unprocessed',
  40 + residentRegStats: 'Resident Registration Statistics',
  41 + unregistered: 'Unregistered',
  42 + registered: 'Registered',
  43 + unboundRoom: 'Unbound Room',
  44 + boundRoom: 'Bound Room',
  45 + residentInfo: 'Resident Info'
11 46 }
12 47 },
13 48 zh: {
... ... @@ -19,6 +54,41 @@ export const messages = {
19 54 repairCount: '报修单数',
20 55 communityFeeStats: '小区缴费统计',
21 56 communityRepairStats: '小区报修统计'
  57 + },
  58 + propertyIndex: {
  59 + home: '首页',
  60 + dashboard: '控制台',
  61 + communityInfo: '小区信息',
  62 + building: '楼宇',
  63 + house: '房屋',
  64 + shop: '商铺',
  65 + parkingSpace: '车位',
  66 + residentReg: '住户登记',
  67 + registerResident: '登记住户',
  68 + vehicle: '车辆',
  69 + viewVehicle: '查看车辆',
  70 + unit: '个',
  71 + ownerFeedback: '业主反馈',
  72 + noFeedback: '当前没有业主反馈内容',
  73 + feedback: '反馈',
  74 + completed: '完成',
  75 + followingUp: '跟进中',
  76 + transferRepair: '已转报修单',
  77 + repairStats: '报修统计',
  78 + allRepair: '全部报修',
  79 + toBeDispatched: '待派单',
  80 + processing: '处理中',
  81 + processed: '已处理',
  82 + complaintStats: '投诉统计',
  83 + allComplaint: '全部投诉',
  84 + repairInfo: '报修信息',
  85 + unprocessed: '未处理',
  86 + residentRegStats: '住户注册统计',
  87 + unregistered: '未注册',
  88 + registered: '已注册',
  89 + unboundRoom: '未绑定房屋',
  90 + boundRoom: '已绑定房屋',
  91 + residentInfo: '住户信息'
22 92 }
23 93 }
24 94 }
25 95 \ No newline at end of file
... ...