Files
dvcp_v2_webapp/project/fengdu/AppBIBoard/AppBIBoard.vue

1207 lines
39 KiB
Vue
Raw Normal View History

2023-10-11 18:21:40 +08:00
<template>
<section class="AppBIBoard" :class="{fullscreen}">
<ai-fit-view>
2023-10-24 16:04:19 +08:00
<ai-dv-wrapper ref="fddv" title="丰收号-家庭互助" :instance="instance" :mask="false">
2023-10-11 18:21:40 +08:00
<template v-slot:head="head">
2023-10-19 17:19:15 +08:00
<fengdu-head v-model="areaId" v-bind="head" @fullscreen="handleFullScreen" @setting="handleSetting"/>
2023-10-11 18:21:40 +08:00
</template>
2023-10-13 18:10:45 +08:00
<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>
2023-10-23 16:32:13 +08:00
<ai-echart :ops="chart" :data="calcProgress(chartData)">
2023-10-18 10:34:41 +08:00
<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>
2023-10-13 18:10:45 +08:00
</div>
<div class="chart">
<div class="title">人员活跃7</div>
2023-10-23 16:32:13 +08:00
<ai-echart :ops="chart" :data="calcProgress(chartData2)">
2023-10-18 10:34:41 +08:00
<div class="legend">
2023-10-23 16:32:13 +08:00
<ai-highlight v-for="item in chartData2" :key="item.name" :content="`@v${item.value}`"
2023-10-18 10:34:41 +08:00
:value="item.name" color="#9BB7D4" class="flex center mar-b8"/>
</div>
</ai-echart>
2023-10-13 18:10:45 +08:00
</div>
</div>
</fd-card>
2023-10-31 16:09:11 +08:00
<fd-card class="mar-t14" :label="leftBottom">
<div v-if="leftBottom=='志愿者'" class="jumpBtn" slot="right" @click="handleJump">前往志愿者平台
2023-10-18 14:59:52 +08:00
<div class="el-icon-position"/>
</div>
2023-10-31 18:03:52 +08:00
<el-carousel arrow="never" class="mar-t8" @change="v=>leftBottom=['志愿者','互助会'][v]" :interval="6000">
2023-10-31 16:09:11 +08:00
<el-carousel-item name="志愿者">
<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 v-model="fraternity" class="areaPicker" placeholder="团队选择" :select-list="fraternities"
2023-11-01 11:34:27 +08:00
:prop="{label:'fraternity_name',value:'fraternity_id'}"
2023-10-31 16:09:11 +08:00
@select="getVolunteerData(areaId)"/>
</div>
<dv-scroll-board :config="volunteerConfig"/>
</el-carousel-item>
<el-carousel-item name="互助会">
<dv-scroll-board class="origin" :config="fraternityTypeConfig" @click="getFraternityData"
style="height:360px"/>
</el-carousel-item>
</el-carousel>
2023-10-13 18:10:45 +08:00
</fd-card>
</div>
2023-10-19 17:19:15 +08:00
<div class="center fill relative">
2023-10-24 18:12:13 +08:00
<fd-map ref="map" class="w100 h100" v-model="map" :root="areaId"/>
2023-10-19 17:19:15 +08:00
<fd-card class="centerBottom pad-b8" label="实时动态">
<dv-scroll-board class="mar-t14" :config="realtimeEvents" style="height: 114px"
2023-10-23 10:48:30 +08:00
@click="handleRealtimeEventDialog"/>
2023-10-13 18:10:45 +08:00
</fd-card>
</div>
<div class="right">
<fd-card label="功德银行">
2023-10-19 17:19:15 +08:00
<template #right>
2023-10-23 16:32:13 +08:00
<div class="shortcut" v-for="cut in shortcuts" :key="cut.k" @click="shortcut=cut.k"
:class="{active:shortcut==cut.k}" v-text="cut.v"/>
2023-10-19 17:19:15 +08:00
</template>
<div class="boxSta flex">
<div class="flex text">
<div>获取总积分</div>
2023-10-23 10:48:30 +08:00
<p v-text="GongdeBank.total"/>
2023-10-19 17:19:15 +08:00
</div>
</div>
<div class="staPanel simple right flex mar-t14">
2023-10-23 10:48:30 +08:00
<div class="fill" v-for="(v,k) in GongdeBank.users" :key="k">
2023-10-19 17:19:15 +08:00
<div v-text="k"/>
<b v-text="v"/>
</div>
</div>
2023-10-25 12:07:12 +08:00
<div class="boxSta box2 flex">
2023-10-19 17:19:15 +08:00
<div class="flex text">
<div>兑换总积分</div>
2023-10-23 10:48:30 +08:00
<p v-text="GongdeBank.useTotal"/>
2023-10-19 17:19:15 +08:00
</div>
</div>
<div class="staPanel simple right flex mar-t14">
2023-10-23 10:48:30 +08:00
<div class="fill" v-for="(v,k) in GongdeBank.stores" :key="k">
2023-10-19 17:19:15 +08:00
<div v-text="k"/>
<b v-text="v"/>
</div>
</div>
<div class="grid c-3 pad-t14 pad-b20">
2023-10-23 10:48:30 +08:00
<div class="staPanel" v-for="(v,k) in GongdeBank.tasks">
2023-10-19 17:19:15 +08:00
<div v-text="k"/>
<b v-text="v"/>
</div>
</div>
2023-10-13 18:10:45 +08:00
</fd-card>
2023-10-19 17:19:15 +08:00
<fd-card label="门户应用统计" class="mar-t14 pad-b20">
<dv-scroll-board class="mar-t14" :config="appSta" style="height: 304px"/>
2023-10-13 18:10:45 +08:00
</fd-card>
</div>
2023-10-11 18:21:40 +08:00
</ai-dv-wrapper>
2023-10-31 16:09:11 +08:00
<fd-dialog v-model="dialog" :title="detail.eventType" :extra-dialog.sync="fraternityExtra"
:extra-title="detail.extraTitle">
2023-10-23 18:07:14 +08:00
<template v-if="detail.mapType=='store'">
<b class="title mar-t8 mar-b16">店铺商品</b>
<carousel autoplay :perPage="3" autoplayHoverPause navigationEnabled :paginationEnabled="false"
class="mar-h32"
navigationNextLabel=" " navigationPrevLabel="">
<slide class="goods" v-for="good in detail.goods" :key="good.id">
<img :src="good.goods.picUrl"/>
<div class="mar-t8" v-text="good.goods.title"/>
</slide>
</carousel>
2023-10-23 18:07:14 +08:00
<b class="title mar-t14 mar-b12">订单列表</b>
<dv-scroll-board :config="goodsConfig" style="height: 152px"/>
</template>
2023-10-31 11:36:39 +08:00
<template v-else-if="detail.mapType=='fraternitySta'">
<el-input placeholder="请输入互助会名称..." class="areaPicker mar-b20" size="small"
v-model="fraternityFilter"/>
2023-10-31 16:09:11 +08:00
<dv-scroll-board v-loading="fraternityLoading" :config="fraternityConfig" style="height: 380px"
element-loading-background="rgba(0, 0, 0, 0.2)" @click="handleFraternityTableClick"/>
<div slot="extra">
2023-10-31 18:03:52 +08:00
<dv-scroll-board class="mar-t10" :config="fraternityExtraConfig" style="height: 380px"
:class="{origin:fraternityExtraConfig.header.length==0}"/>
2023-10-31 16:09:11 +08:00
</div>
2023-10-31 11:36:39 +08:00
</template>
<template v-else-if="detail.mapType=='fraternity'">
<div class="flex normal">
<el-image class="fraternityImg" :src="detail.cover_url"/>
<div class="mar-l16 fill" v-html="detail.introduction"/>
</div>
</template>
<template v-else-if="detail.mapType=='area'">
<div class="staPanel area right mar-t12 mar-b24 grid c-4">
<fd-item v-for="(v,k) in detail.sta" :key="k" :label="k"><b v-text="v"/></fd-item>
</div>
<div class="flex mar-b14">
<div class="shortcut" v-for="cut in areaStaTypes" :key="cut.k" @click="areaStaType=cut.k"
:class="{active:areaStaType==cut.k}" v-text="cut.v"/>
</div>
<dv-scroll-board :config="areaTableConfig" style="height: 152px"/>
2023-10-23 18:07:14 +08:00
</template>
<template v-else>
<div v-if="detail.header" class="contentHead" v-html="detail.header"/>
<el-row type="flex" class="fill">
<el-carousel v-if="detail.imgs" class="fill">
<el-carousel-item v-for="(img,i) in detail.imgs" :key="i">
<el-image :src="img" :preview-src-list="detail.imgs"/>
</el-carousel-item>
</el-carousel>
<fd-scrollbar v-if="detail.form" class="fill mar-l24">
<fd-item v-for="(v,k) in detail.form" :key="k" :label="k" :value="v"/>
</fd-scrollbar>
<fd-scrollbar v-if="detail.content" class="fill mar-l14">
<div v-html="detail.content"/>
</fd-scrollbar>
</el-row>
</template>
2023-10-23 16:32:13 +08:00
</fd-dialog>
2023-10-11 18:21:40 +08:00
</ai-fit-view>
</section>
</template>
<script>
import AiFitView from "dui/packages/layout/AiFitView.vue";
import FengduHead from "./components/fengduHead.vue";
2023-10-13 18:10:45 +08:00
import FdCard from "./components/fdCard.vue";
import AiEchart from "dui/packages/tools/AiEchart.vue";
import AiHighlight from "dui/packages/layout/AiHighlight.vue";
2023-10-18 10:34:41 +08:00
import AiInfoItem from "dui/packages/basic/AiInfoItem.vue";
import AiWrapper from "dui/packages/basic/AiWrapper.vue";
2023-10-18 14:59:52 +08:00
import Vue from "vue";
import {scrollBoard} from "@jiaminghi/data-view"
2023-10-23 09:18:23 +08:00
import FdMap from "./components/fdMap.vue";
2023-10-23 16:32:13 +08:00
import FdDialog from "./components/fdDialog.vue";
import FdItem from "./components/fdItem.vue";
import FdScrollbar from "./components/fdScrollbar.vue";
import {Carousel, Slide} from "vue-carousel"
const tableConfigs = {
headerBGC: 'rgba(33, 180, 253, 0.1)',
2023-10-31 16:09:11 +08:00
headerHeight: 38,
oddRowBGC: 'rgba(112, 112, 112, 0)',
evenRowBGC: 'rgba(112, 112, 112, 0)',
rowNum: 3,
}
const genderDict = {
1: '男', 2: '女', 3: '未知', 0: '未知'
}
2023-10-30 17:48:04 +08:00
const getCluster = (points, options = {big: {}, normal: {}}, num = 10) => {
2023-10-31 11:36:39 +08:00
const big = [], {distance = 0.03} = options
2023-10-30 17:48:04 +08:00
const pointInsideCircle = (point, circle, r) => {
if (r === 0) return false
const dx = circle[0] - point[0]
const dy = circle[1] - point[1]
return dx * dx + dy * dy <= r * r
}
return points.map(e => {
e.coord = e.coord.map(c => Number(c))
if (big.length == 0 ||
2023-10-31 11:36:39 +08:00
!big.find(b => pointInsideCircle(e.coord, b, distance)) && big.length < num && e.introduction) {
2023-10-30 17:48:04 +08:00
big.push(e.coord)
return {
...e,
...options.big,
}
} else {
return {
...e,
...options.normal
}
}
})
}
2023-10-11 18:21:40 +08:00
export default {
name: "AppBIBoard",
label: "丰都指挥舱",
2023-10-23 16:32:13 +08:00
components: {
FdScrollbar, Carousel, Slide,
2023-10-23 16:32:13 +08:00
FdItem, FdDialog, FdMap, AiWrapper, AiInfoItem, AiHighlight, AiEchart, FdCard, FengduHead, AiFitView
},
2023-10-11 18:21:40 +08:00
props: {
instance: Function,
dict: Object
},
data() {
return {
2023-10-19 17:19:15 +08:00
areaId: '',
fraternity: '',
2023-10-13 18:10:45 +08:00
fullscreen: false,
2023-10-23 16:32:13 +08:00
sta: {},
2023-10-13 18:10:45 +08:00
chart: {
2023-10-18 10:34:41 +08:00
legend: {show: false},
2023-10-13 18:10:45 +08:00
series: {
type: 'gauge',
startAngle: 90,
endAngle: -270,
center: ['50%', 74],
radius: 50,
progress: {
2023-10-18 10:34:41 +08:00
show: true,
2023-10-13 18:10:45 +08:00
overlap: false,
roundCap: true,
clip: false,
2023-10-18 10:34:41 +08:00
itemStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{offset: 0, color: '#139AFF'},
{offset: 1, color: '#0ED5A6'},
]
}
},
2023-10-13 18:10:45 +08:00
},
2023-10-18 10:34:41 +08:00
pointer: {show: false},
splitLine: {show: false},
axisTick: {show: false},
axisLabel: {show: false},
2023-10-13 18:10:45 +08:00
axisLine: {
2023-10-18 10:34:41 +08:00
lineStyle: {width: 6, color: [[1, 'rgba(102, 121, 138, 0.4)']]},
},
detail: {
valueAnimation: true,
offsetCenter: [0, 0],
fontSize: 24,
formatter: '{value}%',
color: "#02FEFF",
2023-10-19 17:19:15 +08:00
fontFamily: "DIN",
2023-10-18 10:34:41 +08:00
width: 50,
lineHeight: 50,
padding: 12,
borderWidth: 1,
borderColor: 'rgba(102, 121, 138, 0.4)',
borderRadius: 50
},
},
2023-10-13 18:10:45 +08:00
},
2023-10-18 10:34:41 +08:00
chartData: [
2023-10-23 16:32:13 +08:00
// {name: "活跃居民群", value: 3502},
// {name: "全部居民群", value: 5118},
2023-10-18 14:59:52 +08:00
],
2023-10-23 16:32:13 +08:00
chartData2: [],
volunteers: {},
2023-10-18 14:59:52 +08:00
volunteerConfig: {
...tableConfigs,
2023-10-18 14:59:52 +08:00
header: ['所属团队', '姓名', '性别', '年龄'],
rowNum: 4,
columnWidth: [250, 80],
2023-10-18 14:59:52 +08:00
align: ['left', 'left', 'left', 'center'],
carousel: 'page',
data: [
// ['三合街道丁庄社区互助会', '张珊珊', '女', 32],
// ['三合街道丁庄社区互助会', '王富贵', '女', 32],
// ['三合街道丁庄社区互助会', '阿萨德', '男', 23],
// ['三合街道丁庄社区互助会', '阿连德', '男', 54],
// ['三合街道丁庄社区互助会', '王柏柏', '女', 66],
// ['三合街道丁庄社区互助会', '赵二狗', '男', 41],
// ['三合街道丁庄社区互助会', '唯一键', '女', 13],
// ['三合街道丁庄社区互助会', '卡萨丁', '男', 32],
// ['三合街道丁庄社区互助会', '卡萨丁', '男', 32],
// ['三合街道丁庄社区互助会', '卡萨丁', '男', 32],
// ['三合街道丁庄社区互助会', '张珊珊', '女', 32],
// ['三合街道丁庄社区互助会', '张珊珊', '女', 32],
2023-10-18 14:59:52 +08:00
]
},
2023-10-19 17:19:15 +08:00
appSta: {
...tableConfigs,
2023-10-19 17:19:15 +08:00
header: ['应用名称', '本日点击', '累计点击'],
rowNum: 7,
columnWidth: [250],
align: ['left', 'right', 'right'],
data: [
2023-10-23 10:48:30 +08:00
// ['渝快办', 178, 266],
// ['公交乘车码', 178, 266],
// ['警快办', 178, 266],
// ['医保电子凭证', 178, 266],
// ['居民上报', 178, 266],
// ['医保电子凭证', 178, 266],
// ['居民上报', 178, 266],
2023-10-19 17:19:15 +08:00
]
},
realtimeEvents: {
...tableConfigs,
2023-10-19 17:19:15 +08:00
columnWidth: [226],
align: ['center', 'left'],
data: [
2023-10-23 10:48:30 +08:00
// ['<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>', '三角路社区居民-陈思宇在丰收号小程序中进行了物品兑换'],
2023-10-19 17:19:15 +08:00
]
},
2023-10-23 16:32:13 +08:00
shortcut: 3,
2023-10-23 10:48:30 +08:00
GongdeBank: {},
2023-10-23 16:32:13 +08:00
map: null,
dialog: false,
detail: {},
areaStaType: 'grid',
fraternities: [],
2023-10-31 16:09:11 +08:00
fraternityTypes: [],
fraternityFilter: '',
fraternityLoading: false,
fraternityExtra: false,
leftBottom: '志愿者'
2023-10-11 18:21:40 +08:00
}
},
2023-10-18 14:59:52 +08:00
computed: {
2023-10-23 16:32:13 +08:00
shortcuts: () => [
{k: '3', v: '昨日'},
{k: '0', v: '近七天'},
{k: '1', v: '近30天'},
{k: '2', v: '近一年'},
],
areaStaTypes: () => [
{k: 'grid', v: '网格'},
{k: 'resident', v: '居民群'},
{k: 'volunteer', v: '互助会'},
],
goodsConfig: v => ({
...tableConfigs,
header: ['兑换人', '兑换商品', '数量', '积分', '状态'],
data: v.detail.orders?.map(e => [e.integralUserName, e.goodsTitle, e.quantity, e.goodsIntegralPrice,
`<div class="statusTag ${e.status > 0 ? 'success' : ''}">${v.dict.getLabel('integralSGOStatus', e.status)}</div>`]),
align: ['left', 'left', 'right', 'right', 'center'],
}),
areaTableConfig: v => ({
...tableConfigs,
...{
grid: {
header: ['村/社区', '网格名称', '网格员人数'],
align: ['left', 'left', 'right'],
data: v.detail.girdList?.map(e => [e.parentGirdName, e.girdName, e.girdMemberCount])
},
resident: {
header: ['群名称', '群主', '群人数'],
align: ['left', 'left', 'right'],
2023-10-24 14:27:33 +08:00
columnWidth: [250],
data: v.detail.groupList?.map(e => [e.name, e.ownerName, e.memberCount])
2023-10-24 14:27:33 +08:00
},
volunteer: {
2023-10-31 11:36:39 +08:00
header: ['互助会类型', '互助会数量', '会员数'],
align: ['left', 'right', 'right'],
2023-10-24 14:27:33 +08:00
columnWidth: [250],
2023-10-31 11:36:39 +08:00
data: v.detail.fraternities?.map(e => [e.type, e.number, e.member_number])
}
}[v.areaStaType]
2023-10-31 11:36:39 +08:00
}),
fraternityConfig: v => ({
...tableConfigs,
header: ['互助会', '家长数量', '学生数量', '活动数量'],
2023-10-31 16:09:11 +08:00
columnWidth: [280],
2023-10-31 11:36:39 +08:00
align: ['left', 'right', 'right', 'right'],
rowNum: 9,
2023-10-31 16:09:11 +08:00
data: v.detail.list.filter(e => !v.fraternityFilter || e.fraternity_name.indexOf(v.fraternityFilter) > -1)
.map(e => [e.fraternity_name, e.par_num, e.stu_num, e.act_num])
}),
fraternityExtraConfig: v => ({
...tableConfigs, rowNum: 10,
header: ['姓名', '性别', '年龄'],
align: ['left', 'center', 'right'],
data: v.detail.extra,
...v.detail.others
}),
fraternityTypeConfig: v => ({
oddRowBGC: 'rgba(112, 112, 112, 0)',
evenRowBGC: 'rgba(112, 112, 112, 0)',
rowNum: 3,
data: v.fraternityTypes.map(e => [`
<div class="title mar-t10">${e.type}</div>
2023-10-31 18:03:52 +08:00
<div class="staPanel simple right flex mar-t10" >
2023-10-31 16:09:11 +08:00
<div class="fill"><div>互助会</div><b>${e.number || 0}</b></div>
<div class="fill"><div>会员数量</div><b>${e.member_number || 0}</b></div>
<div class="fill"><div>活动数量</div><b>${e.activity_number || 0}</b></div>
</div>
`])
})
2023-10-18 14:59:52 +08:00
},
2023-10-23 10:48:30 +08:00
watch: {
shortcut() {
this.getGdyh(this.areaId)
2023-10-23 16:32:13 +08:00
},
dialog(v) {
!v && (this.detail = {})
2023-10-24 16:04:19 +08:00
},
areaId(v) {
!!v && this.getData()
2023-10-23 10:48:30 +08:00
}
},
2023-10-11 18:21:40 +08:00
methods: {
handleFullScreen() {
this.fullscreen = this.$refs.fddv.handleFullScreen()
},
handleSetting(v) {
this.$refs.fddv.dialog = v
2023-10-18 10:34:41 +08:00
},
2023-10-23 16:32:13 +08:00
calcProgress(data = []) {
2023-10-24 18:10:46 +08:00
const value = data.length > 0 ? (data[0].value / data.at(-1).value * 100 || 0).toFixed(0) : 0
2023-10-18 10:34:41 +08:00
return [{value}]
2023-10-18 14:59:52 +08:00
},
2023-10-23 10:48:30 +08:00
getData(c = 0) {
2023-10-19 17:19:15 +08:00
const {areaId} = this.$data
2023-10-23 10:48:30 +08:00
if (areaId) {
2023-10-30 17:48:04 +08:00
const loading = this.$loading({
text: "正在加载数据...",
background: 'rgba(0,0,0,.91)',
})
Promise.all([
2023-10-30 17:48:04 +08:00
this.getMiniAppInfo(),
this.getRealTimeDynamic(areaId),
this.getWxGroupOverview(areaId),
this.getGdyh(areaId),
this.getFraternitySta(this.transferAreaCode(areaId)),
2023-10-31 16:09:11 +08:00
this.getFraternityTypes(areaId).then(data => this.fraternityTypes = data),
2023-11-01 11:34:27 +08:00
this.getFraternities(this.transferAreaCode(areaId)).then(() => this.getMapData(areaId)),
this.getVolunteerData(areaId)
2023-10-30 17:48:04 +08:00
]).finally(() => loading.close())
2023-10-23 10:48:30 +08:00
} 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) {
2023-10-19 17:19:15 +08:00
this.instance.post("/app/fdDiy/realTimeDynamic", null, {params: {areaId}}).then(res => {
2023-10-23 10:48:30 +08:00
if (res?.data) {
2023-10-23 16:32:13 +08:00
const meta = res.data,
data = meta.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}
2023-10-23 10:48:30 +08:00
}
})
},
getWxGroupOverview(areaId) {
this.instance.post("/app/fdDiy/wxGroupOverview", null, {params: {areaId}}).then(res => {
2023-10-19 17:19:15 +08:00
if (res?.data) {
2023-10-23 16:32:13 +08:00
const {群数量 = 0, 群主人数 = 0, 群成员数量 = 0} = res.data
this.sta = {
群数量, 群主人数,
'群人员活跃数(30天)': Number(res.data['群人员活跃数(30天)']).toLocaleString(),
'群消息数(30天)': Number(res.data['群消息数(30天)']).toLocaleString(),
}
this.chartData = [
{name: "活跃居民群", value: Math.ceil(res.data["活跃居民群数量(7天)"] / 7)},
{name: "全部居民群", value: 群数量},
]
this.chartData2 = [
{name: "活跃居民数", value: res.data["活跃群成员数量(7天)"]},
{name: "群成员数量", value: 群成员数量},
]
2023-10-19 17:19:15 +08:00
}
})
2023-10-23 10:48:30 +08:00
},
getGdyh(areaId) {
this.instance.post("/app/fdDiy/gdyh", null, {params: {areaId, type: this.shortcut}}).then(res => {
if (res?.data) {
const {
2023-10-23 18:07:14 +08:00
宣发发布任务数 = 0,
宣发未审核数 = 0,
宣发审核通过数 = 0,
店铺总数 = 0,
2023-10-23 10:48:30 +08:00
店品库存量 = 0,
2023-10-23 18:07:14 +08:00
兑换物品数量 = 0,
2023-10-23 10:48:30 +08:00
获取积分总数: total = 0,
居民签到人次: 签到人数 = 0,
积分申请次数: 申请人数 = 0,
兑换总积分: useTotal = 0
} = res.data
this.GongdeBank = {
total, useTotal,
users: {
参与人数: 签到人数 + 申请人数,
申请人数,
签到人数
},
stores: {店铺总数, 店品库存量, 兑换物品数量},
tasks: {
宣发发布任务数,
审核通过率: (宣发审核通过数 / 宣发发布任务数 * 100 || 0).toFixed(2) + "%",
宣发未审核数,
}
}
}
})
},
getMapData(visibleId) {
2023-10-23 18:07:14 +08:00
const initMap = new Promise(resolve => {
const load = (c = 0) => {
2023-10-31 11:36:39 +08:00
if (this.map && this.$refs.map) {
2023-10-23 18:07:14 +08:00
resolve()
} else if (c < 10) setTimeout(() => load(++c), 500)
}
load()
})
this.instance.post("/app/appintegralsupermarketshop/list", null, {params: {visibleId, size: 9999}}).then(res => {
2023-10-23 18:07:14 +08:00
if (res?.data) {
initMap.then(() => {
2023-10-24 18:17:56 +08:00
this.map.clear()
this.$refs.map.init()
2023-10-30 17:48:04 +08:00
const {records} = res.data,
fraternities = this.fraternities.filter(e => !!e.longtitude)
2023-10-23 18:07:14 +08:00
this.map.on('click', e => {
if (e.data?.marker == 'store') {//点击店铺
2023-10-23 18:07:14 +08:00
this.getMapStore(e.data)
2023-10-30 17:48:04 +08:00
} else if (e.data?.marker == 'fraternity') {//点击互助会
2023-10-31 11:36:39 +08:00
this.dialog = true
const {fraternity_name, marker: mapType} = e.data
this.detail = {eventType: fraternity_name, mapType, ...e.data}
} else if (e.data?.unique_id) {//点击地区
this.getMapArea(e.data)
2023-10-23 18:07:14 +08:00
}
})
this.map.setOption({
series: {
markPoint: {
symbolSize: 24,
label: {
show: true,
position: 'right',
formatter: '{b}',
2023-10-30 17:48:04 +08:00
distance: 2,
2023-10-23 18:07:14 +08:00
},
2023-10-30 17:48:04 +08:00
data: [
...getCluster(records.filter(e => !!e.lng).map(e => ({
...e,
marker: 'store',
coord: [e.lng, e.lat],
name: e.title,
label: {color: "#FECA86"},
})), {
big: {symbol: "image://https://cdn.cunwuyun.cn/fengdu/fdStoreIcon.png"},
normal: {
itemStyle: {color: "#FECA86"},
label: {show: false, emphasis: {show: true, color: "#FECA86"}},
symbol: 'circle',
symbolSize: 6
}
}),
...getCluster(fraternities.map(e => ({
...e,
marker: 'fraternity',
coord: [e.longtitude, e.latitude],
name: e.fraternity_name,
label: {color: "#70FF8A"},
})), {
big: {symbol: "image://https://cdn.cunwuyun.cn/fengdu/fdFraternitIcon.png"},
normal: {
itemStyle: {color: "#70FF8A"},
label: {show: false, emphasis: {show: true, color: "#70FF8A"}},
symbol: 'circle',
symbolSize: 6
}
})
],
2023-10-23 18:07:14 +08:00
}
}
})
})
}
})
},
getMapStore(store = {}) {
this.instance.post("/app/fdDiy/mapShopInfo", null, {params: {id: store.id}}).then(res => {
if (res?.data) {
this.dialog = true
this.detail = {eventType: store.name, mapType: store.marker, ...res.data}
}
})
},
getMapArea(area) {
2023-10-31 11:36:39 +08:00
let info = {}, fraternity = {}
Promise.all([
this.instance.post("/app/fdDiy/mapAreaInfo", null, {params: {areaId: area.unique_id.padEnd(12, '0')}}).then(res => {
if (res?.data) {
return info = res.data
}
2023-10-31 11:36:39 +08:00
}),
2023-10-31 18:03:52 +08:00
this.getFraternityTypes(area.unique_id).then(list => {
2023-10-31 16:09:11 +08:00
let 互助会 = 0, 会员数量 = 0
list.forEach(e => {
互助会 += e.number
会员数量 += e.member_number
})
return fraternity = {互助会, 会员数量, list}
2023-10-31 11:36:39 +08:00
})
]).then(() => {
this.dialog = true
const {村社区数量, 居民群数量, 居民数, 网格数, 群成员数量, 户数} = info,
{互助会 = 0, 会员数量 = 0} = fraternity
this.detail = {
eventType: area.name,
mapType: 'area', ...info, fraternities: fraternity.list,
sta: {村社区数量, 居民群数量, 居民数, 网格数, 群成员数量, 户数, 互助会, 会员数量}
}
})
2023-10-31 11:36:39 +08:00
2023-10-30 17:48:04 +08:00
},
2023-10-23 10:48:30 +08:00
handleRealtimeEventDialog({rowIndex}) {
const row = this.realtimeEvents.meta[rowIndex]
if (row.bizId) {
const action = {
2023-10-23 16:32:13 +08:00
积分申请: "/app/appintegraluserapply/queryDetailById",
物品兑换: "/app/appintegralsupermarketorder/queryDetailById",
精选动态: "/app/appcontentinfo/queryDetailById",
2023-10-23 10:48:30 +08:00
}[row.type]
this.instance.post(action, null, {params: {id: row.bizId}}).then(res => {
if (res?.data) {
2023-10-23 16:32:13 +08:00
this.dialog = true
if (row.type == '积分申请') {
const {
applyItemName: 事件类型,
integralUserName: 申请人,
areaName: 所属地区,
createTime: 申请时间,
girdName: 所属网格,
content: 事件描述,
applyIntegral: 积分值,
phone: 手机号,
status,
files
} = res.data
this.detail.imgs = files?.map(e => e.accessUrl)
this.detail.form = {
事件类型,
申请人,
所属地区,
申请时间,
事件描述,
积分值,
手机号,
所属网格,
状态: `<div class="statusTag ${status > 0 ? 'success' : ''}">${this.dict.getLabel('appIntegralApplyEventStatus', status)}</div>`
}
} else if (row.type == '物品兑换') {
const {
status,
examineUserName: 核销人,
examineTime: 核销时间,
goodsPicUrl,
integralUserName: 兑换人,
goodsTitle: 兑换商品,
quantity: 数量,
usedIntegral: 消耗积分,
createTime: 兑换时间,
agentOrder
} = res.data
this.detail.imgs = [goodsPicUrl].flat().filter(Boolean) || []
this.detail.form = {
兑换人,
兑换商品,
数量,
消耗积分,
是否代兑换: this.dict.getLabel("yesOrNo", agentOrder),
兑换时间,
状态: `<div class="statusTag ${status > 0 ? 'success' : ''}">${this.dict.getLabel('appIntegralApplyEventStatus', status)}</div>`,
核销人,
核销时间
}
} else if (row.type == '精选动态') {
const {content, files, title, createUserName, girdName} = res.data
this.detail.imgs = files?.map(e => e.accessUrl)
this.detail.content = content
this.detail.header = ` <b>${title}</b>
<div class="flex normal mar-t8">
<div>${girdName}</div>
<div class="mar-l8">${createUserName}</div>
</div>`
}
this.detail = {eventType: row.type, ...this.detail}
2023-10-23 10:48:30 +08:00
}
})
}
2023-10-23 18:07:14 +08:00
},
handleJump() {
window.open("http://datas.fdxjtjyhzzyfw.cn/")
2023-10-25 12:07:12 +08:00
},
getVolunteerData(area_code) {
2023-10-30 17:48:04 +08:00
area_code = this.transferAreaCode(area_code)
return this.instance.get("/hzh/find-volunteer-list-detail", {
params: {
page_size: 40,
area_code,
2023-11-01 11:34:27 +08:00
team_id: this.fraternity
}
}).then(res => {
if (res?.data) {
this.volunteerConfig = {
...this.volunteerConfig,
data: res.data.map(e => [e.team_name, e.vol_name, genderDict[e.vol_gender], e.vol_age])
}
}
})
},
getFraternities(area_code) {
2023-10-30 17:48:04 +08:00
return this.instance.get("/hzh/find-fraternity-detail", {params: {page_size: 999, area_code}}).then(res => {
if (res?.data) {
2023-11-01 11:34:27 +08:00
// this.fraternity = res.data[0]?.fraternity_id
2023-10-30 17:48:04 +08:00
return this.fraternities = res.data || []
}
})
},
getFraternitySta(area_code) {
2023-10-30 17:48:04 +08:00
return this.instance.get("/hzh/count-vol-team", {params: {page_size: 999, area_code}}).then(res => {
if (res?.data) {
let 团队数量 = 0, 志愿者数量 = 0, 服务学员数量 = 0
res.data.forEach(e => {
团队数量++
志愿者数量 += e.vol_num
服务学员数量 += e.stu_num
})
this.volunteers = {团队数量, 志愿者数量, 服务学员数量}
}
})
2023-10-30 17:48:04 +08:00
},
transferAreaCode(code) {//与互助会地区编码互通
2023-10-31 11:36:39 +08:00
const format = str => Number(str).toString().padStart(3, '0'),
last = /0{6}$/.test(code) ? '' : format(code.substring(6, 9))
return code.substring(0, 6) + last
},
2023-10-31 16:09:11 +08:00
getFraternityData(args) {
2023-10-31 18:03:52 +08:00
const row = this.fraternityTypes[args.rowIndex]
2023-10-31 16:09:11 +08:00
this.dialog = true
2023-11-01 11:34:27 +08:00
this.detail = {eventType: row.type, mapType: 'fraternitySta', list: [], fraternity_type: row.type_id}
2023-10-31 11:36:39 +08:00
const area_code = this.transferAreaCode(this.areaId)
2023-10-31 16:09:11 +08:00
this.fraternityLoading = true
2023-11-01 11:34:27 +08:00
this.instance.get("/hzh/find-fraternity-member-detail", {
params: {
area_code,
fraternity_type: row.type_id
}
}).then(res => {
2023-10-31 11:36:39 +08:00
if (res?.data) {
2023-10-31 16:09:11 +08:00
this.detail = {...this.detail, list: res.data}
2023-10-31 11:36:39 +08:00
}
2023-10-31 16:09:11 +08:00
}).finally(() => this.fraternityLoading = false)
},
handleFraternityTableClick(args) {
2023-11-01 11:34:27 +08:00
const {columnIndex: type, rowIndex} = args,
{fraternity_type} = this.detail
2023-10-31 16:09:11 +08:00
if (type > 0) {
const current = this.detail.list[rowIndex]
this.fraternityExtra = true
this.$set(this.detail, 'extraType', type)
this.$set(this.detail, 'extraTitle', {
2023-10-31 18:03:52 +08:00
1: '家长名单', 2: '学生名单', 3: '活动情况'
2023-10-31 16:09:11 +08:00
}[type])
if (type == 3) {
2023-10-31 18:03:52 +08:00
this.$set(this.detail, 'others', {header: [], rowNum: 3})
2023-11-01 11:34:27 +08:00
this.instance.get("/hzh/find-fraternity-activity-detail", {
params: {
area_code: this.transferAreaCode(this.areaId),
fraternity_type
}
}).then(res => {
2023-10-31 18:03:52 +08:00
if (res?.data) {
this.$set(this.detail, 'extra', res.data.map(e => [`
<div class="staPanel activity flex mar-t10" >
<img class="actImg" src="${e.icon_url}"/>
<div class="fill mar-l14">
<b>${e.activity_name}</b>
2023-10-31 18:06:18 +08:00
<div class="flex mar-b8 mar-t16 el-icon-time">&nbsp;&nbsp;${e.start_time + "-" + e.end_time}</div>
<div class="flex el-icon-location">&nbsp;&nbsp;${e.activity_address}</div></div></div>`]))
2023-10-31 18:03:52 +08:00
}
})
} else {
this.$set(this.detail, 'extra', current[{
1: 'parent', 2: 'student'
}[type]]?.map(e => [e.name, genderDict[e.gender], e.age]) || [])
2023-10-31 16:09:11 +08:00
}
}
2023-10-31 11:36:39 +08:00
},
2023-10-31 16:09:11 +08:00
getFraternityTypes(area_code) {
area_code = this.transferAreaCode(area_code)
return this.instance.get("/hzh/count-fraternity", {params: {area_code}}).then(res => {
if (res?.data) {
return res.data
}
})
}
2023-10-11 18:21:40 +08:00
},
2023-10-18 14:59:52 +08:00
created() {
Vue.use(scrollBoard)
this.dict.load('appIntegralApplyEventStatus', 'yesOrNo', 'integralSGOStatus')
2023-10-18 14:59:52 +08:00
},
2023-10-11 18:21:40 +08:00
}
</script>
<style scoped lang="scss">
.AppBIBoard {
2023-10-13 18:10:45 +08:00
color: #CDDBEA;
font-size: 14px;
2023-10-18 14:59:52 +08:00
: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;
&::placeholder {
color: inherit;
}
}
.el-input__icon {
color: #B3DDE5;
2023-10-18 14:59:52 +08:00
}
.el-input__suffix {
color: #B3DDE5;
}
}
2023-10-11 18:21:40 +08:00
&.fullscreen {
position: fixed;
z-index: 202310111819;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
2023-10-12 18:17:46 +08:00
:deep(.viewPanel) {
background-image: url("./assets/img_bg.png");
2023-10-13 18:10:45 +08:00
& > .fill {
display: flex;
gap: 20px;
padding: 12px 24px 0;
}
}
.left, .right {
width: 480px;
flex-shrink: 0;
}
.grid {
display: grid;
gap: 14px;
&.c-2 {
2023-10-19 17:19:15 +08:00
grid-template-columns:1fr 1fr;
}
&.c-3 {
grid-template-columns:1fr 1fr 1fr;
2023-10-13 18:10:45 +08:00
}
&.c-4 {
grid-template-columns:1fr 1fr 1fr 1fr;
}
2023-10-13 18:10:45 +08:00
}
2023-10-31 16:09:11 +08:00
:deep(.staPanel) {
2023-10-13 18:10:45 +08:00
text-align: center;
font-size: 15px;
line-height: 20px;
background: url("./assets/staPanel-bg.png") no-repeat;
2023-10-19 17:19:15 +08:00
background-size: 100% 100%;
2023-10-13 18:10:45 +08:00
height: 80px;
padding-top: 14px;
2023-10-19 17:19:15 +08:00
width: 100%;
2023-10-13 18:10:45 +08:00
2023-10-18 14:59:52 +08:00
b {
2023-10-19 17:19:15 +08:00
font-family: DIN;
2023-10-13 18:10:45 +08:00
font-size: 22px;
color: #02FEFF;
letter-spacing: 0;
line-height: 36px;
}
2023-10-19 17:19:15 +08:00
&.simple {
background: #ffffff0a;
padding-top: 0;
&.right {
color: #9BB7D4;
b {
color: #FFFFFF;
}
}
}
&.area {
background: #ffffff0a;
padding: 16px 8px;
gap: 14px;
b {
font-size: 16px;
color: #FFFFFF;
line-height: 16px;
}
:deep(.fdItem) {
margin-bottom: 0;
& > label {
color: #9BB7D4;
}
}
}
2023-10-31 18:03:52 +08:00
&.activity {
background: #ffffff0a;
padding: 14px;
height: 108px;
text-align: left;
b {
color: #FFFFFF;
}
.actImg {
width: 80px;
height: 80px;
flex-shrink: 0;
}
}
2023-10-13 18:10:45 +08:00
}
.chart {
2023-10-18 10:34:41 +08:00
.legend {
position: absolute;
left: 0;
right: 0;
bottom: 0;
}
2023-10-19 17:19:15 +08:00
.AiEchart {
height: 204px;
}
2023-10-12 18:17:46 +08:00
}
2023-10-18 14:59:52 +08:00
2023-10-31 16:09:11 +08:00
:deep(.title ) {
2023-10-18 14:59:52 +08:00
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;
2023-10-31 16:09:11 +08:00
&.origin {
.row-item {
border: none;
height: unset;
line-height: normal;
}
.ceil {
padding: 0;
}
}
2023-10-18 14:59:52 +08:00
.header-item {
color: #02FEFF;
}
.row-item {
2023-10-19 17:19:15 +08:00
height: 38px;
2023-10-18 14:59:52 +08:00
line-height: 38px;
2023-10-19 17:19:15 +08:00
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;
2023-10-18 14:59:52 +08:00
}
2023-10-23 10:48:30 +08:00
.blue {
color: #02FEFF;
cursor: pointer;
}
.ceil > .statusTag {
margin-top: 19px;
transform: translateY(-50%);
}
2023-10-18 14:59:52 +08:00
}
2023-10-19 17:19:15 +08:00
.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;
2023-10-23 10:48:30 +08:00
padding-right: 40px;
2023-10-19 17:19:15 +08:00
justify-content: flex-end;
background: url("./assets/box.png") no-repeat 80px center;
height: 82px;
font-size: 16px;
.text {
color: #FFFFFF;
2023-10-23 10:48:30 +08:00
width: 200px;
2023-10-19 17:19:15 +08:00
justify-content: space-between;
& > p {
font-family: DIN;
font-size: 26px;
color: #02FEFF;
}
}
&.box2 {
2023-10-25 12:07:12 +08:00
background-image: url("./assets/box2.png");
}
2023-10-19 17:19:15 +08:00
}
2023-10-23 16:32:13 +08:00
:deep(.statusTag ) {
height: 20px;
line-height: 20px;
padding: 0 8px;
2023-10-23 16:32:13 +08:00
color: #FFB300;
background: #ffcb5224;
width: fit-content;
2023-10-23 16:32:13 +08:00
&.success {
color: #07B794;
background: #13f6c924;
}
}
:deep(.contentHead) {
width: 100%;
height: 89px;
background: url("./assets/contentHead.png") no-repeat;
margin-top: 16px;
margin-bottom: 14px;
padding: 16px;
background-size: 100% 89px;
& > b {
font-size: 16px;
color: #02FEFF;
letter-spacing: 0;
}
}
:deep(.VueCarousel) {
.goods {
font-size: 16px;
color: #02FEFF;
text-align: center;
& > img {
background: url("./assets/goodBg.png");
padding: 10px;
width: 130px;
height: 138px;
}
}
.VueCarousel-navigation-button {
width: 32px;
height: 32px;
background: url("./assets/carousel-nav-btn.png") no-repeat;
outline: none;
border-color: transparent;
&.VueCarousel-navigation-next {
transform: translate(100%, -50%) rotate(180deg);
}
&:active {
opacity: .8;
}
}
}
2023-10-31 11:36:39 +08:00
.fraternityImg {
width: 244px;
height: 268px;
flex-shrink: 0;
}
2023-10-31 16:09:11 +08:00
:deep(.el-carousel) {
.el-carousel__container {
height: 372px;
}
.el-carousel__indicators {
.el-carousel__indicator {
.el-carousel__button {
width: 6px;
height: 6px;
border-radius: 50%;
background: #679a9a80;
flex-shrink: 0;
}
&.is-active > .el-carousel__button {
background: #02FEFF;
}
}
}
}
2023-10-11 18:21:40 +08:00
}
</style>