Files
dvcp_v2_webapp/project/fengdu/AppBIBoard/AppBIBoard.vue
2023-10-23 10:48:30 +08:00

607 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<section class="AppBIBoard" :class="{fullscreen}">
<ai-fit-view @scale="v=>scale=v">
<ai-dv-wrapper ref="fddv" title="丰收号-家庭互助" :instance="instance" :mask="false" @pick="getData()">
<template v-slot:head="head">
<fengdu-head v-model="areaId" v-bind="head" @fullscreen="handleFullScreen" @setting="handleSetting"/>
</template>
<div class="left">
<fd-card label="社群动态概况">
<div class="grid c-2 pad-t14 pad-b20">
<div class="staPanel" v-for="(v,k) in sta" :key="k">
<div v-text="k"/>
<b v-text="v"/>
</div>
<div class="chart">
<div class="title">群活跃率7</div>
<ai-echart :ops="chart" :data="calcProgress()">
<div class="legend">
<ai-highlight v-for="item in chartData" :key="item.name" :content="`@v${item.value}`"
:value="item.name" color="#9BB7D4" class="flex center mar-b8"/>
</div>
</ai-echart>
</div>
<div class="chart">
<div class="title">人员活跃7</div>
<ai-echart :ops="chart" :data="calcProgress()">
<div class="legend">
<ai-highlight v-for="item in chartData" :key="item.name" :content="`@v${item.value}`"
:value="item.name" color="#9BB7D4" class="flex center mar-b8"/>
</div>
</ai-echart>
</div>
</div>
</fd-card>
<fd-card class="mar-t14" label="志愿者">
<div class="jumpBtn" slot="right">前往志愿者平台
<div class="el-icon-position"/>
</div>
<div class="staPanel simple flex mar-t10">
<div class="fill" v-for="(v,k) in volunteers" :key="k">
<div v-text="k"/>
<b v-text="v"/>
</div>
</div>
<div class="flex mar-v12">
<b class="fill title">志愿者名单</b>
<ai-select class="areaPicker" placeholder="团队选择"/>
</div>
<dv-scroll-board ref="volunteerTable" :config="volunteerConfig"/>
<div class="dots flex center">
<div class="dot" v-for="i in tablePages" :key="i" :class="{current:current==i}"/>
</div>
</fd-card>
</div>
<div class="center fill relative">
<fd-map class="w100 h100" v-model="map"/>
<fd-card class="centerBottom pad-b8" label="实时动态">
<dv-scroll-board class="mar-t14" :config="realtimeEvents" style="height: 228px"
@click="handleRealtimeEventDialog"/>
</fd-card>
</div>
<div class="right">
<fd-card label="功德银行">
<template #right>
<div class="shortcut" v-for="(v,k) in shortcuts" :key="k" @click="shortcut=k"
:class="{active:shortcut==k}" v-text="v"/>
</template>
<div class="boxSta flex">
<div class="flex text">
<div>获取总积分</div>
<p v-text="GongdeBank.total"/>
</div>
</div>
<div class="staPanel simple right flex mar-t14">
<div class="fill" v-for="(v,k) in GongdeBank.users" :key="k">
<div v-text="k"/>
<b v-text="v"/>
</div>
</div>
<div class="boxSta flex">
<div class="flex text">
<div>兑换总积分</div>
<p v-text="GongdeBank.useTotal"/>
</div>
</div>
<div class="staPanel simple right flex mar-t14">
<div class="fill" v-for="(v,k) in GongdeBank.stores" :key="k">
<div v-text="k"/>
<b v-text="v"/>
</div>
</div>
<div class="grid c-3 pad-t14 pad-b20">
<div class="staPanel" v-for="(v,k) in GongdeBank.tasks">
<div v-text="k"/>
<b v-text="v"/>
</div>
</div>
</fd-card>
<fd-card label="门户应用统计" class="mar-t14 pad-b20">
<dv-scroll-board class="mar-t14" :config="appSta" style="height: 304px"/>
</fd-card>
</div>
</ai-dv-wrapper>
</ai-fit-view>
</section>
</template>
<script>
import AiFitView from "dui/packages/layout/AiFitView.vue";
import FengduHead from "./components/fengduHead.vue";
import FdCard from "./components/fdCard.vue";
import AiEchart from "dui/packages/tools/AiEchart.vue";
import AiHighlight from "dui/packages/layout/AiHighlight.vue";
import AiInfoItem from "dui/packages/basic/AiInfoItem.vue";
import AiWrapper from "dui/packages/basic/AiWrapper.vue";
import Vue from "vue";
import {scrollBoard} from "@jiaminghi/data-view"
import FdMap from "./components/fdMap.vue";
export default {
name: "AppBIBoard",
label: "丰都指挥舱",
components: {FdMap, AiWrapper, AiInfoItem, AiHighlight, AiEchart, FdCard, FengduHead, AiFitView},
props: {
instance: Function,
dict: Object
},
data() {
return {
areaId: '',
scale: 1,
fullscreen: false,
sta: {
群总数: 5118,
群主人数: 956,
'活跃群成员(30天)': '214,098',
'群消息(30天)': '1,214,098',
},
chart: {
legend: {show: false},
series: {
type: 'gauge',
startAngle: 90,
endAngle: -270,
center: ['50%', 74],
radius: 50,
progress: {
show: true,
overlap: false,
roundCap: true,
clip: false,
itemStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{offset: 0, color: '#139AFF'},
{offset: 1, color: '#0ED5A6'},
]
}
},
},
pointer: {show: false},
splitLine: {show: false},
axisTick: {show: false},
axisLabel: {show: false},
axisLine: {
lineStyle: {width: 6, color: [[1, 'rgba(102, 121, 138, 0.4)']]},
},
detail: {
valueAnimation: true,
offsetCenter: [0, 0],
fontSize: 24,
formatter: '{value}%',
color: "#02FEFF",
fontFamily: "DIN",
width: 50,
lineHeight: 50,
padding: 12,
borderWidth: 1,
borderColor: 'rgba(102, 121, 138, 0.4)',
borderRadius: 50
},
},
},
chartData: [
{name: "活跃居民群", value: 3502},
{name: "全部居民群", value: 5118},
],
volunteers: {
团队数量: 125,
志愿者数量: 13,
服务学员数量: 5
},
volunteerConfig: {
header: ['所属团队', '姓名', '性别', '年龄'],
headerBGC: 'rgba(33, 180, 253, 0.1)',
oddRowBGC: 'rgba(112, 112, 112, 0)',
evenRowBGC: 'rgba(112, 112, 112, 0)',
rowNum: 4,
headerHeight: 38,
columnWidth: [250],
align: ['left', 'left', 'left', 'center'],
carousel: 'page',
data: [
['三合街道丁庄社区互助会', '张珊珊', '女', 32],
['三合街道丁庄社区互助会', '王富贵', '女', 32],
['三合街道丁庄社区互助会', '阿萨德', '男', 23],
['三合街道丁庄社区互助会', '阿连德', '男', 54],
['三合街道丁庄社区互助会', '王柏柏', '女', 66],
['三合街道丁庄社区互助会', '赵二狗', '男', 41],
['三合街道丁庄社区互助会', '唯一键', '女', 13],
['三合街道丁庄社区互助会', '卡萨丁', '男', 32],
['三合街道丁庄社区互助会', '卡萨丁', '男', 32],
['三合街道丁庄社区互助会', '卡萨丁', '男', 32],
['三合街道丁庄社区互助会', '张珊珊', '女', 32],
['三合街道丁庄社区互助会', '张珊珊', '女', 32],
]
},
appSta: {
header: ['应用名称', '本日点击', '累计点击'],
headerBGC: 'rgba(33, 180, 253, 0.1)',
oddRowBGC: 'rgba(112, 112, 112, 0)',
evenRowBGC: 'rgba(112, 112, 112, 0)',
rowNum: 7,
headerHeight: 38,
columnWidth: [250],
align: ['left', 'right', 'right'],
data: [
// ['渝快办', 178, 266],
// ['公交乘车码', 178, 266],
// ['警快办', 178, 266],
// ['医保电子凭证', 178, 266],
// ['居民上报', 178, 266],
// ['医保电子凭证', 178, 266],
// ['居民上报', 178, 266],
]
},
current: 1,
realtimeEvents: {
rowNum: 6,
oddRowBGC: 'rgba(112, 112, 112, 0)',
evenRowBGC: 'rgba(112, 112, 112, 0)',
columnWidth: [226],
align: ['center', 'left'],
data: [
// ['<div class="timeRow">2023-10-19 14:55:32</div>', '汇南社区-张三 创建了新的居民群'],
// ['<div class="timeRow">2023-10-19 14:55:32</div>', '汇南社区-张三 邀请居民"蓝天白云"加入居民群“书院社区2群”'],
// ['<div class="timeRow">2023-10-19 14:55:32</div>', '汇南社区-张三 将居民"蓝天白云"踢出居民群 “书院社区2群”'],
// ['<div class="timeRow">2023-10-19 14:55:32</div>', '滨江东路社区居民-陈思宇在丰收号小程序中进行了打卡签到'],
// ['<div class="timeRow">2023-10-19 14:55:32</div>', '滨江东路社区居民-陈思宇在丰收号小程序中进行了积分申请'],
// ['<div class="timeRow">2023-10-19 14:55:32</div>', '滨滨江东路社区居民-陈思宇在丰收号小程序中进行了物品兑换'],
// ['<div class="timeRow">2023-10-18 14:55:32</div>', '三角路社区居民-陈思宇在丰收号小程序中进行了物品兑换'],
// ['<div class="timeRow">2023-10-18 14:55:32</div>', '三角路社区居民-陈思宇在丰收号小程序中进行了物品兑换'],
// ['<div class="timeRow">2023-10-18 14:55:32</div>', '三角路社区居民-陈思宇在丰收号小程序中进行了物品兑换'],
]
},
shortcut: 0,
GongdeBank: {},
map: null
}
},
computed: {
tablePages: v => Math.ceil(v.volunteerConfig.data.length / v.volunteerConfig.rowNum) || 0,
shortcuts: () => Object.assign({0: '昨日', 1: '近七天', 2: '近30天', 3: '近一年'})
},
watch: {
shortcut() {
this.getGdyh(this.areaId)
}
},
methods: {
handleFullScreen() {
this.fullscreen = this.$refs.fddv.handleFullScreen()
},
handleSetting(v) {
this.$refs.fddv.dialog = v
},
calcProgress() {
const value = (this.chartData[0].value / this.chartData.at(-1).value * 100).toFixed(0)
return [{value}]
},
watchTablePageChange(c = 0) {
if (this.$refs.volunteerTable) {
this.$refs.volunteerTable.$watch('animationIndex', i => {
this.current = Math.floor(i / 4) + 1
})
} else if (c < 5) {
setTimeout(() => this.watchTablePageChange(++c), 500)
}
},
getData(c = 0) {
const {areaId} = this.$data
if (areaId) {
this.getMiniAppInfo()
this.getRealTimeDynamic(areaId)
this.getWxGroupOverview(areaId)
this.getGdyh(areaId)
} else if (c < 10) setTimeout(() => this.getData(++c), 500)
else console.error(`尝试${c}次加载数据,无法过去数据`)
},
getMiniAppInfo() {
this.instance.post("/app/fdDiy/miniAppInfo").then(res => {
if (res?.data) {
const data = res.data.map(e => [e.name || "应用", e.lastDayClick, e.totalClick])
this.appSta = {...this.appSta, data}
}
})
},
getRealTimeDynamic(areaId) {
this.instance.post("/app/fdDiy/realTimeDynamic", null, {params: {areaId}}).then(res => {
if (res?.data) {
const data = res.data.map(e => [`<div class="timeRow">${e.eventTime}</div>`, `<div class="flex">${e.bizId ? e.description.replace(e.type, `<div class="blue">${e.type}</div>`) : e.description}</div>`])
this.realtimeEvents = {...this.realtimeEvents, data, meta: res.data}
}
})
},
getWxGroupOverview(areaId) {
this.instance.post("/app/fdDiy/wxGroupOverview", null, {params: {areaId}}).then(res => {
if (res?.data) {
}
})
},
getGdyh(areaId) {
this.instance.post("/app/fdDiy/gdyh", null, {params: {areaId, type: this.shortcut}}).then(res => {
if (res?.data) {
const {
宣发发布任务数,
宣发未审核数,
宣发审核通过数,
店铺总数,
店品库存量 = 0,
兑换物品数量,
获取积分总数: total = 0,
居民签到人次: 签到人数 = 0,
积分申请次数: 申请人数 = 0,
兑换总积分: useTotal = 0
} = res.data
this.GongdeBank = {
total, useTotal,
users: {
参与人数: 签到人数 + 申请人数,
申请人数,
签到人数
},
stores: {店铺总数, 店品库存量, 兑换物品数量},
tasks: {
宣发发布任务数,
审核通过率: (宣发审核通过数 / 宣发发布任务数 * 100 || 0).toFixed(2) + "%",
宣发未审核数,
}
}
}
})
},
handleRealtimeEventDialog({rowIndex}) {
const row = this.realtimeEvents.meta[rowIndex]
if (row.bizId) {
const action = {
积分申请: "",
物品兑换: "",
精选动态: "",
}[row.type]
this.instance.post(action, null, {params: {id: row.bizId}}).then(res => {
if (res?.data) {
}
})
}
console.log(row)
}
},
created() {
Vue.use(scrollBoard)
this.getData()
},
mounted() {
this.watchTablePageChange()
}
}
</script>
<style scoped lang="scss">
.AppBIBoard {
color: #CDDBEA;
font-size: 14px;
:deep(.areaPicker) {
max-width: 300px;
input {
background: rgba(0, 54, 82, 0.9);
border: 1px solid rgba(42, 122, 146, 0.7);
border-radius: 2.2px;
color: #B3DDE5;
cursor: pointer;
}
.el-input__suffix {
color: #B3DDE5;
}
}
&.fullscreen {
position: fixed;
z-index: 202310111819;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
:deep(.viewPanel) {
background-image: url("./assets/img_bg.png");
& > .fill {
display: flex;
gap: 20px;
padding: 12px 24px 0;
}
}
.left, .right {
width: 480px;
flex-shrink: 0;
}
.grid {
display: grid;
gap: 14px;
&.c-2 {
grid-template-columns:1fr 1fr;
}
&.c-3 {
grid-template-columns:1fr 1fr 1fr;
}
}
.staPanel {
text-align: center;
font-size: 15px;
line-height: 20px;
background: url("./assets/staPanel-bg.png") no-repeat;
background-size: 100% 100%;
height: 80px;
padding-top: 14px;
width: 100%;
b {
font-family: DIN;
font-size: 22px;
color: #02FEFF;
letter-spacing: 0;
line-height: 36px;
}
&.simple {
background: #ffffff0a;
padding-top: 0;
&.right {
color: #9BB7D4;
b {
color: #FFFFFF;
}
}
}
}
.chart {
.legend {
position: absolute;
left: 0;
right: 0;
bottom: 0;
}
.AiEchart {
height: 204px;
}
}
.title {
padding-left: 10px;
line-height: 30px;
background-image: linear-gradient(270deg, #1f436600 0%, #245a7570 99%);
}
.jumpBtn {
background-image: linear-gradient(180deg, rgba(90, 200, 246, 0.4) 0%, rgba(1, 51, 101, 0.4) 84%);
box-shadow: inset 0 2px 8px 0 rgba(51, 187, 255, 0.5);
border-radius: 15px;
font-weight: 500;
font-size: 12px;
color: #02FEFF;
padding: 8px 16px;
height: 30px;
user-select: none;
cursor: pointer;
margin-top: -7px;
}
:deep(.dv-scroll-board) {
height: 200px;
.header-item {
color: #02FEFF;
}
.row-item {
height: 38px;
line-height: 38px;
border-bottom: 1px solid #154270;
margin-top: -1px;
}
.timeRow {
background-image: url("./assets/realtimeIcon.png");
background-repeat: no-repeat;
background-position: 20px center;
text-indent: 24px;
}
.blue {
color: #02FEFF;
cursor: pointer;
}
}
.dots {
height: 36px;
padding-top: 22px;
padding-bottom: 8px;
.dot {
width: 6px;
height: 6px;
border-radius: 50%;
background: #679a9a80;
margin-right: 8px;
&.current {
background: #02FEFF;
}
&:last-of-type {
margin-right: 0;
}
}
}
.centerBottom {
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
.shortcut {
background: #1f9ecc29;
padding: 4px 13px;
color: #1FBECC;
font-size: 13px;
margin-left: 4px;
margin-top: -7px;
border: 1px solid transparent;
cursor: pointer;
height: fit-content;
&:first-of-type {
margin-left: 0;
}
&.active {
border-color: #20B4C5;
color: #4ED8E4;
}
}
.boxSta {
margin-top: 16px;
padding-right: 40px;
justify-content: flex-end;
background: url("./assets/box.png") no-repeat 80px center;
height: 82px;
font-size: 16px;
.text {
color: #FFFFFF;
width: 200px;
justify-content: space-between;
& > p {
font-family: DIN;
font-size: 26px;
color: #02FEFF;
}
}
}
}
</style>