From 7742bdaeedcbaf5f1cf7c5b488019b6023894f81 Mon Sep 17 00:00:00 2001 From: hejianhao <15708179461@qq.com> Date: 星期一, 24 三月 2025 18:03:40 +0800 Subject: [PATCH] Merge branch 'master' of http://120.76.84.145:10101/gitblit/r/H5/chongzhou-screen --- src/components/datascreen/RightPanel.vue | 898 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 files changed, 833 insertions(+), 65 deletions(-) diff --git a/src/components/datascreen/RightPanel.vue b/src/components/datascreen/RightPanel.vue index fc446ce..f255693 100644 --- a/src/components/datascreen/RightPanel.vue +++ b/src/components/datascreen/RightPanel.vue @@ -2,22 +2,74 @@ <div class="right-panel"> <!-- 右侧第一块 --> <div class="panel-item top-panel-item"> - <div class="box-title">本月进度值比</div> - <div class="circle-progress"> - <!-- <v-chart class="chart" :option="circleOption" autoresize /> --> + <div class="box-title">安置房类型占比</div> + <div class="house-type-content"> + <div class="cityGreenLand-charts" ref="cityGreenLandCharts"></div> + <div class="right-content"> + <div class="table-header"> + <div class="header-item">数量</div> + <div class="header-item">面积</div> + <div class="header-item">占比</div> + </div> + <div class="data-list"> + <div + class="data-item" + :class="{ activeItem: item.name === currentType.name }" + v-for="(item, index) in houseTypeData" + :key="index" + @click="changeCurrentType(item)" + > + <div class="item-dot" :style="{ background: item.color }"></div> + <div class="item-name">{{ item.name }}</div> + <div class="item-value" :style="{ color: item.color }"> + {{ item.value }} + </div> + <div class="item-area" :style="{ color: item.color }"> + {{ item.area }} + </div> + <div class="item-percent" :style="{ color: item.color }"> + {{ item.percent }} + </div> + </div> + </div> + </div> </div> </div> <!-- 右侧第二块 --> <div class="panel-item middle-panel-item"> - <div class="box-title">各季度进度值统计</div> - <div class="bar-chart"> - <!-- <v-chart class="chart" :option="barOption" autoresize /> --> + <div class="box-title">本月应补偿占比</div> + <div class="compensation-content"> + <div class="circle-chart"> + <div + ref="compensationCharts" + id="compensationCharts" + style="width: 100%; height: 100%" + ></div> + <div class="compensation-list"> + <div class="compensation-center"> + <div class="total-value">{{ (total*1).toFixed(2) }}</div> + <div class="total-name">总额(万元)</div> + </div> + <div class="compensation-item"> + <div + class="compensation-item-name" + v-for="item in twoEcharts" + :key="item.name" + > + <div class="item-name">{{ item.value }}%</div> + <div class="item-value">{{ item.name }}</div> + <div class="item-dot" :style="{ background: item.color }"></div> + </div> + </div> + </div> + </div> </div> </div> <!-- 右侧第三块 --> <div class="panel-item bottom-panel-item"> + <div class="box-title">各季度应补偿金额</div> <div class="box-title">各季度应补偿总额</div> <div class="pie-chart"> <v-chart class="chart" :option="barOption" autoresize /> @@ -27,6 +79,9 @@ </template> <script> +import * as echarts from "echarts"; +import "echarts-gl"; + export default { name: 'RightPanel', props: { @@ -36,66 +91,97 @@ } }, data() { - return { - circleOption: { - series: [{ - type: 'pie', - radius: ['75%', '80%'], - label: { - show: false - }, - data: [ - { - value: 78.8, - name: '完成率', - itemStyle: { - color: '#00ffff' - } - }, - { - value: 21.2, - name: '剩余', - itemStyle: { - color: 'rgba(0,255,255,0.2)' - } - } - ] - }] + const houseTypeData = [ + { + name: "新建商品住房", + value: 321, + area: 35344, + percent: "56.8%", + color: "#00ffff", }, + { + name: "商业用房", + value: 321, + area: 35344, + percent: "34.5%", + color: "#34D160", + }, + { + name: "停车位", + value: 321, + area: 35344, + percent: "56.8%", + color: "#F8B551", + }, + { + name: "二手住房", + value: 321, + area: 35344, + percent: "56.8%", + color: "#BF40BF", + }, + ]; + + return { + houseTypeData, + currentType: houseTypeData[0], + total: null, barOption: {}, + twoEcharts: [ + { + name: "首付款", + value: 78.8, + color: "#00ffff", + }, + { + name: "季度款", + value: 78.8, + color: "#34D160", + }, + { + name: "过渡补贴", + value: 78.8, + color: "#F8B551", + }, + ], typeDistOption: { tooltip: { - trigger: 'item' + trigger: "item", }, - series: [{ - type: 'pie', - radius: ['65%', '80%'], - label: { - show: false + series: [ + { + type: "pie", + radius: ["65%", "80%"], + label: { + show: false, + }, + data: [ + { value: 40, name: "商品房" }, + { value: 30, name: "安置房" }, + { value: 30, name: "其他" }, + ], + itemStyle: { + color: function (params) { + const colorList = ["#00ffff", "#7cb9e8", "rgba(0,255,255,0.5)"]; + return colorList[params.dataIndex]; + }, + }, }, - data: [ - { value: 40, name: '商品房' }, - { value: 30, name: '安置房' }, - { value: 30, name: '其他' } - ], - itemStyle: { - color: function (params) { - const colorList = ['#00ffff', '#7cb9e8', 'rgba(0,255,255,0.5)']; - return colorList[params.dataIndex]; - } - } - }] - } + ], + }, }; }, - mounted() { - // 组件挂载后初始化地图 this.$nextTick(() => { + this.init(); + this.initCompensationOption(this.twoEcharts); this.initBarChart(); }); }, methods: { + changeCurrentType(type) { + this.currentType = type; + }, initBarChart() { if (!this.data.quarterPayResponses || !this.data.quarterPayResponses[0]) return; @@ -216,20 +302,379 @@ } ] }; - } + }, + init() { + const chartDom = this.$refs.cityGreenLandCharts; + if (!chartDom) return; + + const myChart = echarts.init(chartDom); + + let colors = ["#286DF7ee", "#04F7FDee", "#E23AA9ee", "#FFC852ee"]; + let xData = ["第一产业", "第二产业", "第三产业", "城乡居民生活用电"]; + let yData = [25, 25, 25, 25]; + // 传入数据生成 option + let optionsData = []; + for (let i = 0; i < xData.length; i++) { + optionsData.push({ + name: xData[i], + value: yData[i], + itemStyle: { + color: colors[i], + }, + }); + } + + const series = this.getPie3D(optionsData, 0.55); + + series.push({ + name: "pie2d", + type: "pie", + labelLine: { + show: false, + length: 60, + length2: 60, + }, + startAngle: -50, + clockwise: false, + radius: ["0", "0"], + center: ["50%", "50%"], + data: optionsData, + itemStyle: { + opacity: 0, + }, + }); + + let option = { + animation: true, + labelLine: { + show: false, + }, + xAxis3D: { + min: -1, + max: 1, + }, + yAxis3D: { + min: -1, + max: 1, + }, + zAxis3D: { + min: -1, + max: 1, + }, + grid3D: { + show: false, + boxHeight: 0.5, + bottom: "50%", + viewControl: { + distance: 280, + alpha: 30, + beta: 40, + zoom: 40, + rotateSensitivity: 0, + zoomSensitivity: 0, + panSensitivity: 0, + autoRotate: false, + }, + }, + series: series, + }; + + myChart.setOption(option); + + window.addEventListener("resize", () => { + myChart.resize(); + }); + }, + + getParametricEquation( + startRatio, + endRatio, + isSelected, + isHovered, + k, + height + ) { + let midRatio = (startRatio + endRatio) / 2; + let startRadian = startRatio * Math.PI * 2; + let endRadian = endRatio * Math.PI * 2; + let midRadian = midRatio * Math.PI * 2; + + if (startRatio === 0 && endRatio === 1) { + isSelected = false; + } + + k = typeof k !== "undefined" ? k : 1 / 3; + + let offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0; + let offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0; + + let hoverRate = isHovered ? 1.05 : 1; + + return { + u: { + min: -Math.PI, + max: Math.PI * 3, + step: Math.PI / 32, + }, + v: { + min: 0, + max: Math.PI * 2, + step: Math.PI / 20, + }, + x: function (u, v) { + if (u < startRadian) { + return ( + offsetX + + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate + ); + } + if (u > endRadian) { + return ( + offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate + ); + } + return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate; + }, + y: function (u, v) { + if (u < startRadian) { + return ( + offsetY + + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate + ); + } + if (u > endRadian) { + return ( + offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate + ); + } + return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate; + }, + z: function (u, v) { + if (u < -Math.PI * 0.5) { + return Math.sin(u); + } + if (u > Math.PI * 2.5) { + return Math.sin(u); + } + return Math.sin(v) > 0 ? 2 * height : -1; + }, + }; + }, + + getPie3D(pieData, internalDiameterRatio) { + let series = []; + let sumValue = 0; + let startValue = 0; + let endValue = 0; + let k = + typeof internalDiameterRatio !== "undefined" + ? (1 - internalDiameterRatio) / (1 + internalDiameterRatio) + : 1 / 3; + + for (let i = 0; i < pieData.length; i++) { + sumValue += pieData[i].value; + + let seriesItem = { + name: + typeof pieData[i].name === "undefined" + ? `series${i}` + : pieData[i].name, + type: "surface", + parametric: true, + wireframe: { + show: false, + }, + pieData: pieData[i], + pieStatus: { + selected: false, + hovered: false, + k: k, + }, + }; + + if (typeof pieData[i].itemStyle != "undefined") { + let itemStyle = {}; + typeof pieData[i].itemStyle.color != "undefined" + ? (itemStyle.color = pieData[i].itemStyle.color) + : null; + typeof pieData[i].itemStyle.opacity != "undefined" + ? (itemStyle.opacity = pieData[i].itemStyle.opacity) + : null; + seriesItem.itemStyle = itemStyle; + } + series.push(seriesItem); + } + + for (let i = 0; i < series.length; i++) { + endValue = startValue + series[i].pieData.value; + series[i].pieData.startRatio = startValue / sumValue; + series[i].pieData.endRatio = endValue / sumValue; + series[i].parametricEquation = this.getParametricEquation( + series[i].pieData.startRatio, + series[i].pieData.endRatio, + false, + false, + k, + series[i].pieData.value + ); + startValue = endValue; + } + + series.push({ + name: "mouseoutSeries", + type: "surface", + parametric: true, + wireframe: { + show: false, + }, + itemStyle: { + opacity: 0, + color: "#f0f", + }, + parametricEquation: { + u: { + min: 0, + max: Math.PI * 2, + step: Math.PI / 20, + }, + v: { + min: 0, + max: Math.PI, + step: Math.PI / 20, + }, + x: function (u, v) { + return ((Math.sin(v) * Math.sin(u) + Math.sin(u)) / Math.PI) * 2; + }, + y: function (u, v) { + return ((Math.sin(v) * Math.cos(u) + Math.cos(u)) / Math.PI) * 2; + }, + z: function (u, v) { + return Math.cos(v) > 0 ? 0 : -20; + }, + }, + }); + series.push({ + name: "mouseoutSeries", + type: "surface", + parametric: true, + wireframe: { + show: false, + }, + itemStyle: { + opacity: 0.1, + color: "#0ff", + }, + parametricEquation: { + u: { + min: 0, + max: Math.PI * 2, + step: Math.PI / 20, + }, + v: { + min: 0, + max: Math.PI, + step: Math.PI / 20, + }, + x: function (u, v) { + return ((Math.sin(v) * Math.sin(u) + Math.sin(u)) / Math.PI) * 2; + }, + y: function (u, v) { + return ((Math.sin(v) * Math.cos(u) + Math.cos(u)) / Math.PI) * 2; + }, + z: function (u, v) { + return Math.cos(v) > 0 ? -15 : -30; + }, + }, + }); + return series; + }, + + initCompensationOption(data) { + const chartDom = this.$refs.compensationCharts; + if (!chartDom) return; + + const chartCompensation = echarts.init(chartDom); + + let option = { + polar: { + radius: [50, "70%"], + center: ["50%", "40%"], + }, + grid: { + left: "10%", + bottom: "40%", + width: "80%", + height: "100%", + }, + angleAxis: { + max: 7, + startAngle: 75, + show: false, + axisTick: { + show: false, + }, + axisLine: { show: false }, + minorSplitLine: { show: false }, + }, + radiusAxis: { + type: "category", + show: false, + data: [], + axisTick: { + show: false, + }, + }, + tooltip: { show: false }, + series: { + type: "bar", + barMaxWidth: "11px", + showBackground: true, + roundCap: true, + backgroundStyle: { + color: "rgba(255, 255, 255, 0.1)", + }, + data: [], + coordinateSystem: "polar", + }, + }; + + let max = 0; + let total = 0; + let arr = []; + for (let i = 0; i < data.length; i++) { + max = Math.max(max, data[i].value); + total += data[i].value; + arr.push({ + value: data[i].value, + itemStyle: { color: data[i].color }, + }); + } + this.total = total; + option.angleAxis.max = total; + option.radiusAxis.data = data.map((item) => item.name); + option.series.data = arr; + + chartCompensation.setOption(option); + + window.addEventListener("resize", () => { + chartCompensation.resize(); + }); + }, }, - watch: { - data: { - handler() { - this.initBarChart(); - }, - deep: true - } - } }; </script> <style lang="less" scoped> +.water-eval-container { + width: 100%; + height: 100%; +} + +.cityGreenLand-charts { + width: 170px; + height: 100%; +} + .right-panel { position: absolute; top: 111px; @@ -243,36 +688,359 @@ .top-panel-item { height: 268px; - background: url('@/assets/right-top-bg.png') no-repeat center center; + background: url("@/assets/right-middle-bg.png") no-repeat center center; background-size: 100% 100%; } .middle-panel-item { margin-top: 21px; height: 303px; - background: url('@/assets/right-middle-bg.png') no-repeat center center; + background: url("@/assets/right-middle-bg.png") no-repeat center center; background-size: 100% 100%; } .bottom-panel-item { margin-top: 21px; height: 335px; - background: url('@/assets/right-bottom-bg.png') no-repeat center center; + background: url("@/assets/right-bottom-bg.png") no-repeat center center; background-size: 100% 100%; } .box-title { font-size: 14px; - color: #19ECFF; + color: #19ecff; text-align: center; padding-top: 9px; line-height: 21px; } + .house-type-content { + height: calc(100% - 30px); + display: flex; + padding: 10px 13px; + + .pie-chart { + position: relative; + width: 45%; + height: 100%; + display: flex; + align-items: center; + + &::after { + content: ""; + position: absolute; + bottom: 15%; + left: 50%; + transform: translateX(-50%); + width: 60%; + height: 10px; + background: radial-gradient( + ellipse at center, + rgba(0, 255, 255, 0.3) 0%, + rgba(0, 0, 0, 0) 70% + ); + border-radius: 50%; + filter: blur(3px); + z-index: 0; + } + + .center-text { + position: absolute; + left: 40%; + top: 50%; + transform: translate(-50%, -50%); + text-align: center; + z-index: 2; + padding: 10px 15px; + border-radius: 4px; + background: rgba(0, 0, 0, 0.2); + backdrop-filter: blur(2px); + + .percent { + display: block; + font-size: 28px; + color: #fff; + font-weight: bold; + } + + .type { + display: block; + font-size: 14px; + color: #19ecff; + margin-top: 5px; + } + } + } + + .type-list { + flex: 1; + margin-left: 30px; + display: flex; + flex-direction: column; + justify-content: space-around; + + .type-item { + display: grid; + grid-template-columns: auto 1fr 1fr 1fr; + gap: 15px; + align-items: center; + cursor: pointer; + padding: 5px 10px; + transition: all 0.3s; + position: relative; + + &:hover { + background: rgba(25, 236, 255, 0.1); + border-radius: 4px; + } + + &::before { + content: ""; + position: absolute; + left: 0; + right: 0; + bottom: -5px; + height: 1px; + background: linear-gradient( + 90deg, + transparent, + rgba(25, 236, 255, 0.2), + transparent + ); + } + + .dot { + width: 8px; + height: 8px; + border-radius: 50%; + margin-right: 8px; + box-shadow: 0 0 5px rgba(255, 255, 255, 0.3); + } + + .name { + color: #fff; + font-size: 14px; + } + + .value { + color: #00ffff; + font-size: 14px; + text-align: center; + } + + .area { + color: #00ffff; + font-size: 14px; + text-align: center; + } + + .percent { + color: #00ffff; + font-size: 14px; + text-align: right; + } + } + } + + .right-content { + flex: 1; + height: 100%; + overflow: hidden; + display: flex; + flex-direction: column; + padding-top: 27px; + + .table-header { + display: flex; + align-items: center; + padding: 0 19px 0px 118px; + margin-bottom: 8px; + + .header-item { + color: #b6d9fc; + font-weight: 400; + font-size: 10px; + text-align: center; + + &:nth-child(1) { + width: 60px; + } + + &:nth-child(2) { + width: 80px; + } + + &:nth-child(3) { + width: 60px; + text-align: right; + } + } + } + + .data-list { + flex: 1; + overflow-y: auto; + // padding-right: 10px; + + &::-webkit-scrollbar { + display: none; + } + + .data-item { + display: flex; + align-items: center; + padding: 5px 7px 5px 4px; + position: relative; + margin-bottom: 21px; + cursor: pointer; + + &:not(:last-child)::after { + content: ""; + position: absolute; + left: 0; + right: 0; + bottom: 0; + height: 1px; + background: linear-gradient( + 90deg, + transparent, + rgba(25, 236, 255, 0.2), + transparent + ); + } + + .item-dot { + width: 8px; + height: 8px; + flex-shrink: 0; + border-radius: 50%; + margin-right: 3px; + box-shadow: 0 0 5px rgba(255, 255, 255, 0.3); + } + + .item-name { + width: 100px; + color: #fff; + font-weight: 500; + font-size: 12px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .item-value { + width: 60px; + color: #00ffff; + font-size: 12px; + text-align: center; + } + + .item-area { + width: 80px; + color: #00ffff; + font-size: 12px; + text-align: center; + } + + .item-percent { + width: 60px; + color: #00ffff; + font-size: 12px; + text-align: right; + } + } + .activeItem { + box-sizing: border-box; + background: rgba(105, 192, 255, 0.12); + border-radius: 4px; + border: 1px solid rgba(105, 192, 255, 0.29); + } + } + } + } + .chart { width: 100%; height: 100%; } + + .middle-panel-item { + .compensation-content { + height: calc(100% - 30px); + display: flex; + flex-direction: column; + align-items: center; + padding: 20px; + + .circle-chart { + width: 100%; + height: 260px; + position: relative; + } + + .compensation-list { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + margin-top: 20px; + padding: 0 40px 0px 40px; + .compensation-center { + display: flex; + flex: 1; + justify-content: center; + align-items: center; + flex-direction: column; + .total-value { + font-family: PangMenZhengDao; + font-size: 28px; + color: #ffffff; + margin-bottom: 11px; + } + .total-name { + font-family: SourceHanSansCN, SourceHanSansCN; + font-weight: 400; + font-size: 12px; + color: rgba(255, 255, 255, 1); + } + } + + .compensation-item { + width: 100%; + height: 45px; + display: flex; + justify-content: space-between; + align-items: center; + .compensation-item-name { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + .item-name { + font-size: 16px; + color: #ffffff; + margin-bottom: 5px; + font-family: "pangmenzhengdao"; + } + .item-value { + font-weight: 400; + font-size: 12px; + color: #ffffff; + margin-bottom: 2px; + } + .item-dot { + width: 8px; + height: 8px; + border-radius: 50%; + } + } + } + } + } + } } .pie-chart { -- Gitblit v1.7.1