您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
acfun统计(目前只包含送出礼物和收到礼物的统计)
当前为
// ==UserScript== // @name acfun统计 // @description acfun统计(目前只包含送出礼物和收到礼物的统计) // @namespace syachiku // @author syachiku // @match https://www.acfun.cn/member* // @run-at document-end // @grant GM_addStyle // @grant GM_xmlhttpRequest // @version 0.0.11 // @require https://cdnjs.cloudflare.com/ajax/libs/qs/6.9.4/qs.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.12/vue.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/element-ui/2.14.1/index.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/echarts/5.0.2/echarts.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/exceljs/4.2.0/exceljs.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.9.0/viewer.min.js // ==/UserScript== ;(async function(){ Vue.use(ELEMENT); Vue.prototype.$message = ELEMENT.Message; const config = { ACFUN_SERVER : 'https://www.acfun.cn', ACFUN_MOBILE_SERVER : 'https://m.acfun.cn', ACFUN_API_SERVER : 'http://api-ipv6.app.acfun.cn', ACFUNLIVE_SERVER : 'https://live.acfun.cn', URLS : { ACFUN_USER : { INFO : '/rest/pc-direct/user/userInfo', PUSH : '/member/#area=push', FOLLOWING : '/member/#area=following', FOLLOWER : '/member/#area=followers', SPACE : '/u', FEED : '/rest/app/feed/followFeedV2', }, WALLET : { SEND_GIFT : '/rest/apph5-direct/pay/reward/giveRecords', RECEIVE_GIFT : '/rest/apph5-direct/pay/reward/receiveRecords', } }, HEADERS : { ACFUN_API_SERVER : { acPlatform : 'ANDROID_PHONE', appVersion : '6.40.1.486', }, }, UBB : { PATTERN : { AT : /\[at\s+uid=(?<uid>\d+)\]\@(?<userName>.+?)\[\/at\]/g, IMG : /\[img=(?<title>.+?)\](?<url>.+?)\[\/img\]/g, }, }, }; // 是否为空 function isNullOrEmpty(val){ return _.isUndefined(val) || _.isNull(val) || _.isNaN(val) || (((_.isObject(val) && !_.isDate(val)) || _.isArray(val) || _.isString(val)) && _.isEmpty(val)) } function matchAll(text, pattern){ var result = []; for(var match of text.matchAll(pattern)){ result.push({ text : match[0], groups : match.groups, }); } return result; } // 通用请求 function commonRequrest(url, method, form, raw, callback, headers){ var isSuccess = false; var data = null; if(!headers){ headers = {}; } if(!raw){ if(method == 'post'){ headers['Content-Type'] = 'application/x-www-form-urlencoded'; if(form){ form = Qs.stringify(form); } } } if(method == 'get' && form){ form = Qs.stringify(form); url += '?' + form; } // 获取了token if(config.TOKEN){ headers['Authorization'] = `Token ${config.TOKEN}`; } GM_xmlhttpRequest({ synchronous : !_.isFunction(callback), method : method, url : url, data : form, headers : headers, onload : function(res){ // 200 if(res.status==200){ if(raw){ callback(true, res.responseText); } else{ res = JSON.parse(res.responseText); isSuccess = res[config.RESPONSE.FIELD.STATUS] == config.RESPONSE.STATUS.SUCCESS; data = res[config.RESPONSE.FIELD.DATA]; if(_.isFunction(callback)){ callback(isSuccess, data); } } } else{ if(_.isFunction(callback)){ callback(isSuccess, data); } } }, onerror : function(){ if(_.isFunction(callback)){ callback(isSuccess, data); } }, onabort : function(){ if(_.isFunction(callback)){ callback(isSuccess, data); } }, }); return [isSuccess, data]; } function addCssResource(url){ commonRequrest(url, 'get', null, true, function(isSuccess, css){ if(isSuccess){ GM_addStyle(css); } }) } // 添加element-ui样式 addCssResource('https://cdnjs.cloudflare.com/ajax/libs/element-ui/2.14.1/theme-chalk/index.min.css'); // 加载图片查看器样式 addCssResource('https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.9.0/viewer.min.css'); var statVue = null; var feedVue = null; // 加载统计页面Vue实例 function loadStatVue(){ // 若vue已实例化,且对应的el元素存在,则表示已加载结束 if(statVue && !document.querySelector('#acfunstat-container')){ return true; } // 容器 var navEle = document.querySelector('#list-guide-left'); // 容器不存在 if(!navEle){ return false; } // 添加导航选项 var navItem = document.createElement('div'); navItem.classList.add('part-guide-left'); navItem.innerHTML = ` <div class="banner"> <a href="javascript:void(0)" class="tab fixed"> <i class="icon icon-bar-chart"></i>统计 </a> </div> `; // 监听点击事件 navItem.addEventListener('click', function(e){ e.stopPropatation = true; // 若vue已实例化,且对应的el元素存在,则表示已加载结束 if(statVue && !document.querySelector('#acfunstat-container')){ return; } // 删除其它菜单项的active类 var activeNavItem = navEle.querySelector('.part-guide-left.active'); activeNavItem.classList.remove('active'); // 添加active类 navItem.classList.add('active'); // 修改展示内容 document.querySelector('#area-main-right').innerHTML = ` <style> @font-face{ font-family:element-icons; src:url('https://cdnjs.cloudflare.com/ajax/libs/element-ui/2.14.1/theme-chalk/fonts/element-icons.ttf'); } #block-first .item{ font-family: verdana,Tahoma,Arial,"微软雅黑","宋体",sans-serif; margin: 0 0 16px; width : 50%; } #block-first .item .l .icon { font-size: 24px; color: #ccc; margin: 12px 8px 0 0; } #block-first .item .a { font-size: 18px; font-weight: bold; letter-spacing: -.1em; line-height: 1.2; color: #333; } #block-first .item .a .pts { font-family: Candara,verdana,Tahoma,Arial,"微软雅黑","宋体",sans-serif; font-size: 32px; margin: 0 8px; } #block-first .item .b { font-size: 12px; font-style: italic; line-height: 1.2; color: #999; } #block-detail .item{ width : 50%; } #block-detail .item li { list-style:none; color: #3a9bd9 !important; } #block-detail .item li span { color: #666; font-weight: bold; } #block-detail .item.l{ border-right: 1px solid #ddd; } .el-table__body-wrapper.is-scrolling-none::-webkit-scrollbar{ width: 10px; height: 1px; } .el-table__body-wrapper.is-scrolling-none::-webkit-scrollbar-thumb { border-radius: 10px; -webkit-box-shadow: inset 0 0 5px rgba(0,0,0,0.2); background: #535353; } .el-table__body-wrapper.is-scrolling-none::-webkit-scrollbar-track { -webkit-box-shadow: inset 0 0 5px rgba(0,0,0,0.2); border-radius: 10px; background: #EDEDED; } .btn-toggle-info{ border-top: 1px dashed #999; text-align: center; color: #08c; height: 16px; line-height: 16px; } .btn-toggle-info span{ display: block; margin-top: -8px; cursor: pointer; background-color: #fff; width: 128px; } #gift-trend-container{ height : 200px; width : 100%; } </style> <div id="block-title-banner"> <p>统计</p> <div> <a href="/member/">AcFun</a><span class="d">Stat</span> </div> <span class="clearfix"></span> </div> <div id="block-banner-right" class="block banner"> <a href="#area=acfunstat" data-type="views" class="tab"> <i class="icon"></i>送出/收到礼物 </a> </div> <div id="acfunstat-container" v-cloak> <div class="block" v-if="isGettingSendGiftList"> <div class="mainer"> <span>正在获取送出礼物记录。已获取{{sendGiftList.length}}条记录</span> </div> </div> <div class="block" v-if="isGettingReceiveGiftList"> <div class="mainer"> <span>正在获取收到礼物记录。已获取{{receiveGiftList.length}}条记录</span> </div> </div> <template v-if="hasGetSendGiftList && hasGetReceiveGiftList"> <div id="block-first" class="block"> <div class="mainer"> <div class="banner"> <p class="tab fixed">总体{{filterText}}</p> <p class="r"> <i class="icon icon-cog" title="配置" style="color: #3a9bd9;font-size:24px;cursor:pointer;" @click="openSettingDialog"></i> <i class="icon icon-book" title="导出excel" style="color: #3a9bd9;font-size:24px;cursor:pointer;" @click="exportGift"></i> </p> </div> <div class="item l"> <div class="l"> <i style="color: #f69;" class="icon icon-gift"></i> </div> <div class="l"> <div class="a"> 送出礼物价值<span id="pts-online-splash" style="color: #f69;" class="pts">{{send}}</span>AC币 </div> <div class="b"> 用户送出礼物价值的AC币总和 </div> </div> <span class="clearfix"></span> </div> <div class="item r"> <div class="l"> <i style="color: #f69;" class="icon icon-gift"></i> </div> <div class="l"> <div class="a"> 收到礼物价值<span id="pts-online-splash" style="color: #f69;" class="pts">{{receive}}</span>钻石 </div> <div class="b"> 用户收到礼物价值的钻石总和 </div> </div> <span class="clearfix"></span> </div> <span class="clearfix"></span> </div> </div> <div id="block-detail" class="block"> <div class="mainer"> <div class="item l"> <div class="banner"> <p class="tab fixed">送出礼物用户排行</p> </div> <div id="send-gift-user-table"> <el-table :data="sendUserList" style="width: 100%" class="user-table" height="400"> <el-table-column prop="userName" label="用户名" min-width="50%"> <template slot-scope="scope"> <el-avatar shape="circle" fit="fill" size="40" :src="scope.row.photo"></el-avatar> <el-link style="cursor:pointer;" @click="toUserSpace(scope.row)">{{scope.row.userName}}</el-link> </template> </el-table-column> <el-table-column prop="uid" label="用户uid" min-width="30%"> </el-table-column> <el-table-column prop="send" label="AC币" min-width="20%"> </el-table-column> </el-table> </div> <span class="clearfix"></span> </div> <div class="item r"> <div class="banner"> <p class="tab fixed">收到礼物用户排行</p> </div> <div id="receive-gift-user-table"> <el-table :data="receiveUserList" style="width: 100%" class="user-table" height="400"> <el-table-column prop="userName" label="用户名" min-width="50%"> <template slot-scope="scope"> <el-avatar shape="circle" fit="fill" size="40" :src="scope.row.photo"></el-avatar> <el-link style="cursor:pointer;" @click="toUserSpace(scope.row)">{{scope.row.userName}}</el-link> </template> </el-table-column> <el-table-column prop="uid" label="用户uid" min-width="30%"> </el-table-column> <el-table-column prop="receive" label="钻石" min-width="20%"> </el-table-column> </el-table> </div> <span class="clearfix"></span> </div> <span class="clearfix"></span> </div> </div> <p class="btn-toggle-info" @click="handleShowGiftTrend" v-if="!showGiftTrend"><span><i class="icon icon-chevron-down"></i>点击查看礼物趋势</span></p> <div class="block" v-if="showGiftTrend"> <div class="mainer"> <div class="banner"> <p class="tab fixed">{{switchToSendGiftTrend?'送出礼物趋势':'收到礼物趋势'}}</p> <div class="r"> <el-form :inline="true" :model="giftTrendFormData" size="mini"> <el-form-item> <el-select v-model="giftTrendFormData.unit" style="width:100px;"> <el-option label="按天展示" value="day" key="day"></el-option> <el-option label="按周展示" value="week" key="week"></el-option> <el-option label="按月展示" value="month" key="month"></el-option> <el-option label="按年展示" value="year" key="year"></el-option> </el-select> </el-form-item> <el-form-item v-if="switchToSendGiftTrend"> <el-select v-model="giftTrendFormData.uid" filterable placeholder="用户筛选"> <el-option label="不筛选" value=""></el-option> <el-option :label="userInfo.userName" :value="userInfo.uid" :key="userInfo.uid" v-for="userInfo in sendUserList"></el-option> </el-select> </el-form-item> <el-form-item v-else> <el-select v-model="giftTrendFormData.uid" filterable placeholder="用户筛选"> <el-option label="不筛选" value=""></el-option> <el-option :label="userInfo.userName" :value="userInfo.uid" :key="userInfo.uid" v-for="userInfo in receiveUserList"/> </el-select> </el-form-item> <el-form-item> <el-button type="primary" @click="handleSwitchToSendGiftTrend">{{switchToSendGiftTrend?'切换至收到礼物趋势':'切换至送出礼物趋势'}}</el-button> </el-form-item> </el-form> </div> </div> <div id="gift-trend-container"> </div> </div> </div> </template> <el-drawer :title="switchToSendGiftTrend?'送出礼物详情':'收到礼物详情'" :visible.sync="showGiftDetail" direction="ltr" :modal="false" :size="670"> <div v-if="switchToSendGiftTrend"> <div id="send-gift-table"> <el-table :data="giftDetailList" style="width: 100%" class="user-table" height="500"> <el-table-column prop="userName" label="用户名" :width="200"> <template slot-scope="scope"> <el-avatar shape="circle" fit="fill" size="40" :src="userInfo[scope.row.userId].photo"></el-avatar> <el-link style="cursor:pointer;" @click="toUserSpace(userInfo[scope.row.userId])">{{userInfo[scope.row.userId].userName}}</el-link> </template> </el-table-column> <el-table-column prop="userId" label="用户uid" :width="100"> </el-table-column> <el-table-column prop="createTimeText" label="送出时间" :width="150"> </el-table-column> <el-table-column prop="giftText" label="送出礼物" :width="100"> </el-table-column> <el-table-column prop="acoin" label="AC币" :width="70"> </el-table-column> </el-table> </div> </div> <div v-else> <div id="receive-gift-table"> <el-table :data="giftDetailList" style="width: 100%" class="user-table" height="500"> <el-table-column prop="userName" label="用户名" width="200"> <template slot-scope="scope"> <el-avatar shape="circle" fit="fill" size="40" :src="userInfo[scope.row.userId].photo"></el-avatar> <el-link style="cursor:pointer;" @click="toUserSpace(userInfo[scope.row.userId])">{{userInfo[scope.row.userId].userName}}</el-link> </template> </el-table-column> <el-table-column prop="userId" label="用户uid" width="100"> </el-table-column> <el-table-column prop="createTimeText" label="收到时间" width="150"> </el-table-column> <el-table-column prop="giftText" label="收到礼物" width="100"> </el-table-column> <el-table-column prop="azuanAmount" label="钻石" width="70"> </el-table-column> </el-table> </div> </div> </el-drawer> <el-dialog title="设置" :visible.sync="settingFormDialogVisible" :modal="false" width="550px" custom-class="setting-form-dialog" :modal-append-to-body="false"> <el-form :model="settingFormData" class="setting-form" ref="settingForm" :rules="settingFormRules" @submit.native.prevent> <el-form-item label="礼物筛选" label-width="130px" prop="isContainPeach"> <el-switch v-model="settingFormData.isContainPeach" active-text="包括桃子" inactive-text="不包括桃子"> </el-switch> </el-form-item> <el-form-item label="时间范围" label-width="130px" prop="dateRegion"> <el-date-picker v-model="settingFormData.dateRegion" type="daterange" align="right" unlink-panels range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" :picker-options="settingFormPickerOptions" style="width:100%" > </el-date-picker> </el-form-item> <el-form-item style="display:flex;justify-content:center;"> <el-button type="primary" @click="handleSettingFormSubmit">提交</el-button> </el-form-item> </el-form> </el-dialog> </div> `; history.replaceState(null, null, '/member/#area=acfunstat'); // 初始化实例 new Vue({ el : '#acfunstat-container', data : function(){ return { send : 0, receive : 0, sendGiftList : [], receiveGiftList : [], giftDetailList : [], showGiftDetail : false, showGiftTrend : false, sendUserList : [], receiveUserList : [], userInfo : {}, isGettingSendGiftList : false, isGettingReceiveGiftList : false, hasGetReceiveGiftList : false, hasGetSendGiftList : false, filterText : '', settingFormDialogVisible : false, settingFormData : { isContainPeach : true, }, settingFormRules : { }, settingFormPickerOptions : { shortcuts : [{ text : '本周', onClick(picker) { const end = moment().endOf('week').add(1, 'days')._d; const start = moment().startOf('week').add(1, 'days')._d; picker.$emit('pick', [start, end]); }, },{ text : '上周', onClick(picker) { const end = moment().subtract(1, 'weeks').endOf('week').add(1, 'days')._d; const start = moment().subtract(1, 'weeks').startOf('week').add(1, 'days')._d; picker.$emit('pick', [start, end]); }, },{ text : '本月', onClick(picker) { const end = moment().endOf('month')._d; const start = moment().startOf('month')._d; picker.$emit('pick', [start, end]); }, },{ text : '上月', onClick(picker) { const end = moment().subtract(1, 'months').endOf('month')._d; const start = moment().subtract(1, 'months').startOf('month')._d; picker.$emit('pick', [start, end]); }, },] }, switchToSendGiftList : true, switchToSendGiftTrend : true, giftTrendFormData : { unit : 'day', }, }; }, methods : { getUserInfo : function(uid, userName, callback){ var vue = this; if(uid in this.userInfo){ if(_.isFunction(callback)){ callback(true, this.userInfo[uid]); } return; } // 获取用户信息 commonRequrest(config.ACFUNLIVE_SERVER + config.URLS.ACFUN_USER.INFO + `?userId=${uid}`, 'get', null, true, function(isSuccess, data){ var userInfo = null; if(data){ data = JSON.parse(data); if(data.result == 0){ userInfo = { uid : uid, photo : data.profile.headUrl, userName : data.profile.name, }; } else{ userInfo = { uid : uid, userName : userName, photo : 'https://tx-free-imgs.acfun.cn/style/image/defaultAvatar.jpg', }; } } else{ userInfo = { uid : uid, userName : userName, photo : 'https://tx-free-imgs.acfun.cn/style/image/defaultAvatar.jpg', }; } vue.userInfo[uid] = userInfo; if(_.isFunction(callback)){ callback(isSuccess, userInfo); } }); }, getSendGiftList : function(callback){ var vue = this; var startDate = null,endDate=null; var isContainPeach = this.settingFormData.isContainPeach; // 筛选了时间范围 if(this.settingFormData.dateRegion && this.settingFormData.dateRegion.length==2){ startDate = this.settingFormData.dateRegion[0].getTime(); endDate = this.settingFormData.dateRegion[1].getTime(); } // 获取数据时的游标 var pcursor = "0"; var getSendGiftList = function(){ vue.isGettingSendGiftList = true; if(pcursor == 'no_more'){ // 统计送出礼物总ac币 vue.send = _.sumBy(_.flatMap(vue.userInfo), 'send'); vue.send = vue.send?vue.send:0; // 讲用户按送出ac币价值倒序 vue.sendUserList = _.sortBy(_.filter(vue.userInfo, (userInfo)=>{return userInfo.send>0;}), function(userInfo){ return -userInfo.send; }); vue.isGettingSendGiftList = false; vue.hasGetSendGiftList = true; if(_.isFunction(callback)){ callback(); } return; } else{ commonRequrest(config.ACFUN_MOBILE_SERVER + config.URLS.WALLET.SEND_GIFT, 'get',{pcursor : pcursor,},true, function(isSuccess, data){ // 获取数据失败 if(!isSuccess){ vue.$message({ type : 'error', message : '获取送出礼物列表失败', }); pcursor = 'no_more'; getSendGiftList(); } else{ data = JSON.parse(data); pcursor = data['pcursor']; if(data.records || data.records.length==0){ var uids = {}; var uidUserNameMapper = {}; // 获取用户信息 data.records.forEach(function(record){ // 指定了起始时间 if(startDate && record.createTime<startDate){ pcursor = "no_more"; return; } // 指定了终止时间 else if(endDate && record.createTime>endDate){ return; } // 不包含桃子 else if(!isContainPeach && record.giftName == '桃子'){ return; } if(!(record.userId in uids)){ uids[record.userId] = []; } uidUserNameMapper[record.userId] = record.userName; var now = moment(record.createTime); // 设置送出时间 record.createTimeText = now.format('YYYY-MM-DD hh:mm:ss'); record.giftText = `${record.giftCount}个${record.giftName}`; // 设置时间单位,便于获取趋势 record.dayUnitText = now.format('YYYY-MM-DD'); record.monthUnitText = now.format('YYYY-MM'); record.yearUnitText = now.format('YYYY'); record.weekUnitText = now.startOf('week').add(1, 'days').format('YYYY-MM-DD'); uids[record.userId].push(record); vue.sendGiftList.push(record); }); // 没有任何记录 if(Object.keys(uids).length==0){ getSendGiftList(); } else{ var nextGetSendGiftList = _.after(Object.keys(uids).length, getSendGiftList); for(var uid in uids){ vue.getUserInfo(uid, uidUserNameMapper[uid], function(isSuccess, userInfo){ // 统计送出给用户AC币 if(userInfo.sendGiftList == null){ userInfo.sendGiftList = []; } if(userInfo.send==null){ userInfo.send = 0; } userInfo.sendGiftList.splice(userInfo.sendGiftList.length, 0, ...uids[userInfo.uid]); userInfo.send += _.sumBy(uids[userInfo.uid], 'acoin'); nextGetSendGiftList(); }); } } } else{ getSendGiftList(); } } }, ); } } getSendGiftList(); }, getReceiveGiftList : function(callback){ var vue = this; var startDate = null,endDate=null; var isContainPeach = this.settingFormData.isContainPeach; // 筛选了时间范围 if(this.settingFormData.dateRegion && this.settingFormData.dateRegion.length==2){ startDate = this.settingFormData.dateRegion[0].getTime(); endDate = this.settingFormData.dateRegion[1].getTime(); } // 获取数据时的游标 var pcursor = "0"; var getReceiveGiftList = function(){ vue.isGettingReceiveGiftList = true; if(pcursor == 'no_more'){ // 统计送出礼物总ac币 vue.receive = _.sumBy(_.flatMap(vue.userInfo), 'receive'); vue.receive = vue.receive?vue.receive:0; // 讲用户按送出ac币价值倒序 vue.receiveUserList = _.sortBy(_.filter(vue.userInfo, (userInfo)=>{return userInfo.receive>0;}), function(userInfo){ return -userInfo.receive; }); vue.isGettingReceiveGiftList = false; vue.hasGetReceiveGiftList = true; if(_.isFunction(callback)){ callback(); } return; } else{ commonRequrest(config.ACFUN_MOBILE_SERVER + config.URLS.WALLET.RECEIVE_GIFT, 'get',{pcursor : pcursor,},true, function(isSuccess, data){ // 获取数据失败 if(!isSuccess){ vue.$message({ type : 'error', message : '获取送出礼物列表失败', }); pcursor = 'no_more'; getReceiveGiftList(); } else{ data = JSON.parse(data); pcursor = data['pcursor']; if(data.records || data.records.length==0){ var uids = {}; var uidUserNameMapper = {}; // 获取用户信息 data.records.forEach(function(record){ // 指定了起始时间 if(startDate && record.createTime<startDate){ pcursor = "no_more"; return; } // 指定了终止时间 else if(endDate && record.createTime>endDate){ return; } // 不包含桃子 else if(!isContainPeach && record.giftName == '桃子'){ return; } if(!(record.userId in uids)){ uids[record.userId] = []; } uidUserNameMapper[record.userId] = record.userName; var now = moment(record.createTime); // 设置送出时间 record.createTimeText = now.format('YYYY-MM-DD hh:mm:ss'); record.giftText = `${record.giftCount}个${record.giftName}`; // 设置时间单位,便于获取趋势 record.dayUnitText = now.format('YYYY-MM-DD'); record.monthUnitText = now.format('YYYY-MM'); record.yearUnitText = now.format('YYYY'); record.weekUnitText = now.startOf('week').add(1, 'days').format('YYYY-MM-DD'); uids[record.userId].push(record); vue.receiveGiftList.push(record); }); // 没有任何记录 if(Object.keys(uids).length==0){ getReceiveGiftList(); } else{ var nextGetReceiveGiftList = _.after(Object.keys(uids).length, getReceiveGiftList); for(var uid in uids){ vue.getUserInfo(uid, uidUserNameMapper[uid], function(isSuccess, userInfo){ // 统计送出给用户AC币 if(userInfo.receiveGiftList == null){ userInfo.receiveGiftList = []; } if(userInfo.receive==null){ userInfo.receive = 0; } userInfo.receiveGiftList.splice(userInfo.receiveGiftList.length, 0, ...uids[userInfo.uid]); userInfo.receive += _.sumBy(uids[userInfo.uid], 'azuanAmount'); nextGetReceiveGiftList(); }); } } } else{ getReceiveGiftList(); } } }, ); } } getReceiveGiftList(); }, // 渲染趋势 renderGiftTrend : function(){ var vue = this; var data = this.switchToSendGiftTrend?this.sendGiftList:this.receiveGiftList; // 筛选用户 if(this.giftTrendFormData.uid){ data = _.filter(data, {userId:_.parseInt(this.giftTrendFormData.uid)}); } // 按时间分组 data = _.groupBy(data, function(item){ // 按天筛选 if(vue.giftTrendFormData.unit == 'day'){ return item.dayUnitText; } // 按周筛选 if(vue.giftTrendFormData.unit == 'week'){ return item.weekUnitText; } // 按月筛选 if(vue.giftTrendFormData.unit == 'month'){ return item.monthUnitText; } // 按年筛选 if(vue.giftTrendFormData.unit == 'year'){ return item.yearUnitText; } }); // 转化格式 var lineNameData = _.sortBy(Object.keys(data)); var lineValueData = []; lineNameData.forEach(function(unit){ lineValueData.push(_.sumBy(data[unit], vue.switchToSendGiftTrend?'acoin':'azuanAmount')); }); var chart = echarts.init(document.getElementById('gift-trend-container')); var option = { xAxis: { type: 'category', name : '时间', data : lineNameData, }, yAxis: { type: 'value', name : this.switchToSendGiftTrend?'AC币':'钻石', }, series: [{ type: 'line', data : lineValueData, name : this.switchToSendGiftTrend?'AC币':'钻石', },], tooltip : { trigger : 'axis', axisPointer : { type : 'line', axis : 'x', }, confine : true, }, dataZoom : [{ type : 'inside', orient : 'horizontal', }], }; chart.setOption(option); chart.on('click', function (params) { // 隐藏tooltip chart.dispatchAction({ type: 'hideTip', }); // 设置礼物数据 vue.giftDetailList = data[params.name]; // 展示 vue.showGiftDetail = true; }); }, // 打开设置弹窗 openSettingDialog : function(){ this.settingFormDialogVisible = true; }, // 更改设置提交 handleSettingFormSubmit : function(){ var vue = this; this.$refs.settingForm.validate((valid) => { // 通过校验 if(valid){ this.hasGetSendGiftList = false; this.hasGetReceiveGiftList = false; this.showGiftDetail = false; this.showGiftTrend = false; this.send = 0; this.receive = 0; this.sendGiftList = []; this.receiveGiftList = []; this.giftDetailList = []; this.sendUserList = []; this.receiveUserList = []; for(var uid in this.userInfo){ this.userInfo[uid] = { uid : uid, userName : this.userInfo[uid].userName, photo : this.userInfo[uid].photo, }; } this.$message({ type : 'info', message : '开始获取数据', }); this.settingFormDialogVisible = false; this.getSendGiftList(function(){ vue.getReceiveGiftList(function(){ vue.$message({ type : 'success', message : '数据获取成功', }); // 生成筛选文字 vue.filterText = vue.formatFilterText(); }); }); } }); }, // 导出excel exportGift : function(){ var vue = this; var workbook = new ExcelJS.Workbook(); var sheet = workbook.addWorksheet('送出礼物用户排行榜'); sheet.columns = [ { key: 'userName', width: 30, }, { key: 'uid', width: 10, }, { key: 'acoin', width: 20, }, ]; var rowIndex = 1; sheet.addRow({userName: '用户名', uid : '用户uid', 'acoin' : 'AC币'}); // 设置列名样式 var headerRow = sheet.getRow(rowIndex); for(var i=1;i<=sheet.columns.length;++i){ headerRow.getCell(i).alignment = {vertical: 'middle', horizontal: 'center'}; headerRow.getCell(i).border = { top: {style:'thin'}, left: {style:'thin'}, bottom: {style:'thin'}, right: {style:'thin'}, }; } rowIndex += 1; // 获取送出礼物用户排行 this.sendUserList.forEach(function(userInfo){ sheet.addRow({userName: userInfo.userName, uid : userInfo.uid, acoin:userInfo.send}); // 设置记录样式 var recordRow = sheet.getRow(rowIndex); for(var i=1;i<=sheet.columns.length;++i){ // recordRow.getCell(i).alignment = {vertical: 'middle', horizontal: 'center'}; recordRow.getCell(i).border = { top: {style:'thin'}, left: {style:'thin'}, bottom: {style:'thin'}, right: {style:'thin'}, }; } rowIndex += 1; }); sheet = workbook.addWorksheet('收到礼物用户排行榜'); sheet.columns = [ { key: 'userName', width: 30, }, { key: 'uid', width: 10, }, { key: 'azuanAmount', width: 20, }, ]; rowIndex = 1; sheet.addRow({userName: '用户名', uid : '用户uid', 'azuanAmount' : '钻石'}); // 设置列名样式 var headerRow = sheet.getRow(rowIndex); for(var i=1;i<=sheet.columns.length;++i){ headerRow.getCell(i).alignment = {vertical: 'middle', horizontal: 'center'}; headerRow.getCell(i).border = { top: {style:'thin'}, left: {style:'thin'}, bottom: {style:'thin'}, right: {style:'thin'}, }; } rowIndex += 1; // 获取送出礼物用户排行 this.receiveUserList.forEach(function(userInfo){ sheet.addRow({userName: userInfo.userName, uid : userInfo.uid, azuanAmount:userInfo.receive}); // 设置记录样式 var recordRow = sheet.getRow(rowIndex); for(var i=1;i<=sheet.columns.length;++i){ // recordRow.getCell(i).alignment = {vertical: 'middle', horizontal: 'center'}; recordRow.getCell(i).border = { top: {style:'thin'}, left: {style:'thin'}, bottom: {style:'thin'}, right: {style:'thin'}, }; } rowIndex += 1; }); sheet = workbook.addWorksheet('送出礼物详情'); sheet.columns = [ { key: 'userName', width: 30, }, { key: 'uid', width: 10, }, { key: 'createTimeText', width: 20, }, { key: 'giftName', width: 20, }, { key: 'giftCount', width: 20, }, { key: 'acoin', width: 20, }, ]; var rowIndex = 1; sheet.addRow({userName: '用户名', uid : '用户uid', createTimeText : '送出时间', giftName:'礼物名称', giftCount:'礼物数量', acoin : 'AC币'}); // 设置列名样式 var headerRow = sheet.getRow(rowIndex); for(var i=1;i<=sheet.columns.length;++i){ headerRow.getCell(i).alignment = {vertical: 'middle', horizontal: 'center'}; headerRow.getCell(i).border = { top: {style:'thin'}, left: {style:'thin'}, bottom: {style:'thin'}, right: {style:'thin'}, }; } rowIndex += 1; // 获取送出礼物详情 this.sendGiftList.forEach(function(giftDetail){ sheet.addRow({userName: giftDetail.userName, uid : giftDetail.userId, createTimeText:giftDetail.createTimeText, giftName:giftDetail.giftName, giftCount:giftDetail.giftCount, acoin:giftDetail.acoin}); // 设置记录样式 var recordRow = sheet.getRow(rowIndex); for(var i=1;i<=sheet.columns.length;++i){ // recordRow.getCell(i).alignment = {vertical: 'middle', horizontal: 'center'}; recordRow.getCell(i).border = { top: {style:'thin'}, left: {style:'thin'}, bottom: {style:'thin'}, right: {style:'thin'}, }; } rowIndex += 1; }); sheet = workbook.addWorksheet('收到礼物详情'); sheet.columns = [ { key: 'userName', width: 30, }, { key: 'uid', width: 10, }, { key: 'createTimeText', width: 20, }, { key: 'giftName', width: 20, }, { key: 'giftCount', width: 20, }, { key: 'azuanAmount', width: 20, }, ]; var rowIndex = 1; sheet.addRow({userName: '用户名', uid : '用户uid', createTimeText : '收到时间', giftName:'礼物名称', giftCount:'礼物数量', azuanAmount : '钻石'}); // 设置列名样式 var headerRow = sheet.getRow(rowIndex); for(var i=1;i<=sheet.columns.length;++i){ headerRow.getCell(i).alignment = {vertical: 'middle', horizontal: 'center'}; headerRow.getCell(i).border = { top: {style:'thin'}, left: {style:'thin'}, bottom: {style:'thin'}, right: {style:'thin'}, }; } rowIndex += 1; // 获取送出礼物详情 this.receiveGiftList.forEach(function(giftDetail){ sheet.addRow({userName: giftDetail.userName, uid : giftDetail.userId, createTimeText:giftDetail.createTimeText, giftName:giftDetail.giftName, giftCount:giftDetail.giftCount, azuanAmount:giftDetail.azuanAmount}); // 设置记录样式 var recordRow = sheet.getRow(rowIndex); for(var i=1;i<=sheet.columns.length;++i){ // recordRow.getCell(i).alignment = {vertical: 'middle', horizontal: 'center'}; recordRow.getCell(i).border = { top: {style:'thin'}, left: {style:'thin'}, bottom: {style:'thin'}, right: {style:'thin'}, }; } rowIndex += 1; }); ;(async function(){ var buffer = await workbook.xlsx.writeBuffer(); var file = new File([buffer], `【${moment().format('YYYY-MM-DD')}】acfun统计${vue.filterText}.xlsx`); saveAs(file); })(); }, // 展示趋势 handleShowGiftTrend : function(){ this.showGiftTrend = true; this.$nextTick(function(){ this.renderGiftTrend(); }); }, // 切换趋势 handleSwitchToSendGiftTrend : function(){ this.switchToSendGiftTrend = !this.switchToSendGiftTrend; this.$nextTick(function(){ this.renderGiftTrend(); }); }, // 跳转至用户主页 toUserSpace : function(userInfo){ window.open(config.ACFUN_SERVER + config.URLS.ACFUN_USER.SPACE + `/${userInfo.uid}`); }, formatFilterText : function(){ var dateRegionText = null,isContainPeachText=null; // 筛选了时间范围 if(this.settingFormData.dateRegion && this.settingFormData.dateRegion.length==2){ dateRegionText = `${moment(this.settingFormData.dateRegion[0]).format('YYYY-MM-DD')} 至 ${moment(this.settingFormData.dateRegion[1]).format('YYYY-MM-DD')}`; } if(!this.settingFormData.isContainPeach){ isContainPeachText = '不包含桃子'; } var texts = _.filter([dateRegionText, isContainPeachText]).join('、'); if(isNullOrEmpty(texts)){ return ''; } else{ return '(' + texts + ')'; } }, }, computed : { }, watch: { // 监听趋势表单数据变化 giftTrendFormData : { deep : true, handler : function(newVal, oldVal){ if(this.showGiftTrend){ this.renderGiftTrend(); } }, }, }, mounted : function(){ // 打开弹窗 this.openSettingDialog(); }, }); }); navEle.append(navItem); return true; } // 加载动态页面Vue实例 function loadFeedVue(){ var vue = null; // 若vue已实例化,且对应的el元素存在,则表示已加载结束 if(vue && !document.querySelector('#acfunfeed-container')){ return true; } // 检查是否为“圈子”导航菜单 pushEle = document.querySelector('#list-guide-left a[href="#area=push"]'); if(pushEle){ if(!pushEle.parentElement.parentElement.classList.contains('active')){ return false; } } else{ return false; } // 容器 var navEle = document.querySelector('#block-banner-right'); // 容器不存在,无法挂载 if(!navEle){ return false; } // 添加导航选项 var navItem = document.createElement('a'); navItem.id = 'area-feed'; navItem.href = 'javascript:void(0)'; navItem.classList.add('tab'); navItem.innerHTML = ` <i class="icon"></i> 动态推送 <span class="hint hidden hint-feed-left">(0)</span> `; // 添加元素 navEle.append(navItem); // 监听点击事件 navItem.addEventListener('click', function(e){ e.stopPropatation = true; // 若vue已实例化,且对应的el元素存在,则表示已加载结束 if(feedVue && !document.querySelector('#acfunfeed-container')){ return; } // 删除其它菜单项的active类 var activeNavItem = navEle.querySelector('.active'); activeNavItem.classList.remove('active'); // 添加active类 navItem.classList.add('active'); history.replaceState(null, null, '/member/#area=feed'); // 修改标题 document.querySelector('#block-title-banner p').innerText = '动态推送'; document.querySelector('#block-title-banner .d').innerText = 'Feed'; document.title = '动态推送'; // 分页HTML var paginatorHTML = ` <div class="area-pager"> <span class="pager pager-last" v-if="page>1" @click="toFirstPage"><i class="icon icon-step-backward" title="最初"></i></span> <span class="pager pager-fore" v-if="page>1" @click="toPrevPage"><i class="icon icon-chevron-left" title="上一页"></i></span> <span :class="{pager:true,'pager-fores':choosePage!=page,'pager-here':choosePage==page,'active':choosePage==page}" :data-page="choosePage" @click="toJumpPage(choosePage)" :key="choosePage" v-for="choosePage in pages">{{choosePage}}</span> <span class="pager pager-hind" @click="toNextPage"><i class="icon icon-chevron-right" title="下一页"></i></span> <span class="pager pager-first" @click="toFinalPage"><i class="icon icon-step-forward" title="最末"></i></span> <span class="hint">当前位置:<input class="ipt-pager" type="number" v-model="jumpPage" :data-max="total"><button class="btn mini btn-pager" @click="toJumpPage(jumpPage)">跳页</button> 共{{total}}页</span> <span class="clearfix"></span> </div> `; // 视频内容HTML var videoHTML = ` <div :data-aid="feed.resourceId" :class="{block:true,item:!isInRepost}" :key="feed.resourceId"> <div class="inner"> <div class="l"> <a target="_blank" :href="feed.shareUrl" class="thumb thumb-preview"><img :data-aid="feed.resourceId" :src="feed.coverUrl" class="preview" /> <div class="cover"></div></a> <a target="_blank" :href="feed.userInfo.shareUrl" :title="feed.userInfo.hoverText" class="thumb thumb-avatar"><img :data-uid="feed.userInfo.id" :data-name="feed.userInfo.name" :src="feed.userInfo.headUrl" class="avatar" /></a> </div> <div class="r"> <p class="block-title"><a :href="feed.channel.shareUrl" :title="feed.channel.hoverText" target="_blank" class="channel">{{feed.channel.name}}</a><a :data-aid="feed.resourceId" target="_blank" :href="feed.shareUrl" class="title">{{feed.caption}}</a></p> <div class="info"> <a target="_blank" :data-uid="feed.userInfo.id" :href="feed.userInfo.shareUrl" class="name">{{feed.userInfo.name}}</a> / 发布于 <span class="time">{{feed.time}}</span> / 播放: <span class="views pts">{{feed.detail.viewCount}}</span> 评论: <span class="comments pts">{{feed.detail.commentCount}}</span> 收藏: <span class="favors pts">{{feed.detail.stowCount}}</span> </div> <p class="desc">{{feed.detail.description}}</p> <div class="area-tag"> <template v-if="feed.tag && feed.tag.length>0"> <a class="tag" target="_blank" :key="tag.tagId" v-for="tag in feed.tag" :href="tag.shareUrl">{{tag.tagName}}</a> </template> <template v-else> 该稿件暂无标签。 </template> </div> </div> <span class="clearfix"></span> </div> </div> `; // 文章内容HTML var articleHTML = ` <div :data-aid="feed.resourceId" :class="{block:true,item:!isInRepost}" :key="feed.resourceId"> <div class="inner"> <div class="l"> <a target="_blank" :href="feed.shareUrl" class="thumb thumb-preview"><img :data-aid="feed.resourceId" :src="feed.coverUrl" class="preview" /> <div class="cover"></div></a> <a target="_blank" :href="feed.userInfo.shareUrl" :title="feed.userInfo.hoverText" class="thumb thumb-avatar"><img :data-uid="feed.userInfo.id" :data-name="feed.userInfo.name" :src="feed.userInfo.headUrl" class="avatar" /></a> </div> <div class="r"> <p class="block-title"><a :href="feed.channel.shareUrl" :title="feed.channel.hoverText" target="_blank" class="channel">{{feed.channel.name}}</a><a :data-aid="feed.resourceId" target="_blank" :href="feed.shareUrl" class="title">{{feed.caption}}</a></p> <div class="info"> <a target="_blank" :data-uid="feed.userInfo.id" :href="feed.userInfo.shareUrl" class="name">{{feed.userInfo.name}}</a> / 发布于 <span class="time">{{feed.time}}</span> / 播放: <span class="views pts">{{feed.viewCount}}</span> 评论: <span class="comments pts">{{feed.commentCount}}</span> 收藏: <span class="favors pts">{{feed.stowCount}}</span> </div> <p class="desc">{{feed.beginParagraph}}</p> <div class="area-tag"> <template v-if="feed.tag && feed.tag.length>0"> <a class="tag" target="_blank" :key="tag.tagId" v-for="tag in feed.tag" :href="tag.shareUrl">{{tag.tagName}}</a> </template> <template v-else> 该稿件暂无标签。 </template> </div> </div> <span class="clearfix"></span> </div> </div> `; // 动态内容HTML var activityHTML = ` <div :data-aid="feed.resourceId" :class="{block:true,item:!isInRepost}" :key="feed.resourceId"> <div :class="{inner : true, repost:feed.isRepost}"> <div class="l" v-if="!feed.isRepost"> <a target="_blank" class="thumb thumb-preview" @click.prevent.stop="handleActivityCoverClick(feed, $event)"><img :data-aid="feed.resourceId" :src="feed.coverUrl" class="preview" /> <div class="cover"></div></a> <a target="_blank" :href="feed.userInfo.shareUrl" :title="feed.userInfo.hoverText" class="thumb thumb-avatar"><img :data-uid="feed.userInfo.id" :data-name="feed.userInfo.name" :src="feed.userInfo.headUrl" class="avatar" /></a> </div> <div class="r"> <p class="block-title"><a href="javascript:void(0)" :title="feed.isRepost?'转发':'动态'" target="_blank" class="channel">{{feed.isRepost?'转发':'动态'}}</a><a :data-aid="feed.resourceId" target="_blank" :href="feed.shareUrl" class="title">{{feed.caption}}</a></p> <div class="info"> <a target="_blank" :data-uid="feed.userInfo.id" :href="feed.userInfo.shareUrl" class="name">{{feed.userInfo.name}}</a> / 发布于 <span class="time">{{feed.time}}</span> </div> <p class="desc" style="white-space:pre-line;" v-html="feed.moment.htmlText" @click="handleActivityContentClick(feed, $event)"></p> <!-- 包含转发内容 --> <template v-if="feed.repostSource"> <p class="btn-toggle-info"><span><i class="icon icon-chevron-down"></i>以下是转发内容</span></p> <div class="area-repost"> <!-- 转发视频 --> <template v-if="feed.repostSource.isVideo"> <feed-video :feed="feed.repostSource" :isInRepost="true"/> </template> <!-- 转发文章 --> <template v-else-if="feed.repostSource.isArticle"> <feed-article :feed="feed.repostSource" :isInRepost="true"/> </template> <!-- 转发动态 --> <template v-if="feed.repostSource.isActivity"> <feed-activity :feed="feed.repostSource" :isInRepost="true" @content-click="handleActivityContentClick" @cover-click="handleActivityCoverClick"/> </template> </div> </template> </div> <span class="clearfix"></span> </div> </div> `; Vue.component('feed-paginator', { data : function(){ return { page : 1, pageSize : 20, pageRange : 4, jumpPage : 1, }; }, methods : { toNextPage : function(){ this.page += 1; this.jumpPage = this.page; this.$emit('change', { page : this.page, total : this.total, pageSize : this.pageSize, pcursor : this.pcursors[this.page-1], }); }, toPrevPage : function(){ this.page -= 1; this.jumpPage = this.page; this.$emit('change', { page : this.page, total : this.total, pageSize : this.pageSize, pcursor : this.pcursors[this.page-1], }); }, toFinalPage : function(){ this.page = this.total; this.jumpPage = this.page; this.$emit('change', { page : this.page, total : this.total, pageSize : this.pageSize, pcursor : this.pcursors[this.page-1], }); }, toFirstPage : function(){ this.page = 1; this.jumpPage = this.page; this.$emit('change', { page : this.page, total : this.total, pageSize : this.pageSize, pcursor : this.pcursors[this.page-1], }); }, toJumpPage : function(page){ if(page>this.total){ this.$message({ type : 'error', message : `无法跳至指定位置(页码不得大于${this.total})`, }); } else{ this.page = page; this.$emit('change', { page : this.page, total : this.total, pageSize : this.pageSize, pcursor : this.pcursors[this.page-1], }); } }, }, computed : { total : function(){ return this.pcursors.length; }, minPage : function(){ // 当前页码往前N页 return Math.max(1, this.page - this.pageRange); }, maxPage : function(){ // 当前页码往后N页 return Math.min(this.total, this.page + this.pageRange); }, pages : function(){ var minPage = this.minPage,maxPage = this.maxPage; var pages = []; for(var page=minPage;page<=maxPage;++page){ pages.push(page); } return pages; }, }, props : ['pcursors', 'pcursor', 'page'], template : paginatorHTML, }); Vue.component('feed-video', { data : function(){ return {}; }, props : ['feed', 'isInRepost'], template : videoHTML, }); Vue.component('feed-article', { data : function(){ return {}; }, props : ['feed', 'isInRepost'], template : articleHTML, }); Vue.component('feed-activity', { data : function(){ return {}; }, props : ['feed', 'isInRepost'], methods : { // 点击动态内容 handleActivityContentClick : function(feed, event){ this.$emit('content-click', feed, event); }, // 点击动态封面 handleActivityCoverClick : function(feed, event){ this.$emit('cover-click', feed, event); }, }, template : activityHTML, }); // 修改展示内容 document.querySelector('#block-first>.mainer').innerHTML = ` <style> .btn-toggle-info{ margin-top : 10px; border-top: 1px dashed #999; text-align: center; color: #999; height: 16px; line-height: 16px; } .btn-toggle-info span{ display: block; margin-top: -8px; background-color: #fff; width: 128px; } #block-first .name { color : #c66 !important; } #block-first .banner .more { overflow: visible; margin: 0 8px 0 0; padding: 0 } #block-first .banner .more:hover { background: none; box-shadow: none } #block-first .mainer { padding: 8px } #block-first .unit .l { width: 120px; padding: 0 0 0 40px } #block-first .unit .r { width: 620px } #block-first .subtitle { margin: 4px 0; height: 24px; line-height: 24px; font-size: 13px; padding: 0 4px; border-radius: 2px; box-shadow: 0 1px 1px rgba(0,0,0,0.2); background-color: #c66; color: #fff; display: inline-block; *display: inline; cursor: default } #block-first .item { position: relative; overflow: hidden; border: 1px solid #eee; box-shadow: none; background-color: #fcfcfc } #block-first .item:hover .block-manage { right: 8px } #block-first .item .area-cont { width: auto; height: auto; margin: 8px 10px; padding: 8px; background-color: #ffe; color: #333; display: none; border: 1px solid #ddd; border-top: 1px solid #ebebeb; border-bottom: 1px solid #b7b7b7; box-shadow: 0 1px 1px rgba(0,0,0,0.1) } #block-first .item .desc { color: #666; margin: 4px auto 0 } #block-first .item .block-manage { position: absolute; left: auto; top: auto; right: -128px; bottom: 8px; transition: .2s all ease .2s } #block-first .item .l { position: relative; width : 19%; } #block-first .item .r { position: relative; width : 78%; } #block-first .item .repost { width : 97%; } #block-first .item .repost>.r { position: relative; width : 100%; } #block-first .item .thumb { border: none; background: none; box-shadow: none } #block-first .item .preview { width: 122px; height: 69.5px } #block-first .item .avatar { width: 40px; height: 40px; box-shadow: 0 1px 4px rgba(0,0,0,0.3); background-color: #fff; border-radius: 2px } #block-first .item .thumb-preview { margin: 8px 0 16px 8px } #block-first .item .thumb-avatar { position: absolute; left: 96px; top: 45px } #block-first .item .block-title { margin: 10px auto 0 } #block-first .item .channel { background-color: #c66; position: static; display: inline-block; *display: inline; margin: 0 4px 4px 0; padding: 0 4px } #block-first .item .title { color: #08c; font-size: 14px } #block-first .inner { position: relative } #block-first #list-feed-feed .item .info { color: #999; margin: 4px auto 0 } #block-first .area-tag { display: inline-block; *display: inline; border-top: 1px dashed #ddd; margin: 8px 0 16px; padding: 8px 16px 0 0; color: #999; font-size: 12px } #block-first .area-tag a { margin: 0 8px 8px 0; color: #369 } #block-first .area-repost { padding : 10px !important; } #block-first .area-repost .block .r{ width : 76%; } #block-first .btn-history-delete { float: right; height: 24px; line-height: 24px; font-size: 12px; color: #999; background-color: #eee; padding: 0 8px; border-radius: 2px; box-shadow: inset 0 1px 2px rgba(0,0,0,0.2); cursor: pointer; font-family: "Microsoft YaHei","微软雅黑",tahoma,arial,simsun,"宋体"; margin: 4px } #block-first .btn-history-delete:hover { color: #fff; background-color: #c33; box-shadow: inset 0 1px 2px rgba(0,0,0,0.5) } #block-first .removed { text-align: center; line-height: 8; color: #999 } #block-first .hint-list-index { position: absolute; left: auto; top: auto; right: 12px; bottom: 0; font-size: 64px; line-height: 64px; height: 64px; width: auto; text-align: right; color: #eee; z-index: 0; letter-spacing: -.1em; cursor: default } #block-first .area-pager { padding: 0; margin: 8px auto } #block-first .area-pager .pager { min-width: 31px } #block-first .item-comms .area-cont { display: block } .no-rgba #block-first .item { border-color: #ccc } #list-channel-push { margin: 8px auto 16px; padding: 0 0 16px; border-bottom: 1px dashed #ddd } #list-group-push { overflow: visible; margin: 0 auto 16px; padding: 0 0 16px; border-bottom: 1px #ddd dashed } #list-group-push .item-push { display: inline-block; *display: inline; float: left; margin: 4px 8px 0 0; position: relative; overflow: hidden; border-color: rgba(0,0,0,0.1) } .btn-manage-push { min-width: 0; *width: auto; padding: 0 } .btn-manage-push .icon { margin: 0 .2em } .btn-manage-push .item { background-color: #fff } @media screen and (min-width:1440px) { #list-feed-feed .item .l { width: 16%; } #list-feed-feed .item .r { width: 82%; } #block-first .area-repost .block .r { width: 82%; } #block-first .item .preview { width: 130px; height: 74px } #block-first .item .thumb-avatar { top: 48px; left: 104px } } #block-first .item .ubb-at { cursor : pointer; color : #08c; } #block-first .item .ubb-img { cursor : pointer; color : #08c; } </style> <p class="alert alert-info">目前还不支持交互功能,如评论、点赞、投蕉。。。</p> <div id="acfunfeed-container" v-cloak> <!-- 分页 --> <div> <feed-paginator :pcursors="pcursors" :pcursor="pcursor" :page="page" @change="getFeedList"/> </div> <div id="list-feed-feed"> <template v-for="feed in feedList"> <!-- 视频 --> <feed-video :feed="feed" :isInRepost="false" v-if="feed.isVideo"></feed-video> <!-- 文章 --> <feed-article :feed="feed" :isInRepost="false" v-else-if="feed.isArticle"></feed-article> <!-- 动态 --> <feed-activity :feed="feed" :isInRepost="false" v-else-if="feed.isActivity" @content-click="handleActivityContentClick" @cover-click="handleActivityCoverClick"></feed-activity> </template> </div> <!-- 分页 --> <div> <feed-paginator :pcursors="pcursors" :pcursor="pcursor" :page="page" @change="getFeedList"/> </div> <!-- 一个隐藏域用于显示图片 --> <div id="preview-image" class="hidden" v-if="previewImages && previewImages.length>0"> <li v-for="image in previewImages"><img :src="image.originUrl?image.originUrl:image.url" :alt="image.title?image.title:'图片'"></li> </div> </div> `; // 初始化实例 new Vue({ el : '#acfunfeed-container', data : function(){ return { page : 1, pcursor : "0", pcursors : ["0"], feedList : [], previewImages : null, }; }, methods : { getUserInfo : function(uid, userName, callback){ var vue = this; if(uid in this.userInfo){ if(_.isFunction(callback)){ callback(true, this.userInfo[uid]); } return; } // 获取用户信息 commonRequrest(config.ACFUNLIVE_SERVER + config.URLS.ACFUN_USER.INFO + `?userId=${uid}`, 'get', null, true, function(isSuccess, data){ var userInfo = null; if(data){ data = JSON.parse(data); if(data.result == 0){ userInfo = { uid : uid, photo : data.profile.headUrl, userName : data.profile.name, }; } else{ userInfo = { uid : uid, userName : userName, photo : 'https://tx-free-imgs.acfun.cn/style/image/defaultAvatar.jpg', }; } } else{ userInfo = { uid : uid, userName : userName, photo : 'https://tx-free-imgs.acfun.cn/style/image/defaultAvatar.jpg', }; } vue.userInfo[uid] = userInfo; if(_.isFunction(callback)){ callback(isSuccess, userInfo); } }); }, getFeedList : function(pageObj){ var vue = this; this.page = pageObj.page; var position = $("#block-first").offset(); position.top = position.top-60; $("html,body").animate({scrollTop:position.top}, 100); // 已获取结束 if(pageObj.pcursor == "no_more"){ callback(true, []); return; } commonRequrest(config.ACFUN_API_SERVER + config.URLS.ACFUN_USER.FEED, 'get',{pcursor : pageObj.pcursor,count:pageObj.pageSize,},true, function(isSuccess, data){ if(!isSuccess){ vue.$message({ type : 'error', message : '获取动态推送失败', }); return; } data = JSON.parse(data); // 最新一页 if(pageObj.page == pageObj.total){ vue.pcursors.push(data.pcursor); } data.feedList.forEach(function(feed){ vue.processFeed(feed); }); vue.feedList = data.feedList; }, config.HEADERS.ACFUN_API_SERVER, ); }, // 跳转至用户主页 toUserSpace : function(userInfo){ window.open(config.ACFUN_SERVER + config.URLS.ACFUN_USER.SPACE + `/${userInfo.uid}`); }, // 处理动态 processFeed : function(feed){ feed.userInfo.shareUrl = `/u/${feed.userInfo.id}`; feed.userInfo.hoverText = `点击访问[${feed.userInfo.name}]的个人空间`; feed.tagResourceTypeText = this.getResourceText(feed.tagResourceType); // 动态类型 if(feed.tagResourceType == 3){ // 设置动态文本 feed.moment.htmlText = this.ubb2html(feed, feed.moment.text); // 转发动态 if(feed.repostSource){ feed.isRepost = true; // 处理转发内容 this.processFeed(feed.repostSource); feed.caption = `${feed.userInfo.name}转发了@${feed.repostSource.userInfo.name}的${feed.repostSource.tagResourceTypeText}`; } else{ feed.caption = `${feed.userInfo.name}发布了新动态`; } feed.isActivity = true; } // 视频类型 else if(feed.tagResourceType == 2){ feed.channel.shareUrl = `/v/list${feed.channel.id}/index.htm`; feed.channel.hoverText = `点击访问${feed.channel.name}频道`; // 无简介 if(!feed.detail.description){ feed.detail.description = '此稿件暂无简介。'; } // 包含标签 if(feed.tag && feed.tag.length>0){ feed.tag.forEach(function(tag){ tag.shareUrl = `/search?keyword=${tag.tagName}`; }); } feed.isVideo = true; } // 文章类型 else if(feed.tagResourceType == 1){ feed.caption = feed.articleTitle; feed.channel.shareUrl = `/v/list${feed.channel.id}/index.htm`; feed.channel.hoverText = `点击访问${feed.channel.name}频道`; // 包含标签 if(feed.tag && feed.tag.length>0){ feed.tag.forEach(function(tag){ tag.shareUrl = `/search?keyword=${tag.tagName}`; }); } feed.isArticle = true; } }, // 获取动态类型 getResourceText : function(resourceType){ if(resourceType == 1){ return '文章'; } else if(resourceType == 2){ return '视频'; } else if(resourceType == 3){ return '动态'; } }, // ubb转html ubb2html : function(feed, text){ // 转化艾特 var matchAt = matchAll(text, config.UBB.PATTERN.AT); matchAt.forEach(function(match){ var html = `<a target="_blank" href="${config.ACFUN_SERVER + config.URLS.ACFUN_USER.SPACE}/${match.groups.uid}" class="ubb-at">@${match.groups.userName}</a>`; text = text.replace(match.text, html); }); // 转化图片 var matchImg = matchAll(text, config.UBB.PATTERN.IMG); var images = []; matchImg.forEach(function(match){ var html = `<span class="ubb-img"><i class="icon icon-image"></i>${match.groups.title}</span>`; text = text.replace(match.text, html); images.push(match.groups); }); if(images.length>0){ feed.moment.imgs = images; } return text; }, handleActivityContentClick : function(feed, event){ // 点击查看图片 if(event.target.classList.contains('ubb-img') || event.target.parentElement.classList.contains('ubb-img')){ this.openImageViewer(feed.moment.imgs); } }, handleActivityCoverClick : function(feed, event){ // 查看动态图片 if(feed.moment.imgs && feed.moment.imgs.length>0){ this.openImageViewer(feed.moment.imgs); } }, openImageViewer : function(images){ this.previewImages = images; this.$nextTick(function(){ // 已初始化,则更新图片数据 if(this.gallery){ this.gallery.update(); } // 初始化 else{ this.gallery = new Viewer(document.getElementById('preview-image')); } this.gallery.show(); }); }, }, computed : { }, mounted : function(){ this.getFeedList({ page : 1, total : 1, pcursor : "0", }); }, }); }); return true; } function checkLoadVue(loadFunc){ window.setTimeout(function(){ var isSuccess = loadFunc(); console.log('加载', isSuccess); if(!isSuccess){ checkLoadVue(); } }, 1000); } window.onload = function(){ checkLoadVue(loadStatVue); // 推送页面 if([config.ACFUN_SERVER + config.URLS.ACFUN_USER.PUSH, config.ACFUN_SERVER + config.URLS.ACFUN_USER.FOLLOWER, config.ACFUN_SERVER + config.URLS.ACFUN_USER.FOLLOWING].indexOf(window.location.href) != -1){ checkLoadVue(loadFeedVue); } }; window.onhashchange = function(event){ // 推送页面 if([config.ACFUN_SERVER + config.URLS.ACFUN_USER.PUSH, config.ACFUN_SERVER + config.URLS.ACFUN_USER.FOLLOWER, config.ACFUN_SERVER + config.URLS.ACFUN_USER.FOLLOWING].indexOf(window.location.href) != -1){ checkLoadVue(loadFeedVue); } }; })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址