937 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			937 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <template>
 | ||
|   <section class="AppBIBoard" :class="{fullscreen}">
 | ||
|     <ai-fit-view @scale="v=>scale=v">
 | ||
|       <ai-dv-wrapper ref="fddv" title="丰收号-家庭互助" :instance="instance" :mask="false">
 | ||
|         <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(chartData)">
 | ||
|                   <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(chartData2)">
 | ||
|                   <div class="legend">
 | ||
|                     <ai-highlight v-for="item in chartData2" :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" @click="handleJump">前往志愿者平台
 | ||
|               <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" v-model="map" style="height: calc(100% - 114px)"/>
 | ||
|           <fd-card class="centerBottom pad-b8" label="实时动态">
 | ||
|             <dv-scroll-board class="mar-t14" :config="realtimeEvents" style="height: 114px"
 | ||
|                              @click="handleRealtimeEventDialog"/>
 | ||
|           </fd-card>
 | ||
|         </div>
 | ||
|         <div class="right">
 | ||
|           <fd-card label="功德银行">
 | ||
|             <template #right>
 | ||
|               <div class="shortcut" v-for="cut in shortcuts" :key="cut.k" @click="shortcut=cut.k"
 | ||
|                    :class="{active:shortcut==cut.k}" v-text="cut.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>
 | ||
|       <fd-dialog v-model="dialog" :title="detail.eventType">
 | ||
|         <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>
 | ||
|           <b class="title mar-t14 mar-b12">订单列表</b>
 | ||
|           <dv-scroll-board :config="goodsConfig" style="height: 152px"/>
 | ||
|         </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"/>
 | ||
|         </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>
 | ||
|       </fd-dialog>
 | ||
|     </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";
 | ||
| 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)',
 | ||
|   oddRowBGC: 'rgba(112, 112, 112, 0)',
 | ||
|   evenRowBGC: 'rgba(112, 112, 112, 0)',
 | ||
|   headerHeight: 38,
 | ||
|   rowNum: 3,
 | ||
| }
 | ||
| 
 | ||
| export default {
 | ||
|   name: "AppBIBoard",
 | ||
|   label: "丰都指挥舱",
 | ||
|   components: {
 | ||
|     FdScrollbar, Carousel, Slide,
 | ||
|     FdItem, FdDialog, FdMap, AiWrapper, AiInfoItem, AiHighlight, AiEchart, FdCard, FengduHead, AiFitView
 | ||
|   },
 | ||
|   props: {
 | ||
|     instance: Function,
 | ||
|     dict: Object
 | ||
|   },
 | ||
|   data() {
 | ||
|     return {
 | ||
|       areaId: '',
 | ||
|       scale: 1,
 | ||
|       fullscreen: false,
 | ||
|       sta: {},
 | ||
|       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},
 | ||
|       ],
 | ||
|       chartData2: [],
 | ||
|       volunteers: {
 | ||
|         团队数量: 125,
 | ||
|         志愿者数量: 13,
 | ||
|         服务学员数量: 5
 | ||
|       },
 | ||
|       volunteerConfig: {
 | ||
|         ...tableConfigs,
 | ||
|         header: ['所属团队', '姓名', '性别', '年龄'],
 | ||
|         rowNum: 4,
 | ||
|         columnWidth: [250],
 | ||
|         align: ['left', 'left', 'left', 'center'],
 | ||
|         carousel: 'page',
 | ||
|         data: [
 | ||
|           ['三合街道丁庄社区互助会', '张珊珊', '女', 32],
 | ||
|           ['三合街道丁庄社区互助会', '王富贵', '女', 32],
 | ||
|           ['三合街道丁庄社区互助会', '阿萨德', '男', 23],
 | ||
|           ['三合街道丁庄社区互助会', '阿连德', '男', 54],
 | ||
|           ['三合街道丁庄社区互助会', '王柏柏', '女', 66],
 | ||
|           ['三合街道丁庄社区互助会', '赵二狗', '男', 41],
 | ||
|           ['三合街道丁庄社区互助会', '唯一键', '女', 13],
 | ||
|           ['三合街道丁庄社区互助会', '卡萨丁', '男', 32],
 | ||
|           ['三合街道丁庄社区互助会', '卡萨丁', '男', 32],
 | ||
|           ['三合街道丁庄社区互助会', '卡萨丁', '男', 32],
 | ||
|           ['三合街道丁庄社区互助会', '张珊珊', '女', 32],
 | ||
|           ['三合街道丁庄社区互助会', '张珊珊', '女', 32],
 | ||
|         ]
 | ||
|       },
 | ||
|       appSta: {
 | ||
|         ...tableConfigs,
 | ||
|         header: ['应用名称', '本日点击', '累计点击'],
 | ||
|         rowNum: 7,
 | ||
|         columnWidth: [250],
 | ||
|         align: ['left', 'right', 'right'],
 | ||
|         data: [
 | ||
|           // ['渝快办', 178, 266],
 | ||
|           // ['公交乘车码', 178, 266],
 | ||
|           // ['警快办', 178, 266],
 | ||
|           // ['医保电子凭证', 178, 266],
 | ||
|           // ['居民上报', 178, 266],
 | ||
|           // ['医保电子凭证', 178, 266],
 | ||
|           // ['居民上报', 178, 266],
 | ||
|         ]
 | ||
|       },
 | ||
|       current: 1,
 | ||
|       realtimeEvents: {
 | ||
|         ...tableConfigs,
 | ||
|         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: 3,
 | ||
|       GongdeBank: {},
 | ||
|       map: null,
 | ||
|       dialog: false,
 | ||
|       detail: {},
 | ||
|       areaStaType: 'grid'
 | ||
|     }
 | ||
|   },
 | ||
