From e1b782bbac430d8e01d43d5f610a46e4a29f661e Mon Sep 17 00:00:00 2001 From: pyt <626651354@qq.com> Date: 星期二, 20 五月 2025 21:39:41 +0800 Subject: [PATCH] feat --- H5/static/home/Group 2@2x.png | 0 H5/config/index.js | 4 management/config/env.ts | 2 management/package.json | 4 management/src/pages/statistics/service.js | 23 H5/pages/statistics/index.vue | 2025 +++++++++++++++++++++++++------------------ H5/App.vue | 1 management/config/routes.ts | 6 management/src/pages/statistics/index.jsx | 558 ++++++++++++ H5/pages/index/index.vue | 7 management/src/pages/statistics/components/addAndEdit.jsx | 72 + H5/pages/statistics/service.js | 23 12 files changed, 1,856 insertions(+), 869 deletions(-) diff --git a/H5/App.vue b/H5/App.vue index c1c4c02..7634c55 100644 --- a/H5/App.vue +++ b/H5/App.vue @@ -9,7 +9,6 @@ trialNode.innerHTML = '试运行版本'; document.body.appendChild(trialNode); // #endif - }, onShow: function() { diff --git a/H5/config/index.js b/H5/config/index.js index 34bbf76..93b3ec8 100644 --- a/H5/config/index.js +++ b/H5/config/index.js @@ -1,5 +1,5 @@ export default { - BASE_URL: 'https://huacheng.psciio.com', - // BASE_URL: 'http://192.168.110.188:6194', + // BASE_URL: 'https://huacheng.psciio.com', + BASE_URL: 'http://192.168.110.111:6194', imageUrl: 'https://huacheng.psciio.com/api/huacheng-applets/common/uploadimages', } \ No newline at end of file diff --git a/H5/pages/index/index.vue b/H5/pages/index/index.vue index aafca34..93a3e05 100644 --- a/H5/pages/index/index.vue +++ b/H5/pages/index/index.vue @@ -71,7 +71,6 @@ <image class="w-79 h-77 ml-38" src="/static/home/img1.png" mode=""></image> <text class="ml-37 font-bold">回访评价</text> </view> --> - <view class="pt-38 pb-38 bg1 w-333 br-19 mt-19 flex a-center" @click="toStatistics"> <image class="w-81 h-77 ml-38" src="/static/home/img8.png" mode=""></image> <text class="ml-37 font-bold">统计分析</text> @@ -145,7 +144,7 @@ <view class="lineBox mb-10"></view> <view style="height: 546rpx;overflow-y: auto;"> <view @tap.stop="changeRole(item)" v-for="(item,index) in userInfo.permissions" :key="index" - :class="item.identity == userInfo.identity && 'bgcolor2'" + :class="item.name == userInfo.roleName && 'bgcolor2'" class="mt-38 bgcolor1 br-58 fs-31 ml-54 mr-62 py-37 txt-center"> <view>{{ item.name }}</view> </view> @@ -335,8 +334,10 @@ this.changeRolePopup = false this.$refs.dongjiePop.showPopup() } else { + console.log(e); changeIdentity({ - identity: e.identity + identity: e.identity, + levelId: e.identity == 1 ? '' : e.levelId }).then(res => { this.$refs.uToast.show({ type: "success", diff --git a/H5/pages/statistics/index.vue b/H5/pages/statistics/index.vue index 7fe4597..2774d7d 100644 --- a/H5/pages/statistics/index.vue +++ b/H5/pages/statistics/index.vue @@ -1,179 +1,166 @@ - <template> - <view class="content"> - <view v-if="userInfo.isAdmin == 1" class="flex a-center pl-31 pr-31 fs-31 color1 pt-38"> - <text class="mr-15">查看范围:</text> - <view - class="h-77 flex a-center j-between flex1 pl-31 pr-23 border1 br-15 bgColor1" :class="!address && 'color2'"> - <view @click.top="selectPopup=true" class="flex1"> - {{ address || '全部' }} - </view> - <u-icon class="shrink0" v-if="address" @click="clearAddress" name="close-circle"></u-icon> - <image v-else src="/static/down@2x.png" mode="aspectFill" class="w-31 h-31 shrink0"></image> - </view> - </view> - <view class="fs-35 font-bold pt-38 ml-27"> - 处理满意率 - </view> - <view class="ml-29 mr-29 border2 br-15 mt-27 shadow1 flex j-between pl-19 pr-19 pb-35"> - <view class="mt-19 flex1"> - <view class="flex a-center"> - <view class="w-12 h-12 br-6 border3"></view> - <view class="fs-23 ml-15 color3"> - 总体满意率 - </view> - </view> - <view class="fs-46 ml-27 mt-12 font-bold"> - 77% - </view> - </view> - <view class="flex1 flex j-between ml-50"> - <view class="fs-23 mt-42 txt-center"> - <view class="color6"> - 本月 - </view> - <view class="fs-27 font-bold color5 mt-2"> - 88% - </view> - </view> - <view class="fs-23 mt-44"> - <view class="color6"> - 同比上月 - </view> - <view class="txt-aligin-r color4 font-bold mt-4"> - +12% - </view> - </view> - </view> - </view> - <view class="fs-35 font-bold mt-38 ml-27"> - 诉求单统计 - </view> - <view class="flex j-between a-center pl-29 pr-29 mt-27"> - <view class="pl-19 pr-21 shadow1 border2 pt-19 pb-42 flex1 br-15"> - <view class="flex a-center"> - <view class="w-12 h-12 br-6 border3"></view> - <view class="fs-23 ml-15 color3"> - 诉求单量总计 - </view> - </view> - <view class="fs-46 mt-12 font-bold ml-27"> - 448451 - </view> - <view class="flex j-between mt-21"> - <view class="fs-23"> - <view class=""> - 本月 - </view> - <view class="fs-27 font-bold color3 mt-2"> - 4448 - </view> - </view> - <view class="fs-23"> - <view class=""> - 同比上月 - </view> - <view class="font-bold color8 txt-aligin-r mt-4"> - -12% - </view> - </view> - </view> - </view> - <view class="pl-19 pr-21 shadow1 border2 pt-19 pb-42 flex1 ml-31 br-15"> - <view class="flex a-center"> - <view class="w-12 h-12 br-6 border3"></view> - <view class="fs-23 ml-15 color3"> - 平均处理时间(天) - </view> - </view> - <view class="fs-46 mt-12 font-bold ml-27"> - 3.2 - </view> - <view class="flex j-between mt-21"> - <view class="fs-23"> - <view class=""> - 本月 - </view> - <view class="fs-27 font-bold color3 mt-2"> - 2.2 - </view> - </view> - <view class="fs-23"> - <view class=""> - 同比上月 - </view> - <view class="font-bold color4 txt-aligin-r mt-4"> - +12% - </view> - </view> - </view> - </view> - </view> - <view class="flex mt-27 gap25 pl-29 pr-29"> - <view class="flex1 h-154 bgColor2 border4 shadow2 br-19 txt-center"> - <view class="mt-37 fs-35 color4 font-bold"> - 4521 - </view> - <view class="fs-23 mt-8 color3"> - 正在办理 - </view> - </view> - <view class="flex1 h-154 bgColor3 border4 shadow2 br-19 txt-center"> - <view class="mt-37 fs-35 color9 font-bold"> - 321 - </view> - <view class="fs-23 mt-8 color3"> - 审核中 - </view> - </view> - <view class="flex1 h-154 bgColor4 border4 shadow2 br-19 txt-center"> - <view class="mt-37 fs-35 color10 font-bold"> - 6850 - </view> - <view class="fs-23 mt-8 color3"> - 延期办理 - </view> - </view> - <view class="flex1 h-154 bgColor5 border4 shadow2 br-19 txt-center"> - <view class="mt-37 fs-35 color11 font-bold"> - 8451 - </view> - <view class="fs-23 mt-8 color3"> - 已办结 - </view> - </view> - </view> - <view class="pb-35 ml-29 mr-29 border2 br-15 mt-27 shadow1 flex j-between pl-19 pr-19"> - <view class="mt-19 flex1"> - <view class="flex a-center"> - <view class="w-12 h-12 br-6 border3"></view> - <view class="fs-23 ml-15 color3"> - 超时办理 - </view> - </view> - <view class="fs-46 ml-27 mt-12 font-bold"> - 6850 - </view> - </view> - <view class="flex1 flex j-between ml-50"> - <view class="fs-23 mt-42 txt-center"> - <view class="color6"> - 本月 - </view> - <view class="fs-27 font-bold color5 mt-2"> - 4448 - </view> - </view> - <view class="fs-23 mt-44"> - <view class="color6"> - 同比上月 - </view> - <view class="txt-aligin-r color4 font-bold mt-4"> - +12% - </view> - </view> - </view> - </view> - <view class="pb-35 ml-29 mr-29 border2 br-15 mt-27 shadow1 flex j-between pl-19 pr-19"> +<template> + <view class="content"> + <view + v-if="userInfo.isAdmin == 1" + class="flex a-center pl-31 pr-31 fs-31 color1 pt-38" + > + <text class="mr-15">查看范围:</text> + <view + class="h-77 flex a-center j-between flex1 pl-31 pr-23 border1 br-15 bgColor1" + :class="!address && 'color2'" + > + <view @click.top="selectPopup = true" class="flex1"> + {{ address || "全部" }} + </view> + <u-icon + class="shrink0" + v-if="address" + @click="clearAddress" + name="close-circle" + ></u-icon> + <image + v-else + src="/static/down@2x.png" + mode="aspectFill" + class="w-31 h-31 shrink0" + ></image> + </view> + </view> + <view class="fs-35 font-bold pt-38 ml-27"> 处理满意率 </view> + <view + class="ml-29 mr-29 border2 br-15 mt-27 shadow1 flex j-between pl-19 pr-19 pb-35" + > + <view class="mt-19 flex1"> + <view class="flex a-center"> + <view class="w-12 h-12 br-6 border3"></view> + <view class="fs-23 ml-15 color3"> 总体满意率 </view> + </view> + <view class="fs-46 ml-27 mt-12 font-bold"> + {{ statisticsData.satisfaction.total }}% + </view> + </view> + <view class="flex1 flex j-between ml-50"> + <view class="fs-23 mt-42 txt-center"> + <view class="color6"> 本月 </view> + <view class="fs-27 font-bold color5 mt-2"> + {{ statisticsData.satisfaction.month }}% + </view> + </view> + <view class="fs-23 mt-44"> + <view class="color6"> 同比上月 </view> + <view class="txt-aligin-r color4 font-bold mt-4"> + {{ statisticsData.satisfaction.compare > 0 ? "+" : "" + }}{{ statisticsData.satisfaction.compare }}% + </view> + </view> + </view> + </view> + <view class="fs-35 font-bold mt-38 ml-27"> 诉求单统计 </view> + <view class="flex j-between a-center pl-29 pr-29 mt-27"> + <view class="pl-19 pr-21 shadow1 border2 pt-19 pb-42 flex1 br-15"> + <view class="flex a-center"> + <view class="w-12 h-12 br-6 border3"></view> + <view class="fs-23 ml-15 color3"> 诉求单量总计 </view> + </view> + <view class="fs-46 mt-12 font-bold ml-27"> + {{ statisticsData.demands.total }} + </view> + <view class="flex j-between mt-21"> + <view class="fs-23"> + <view class=""> 本月 </view> + <view class="fs-27 font-bold color3 mt-2"> + {{ statisticsData.demands.month }} + </view> + </view> + <view class="fs-23"> + <view class=""> 同比上月 </view> + <view class="font-bold color8 txt-aligin-r mt-4"> + {{ statisticsData.demands.compare > 0 ? "+" : "" + }}{{ statisticsData.demands.compare }} + </view> + </view> + </view> + </view> + <view class="pl-19 pr-21 shadow1 border2 pt-19 pb-42 flex1 ml-31 br-15"> + <view class="flex a-center"> + <view class="w-12 h-12 br-6 border3"></view> + <view class="fs-23 ml-15 color3"> 平均处理时间(天) </view> + </view> + <view class="fs-46 mt-12 font-bold ml-27"> + {{ statisticsData.processTime.total }} + </view> + <view class="flex j-between mt-21"> + <view class="fs-23"> + <view class=""> 本月 </view> + <view class="fs-27 font-bold color3 mt-2"> + {{ statisticsData.processTime.month }} + </view> + </view> + <view class="fs-23"> + <view class=""> 同比上月 </view> + <view class="font-bold color4 txt-aligin-r mt-4"> + {{ statisticsData.processTime.compare > 0 ? "+" : "" + }}{{ statisticsData.processTime.compare }} + </view> + </view> + </view> + </view> + </view> + <view class="flex mt-27 gap25 pl-29 pr-29"> + <view class="flex1 h-154 bgColor2 border4 shadow2 br-19 txt-center"> + <view class="mt-37 fs-35 color4 font-bold"> + {{ statisticsData.status.processing }} + </view> + <view class="fs-23 mt-8 color3"> 正在办理 </view> + </view> + <view class="flex1 h-154 bgColor3 border4 shadow2 br-19 txt-center"> + <view class="mt-37 fs-35 color9 font-bold"> + {{ statisticsData.status.reviewing }} + </view> + <view class="fs-23 mt-8 color3"> 审核中 </view> + </view> + <view class="flex1 h-154 bgColor4 border4 shadow2 br-19 txt-center"> + <view class="mt-37 fs-35 color10 font-bold"> + {{ statisticsData.status.delayed }} + </view> + <view class="fs-23 mt-8 color3"> 延期办理 </view> + </view> + <view class="flex1 h-154 bgColor5 border4 shadow2 br-19 txt-center"> + <view class="mt-37 fs-35 color11 font-bold"> + {{ statisticsData.status.completed }} + </view> + <view class="fs-23 mt-8 color3"> 已办结 </view> + </view> + </view> + <view + class="pb-35 ml-29 mr-29 border2 br-15 mt-27 shadow1 flex j-between pl-19 pr-19" + > + <view class="mt-19 flex1"> + <view class="flex a-center"> + <view class="w-12 h-12 br-6 border3"></view> + <view class="fs-23 ml-15 color3"> 超时办理 </view> + </view> + <view class="fs-46 ml-27 mt-12 font-bold"> + {{ statisticsData.overtime.total }} + </view> + </view> + <view class="flex1 flex j-between ml-50"> + <view class="fs-23 mt-42 txt-center"> + <view class="color6"> 本月 </view> + <view class="fs-27 font-bold color5 mt-2"> + {{ statisticsData.overtime.month }} + </view> + </view> + <view class="fs-23 mt-44"> + <view class="color6"> 同比上月 </view> + <view class="txt-aligin-r color4 font-bold mt-4"> + {{ statisticsData.overtime.compare > 0 ? "+" : "" + }}{{ statisticsData.overtime.compare }} + </view> + </view> + </view> + </view> + <!-- <view class="pb-35 ml-29 mr-29 border2 br-15 mt-27 shadow1 flex j-between pl-19 pr-19"> <view class="mt-19 flex1"> <view class="flex a-center"> <view class="w-12 h-12 br-6 border3"></view> @@ -203,685 +190,1007 @@ </view> </view> </view> - </view> - <view class="mt-27 shadow1 border2 ml-29 mr-29 pt-31 br-15" style="height: 511rpx;"> - <view class="flex mlr-o tabs mb-40"> - <view v-for="(item, index) in tabs" :key="index" - :class="['tab-item', currentTab === index ? 'active' : '']" @click="handleTabClick(index)"> - {{item}} - </view> - </view> - <view ref="chartRef" id="chart" style="width: 100%; height: 405rpx;"></view> - </view> - <view class="fs-35 font-bold mt-38 ml-27"> - 问题类型排名 - </view> - <view class="ml-29 mr-29 mt-27 shadow1 pt-31 border2 pl-38 pr-38 br-15"> - <uni-data-select v-model="value1" :localdata="range"></uni-data-select> - <view class="fs-23"> - <view class="flex a-center mb-38"> - <view class="w-130 color3"> - 教育 - </view> - <u-line-progress :percentage="95" inactiveColor="#EEEEEE" - :activeColor="'linear-gradient(270deg, #FF4934 0%, #FF8064 100%)'" height="38rpx"> - <text class="u-percentage-slot pr-19 fs-23">248</text> - </u-line-progress> - </view> - <view class="flex a-center mb-38"> - <view class="w-130 color3"> - 就业 - </view> - <u-line-progress :percentage="75" inactiveColor="#EEEEEE" - :activeColor="'linear-gradient(270deg, #FEA834 0%, #FFD364 100%)'" height="38rpx"> - <text class="u-percentage-slot pr-19 fs-23">200</text> - </u-line-progress> - </view> - <view class="flex a-center mb-38"> - <view class="w-130 color3"> - 医疗 - </view> - <u-line-progress :percentage="55" inactiveColor="#EEEEEE" - :activeColor="'linear-gradient(270deg, #02BAC0 0%, #05DEE1 100%)'" height="38rpx"> - <text class="u-percentage-slot pr-19 fs-23">174</text> - </u-line-progress> - </view> - <view class="flex a-center mb-38"> - <view class="w-130 color3"> - 住房 - </view> - <u-line-progress :percentage="35" inactiveColor="#EEEEEE" - :activeColor="'linear-gradient(270deg, #4791FF 0%, #7DC4FF 100%)'" height="38rpx"> - <text class="u-percentage-slot pr-19 fs-23">132</text> - </u-line-progress> - </view> - <view class="flex a-center mb-38"> - <view class="w-130 color3"> - 养老 - </view> - <u-line-progress :percentage="15" inactiveColor="#EEEEEE" - :activeColor="'linear-gradient(270deg, #4791FF 0%, #7DC4FF 100%)'" height="38rpx"> - <text class="u-percentage-slot pr-19 fs-23">89</text> - </u-line-progress> - </view> - </view> - </view> - <view class="fs-35 font-bold mt-38 ml-27"> - 评价占比 - </view> - <view class="ml-29 mr-29 mt-27 shadow1 border2 br-15" style="height: 417rpx;"> - <view class="flex pl-38 pr-38"> - <view ref="rateChartRef" id="rateChart" style="width: 288rpx; height: 417rpx;"></view> - <view style="width: 46rpx;"></view> - <view class="flex1 pt-54"> - <view class="mb-27"> - <view class="flex a-center j-between mb-13"> - <text class="fs-23">非常满意</text> - <text class="fs-23 color12">45%</text> - </view> - <view class="progress-bar"> - <view class="progress-inner very-satisfied" style="width: 45%;"></view> - </view> - </view> - <view class="mb-27"> - <view class="flex a-center j-between mb-13"> - <text class="fs-23">满意</text> - <text class="fs-23 color12">20%</text> - </view> - <view class="progress-bar"> - <view class="progress-inner satisfied" style="width: 20%;"></view> - </view> - </view> - <view class="mb-27"> - <view class="flex a-center j-between mb-13"> - <text class="fs-23">一般</text> - <text class="fs-23 color12">30%</text> - </view> - <view class="progress-bar"> - <view class="progress-inner normal" style="width: 30%;"></view> - </view> - </view> - <view class="mb-27"> - <view class="flex a-center j-between mb-13"> - <text class="fs-23">不满意</text> - <text class="fs-23 color12">5%</text> - </view> - <view class="progress-bar"> - <view class="progress-inner unsatisfied" style="width: 5%;"></view> - </view> - </view> - </view> - </view> - </view> - <view class="h-40 safe-b"></view> - <!-- 选择服务社区 --> - <u-popup :show="selectPopup" round="16rpx" @close="selectPopup = false" :safe-area-inset-bottom="false" - @open="openSelectPopup"> - <view class="relative pb-40"> - <image @tap.stop="selectPopup = false" src="@/static/closeImg.png" class="w-35 h-35 absolute" - style="right: 31rpx;top: 46rpx;" /> - <view class="txt-center pt-38 pb-40 fs-35 lh-48 font-bold">请选择服务社区</view> - <view class="flex a-center j-between txt-center py-10 fs-27 font-bold bgColor1"> - <view class="flex1">区县</view> - <view class="flex1">街道</view> - <view class="flex1">社区</view> - </view> - <view class="mb-20"> - <picker-view :value="value" @change="bindChange" class="picker-view" immediate-change> - <picker-view-column> - <view class="item" v-for="(item, index) in county" :key="index"> - {{ item.name }} - </view> - </picker-view-column> - <picker-view-column> - <view class="item" v-for="(item, index) in street" :key="index"> - {{ item.name }} - </view> - </picker-view-column> - <picker-view-column> - <view class="item" v-for="(item, index) in community" :key="index"> - {{ item.name }} - </view> - </picker-view-column> - </picker-view> - </view> - <view class="submitBtn" @click="chooseCommunity">确认</view> - </view> - </u-popup> - </view> - </template> - - <script> - import * as echarts from 'echarts'; - import { - getRegionTree - } from './service.js' - export default { - data() { - return { - userInfo: {}, - address: '', - value: [0, 0, 0], - confirmValue: [0, 0, 0], - county: [], //区县 - street: [], //街道 - community: [], //社区 - value1: 0, - selectPopup: false, - range: [{ - value: 0, - text: "排名前五" - }, - { - value: 1, - text: "排名前十" - }, - { - value: 2, - text: "所有排名" - }, - ], - chart: null, - rateChart: null, - tabs: ['近7天', '近15天', '近30天'], - currentTab: 0, - chartData: { - dates: [ - '2025\n04.17', - '2025\n04.18', - '2025\n04.19', - '2025\n04.20', - '2025\n04.21', - '2025\n04.22', - '2025\n04.23' - ], - demands: [80, 170, 240, 70, 130, 90, 160], - completed: [40, 130, 200, 30, 90, 50, 110] - }, - rateData: [{ - value: 45, - name: '非常满意', - itemStyle: { - color: new echarts.graphic.LinearGradient(1, 0, 0, 0, [{ - offset: 0, - color: '#FF8064' - }, - { - offset: 1, - color: '#FF4934' - } - ]) - } - }, - { - value: 20, - name: '满意', - itemStyle: { - color: new echarts.graphic.LinearGradient(1, 0, 0, 0, [{ - offset: 0, - color: '#05DEE1' - }, - { - offset: 1, - color: '#02BAC0' - } - ]) - } - }, - { - value: 30, - name: '一般', - itemStyle: { - color: new echarts.graphic.LinearGradient(1, 0, 0, 0, [{ - offset: 0, - color: '#7DC4FF' - }, - { - offset: 1, - color: '#4791FF' - } - ]) - } - }, - { - value: 5, - name: '不满意', - itemStyle: { - color: new echarts.graphic.LinearGradient(1, 0, 0, 0, [{ - offset: 0, - color: '#FFD364' - }, - { - offset: 1, - color: '#FEA834' - } - ]) - } - } - ] - } - }, - onLoad() { - this.userInfo = uni.getStorageSync('userInfo') - getRegionTree().then(res => { - this.county = res.data - }) - }, - mounted() { - this.$nextTick(() => { - this.initChart() - this.initRateChart() - }) - }, - methods: { - clearAddress() { - this.address = ''; - this.value = [0, 0, 0]; - this.confirmValue = [0, 0, 0]; - this.street = []; - this.community = []; - }, - //选择服务社区 - chooseCommunity() { - let districts = this.county[this.value[0]].name - let street = this.street[this.value[1]].name - let community = this.community[this.value[2]].name - - this.address = `${districts}-${street}-${community}`; - - this.confirmValue = this.value - this.selectPopup = false - }, - // 切换社区 - bindChange(e, index) { - if (e.detail.value[0] != this.value[0]) { - e.detail.value[1] = 0 - e.detail.value[2] = 0 - } - if (e.detail.value[1] != this.value[1]) { - e.detail.value[2] = 0 - } - this.value = e.detail.value - this.street = this.county[this.value[0]].children - this.community = this.street[this.value[1]].children - }, - openSelectPopup() { - this.value = this.confirmValue - this.street = this.county[this.value[0]].children - this.community = this.street[this.value[1]].children - }, - handleTabClick(index) { - this.currentTab = index - // 这里可以根据不同的 tab 加载不同时间段的数据 - // this.loadChartData(index) - }, - initChart() { - // 在 H5 端使用 document.getElementById - // 在小程序端使用 this.$refs.chartRef - const chartDom = document.getElementById('chart') || this.$refs.chartRef; - this.chart = echarts.init(chartDom); - this.updateChart(); - }, - updateChart() { - const option = { - color: ['#FF7B7B', '#FFB75B'], - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'shadow' - } - }, - legend: { - data: ['诉求单量', '诉求办结数'], - bottom: '0', - itemGap: uni.upx2px(60), - selectedMode: true - }, - grid: { - left: '3%', - right: '4%', - bottom: '15%', - top: '3%', - containLabel: true - }, - xAxis: { - type: 'category', - data: this.chartData.dates, - axisLine: { - lineStyle: { - color: '#E5E5E5' - } - }, - axisTick: { - show: false - }, - axisLabel: { - color: '#888888', - fontSize: uni.upx2px(19), - lineHeight: uni.upx2px(23), - formatter: function(value) { - return value.split('\\n').join('\n') - } - } - }, - yAxis: { - type: 'value', - splitLine: { - lineStyle: { - type: 'dashed', - color: '#fff' - } - }, - axisLine: { - show: false - }, - axisTick: { - show: false - } - }, - series: [{ - name: '诉求单量', - type: 'bar', - barWidth: uni.upx2px(38), - itemStyle: { - borderRadius: [20, 20, 20, 20], - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ - offset: 0, - color: '#FF807E' - }, - { - offset: 1, - color: '#FF4948' - } - ]) - }, - data: this.chartData.demands - }, - { - name: '诉求办结数', - type: 'line', - smooth: true, - symbol: 'circle', - symbolSize: 8, - itemStyle: { - color: '#FFB75B', - borderWidth: 2, - borderColor: '#fff', - shadowColor: '#FB9A0E', - shadowBlur: 8, - shadowOffsetY: 4 - }, - lineStyle: { - width: 2, - curveness: 0.3 - }, - data: this.chartData.completed - } - ] - }; - this.chart && this.chart.setOption(option); - }, - initRateChart() { - const chartDom = document.getElementById('rateChart') || this.$refs.rateChartRef; - this.rateChart = echarts.init(chartDom); - this.updateRateChart(); - }, - updateRateChart() { - const option = { - tooltip: { - trigger: 'item', - confine: true, - // formatter: '{b}: {c}%', - backgroundColor: 'rgba(255, 255, 255, 0.9)', - borderColor: '#FFE0E0', - borderWidth: 1, - textStyle: { - color: '#666666', - fontSize: 12 - }, - padding: [8, 12] - }, - series: [{ - name: '评价占比', - type: 'pie', - radius: ['55%', '100%'], - center: ['50%', '50%'], - avoidLabelOverlap: false, - label: { - show: false - }, - labelLine: { - show: false - }, - emphasis: { - scale: false, - scaleSize: 0 - }, - data: this.rateData - }] - }; - this.rateChart && this.rateChart.setOption(option); - } - } - } - </script> - - <style scoped lang="scss"> - /deep/.uni-select { - width: 231rpx; - height: 65rpx; - margin: 0 auto; - margin-bottom: 38rpx; - font-size: 27rpx; - color: #797F81; - border-color: #E5E5E5; - border-radius: 33rpx; - padding: 0 31rpx 0 40rpx; - - .uni-select__input-text { - color: #797F81; - } - } - - .content { - background: linear-gradient(180deg, #FFDCDB 0%, rgba(255, 255, 255, 0) 100rpx, #fff 100%); - } - - .gap25 { - gap: 25rpx; - } - - .tabs { - width: 412rpx; - background-color: #FFF1F1; - border-radius: 30rpx; - height: 65rpx; - line-height: 65rpx; - font-size: 27rpx; - position: relative; - overflow: hidden; - } - - .tab-item { - color: #797F81; - flex: 1; - text-align: center; - font-weight: 400; - height: 54rpx; - line-height: 54rpx; - border-radius: 27rpx; - margin: 6rpx; - position: relative; - z-index: 1; - transform: translateZ(0); - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - - &.active { - background-color: #fff; - color: #FF4948; - font-weight: 600; - box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1); - transform: scale(1.02); - } - } - - .chart-wrapper { - background: #fff; - border-radius: 20rpx; - padding: 20rpx; - } - - .color1 { - color: #666565; - } - - .color2 { - color: #C1C1C1; - } - - .color3 { - color: #666666; - } - - .color4 { - color: #FF4948; - } - - .color5 { - color: #696969; - } - - .color6 { - color: #A4A4A4; - } - - .color7 { - color: #A7A7A7; - } - - .color8 { - color: #0FB269; - } - - .color9 { - color: #FF5600; - } - - .color10 { - color: #161998; - } - - .color11 { - color: #08AD60; - } - - .color12 { - color: #9C9C9E; - } - - .bgColor1 { - background-color: #fff; - } - - .bgColor2 { - background-color: #FFF1F4; - } - - .bgColor3 { - background-color: #FFF8F4; - } - - .bgColor4 { - background-color: #F4F5FF; - } - - .bgColor5 { - background-color: #F1FFF8; - } - - .border1 { - border: 2rpx solid #D9D9D9; - } - - .border2 { - border: 2rpx solid #FFE0E0; - } - - .border3 { - border: 4rpx solid #FF4948; - box-sizing: border-box; - box-shadow: 0rpx 4rpx 8rpx 0rpx rgba(255, 73, 72, 0.5); - } - - .border4 { - border: 2rpx solid #FFFFFF; - } - - .shadow1 { - box-shadow: 0rpx 0rpx 27rpx 0rpx rgba(0, 0, 0, 0.1); - } - - .shadow2 { - box-shadow: 0rpx 0rpx 15rpx 0rpx rgba(0, 0, 0, 0.1); - } - - .progress-bar { - width: 100%; - height: 8rpx; - background: #EEEEEE; - border-radius: 4rpx; - overflow: hidden; - } - - .progress-inner { - height: 100%; - border-radius: 4rpx; - transition: width 0.3s ease-in-out; - - &.very-satisfied { - background: linear-gradient(270deg, #FF8064 0%, #FF4934 100%); - } - - &.satisfied { - background: linear-gradient(270deg, #05DEE1 0%, #02BAC0 100%); - } - - &.normal { - background: linear-gradient(270deg, #7DC4FF 0%, #4791FF 100%); - } - - &.unsatisfied { - background: linear-gradient(270deg, #FFD364 0%, #FEA834 100%); - } - } - - .picker-view { - height: 460rpx; - font-size: 35rpx; - } - - /deep/.picker-view { - margin: 0 auto; - - .item { - text-align: center; - font-family: PingFangSC, PingFang SC; - font-weight: 600; - font-size: 36rpx; - color: #333333; - line-height: 50rpx; - } - } - - .submitBtn { - width: calc(100% - 62rpx); - margin: 0 31rpx; - line-height: 96rpx; - text-align: center; - background: linear-gradient(270deg, #FC8D55 0%, #FF4948 100%); - border-radius: 48rpx; - font-weight: 600; - font-size: 35rpx; - color: #fff; - } - </style> \ No newline at end of file + </view> --> + <view + class="mt-27 shadow1 border2 ml-29 mr-29 pt-31 br-15" + style="height: 511rpx" + > + <view class="flex mlr-o tabs mb-40"> + <view + v-for="(item, index) in tabs" + :key="index" + :class="['tab-item', currentTab === index ? 'active' : '']" + @click="handleTabClick(index)" + > + {{ item }} + </view> + </view> + <view + ref="chartRef" + id="chart" + style="width: 100%; height: 405rpx" + ></view> + </view> + <view class="fs-35 font-bold mt-38 ml-27"> 问题类型排名 </view> + <view class="ml-29 mr-29 mt-27 shadow1 pt-31 border2 pl-38 pr-38 br-15"> + <uni-data-select v-model="value1" :localdata="range"></uni-data-select> + <view class="fs-23"> + <view class="flex a-center mb-38" v-for="(item, idx) in typeRankList" :key="idx"> + <view class="w-130 color3">{{ item.typeName }}</view> + <u-line-progress + :percentage="item.percent" + inactiveColor="#EEEEEE" + :activeColor="item.gradientColor" + height="38rpx" + > + <text class="u-percentage-slot pr-19 fs-23">{{ item.count }}</text> + </u-line-progress> + </view> + </view> + </view> + <view class="fs-35 font-bold mt-38 ml-27"> 评价占比 </view> + <view + class="ml-29 mr-29 mt-27 shadow1 border2 br-15" + style="height: 417rpx" + > + <view class="flex pl-38 pr-38"> + <view + ref="rateChartRef" + id="rateChart" + style="width: 288rpx; height: 417rpx" + ></view> + <view style="width: 46rpx"></view> + <view class="flex1 pt-54"> + <view class="mb-27"> + <view class="flex a-center j-between mb-13"> + <text class="fs-23">非常满意</text> + <text class="fs-23 color12">45%</text> + </view> + <view class="progress-bar"> + <view + class="progress-inner very-satisfied" + style="width: 45%" + ></view> + </view> + </view> + <view class="mb-27"> + <view class="flex a-center j-between mb-13"> + <text class="fs-23">满意</text> + <text class="fs-23 color12">20%</text> + </view> + <view class="progress-bar"> + <view class="progress-inner satisfied" style="width: 20%"></view> + </view> + </view> + <view class="mb-27"> + <view class="flex a-center j-between mb-13"> + <text class="fs-23">一般</text> + <text class="fs-23 color12">30%</text> + </view> + <view class="progress-bar"> + <view class="progress-inner normal" style="width: 30%"></view> + </view> + </view> + <view class="mb-27"> + <view class="flex a-center j-between mb-13"> + <text class="fs-23">不满意</text> + <text class="fs-23 color12">5%</text> + </view> + <view class="progress-bar"> + <view class="progress-inner unsatisfied" style="width: 5%"></view> + </view> + </view> + </view> + </view> + </view> + <view class="h-40 safe-b"></view> + <!-- 选择服务社区 --> + <u-popup + :show="selectPopup" + round="16rpx" + @close="selectPopup = false" + :safe-area-inset-bottom="false" + @open="openSelectPopup" + > + <view class="relative pb-40"> + <image + @tap.stop="selectPopup = false" + src="@/static/closeImg.png" + class="w-35 h-35 absolute" + style="right: 31rpx; top: 46rpx" + /> + <view class="txt-center pt-38 pb-40 fs-35 lh-48 font-bold" + >请选择服务社区</view + > + <view + class="flex a-center j-between txt-center py-10 fs-27 font-bold bgColor1" + > + <view v-if="hasTier(2)" class="flex1">区县</view> + <view v-if="hasTier(3)" class="flex1">街道</view> + <view v-if="hasTier(4)" class="flex1">社区</view> + </view> + <view class="mb-20"> + <picker-view + :value="value" + @change="bindChange" + class="picker-view" + immediate-change + > + <picker-view-column v-if="hasTier(2)"> + <view + class="item" + v-for="(item, index) in regionTree" + :key="index" + > + {{ item.name }} + </view> + </picker-view-column> + <picker-view-column v-if="hasTier(3)"> + <view + class="item" + v-for="(item, index) in getStreets()" + :key="index" + > + {{ item.name }} + </view> + </picker-view-column> + <picker-view-column v-if="hasTier(4)"> + <view + class="item" + v-for="(item, index) in getCommunities()" + :key="index" + > + {{ item.name }} + </view> + </picker-view-column> + </picker-view> + </view> + <view class="submitBtn" @click="chooseCommunity">确认</view> + </view> + </u-popup> + </view> +</template> + +<script> +import * as echarts from "echarts"; +import { + getRegionTree, + getStaticsPartOne, + getStaticsPartTwo, + getStaticsPartThree, +} from "./service.js"; +export default { + data() { + return { + userInfo: {}, + address: "", + value: [0, 0, 0], + confirmValue: [0, 0, 0], + regionTree: [], // 区域树数据 + value1: 0, + selectPopup: false, + range: [ + { + value: 0, + text: "排名前五", + }, + { + value: 1, + text: "排名前十", + }, + { + value: 2, + text: "所有排名", + }, + ], + chart: null, + rateChart: null, + tabs: ["近7天", "近15天", "近30天"], + currentTab: 0, + chartData: { + dates: [ + "2025\n04.17", + "2025\n04.18", + "2025\n04.19", + "2025\n04.20", + "2025\n04.21", + "2025\n04.22", + "2025\n04.23", + ], + demands: [80, 170, 240, 70, 130, 90, 160], + completed: [40, 130, 200, 30, 90, 50, 110], + }, + rateData: [ + { + value: 45, + name: "非常满意", + itemStyle: { + color: new echarts.graphic.LinearGradient(1, 0, 0, 0, [ + { + offset: 0, + color: "#FF8064", + }, + { + offset: 1, + color: "#FF4934", + }, + ]), + }, + }, + { + value: 20, + name: "满意", + itemStyle: { + color: new echarts.graphic.LinearGradient(1, 0, 0, 0, [ + { + offset: 0, + color: "#05DEE1", + }, + { + offset: 1, + color: "#02BAC0", + }, + ]), + }, + }, + { + value: 30, + name: "一般", + itemStyle: { + color: new echarts.graphic.LinearGradient(1, 0, 0, 0, [ + { + offset: 0, + color: "#7DC4FF", + }, + { + offset: 1, + color: "#4791FF", + }, + ]), + }, + }, + { + value: 5, + name: "不满意", + itemStyle: { + color: new echarts.graphic.LinearGradient(1, 0, 0, 0, [ + { + offset: 0, + color: "#FFD364", + }, + { + offset: 1, + color: "#FEA834", + }, + ]), + }, + }, + ], + statisticsData: { + satisfaction: { + total: 0, + month: 0, + compare: 0, + }, + demands: { + total: 0, + month: 0, + compare: 0, + }, + processTime: { + total: 0, + month: 0, + compare: 0, + }, + status: { + processing: 0, + reviewing: 0, + delayed: 0, + completed: 0, + }, + overtime: { + total: 0, + month: 0, + compare: 0, + }, + completionRate: { + total: 0, + month: 0, + compare: 0, + }, + }, + currentAreaId: '', + currentTier: -1, + typeRankList: [], + }; + }, + onLoad() { + this.userInfo = uni.getStorageSync("userInfo"); + this.initRegionData(); + }, + mounted() { + this.$nextTick(() => { + this.initChart(); + this.initRateChart(); + }); + }, + methods: { + clearAddress() { + this.address = ""; + this.value = [0, 0, 0]; + this.confirmValue = [0, 0, 0]; + this.currentAreaId = ''; + this.currentTier = -1; + this.getStatisticsData("", -1); + this.getChartData(1); + this.getTypeRankData(); + }, + //初始化区域数据 + initRegionData() { + getRegionTree().then((res) => { + if (res.code === 200) { + this.regionTree = [{name: '全部', id: 'all', tier: 2, children: []}, ...(res.data || [])]; + this.value = [0, 0, 0]; + this.confirmValue = [0, 0, 0]; + this.address = "全部"; + this.currentAreaId = ''; + this.currentTier = -1; + this.getStatisticsData("", -1); + this.getChartData(1); + this.getTypeRankData(); + } + }); + }, + // 获取当前选中的区域对象 + getSelectedRegion() { + // 区县 + const county = this.regionTree[this.value[0]]; + if (!county || county.id === "all") return { id: "", tier: -1 }; + // 有街道 + const streets = + county.children && county.children.filter((c) => c && c.tier === 3); + if (streets && streets.length) { + const street = streets[this.value[1] - 1]; // -1 因为有"全部"选项 + if (!street || this.value[1] === 0 || street.id === "all") + return { id: county.id, tier: county.tier }; + const communities = + street.children && street.children.filter((c) => c && c.tier === 4); + if (communities && communities.length) { + const community = communities[this.value[2] - 1]; + if (!community || this.value[2] === 0 || community.id === "all") + return { id: street.id, tier: street.tier }; + return { id: community.id, tier: community.tier }; + } + return { id: street.id, tier: street.tier }; + } + // 区县下直接有社区 + const communities = + county.children && county.children.filter((c) => c && c.tier === 4); + if (communities && communities.length) { + const community = communities[this.value[1] - 1]; + if (!community || this.value[1] === 0 || community.id === "all") + return { id: county.id, tier: county.tier }; + return { id: community.id, tier: community.tier }; + } + // 只选了区县 + return { id: county.id, tier: county.tier }; + }, + // 根据value设置地址显示 + setAddressByValue() { + const names = []; + const county = this.regionTree[this.value[0]]; + if (!county) { + this.address = "全部"; + return; + } + + // 如果选中区县的全部 + if (county.id === "all") { + this.address = "全部"; + return; + } + + names.push(county.name); + + // 检查是否有街道 + const streets = + county.children && county.children.filter((c) => c && c.tier === 3); + if (streets && streets.length) { + const street = streets[this.value[1] - 1]; // -1 因为有"全部"选项 + if (street && street.id !== "all") { + names.push(street.name); + + // 检查街道下是否有社区 + const communities = + street.children && street.children.filter((c) => c && c.tier === 4); + if (communities && communities.length) { + const community = communities[this.value[2] - 1]; + if (community && community.id !== "all") { + names.push(community.name); + } + } + } + } else { + // 区县下直接有社区 + const communities = + county.children && county.children.filter((c) => c && c.tier === 4); + if (communities && communities.length) { + const community = communities[this.value[1] - 1]; + if (community && community.id !== "all") { + names.push(community.name); + } + } + } + + this.address = names.join("-"); + }, + //选择服务社区 + chooseCommunity() { + this.confirmValue = [...this.value]; + this.setAddressByValue(); + const { id, tier } = this.getSelectedRegion(); + this.currentAreaId = id; + this.currentTier = tier; + this.selectPopup = false; + this.getStatisticsData(id, tier); + this.getChartData(this.currentTab + 1); + this.getTypeRankData(); + }, + // 切换社区 + bindChange(e) { + const newValue = e.detail.value; + // 级联重置逻辑 + if (newValue[0] !== this.value[0]) { + newValue[1] = 0; + newValue[2] = 0; + } else if (newValue[1] !== this.value[1]) { + newValue[2] = 0; + } + this.value = newValue; + }, + openSelectPopup() { + this.value = this.confirmValue; + }, + handleTabClick(index) { + this.currentTab = index; + this.getChartData(index + 1); + }, + initChart() { + // 在 H5 端使用 document.getElementById + // 在小程序端使用 this.$refs.chartRef + const chartDom = document.getElementById("chart") || this.$refs.chartRef; + this.chart = echarts.init(chartDom); + this.updateChart(); + }, + updateChart() { + const option = { + color: ["#FF7B7B", "#FFB75B"], + tooltip: { + trigger: "axis", + axisPointer: { + type: "shadow", + }, + }, + legend: { + data: ["诉求单量", "诉求办结数"], + bottom: "0", + itemGap: uni.upx2px(60), + selectedMode: true, + }, + grid: { + left: "3%", + right: "4%", + bottom: "15%", + top: "3%", + containLabel: true, + }, + xAxis: { + type: "category", + data: this.chartData.dates, + axisLine: { + lineStyle: { + color: "#E5E5E5", + }, + }, + axisTick: { + show: false, + }, + axisLabel: { + color: "#888888", + fontSize: uni.upx2px(19), + lineHeight: uni.upx2px(23), + formatter: function (value) { + return value.split("\\n").join("\n"); + }, + }, + }, + yAxis: { + type: "value", + splitLine: { + lineStyle: { + type: "dashed", + color: "#fff", + }, + }, + axisLine: { + show: false, + }, + axisTick: { + show: false, + }, + }, + series: [ + { + name: "诉求单量", + type: "bar", + barWidth: uni.upx2px(38), + itemStyle: { + borderRadius: [20, 20, 20, 20], + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { + offset: 0, + color: "#FF807E", + }, + { + offset: 1, + color: "#FF4948", + }, + ]), + }, + data: this.chartData.demands, + }, + { + name: "诉求办结数", + type: "line", + smooth: true, + symbol: "circle", + symbolSize: 8, + itemStyle: { + color: "#FFB75B", + borderWidth: 2, + borderColor: "#fff", + shadowColor: "#FB9A0E", + shadowBlur: 8, + shadowOffsetY: 4, + }, + lineStyle: { + width: 2, + curveness: 0.3, + }, + data: this.chartData.completed, + }, + ], + }; + this.chart && this.chart.setOption(option); + }, + initRateChart() { + const chartDom = + document.getElementById("rateChart") || this.$refs.rateChartRef; + this.rateChart = echarts.init(chartDom); + this.updateRateChart(); + }, + updateRateChart() { + const option = { + tooltip: { + trigger: "item", + confine: true, + // formatter: '{b}: {c}%', + backgroundColor: "rgba(255, 255, 255, 0.9)", + borderColor: "#FFE0E0", + borderWidth: 1, + textStyle: { + color: "#666666", + fontSize: 12, + }, + padding: [8, 12], + }, + series: [ + { + name: "评价占比", + type: "pie", + radius: ["55%", "100%"], + center: ["50%", "50%"], + avoidLabelOverlap: false, + label: { + show: false, + }, + labelLine: { + show: false, + }, + emphasis: { + scale: false, + scaleSize: 0, + }, + data: this.rateData, + }, + ], + }; + this.rateChart && this.rateChart.setOption(option); + }, + // 添加获取统计数据的方法 + async getStatisticsData(areaId = "", tier = -1) { + try { + const res = await getStaticsPartOne({ + areaId, + tier, + }); + if (res.code === 200) { + this.statisticsData = { + satisfaction: { + total: res.data.satisfactionRate ?? 0, + month: res.data.thisMonthSatisfactionRate ?? 0, + compare: res.data.lastMonthCompareSatisfactionRate ?? 0, + }, + demands: { + total: res.data.allTotal ?? 0, + month: res.data.thisMonthTotal ?? 0, + compare: res.data.lastMonthCompareTotal ?? 0, + }, + processTime: { + total: res.data.averageTime ?? 0, + month: res.data.thisMonthAverageTime ?? 0, + compare: res.data.lastMonthCompareAverageTime ?? 0, + }, + status: { + processing: res.data.nowTransactTotal ?? 0, + reviewing: res.data.auditTransactTotal ?? 0, + delayed: res.data.postponeTransactTotal ?? 0, + completed: res.data.completeTransactTotal ?? 0, + }, + overtime: { + total: res.data.overtimeTransactTotal ?? 0, + month: res.data.thisMonthOvertimeTransactTotal ?? 0, + compare: res.data.lastMonthOvertimeTransactCompareTotal ?? 0, + }, + completionRate: { + total: 0, + month: 0, + compare: 0, + }, + }; + // 更新图表数据 + this.updateChart(); + this.updateRateChart(); + } + } catch (error) { + console.error("获取统计数据失败:", error); + } + }, + hasTier(tier) { + // tier=2: 区县始终有 + if (tier === 2) return true; + // tier=3: 当前区县children里有tier=3 + if (tier === 3) { + const county = this.regionTree[this.value[0]]; + return ( + county && + Array.isArray(county.children) && + county.children.some((c) => c && c.tier === 3) + ); + } + // tier=4: 当前区县children里有tier=4,或街道children里有tier=4 + if (tier === 4) { + const county = this.regionTree[this.value[0]]; + if (!county || !Array.isArray(county.children)) return false; + // 区县下直接有社区 + if (county.children.some((c) => c && c.tier === 4)) return true; + // 区县下有街道,街道下有社区 + const street = county.children[this.value[1]]; + return ( + street && + Array.isArray(street.children) && + street.children.some((c) => c && c.tier === 4) + ); + } + return false; + }, + getStreets() { + const county = this.regionTree[this.value[0]]; + if (!county || !Array.isArray(county.children)) return []; + // 只返回tier=3的 + const streets = county.children.filter((c) => c && c.tier === 3); + return streets.length + ? [{ name: "全部", id: "all", tier: 3, children: [] }, ...streets] + : []; + }, + getCommunities() { + const county = this.regionTree[this.value[0]]; + if (!county || !Array.isArray(county.children)) return []; + // 区县下直接有社区 + const communities = county.children.filter((c) => c && c.tier === 4); + if (communities.length) + return [{ name: "全部", id: "all", tier: 4 }, ...communities]; + // 区县下有街道,街道下有社区 + const street = county.children[this.value[1]]; + if (street && Array.isArray(street.children)) { + const comms = street.children.filter((c) => c && c.tier === 4); + if (comms.length) + return [{ name: "全部", id: "all", tier: 4 }, ...comms]; + } + return []; + }, + async getChartData(timeType = 1) { + try { + const res = await getStaticsPartTwo({ + areaId: this.currentAreaId, + tier: this.currentTier, + timeType + }); + if (res.code === 200 && res.data) { + // 转换数据格式 + const dates = res.data.map(item => item.time.replace(/-/g, '\n').replace(/\n(\d{2})$/, '.$1')); + const demands = res.data.map(item => item.allTotal); + const completed = res.data.map(item => item.completeTotal); + this.chartData = { + dates, + demands, + completed + }; + this.updateChart(); + } + } catch (e) { + console.error('获取图表数据失败', e); + } + }, + async getTypeRankData() { + let rank; + if (this.value1 === 0) rank = 5; + else if (this.value1 === 1) rank = 10; + // value1 === 2 时不传rank + const params = { + areaId: this.currentAreaId, + tier: this.currentTier + }; + if (rank) params.rank = rank; + try { + const res = await getStaticsPartThree(params); + console.log(JSON.stringify(res.data)); + + if (res.code === 200 && Array.isArray(res.data)) { + // 计算最大值 + const max = Math.max(...res.data.map(item => item.allTotal), 1); + // 处理数据,增加percent字段 + this.typeRankList = res.data.map((item, idx) => ({ + typeName: item.name, + count: item.allTotal, + percent: Math.round(item.allTotal / max * 100), + gradientColor: 'linear-gradient(270deg, #FF4934 0%, #FF8064 100%)' + })); + } + } catch (e) { + console.error('获取问题类型排名失败', e); + } + }, + }, + watch: { + value1() { + this.getTypeRankData(); + } + }, +}; +</script> + +<style scoped lang="scss"> +/deep/.uni-select { + width: 231rpx; + height: 65rpx; + margin: 0 auto; + margin-bottom: 38rpx; + font-size: 27rpx; + color: #797f81; + border-color: #e5e5e5; + border-radius: 33rpx; + padding: 0 31rpx 0 40rpx; + + .uni-select__input-text { + color: #797f81; + } +} + +.content { + background: linear-gradient( + 180deg, + #ffdcdb 0%, + rgba(255, 255, 255, 0) 100rpx, + #fff 100% + ); +} + +.gap25 { + gap: 25rpx; +} + +.tabs { + width: 412rpx; + background-color: #fff1f1; + border-radius: 30rpx; + height: 65rpx; + line-height: 65rpx; + font-size: 27rpx; + position: relative; + overflow: hidden; +} + +.tab-item { + color: #797f81; + flex: 1; + text-align: center; + font-weight: 400; + height: 54rpx; + line-height: 54rpx; + border-radius: 27rpx; + margin: 6rpx; + position: relative; + z-index: 1; + transform: translateZ(0); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + + &.active { + background-color: #fff; + color: #ff4948; + font-weight: 600; + box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1); + transform: scale(1.02); + } +} + +.chart-wrapper { + background: #fff; + border-radius: 20rpx; + padding: 20rpx; +} + +.color1 { + color: #666565; +} + +.color2 { + color: #c1c1c1; +} + +.color3 { + color: #666666; +} + +.color4 { + color: #ff4948; +} + +.color5 { + color: #696969; +} + +.color6 { + color: #a4a4a4; +} + +.color7 { + color: #a7a7a7; +} + +.color8 { + color: #0fb269; +} + +.color9 { + color: #ff5600; +} + +.color10 { + color: #161998; +} + +.color11 { + color: #08ad60; +} + +.color12 { + color: #9c9c9e; +} + +.bgColor1 { + background-color: #fff; +} + +.bgColor2 { + background-color: #fff1f4; +} + +.bgColor3 { + background-color: #fff8f4; +} + +.bgColor4 { + background-color: #f4f5ff; +} + +.bgColor5 { + background-color: #f1fff8; +} + +.border1 { + border: 2rpx solid #d9d9d9; +} + +.border2 { + border: 2rpx solid #ffe0e0; +} + +.border3 { + border: 4rpx solid #ff4948; + box-sizing: border-box; + box-shadow: 0rpx 4rpx 8rpx 0rpx rgba(255, 73, 72, 0.5); +} + +.border4 { + border: 2rpx solid #ffffff; +} + +.shadow1 { + box-shadow: 0rpx 0rpx 27rpx 0rpx rgba(0, 0, 0, 0.1); +} + +.shadow2 { + box-shadow: 0rpx 0rpx 15rpx 0rpx rgba(0, 0, 0, 0.1); +} + +.progress-bar { + width: 100%; + height: 8rpx; + background: #eeeeee; + border-radius: 4rpx; + overflow: hidden; +} + +.progress-inner { + height: 100%; + border-radius: 4rpx; + transition: width 0.3s ease-in-out; + + &.very-satisfied { + background: linear-gradient(270deg, #ff8064 0%, #ff4934 100%); + } + + &.satisfied { + background: linear-gradient(270deg, #05dee1 0%, #02bac0 100%); + } + + &.normal { + background: linear-gradient(270deg, #7dc4ff 0%, #4791ff 100%); + } + + &.unsatisfied { + background: linear-gradient(270deg, #ffd364 0%, #fea834 100%); + } +} + +.picker-view { + height: 460rpx; + font-size: 35rpx; +} + +/deep/.picker-view { + margin: 0 auto; + + .item { + text-align: center; + font-family: PingFangSC, PingFang SC; + font-weight: 600; + font-size: 36rpx; + color: #333333; + line-height: 50rpx; + } +} + +.submitBtn { + width: calc(100% - 62rpx); + margin: 0 31rpx; + line-height: 96rpx; + text-align: center; + background: linear-gradient(270deg, #fc8d55 0%, #ff4948 100%); + border-radius: 48rpx; + font-weight: 600; + font-size: 35rpx; + color: #fff; +} +</style> diff --git a/H5/pages/statistics/service.js b/H5/pages/statistics/service.js index fb3db85..77cb17c 100644 --- a/H5/pages/statistics/service.js +++ b/H5/pages/statistics/service.js @@ -1,9 +1,26 @@ import request from '@/utils/request.js' -// 获取区县-街道-社区树 -export const getRegionTree =()=>{ - return request.get(`/api/huacheng-sangeshenbian/bc-region/regionTree-applet`) +// 获取统计分析-第一部分(处理满意率+诉求单量统计上面部分) +export const getStaticsPartOne = (params) => { + return request.post(`/api/huacheng-sangeshenbian/applet/statics/part-one`,params) } +// 获取统计分析-第二部分(处理满意率+诉求单量统计下面部分) +export const getStaticsPartTwo = (params) => { + return request.post(`/api/huacheng-sangeshenbian/applet/statics/part-two`,params) +} + +// 获取统计分析-第三部分(党员申请+编辑党员信息+党员信息详情) +export const getStaticsPartThree = (params) => { + return request.post(`/api/huacheng-sangeshenbian/applet/statics/part-three`,params) +} + +// 获取区域树 +export const getRegionTree = (params) => { + return request.get(`/api/huacheng-sangeshenbian/applet/statics/region-tree`,params) +} + + + // 党员申请 export const apply =(params)=>{ return request.post(`/api/huacheng-sangeshenbian/applet/party-member/apply`,params) diff --git a/H5/static/home/Group 2@2x.png b/H5/static/home/Group 2@2x.png new file mode 100644 index 0000000..aacba4b --- /dev/null +++ b/H5/static/home/Group 2@2x.png Binary files differ diff --git a/management/config/env.ts b/management/config/env.ts index b5c419d..106b31d 100644 --- a/management/config/env.ts +++ b/management/config/env.ts @@ -1,6 +1,6 @@ export default { dev: { - SERVER_URL: 'http://192.168.110.188:6194', + SERVER_URL: 'http://192.168.110.106:6194', // SERVER_URL: 'https://huacheng.psciio.com', }, test: { diff --git a/management/config/routes.ts b/management/config/routes.ts index 019cc93..67a18dc 100644 --- a/management/config/routes.ts +++ b/management/config/routes.ts @@ -34,6 +34,12 @@ ], }, { + name: '统计分析', + path: '/statistics', + component: './statistics/index', + // access: '/system_setting/position_management', + }, + { path: '/setting', // layout: false, name: '系统设置', diff --git a/management/package.json b/management/package.json index e7151bb..2b50278 100644 --- a/management/package.json +++ b/management/package.json @@ -31,7 +31,7 @@ "not ie <= 10" ], "dependencies": { - "@ant-design/charts": "^2.1.2", + "@ant-design/charts": "^2.3.0", "@ant-design/icons": "^4.8.0", "@ant-design/plots": "^2.2.6", "@ant-design/pro-components": "^2.6.35", @@ -42,6 +42,8 @@ "braft-editor": "^2.3.9", "classnames": "^2.3.2", "crypto-js": "^4.2.0", + "echarts": "^5.6.0", + "echarts-for-react": "^3.0.2", "moment": "^2.29.4", "omit.js": "^2.0.2", "rc-menu": "^9.8.2", diff --git a/management/src/pages/statistics/components/addAndEdit.jsx b/management/src/pages/statistics/components/addAndEdit.jsx new file mode 100644 index 0000000..a05e3e7 --- /dev/null +++ b/management/src/pages/statistics/components/addAndEdit.jsx @@ -0,0 +1,72 @@ +import { Form, Input, Modal,Button } from 'antd'; +import { forwardRef, useImperativeHandle, useState } from 'react'; + +const formItemLayout = { + labelCol: { span: 7 }, + wrapperCol: { span: 12 }, +}; + +const AddEditView = ({ visible, onSave, onUpdate, onCancel }, ref) => { + const [form] = Form.useForm(); + const [editData, setEditData] = useState({}); + const [rolesList, setRolesList] = useState(); + + /** + * 确定按钮事件 + */ + const okHandle = () => { + form.validateFields().then((values) => { + if (editData.id) { + values.id = editData.id; + onUpdate(values); + } else { + onSave(values); + } + }); + }; + + useImperativeHandle(ref, () => { + return { + refreshData: (data) => { + form.resetFields(); + form.setFieldsValue(data); + setEditData(data); + }, + clean: () => { + form.resetFields(); + }, + }; + }); + + return ( + <Modal + getContainer={false} + width="25%" + destroyOnClose + title={editData.id ? '编辑职位' : '添加职位'} + open={visible} + onCancel={() => onCancel(false)} + footer={[ + <Button key="back" onClick={() => onCancel(false)}> + 关闭 + </Button>, + <Button key="submit" type="primary" onClick={okHandle}> + 确认 + </Button> + ]} + > + <Form layout="horizontal" {...formItemLayout} form={form} initialValues={{ isAuctioneer: 1 }}> + <Form.Item + name="name" + required + label="职位名称" + rules={[{ required: true, message: '请输入职位名称' }]} + > + <Input placeholder="请输入职位名称" /> + </Form.Item> + </Form> + </Modal> + ); +}; + +export default forwardRef(AddEditView); diff --git a/management/src/pages/statistics/index.jsx b/management/src/pages/statistics/index.jsx new file mode 100644 index 0000000..efee2bc --- /dev/null +++ b/management/src/pages/statistics/index.jsx @@ -0,0 +1,558 @@ +import { buildProTableDataSource, sendRequest, showDelConfirm } from '@/utils/antdUtils'; +import { PageContainer } from '@ant-design/pro-components'; +import { Button, InputNumber, Select, Space, Form, Card, Row, Col, Statistic, DatePicker } from 'antd'; +import { useEffect, useState } from 'react'; +import { ArrowUpOutlined, ArrowDownOutlined } from '@ant-design/icons'; +import { Access, useAccess } from 'umi'; +import AddAndEdit from './components/addAndEdit'; +import { getCommunityList, getNextRegion, getStatisticsData } from './service'; +import ReactECharts from 'echarts-for-react'; +import moment from 'moment'; + +// 同比趋势组件 +const Trend = ({ value }) => { + if (value > 0) { + return ( + <span style={{ color: 'red', marginLeft: 4 }}> + <ArrowUpOutlined /> {Math.abs(value)}% + </span> + ); + } + if (value < 0) { + return ( + <span style={{ color: 'green', marginLeft: 4 }}> + <ArrowDownOutlined /> {Math.abs(value)}% + </span> + ); + } + return <span style={{ marginLeft: 4 }}>0%</span>; +}; + +const statistics = () => { + const [adminLevel, setAdminLevel] = useState(JSON.parse(localStorage.getItem('userInfo')).accountLevel); + const [form] = Form.useForm(); + const [districtOptions, setDistrictOptions] = useState([]); + const [streetOptions, setStreetOptions] = useState([]); + const [communityOptions, setCommunityOptions] = useState([]); + const [dateRange, setDateRange] = useState([]); + const [loading, setLoading] = useState(false); + const [rankType, setRankType] = useState('top5'); + + // 统计数据 + const [stats, setStats] = useState({ + total: 0, + month: 0, + totalMonthRate: 0, + processing: 0, + reviewing: 0, + delayed: 0, + finished: 0, + overtime: 0, + overtimeMonth: 0, + overtimeMonthRate: 0, + avgTime: 0, + avgTimeMonth: 0, + avgTimeRate: 0, + satisfaction: 0, + satisfactionMonth: 0, + satisfactionRate: 0, + }); + + // 图表数据 + const [chartData, setChartData] = useState([]); + const [allTypeData, setAllTypeData] = useState([]); + const [pieData, setPieData] = useState([]); + + // 诉求单量统计图表配置 + const echartsOption = { + tooltip: { + trigger: 'axis', + }, + legend: { + data: ['诉求单量', '诉求办结数'], + }, + grid: { + left: '3%', + right: '3%', + bottom: '10%', + containLabel: true, + }, + dataZoom: [ + { + type: 'slider', + show: true, + startValue: 0, + endValue: 10, + height: 12, + bottom: 0, + showDetail: false, + showDataShadow: false, + fillerColor: '#dbdee5', + borderColor: 'transparent', + zoomLock: true, + brushSelect: false, + handleStyle: { + opacity: 0 + } + }, + { + type: "inside", + zoomOnMouseWheel: false, + moveOnMouseMove: true, + moveOnMouseWheel: true, + }, + ], + xAxis: { + type: 'category', + data: chartData.map(item => item.date), + axisLabel: { + interval: 'auto', + } + }, + yAxis: [ + { + type: 'value', + name: '诉求单量', + min: 0, + }, + { + type: 'value', + name: '诉求办结数', + min: 0, + }, + ], + series: [ + { + name: '诉求单量', + type: 'bar', + data: chartData.map(item => item.count), + yAxisIndex: 0, + itemStyle: { color: '#3b7cff' }, + barWidth: 30, + }, + { + name: '诉求办结数', + type: 'line', + data: chartData.map(item => item.finish), + yAxisIndex: 1, + itemStyle: { color: '#3bcfcf' }, + lineStyle: { width: 2 }, + smooth: true, + }, + ], + }; + + // 问题类型排名图表配置 + const typeRankOption = { + tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } }, + grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true }, + dataZoom: [ + { + type: 'slider', + show: true, + startValue: 0, + endValue: 4, + bottom: 0, + showDetail: false, + showDataShadow: false, + height: '100%', + width: 10, + fillerColor: '#dbdee5', + borderColor: 'transparent', + zoomLock: true, + orient: 'vertical', + brushSelect: false, + handleStyle: { + opacity: 0 + } + }, + { + type: "inside", + zoomOnMouseWheel: false, + moveOnMouseMove: true, + moveOnMouseWheel: true, + orient: 'vertical' + }, + ], + xAxis: { type: 'value', boundaryGap: [0, 0.01] }, + yAxis: { type: 'category', data: allTypeData.map(item => item.name) }, + series: [ + { + name: '数量', + type: 'bar', + data: allTypeData.map(item => item.value), + itemStyle: { color: '#4a90e2' }, + barWidth: 20, + label: { show: true, position: 'right' }, + }, + ], + }; + + // 问题评价占比图表配置 + const pieOption = { + tooltip: { trigger: 'item', formatter: '{b}: {c} ({d}%)' }, + legend: { orient: 'vertical', left: 'right', data: pieData.map(i => i.name) }, + color: ['#4a90e2', '#6dd400', '#f5a623', '#f44336'], + series: [ + { + name: '评价占比', + type: 'pie', + radius: ['50%', '70%'], + avoidLabelOverlap: false, + label: { show: false, position: 'center' }, + emphasis: { label: { show: true, fontSize: 18, fontWeight: 'bold' } }, + labelLine: { show: false }, + data: pieData, + }, + ], + }; + + // 处理表单和rank筛选,组装参数并请求接口 + const handleSearch = async (values) => { + setLoading(true); + let time = ''; + if (dateRange && dateRange.length === 2) { + time = `${dateRange[0].format('YYYY-MM-DD')} - ${dateRange[1].format('YYYY-MM-DD')}`; + } + const params = { + cityCode: values.cityCode, + districtCode: values.districtId, + streetId: values.streetId, + communityId: values.communityId, + time, + rank: rankType === 'all' ? undefined : rankType.replace('top', ''), + }; + try { + const res = await getStatisticsData(params); + const data = res.data.analyticStatisticsOneVo; + setStats({ + total: data.allTotal, + month: data.thisMonthTotal, + totalMonthRate: data.lastMonthCompareTotal, + processing: data.nowTransactTotal, + reviewing: data.auditTransactTotal, + delayed: data.postponeTransactTotal, + finished: data.completeTransactTotal, + overtime: data.overtimeTransactTotal, + overtimeMonth: data.thisMonthOvertimeTransactTotal, + overtimeMonthRate: data.lastMonthOvertimeTransactCompareTotal, + avgTime: data.averageTime, + avgTimeMonth: data.thisMonthAverageTime, + avgTimeRate: data.lastMonthCompareAverageTime, + satisfaction: data.satisfactionRate, + satisfactionMonth: data.thisMonthSatisfactionRate, + satisfactionRate: data.lastMonthCompareSatisfactionRate, + }); + setChartData((res.data.analyticStatisticsTwoVos || []).map(item => ({ + date: item.time, + count: item.allTotal, + finish: item.completeTotal, + }))); + setAllTypeData((res.data.analyticStatisticsThreeVos || []).map(item => ({ + name: item.name, + value: item.allTotal, + }))); + const fourVo = res.data.analyticStatisticsFourVo || {}; + setPieData([ + { value: fourVo.greatSatisfactionRate, name: '非常满意' }, + { value: fourVo.satisfactionRate, name: '满意' }, + { value: fourVo.generalSatisfactionRate, name: '一般' }, + { value: fourVo.dissatisfactionRate, name: '不满意' }, + ]); + } catch (e) { + // 错误处理 + } + setLoading(false); + }; + + // rankType变化时自动触发表单查询 + useEffect(() => { + form.submit(); + }, [rankType]); + + useEffect(() => { + getCommunityList().then(res => { + const { bcRegions, comActs, comStreets } = res.data; + if (adminLevel <= 2) { + setDistrictOptions(bcRegions); + return; + } + if (adminLevel <= 3) { + setStreetOptions(comStreets); + return; + } + setCommunityOptions(comActs); + }); + }, [adminLevel]); + + // 处理区县选择 + const handleDistrictChange = async (value) => { + if (!value) { + setStreetOptions([]); + setCommunityOptions([]); + form.setFieldsValue({ streetId: undefined, communityId: undefined }); + return; + } + const res = await getNextRegion({ id: value, type: 1 }); + setStreetOptions(res.data || []); + setCommunityOptions([]); + form.setFieldsValue({ streetId: undefined, communityId: undefined }); + }; + + // 处理街道选择 + const handleStreetChange = async (value) => { + if (!value) { + setCommunityOptions([]); + form.setFieldsValue({ communityId: undefined }); + return; + } + const res = await getNextRegion({ id: value, type: 2 }); + setCommunityOptions(res.data || []); + form.setFieldsValue({ communityId: undefined }); + }; + + // 根据管理员级别获取可用的筛选项 + const getFilterItems = () => { + const baseItems = [ + { + name: 'communityId', + label: '社区', + component: <Select + style={{ width: 200 }} + options={communityOptions} + placeholder="请选择社区" + fieldNames={{ label: 'name', value: 'communityId' }} + disabled={!form.getFieldValue('streetId')} + />, + }, + ]; + + if (adminLevel <= 3) { + baseItems.unshift({ + name: 'streetId', + label: '街道', + component: <Select + style={{ width: 200 }} + options={streetOptions} + placeholder="请选择街道" + fieldNames={{ label: 'name', value: 'streetId' }} + onChange={handleStreetChange} + disabled={!form.getFieldValue('districtId')} + />, + }); + } + + if (adminLevel <= 2) { + baseItems.unshift({ + name: 'districtId', + label: '区县', + component: <Select + style={{ width: 200 }} + options={districtOptions} + placeholder="请选择区县" + fieldNames={{ label: 'regionName', value: 'regionCode' }} + onChange={handleDistrictChange} + />, + }); + } + + return baseItems; + }; + + return ( + <div> + <PageContainer header={{ + breadcrumb: {}, + }} + title={'统计分析'} + > + {/* 筛选表单 */} + <Card style={{ marginBottom: 24 }}> + <Form + form={form} + layout="inline" + style={{ marginBottom: 24 }} + onFinish={handleSearch} + > + {getFilterItems().map((item) => ( + <Form.Item + key={item.name} + name={item.name} + label={item.label} + > + {item.component} + </Form.Item> + ))} + <Form.Item> + <Space> + <Button type="primary" onClick={() => form.submit()}> + 查询 + </Button> + <Button onClick={() => { + form.resetFields(); + setStreetOptions([]); + setCommunityOptions([]); + }}> + 重置 + </Button> + </Space> + </Form.Item> + </Form> + </Card> + + {/* 标题 */} + <div style={{ fontWeight: 600, fontSize: 18, marginBottom: 16, borderLeft: '4px solid #3b7cff', paddingLeft: 8 }}> + 诉求单量统计 + </div> + + {/* 统计卡片区 */} + <Row gutter={[16, 16]} wrap={false}> + <Col flex="1"> + <Card style={{ height: 120, display: 'flex', flexDirection: 'column', justifyContent: 'center' }}> + <Statistic title="诉求单量总计" value={stats.total} /> + <div> + 本月 {stats.month} + <span style={{ marginLeft: 8 }}> + 同比上月 + <Trend value={stats.totalMonthRate} /> + </span> + </div> + </Card> + </Col> + <Col flex="0 0 180px"> + <Card style={{ height: 120, display: 'flex', flexDirection: 'column', justifyContent: 'center' }}> + <Statistic title="正在办理" value={stats.processing} /> + </Card> + </Col> + <Col flex="0 0 180px"> + <Card style={{ height: 120, display: 'flex', flexDirection: 'column', justifyContent: 'center' }}> + <Statistic title="审核中" value={stats.reviewing} /> + </Card> + </Col> + <Col flex="0 0 180px"> + <Card style={{ height: 120, display: 'flex', flexDirection: 'column', justifyContent: 'center' }}> + <Statistic title="延期办理" value={stats.delayed} /> + </Card> + </Col> + <Col flex="0 0 180px"> + <Card style={{ height: 120, display: 'flex', flexDirection: 'column', justifyContent: 'center' }}> + <Statistic title="已办结" value={stats.finished} /> + </Card> + </Col> + <Col flex="1"> + <Card style={{ height: 120, display: 'flex', flexDirection: 'column', justifyContent: 'center' }}> + <Statistic title="超时办理" value={stats.overtime} /> + <div> + 本月 {stats.overtimeMonth} + <span style={{ marginLeft: 8 }}> + 同比上月 + <Trend value={stats.overtimeMonthRate} /> + </span> + </div> + </Card> + </Col> + </Row> + + <Row gutter={[16, 16]} style={{ marginTop: 16 }}> + <Col> + <Card> + <Statistic title="平均处理时间" value={stats.avgTime + '天'} /> + <div> + 本月 {stats.avgTimeMonth}天 + <span style={{ marginLeft: 8 }}> + 同比上月 + <Trend value={stats.avgTimeRate} /> + </span> + </div> + </Card> + </Col> + <Col> + <Card> + <Statistic title="总体满意率" value={stats.satisfaction + '%'} /> + <div> + 本月 {stats.satisfactionMonth}% + <span style={{ marginLeft: 8 }}> + 同比上月 + <Trend value={stats.satisfactionRate} /> + </span> + </div> + </Card> + </Col> + </Row> + + {/* 时间筛选区 */} + <div style={{ margin: '24px 0' }}> + <Space> + <DatePicker.RangePicker + value={dateRange} + onChange={(dates) => { + setDateRange(dates); + form.setFieldsValue({ time: dates }); + form.submit(); + }} + /> + <Button onClick={() => { + const end = moment(); + const start = moment().subtract(7, 'days'); + const dates = [start, end]; + setDateRange(dates); + form.setFieldsValue({ time: dates }); + form.submit(); + }}>近7天</Button> + <Button onClick={() => { + const end = moment(); + const start = moment().subtract(30, 'days'); + const dates = [start, end]; + setDateRange(dates); + form.setFieldsValue({ time: dates }); + form.submit(); + }}>近30天</Button> + </Space> + </div> + + {/* 图表区 */} + <div style={{ background: '#fff', padding: 24 }}> + <div style={{ width: '100%', overflowX: 'auto' }}> + <div style={{ minWidth: '100%', height: 300 }}> + <ReactECharts + option={echartsOption} + style={{ height: '100%', width: '100%' }} + opts={{ renderer: 'svg' }} + /> + </div> + </div> + </div> + + {/* 问题类型排名 */} + <div style={{ background: '#fff', padding: 24, marginTop: 32 }}> + <div style={{ fontWeight: 600, fontSize: 16, marginBottom: 16, borderLeft: '4px solid #3b7cff', paddingLeft: 8 }}> + 问题类型排名 + <Select + style={{ width: 120, marginLeft: 16 }} + value={rankType} + onChange={setRankType} + options={[ + { label: '排名前5', value: 'top5' }, + { label: '排名前10', value: 'top10' }, + { label: '全部排名', value: 'all' }, + ]} + /> + </div> + <div style={{ maxHeight: 320, overflowY: 'auto' }}> + <ReactECharts option={typeRankOption} style={{ height: Math.max(60 * allTypeData.length, 300) }} /> + </div> + </div> + + {/* 问题评价占比 */} + <div style={{ background: '#fff', padding: 24, marginTop: 32 }}> + <div style={{ fontWeight: 600, fontSize: 16, marginBottom: 16, borderLeft: '4px solid #3b7cff', paddingLeft: 8 }}> + 问题评价占比 + </div> + <ReactECharts option={pieOption} style={{ height: 300 }} /> + </div> + </PageContainer> + </div> + ); +}; + +export default statistics; diff --git a/management/src/pages/statistics/service.js b/management/src/pages/statistics/service.js new file mode 100644 index 0000000..2ace99d --- /dev/null +++ b/management/src/pages/statistics/service.js @@ -0,0 +1,23 @@ +import { request } from '@umijs/max'; + +// 获取社区列表 +export const getCommunityList = async (params) => { + return request('/api/huacheng-sangeshenbian/analytic-statistics/getRegion', { + method: 'GET', + params + }); +} +// 获取下一级区域列表 +export const getNextRegion = async (params) => { + return request('/api/huacheng-sangeshenbian/analytic-statistics/getNextRegion', { + method: 'GET', + params + }); +} +// 获取统计数据 +export const getStatisticsData = async (data) => { + return request('/api/huacheng-sangeshenbian/analytic-statistics/data', { + method: 'post', + data + }); +} \ No newline at end of file -- Gitblit v1.7.1