acfun统计

acfun统计(目前只包含送出礼物和收到礼物的统计)

As of 2021-02-27. See the latest version.

// ==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.10
// @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>&nbsp;&nbsp;共{{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>&nbsp;&nbsp;/&nbsp;&nbsp;发布于
								<span class="time">{{feed.time}}</span>&nbsp;&nbsp;/&nbsp;&nbsp;播放:
								<span class="views pts">{{feed.detail.viewCount}}</span>&nbsp;&nbsp;评论:
								<span class="comments pts">{{feed.detail.commentCount}}</span>&nbsp;&nbsp;收藏:
								<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>&nbsp;&nbsp;/&nbsp;&nbsp;发布于
								<span class="time">{{feed.time}}</span>&nbsp;&nbsp;/&nbsp;&nbsp;播放:
								<span class="views pts">{{feed.viewCount}}</span>&nbsp;&nbsp;评论:
								<span class="comments pts">{{feed.commentCount}}</span>&nbsp;&nbsp;收藏:
								<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>&nbsp;&nbsp;/&nbsp;&nbsp;发布于
								<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 .r {
							width: 750px
						}

						#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);
		}
	};
	
	
	
})();