|   computed: {
 | ||
|     tablePages: v => Math.ceil(v.volunteerConfig.data.length / v.volunteerConfig.rowNum) || 0,
 | ||
|     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'],
 | ||
|           columnWidth: [250],
 | ||
|           data: v.detail.groupList?.map(e => [e.name, e.ownerName, e.memberCount])
 | ||
|         },
 | ||
|         volunteer: {
 | ||
|           header: ['互助会名称', '会长', '会员数'],
 | ||
|           align: ['left', 'left', 'right'],
 | ||
|           columnWidth: [250],
 | ||
|           data: v.detail.volunteers?.map(e => [e.name, e.ownerName, e.memberCount])
 | ||
|         }
 | ||
|       }[v.areaStaType]
 | ||
|     })
 | ||
|   },
 | ||
|   watch: {
 | ||
|     shortcut() {
 | ||
|       this.getGdyh(this.areaId)
 | ||
|     },
 | ||
|     dialog(v) {
 | ||
|       !v && (this.detail = {})
 | ||
|     },
 | ||
|     areaId(v) {
 | ||
|       console.log(v)
 | ||
|       !!v && this.getData()
 | ||
|     }
 | ||
|   },
 | ||
|   methods: {
 | ||
|     handleFullScreen() {
 | ||
|       this.fullscreen = this.$refs.fddv.handleFullScreen()
 | ||
|     },
 | ||
|     handleSetting(v) {
 | ||
|       this.$refs.fddv.dialog = v
 | ||
|     },
 | ||
|     calcProgress(data = []) {
 | ||
|       const value = data.length > 0 ? (data[0].value / data.at(-1).value * 100).toFixed(0) : 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)
 | ||
|         this.getMapData(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 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}
 | ||
|         }
 | ||
|       })
 | ||
|     },
 | ||
|     getWxGroupOverview(areaId) {
 | ||
|       this.instance.post("/app/fdDiy/wxGroupOverview", null, {params: {areaId}}).then(res => {
 | ||
|         if (res?.data) {
 | ||
|           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: 群成员数量},
 | ||
|           ]
 | ||
|         }
 | ||
|       })
 | ||
|     },
 | ||
|     getGdyh(areaId) {
 | ||
|       this.instance.post("/app/fdDiy/gdyh", null, {params: {areaId, type: this.shortcut}}).then(res => {
 | ||
|         if (res?.data) {
 | ||
|           const {
 | ||
|             宣发发布任务数 = 0,
 | ||
|             宣发未审核数 = 0,
 | ||
|             宣发审核通过数 = 0,
 | ||
|             店铺总数 = 0,
 | ||
|             店品库存量 = 0,
 | ||
|             兑换物品数量 = 0,
 | ||
|             获取积分总数: total = 0,
 | ||
|             居民签到人次: 签到人数 = 0,
 | ||
|             积分申请次数: 申请人数 = 0,
 | ||
|             兑换总积分: useTotal = 0
 | ||
|           } = res.data
 | ||
|           this.GongdeBank = {
 | ||
|             total, useTotal,
 | ||
|             users: {
 | ||
|               参与人数: 签到人数 + 申请人数,
 | ||
|               申请人数,
 | ||
|               签到人数
 | ||
|             },
 | ||
|             stores: {店铺总数, 店品库存量, 兑换物品数量},
 | ||
|             tasks: {
 | ||
|               宣发发布任务数,
 | ||
|               审核通过率: (宣发审核通过数 / 宣发发布任务数 * 100 || 0).toFixed(2) + "%",
 | ||
|               宣发未审核数,
 | ||
|             }
 | ||
|           }
 | ||
|         }
 | ||
|       })
 | ||
|     },
 | ||
|     getMapData(areaId) {
 | ||
|       const initMap = new Promise(resolve => {
 | ||
|         const load = (c = 0) => {
 | ||
|           if (this.map) {
 | ||
|             resolve()
 | ||
|           } else if (c < 10) setTimeout(() => load(++c), 500)
 | ||
|         }
 | ||
|         load()
 | ||
|       })
 | ||
|       this.instance.post("/app/appintegralsupermarketshop/list", null, {params: {areaId, size: 9999}}).then(res => {
 | ||
|         if (res?.data) {
 | ||
|           initMap.then(() => {
 | ||
|             const {records} = res.data
 | ||
|             this.map.on('click', e => {
 | ||
|               console.log(e)
 | ||
|               if (e.data?.marker == 'store') {//点击店铺
 | ||
|                 this.getMapStore(e.data)
 | ||
|               } else if (e.data?.unique_id) {//点击地区
 | ||
|                 this.getMapArea(e.data)
 | ||
|               }
 | ||
|             })
 | ||
|             this.map.setOption({
 | ||
|               series: {
 | ||
|                 markPoint: {
 | ||
|                   symbolSize: 24,
 | ||
|                   label: {
 | ||
|                     show: true,
 | ||
|                     position: 'right',
 | ||
|                     formatter: '{b}',
 | ||
|                     distance: 2
 | ||
|                   },
 | ||
|                   data: records.map(e => ({
 | ||
|                     ...e,
 | ||
|                     marker: 'store',
 | ||
|                     coord: [e.lng, e.lat],
 | ||
|                     name: e.title,
 | ||
|                     label: {color: "#FECA86"},
 | ||
|                     symbol: "image://https://cdn.cunwuyun.cn/fengdu/fdStoreIcon.png",
 | ||
|                   }))
 | ||
|                 }
 | ||
|               }
 | ||
|             })
 | ||
|           })
 | ||
|         }
 | ||
|       })
 | ||
|     },
 | ||
|     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) {
 | ||
|       this.instance.post("/app/fdDiy/mapAreaInfo", null, {params: {areaId: area.unique_id.padEnd(12, '0')}}).then(res => {
 | ||
|         if (res?.data) {
 | ||
|           this.dialog = true
 | ||
|           const {村社区数量, 居民群数量, 居民数, 网格数, 群成员数量, 户数, 互助会 = 0, 会员数量 = 0} = res.data
 | ||
|           this.detail = {
 | ||
|             eventType: area.name,
 | ||
|             mapType: 'area', ...res.data,
 | ||
|             sta: {村社区数量, 居民群数量, 居民数, 网格数, 群成员数量, 户数, 互助会, 会员数量}
 | ||
|           }
 | ||
|         }
 | ||
|       })
 | ||
|     },
 | ||
|     handleRealtimeEventDialog({rowIndex}) {
 | ||
|       const row = this.realtimeEvents.meta[rowIndex]
 | ||
|       if (row.bizId) {
 | ||
|         const action = {
 | ||
|           积分申请: "/app/appintegraluserapply/queryDetailById",
 | ||
|           物品兑换: "/app/appintegralsupermarketorder/queryDetailById",
 | ||
|           精选动态: "/app/appcontentinfo/queryDetailById",
 | ||
|         }[row.type]
 | ||
|         this.instance.post(action, null, {params: {id: row.bizId}}).then(res => {
 | ||
|           if (res?.data) {
 | ||
|             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}
 | ||
|           }
 | ||
|         })
 | ||
|       }
 | ||
|     },
 | ||
|     handleJump() {
 | ||
|       window.open("http://datas.fdxjtjyhzzyfw.cn/")
 | ||
|     }
 | ||
|   },
 | ||
|   created() {
 | ||
|     Vue.use(scrollBoard)
 | ||
|     this.getData()
 | ||
|     this.dict.load('appIntegralApplyEventStatus', 'yesOrNo', 'integralSGOStatus')
 | ||
|   },
 | ||
|   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;
 | ||
|     }
 | ||
| 
 | ||
|     &.c-4 {
 | ||
|       grid-template-columns:1fr 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;
 | ||
|         }
 | ||
|       }
 | ||
|     }
 | ||
| 
 | ||
|     &.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;
 | ||
|         }
 | ||
|       }
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   .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;
 | ||
|     }
 | ||
| 
 | ||
|     .ceil > .statusTag {
 | ||
|       margin-top: 19px;
 | ||
|       transform: translateY(-50%);
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   .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;
 | ||
|       }
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   :deep(.statusTag ) {
 | ||
|     height: 20px;
 | ||
|     line-height: 20px;
 | ||
|     padding: 0 8px;
 | ||
|     color: #FFB300;
 | ||
|     background: #ffcb5224;
 | ||
|     width: fit-content;
 | ||
| 
 | ||
|     &.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;
 | ||
|       }
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
| }
 | ||
| </style>
 |