kiic / 生意参谋访客下载

// ==UserScript==
// @name                生意参谋访客下载
// @author              黄逗酱酱
// @icon                https://kiic.oss-cn-beijing.aliyuncs.com/HMicc.png
// @match               *sycm.taobao.com/ipoll/visitor*
// @namespace 	        黄逗酱酱
// @description         生意参谋实时访客下载,方便运营对自己的店铺的商品进行分析和收集支持一次性下载50页和单页下载包含商品id,图片等信息,请勿用于其他用途
// @note                v2.0.0 2021-01-21 功能增加了 一次性下载所有页面,UI化了本脚本,增加了一键复制的功能,更加良好的交互界面版本更新到2.0(革命性升级)
// @note                v2.0.1 2021-01-22 修复了无法一次性下载所有数据的BUG
// @note                v2.1.0 2021-01-23 支持提前结束下载全部功能,功能基本完结 下次更新只会是解决重大bug或者重大功能更新,看着密密麻麻的代码头就疼,肝了这么多天肝完了
// @note                v2.1.2 2021-04-17 紧急修复全部功能
// @note                v2.1.2.1 2021-04-18 修复不显示入店来源
// @connect             *
// @date                01/27/2021
// @require             https://cdn.bootcdn.net/ajax/libs/keypress/2.1.5/keypress.min.js
// @require             https://cdn.jsdelivr.net/npm/file-saver@1.3.8/FileSaver.min.js
// @require             https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js
// @grant               GM_setClipboard
// @version             2.1.2
// @description         zh-cn
// @run-at              document-body
// @license             MPL-2.0
// @namespace           https://greasyfork.org/users/710095
// ==/UserScript==

/**创建一个显示按钮,源码参考自@头号否 ID=39238  许可协议GPL-3.0-only本脚本变更许可协议MPL-2.0
 * ***外部库引用声明***
 * *作者引用的js库均为各大公司cdn 静态资源公共库,感谢:字节跳动,新浪网,bootcdn
 * 用户许可协议:版权声明:本脚本只作为卖家进行本店内数据查看,请尊重网页的robots(https://sycm.taobao.com/robots.txt)文件内的抓取声明在本脚本发布时间内所检索的内容为同意访问
*/
;

( async function(){
   let dasfsagdshsgag=null;

    function sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms))
      }
var MIU_NUMX =1;
var HM_get_;
/**表单头:*日期	访问时间	商品缩略图	商品ID/来源	搜索来源	关键词	标题	IP地址	访客编号	商品主图	商品链接	访客唯一编号 */
var Table_title = ['日期,访问时间,商品缩略图,商品ID/来源,搜索来源,关键词,标题,IP地址,访客编号,商品主图,商品链接,访客唯一编号\n'];
function HM_go() {
	var alicmz = '<div id="onii_alicmz"></div>';
	var getbody = document.getElementsByTagName('body')[0];
	getbody.insertAdjacentHTML('afterbegin', alicmz);
	var style = document.createElement('style');
	style.type = 'text/css';
	var inn_ocss = `#onii_alicmz,.aliwx {
      position: fixed;  top: 5%;  right: 50px;  padding: 10px;  min-width: 130px;  text-align: center;  z-index: 999999999999999;  background: #fff;  border-radius: 15px;  border: 1px solid #1a7cda;}
      .alicmzbtn {  background-color: #1a7cda;  color: #ffffff;  border: 0px solid #f0cab6;  right: 20em;  top: 40em;  z-index: 88;  cursor: pointer;  padding: 5px 20px;  border-radius: 50px;  margin-bottom: 10px;  transition: 0.3s;}
      .alicmzbtn:hover {  color: #fff;  background-color: #1c8ded;}
      .close {  color: #828282;  background-color: #e6e6e6;  width: 80px;  text-align: center;  padding: 0.5em;  border-radius: 2px;  padding-left: 1em;  padding-right: 1em;  text-decoration: none;  transition: 0.3s;}
      .close:hover {  color: #5d5d5d;  background-color: #ffffff;  text-decoration: none;}
      .alicmzbtn a {  color: #1c8ded;  text-decoration: none;}
      .dmcss a {  color: #d3d3d3;  text-decoration: none;}
      .xflogo {  width: 110px;  padding: 15px 10px 15px 10px;}
      #gbxf {  color: #1c8ded;  position: absolute;  right: 8px;  top: 6px;  font-size: 12px;  cursor: pointer;  transition: 0.3s;  border: 1px #000000 solid;  line-height: 9px;  border-radius: 3px;  padding: 1px;}
      #gbxf:hover {  color: #fff;  border: 1px #fa630a solid;background-color: #fa630a;  opacity: 0.8;}
      #smallxf {  position: fixed;  bottom: 36px;  right: 36px;  color: #fe4514;  background-color: #fff;  border: 2.5px solid #1a7cda;  padding: 8px;  font-weight: bold;  font-size: 14px;  cursor: pointer;  border-radius: 27px;  z-index: 999999999999999999;  transition: 0.6s;}
      #smallxf:hover {  bottom: 5px;  box-shadow: rgba(0, 0, 0, 0.04) 0 1px 5px 0px;}
	  .smlogo {  width: 100px;  padding: 2px 5px 0px 5px;}
       .qmsg.qmsg-wrapper{box-sizing:border-box;margin:0;padding:0;color:rgba(0,0,0,.55);font-size:13px;font-variant:tabular-nums;line-height:1;list-style:none;font-feature-settings:"tnum";position:fixed;top:16px;left:0;z-index:999999999999999999999999999;width:100%;pointer-events:none}.qmsg .qmsg-item{padding:8px;text-align:center;-webkit-animation-duration:.3s;animation-duration:.3s;position:relative}.qmsg .qmsg-item .qmsg-count{text-align:center;position:absolute;left:-4px;top:-4px;background-color:red;color:#fff;font-size:12px;line-height:16px;border-radius:2px;display:inline-block;min-width:16px;height:16px;-webkit-animation-duration:.3s;animation-duration:.3s}.qmsg .qmsg-item:first-child{margin-top:-8px}.qmsg .qmsg-content{text-align:left;position:relative;display:inline-block;padding:17px 26px;background:#fff;border-radius:4px;box-shadow:0 4px 12px rgba(0,0,0,.15);pointer-events:all;font-weight:700;font-size:18px;max-width:80%;min-width:80px}.qmsg .qmsg-content [class^="qmsg-content-"]{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.qmsg .qmsg-content .qmsg-content-with-close{padding-right:20px}.qmsg .qmsg-icon{display:inline-block;color:inherit;font-style:normal;line-height:0;text-align:center;text-transform:none;vertical-align:-.125em;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;position:relative;top:1px;margin-right:8px;font-size:16px}.qmsg .qmsg-icon svg{display:inline-block}.qmsg .qmsg-content-info .qmsg-icon{color:#1890ff;user-select:none}.qmsg .qmsg-icon-close{position:absolute;top:11px;right:5px;padding:0;overflow:hidden;font-size:12px;line-height:22px;background-color:transparent;border:0;outline:0;cursor:pointer;color:rgba(0,0,0,.45);transition:color .3s}.qmsg .qmsg-icon-close:hover>svg path{stroke:#555}.qmsg .animate-turn{animation:MessageTurn 1s linear infinite;-webkit-animation:MessageTurn 1s linear infinite}@keyframes MessageTurn{0%{-webkit-transform:rotate(0deg)}25%{-webkit-transform:rotate(90deg)}50%{-webkit-transform:rotate(180deg)}75%{-webkit-transform:rotate(270deg)}100%{-webkit-transform:rotate(360deg)}}@-webkit-keyframes MessageTurn{0%{-webkit-transform:rotate(0deg)}25%{-webkit-transform:rotate(90deg)}50%{-webkit-transform:rotate(180deg)}75%{-webkit-transform:rotate(270deg)}100%{-webkit-transform:rotate(360deg)}}@-webkit-keyframes MessageMoveOut{0%{max-height:150px;padding:8px;opacity:1}to{max-height:0;padding:0;opacity:0}}@keyframes MessageMoveOut{0%{max-height:150px;padding:8px;opacity:1}to{max-height:0;padding:0;opacity:0}}@-webkit-keyframes MessageMoveIn{0%{transform:translateY(-100%);transform-origin:0 0;opacity:0}to{transform:translateY(0);transform-origin:0 0;opacity:1}}@keyframes MessageMoveIn{0%{transform:translateY(-100%);transform-origin:0 0;opacity:0}to{transform:translateY(0);transform-origin:0 0;opacity:1}}@-webkit-keyframes MessageShake{0%,100%{transform:translateX(0px);opacity:1}25%,75%{transform:translateX(-4px);opacity:.75}50%{transform:translateX(4px);opacity:.25}}@keyframes MessageShake{0%,100%{transform:translateX(0px);opacity:1}25%,75%{transform:translateX(-4px);opacity:.75}50%{transform:translateX(4px);opacity:.25}}
	  `;
	style.innerHTML = inn_ocss;
	document.getElementsByTagName('HEAD').item(0).appendChild(style);
	//定义一个全局弹出层

	//创建一个显示按钮
	function aliwxframe() {
		var getkj = document.getElementById("onii_alicmz");
		getkj.innerHTML = `<div id="innbe_xg" class= "alicmzbtn" >开启自动下载</div>
    <div id="thwx" class= "alicmzbtn" >下载本页</div>
	<div id="innbe_xf" class= "alicmzbtn" >下载全部</div>
	<div id="copy_thwx" class= "alicmzbtn" >复制本页</div>
	`;
		document.body.appendChild(getkj);
	}
	aliwxframe();

	var gbxf = '<div id="gbxf" onclick="hidexf();" title="点击隐藏">—</div>';
	var xfkj = document.getElementById('onii_alicmz');
	xfkj.insertAdjacentHTML('afterbegin', gbxf);

	var hdxf = document.getElementById('gbxf');
	hdxf.addEventListener('click', hidexf, false);

	var  omatic_dow= document.getElementById('innbe_xg');
	omatic_dow.addEventListener('click', Automatic_download, false);

	var  d_HM_CSV_At_p= document.getElementById('thwx');
	d_HM_CSV_At_p.addEventListener('click', download_HM_CSV_At_present, false);

	var  HM_HY_= document.getElementById('innbe_xf');
	HM_HY_.addEventListener('click', HM_HY_ALLgo, false);

	var  copy_JHM= document.getElementById('copy_thwx');
	copy_JHM.addEventListener('click', copy_thwxNN, false);

	var smallxf = '<div id="smallxf" style="display:none;" onclick="showcmz();" title="点击恢复"><img src="https://kiic.oss-cn-beijing.aliyuncs.com/imag/sy_cm_icc.svg" class="smlogo"></div>';
	var getcmz = document.getElementById('onii_alicmz');
	getcmz.insertAdjacentHTML('afterend', smallxf);

	var showxf = document.getElementById('smallxf');
	showxf.addEventListener('click', showcmz, false);

	function hidexf() {
		document.getElementById('onii_alicmz').style.display = 'none';
		document.getElementById('smallxf').style.display = 'block';
	};

	function showcmz() {
		document.getElementById('onii_alicmz').style.display = 'block';
		document.getElementById('smallxf').style.display = 'none';
	};
	hidexf();
}

HM_go();
   // 大图解析
   function MAXimg(url) {
	return url
	   .replace(/_[.]webp/img, '')    //_.webp
	   .replace(/_\d+x\d+[.](je?pg|png|gif|wepb)/img, '')  //_pic.jpg_60x60.jpg
	   .replace(/_\d+x\d+[a-z]\d+[.](je?pg|png|gif|wepb)/img, '') //.jpg_60x60q90.jpg
	   .replace(/https?:/img, '') //移除所有连接的协议头无论有没有
	   .replace(/(\\\\+|\/\/+)?img\.alicdn\.com\/tps\/[a-z]\d\/T10B2IXb4cXXcHmcPq(-\d+-\d+[.]gif)?/img, '') //详情页默认的gif防盗
	   .replace(/(\\\\+|\/\/+)?img\.alicdn\.com.{1,12}\/spaceball.gif/img, '') //详情页默认的png防盗
	   .replace(/([.](je?pg|png|gif|wepb))_\d+x\d+[a-z]\d+/img, '$1') //.jpg_640x640q80
	   .replace(/([.](je?pg|png|gif|wepb))_\d+x\d+([a-z]\d+){2,3}([.](je?pg|png|gif|wepb))?/img, '$1')// .jpg_760x760Q50s50.jpg
	   .replace(/(?:.+?)?(\/\/.{1,6}(?:ali|taobao|tb)cdn[.]com\/.+?[.](?:jpe?g|png|gif))(.+?)?$/i, 'https:$1')//只单行加头并且移除本行内所有不需要的信息
	   .replace(/[.]\d+x\d+[.](jpe?g|png|gif|webp)(?:(?:_\d+x\d+[a-z]\d+.[a-z]+_(?:.webp)?)?)/i, '.$1')
	   .replace("https://cbu01.alicdn.com/cms/upload/other/lazyload.png", '');//黑名单
 }

/**关闭网页点击功能 */
function HM_off_html(t) {
	let d = 0;
	if (t !== 1) { d = 'body{pointer-events: none;}' }
	if (t === 1) { d = 'body{pointer-events: all;}' }
	let style = document.createElement('style'); style.type = 'text/css'; let
		inn_ocss = d;
	style.innerHTML = inn_ocss; document.getElementsByTagName('HEAD').item(0).appendChild(style)
}
/**数组拼接器 回执式*/
function push_Array(a, b) {
	var ar = new Array();
	for (var i = 0; i < a.length; i++) {
		ar.push(a[i]);
	}
	for (var j = 0; j < b.length; j++) {
		ar.push(b[j]);
	}
	return ar;
}
/**数组去重函数,回执式 */
function Do_not_repeat_HM(arr) {
	console.log('---开始数据去重---');
	if (!Array.isArray(arr)) {
		console.log('数据错误!');
		return;
	}
	let res = [arr[0]]
	for (let i = 1; i < arr.length; i++) {
		let flag = true
		for (let j = 0; j < res.length; j++) {
			if (arr[i] === res[j]) {
				flag = false;
				break;
			}
		}
		if (flag) {
			res.push(arr[i]);
		}
	}
	return res;
}
var yyyy_mm_dd;
var hM_NAME = 'HM_ROM_users_DATAall';

var store={
    set(value){
        sessionStorage.setItem(hM_NAME,JSON.stringify(value));
    },
    get(){
      return JSON.parse(sessionStorage.getItem(hM_NAME));
    },
    remove(){
        sessionStorage.removeItem(hM_NAME);
    }
  }


/**时间获取器 */
function HM_Time() {
	let date = new Date();
	let yyyy = date.getFullYear(); //获取完整的年份(4位)
	let mm = (date.getMonth() + 1); //获取当前月份(0-11,0代表1月)
	let dd = date.getDate(); //获取当前日(1-31)
	let nn = date.getHours(); //获取当前小时数(0-23)
	let nm = date.getMinutes(); //获取当前分钟数(0-59)
	let nu = date.getSeconds(); //获取当前秒数(0-59)
	yyyy_mm_dd = yyyy + '-' + mm + '-' + dd;
	return yyyy + '-' + mm + '-' + dd;
}
var MAXM;

/***全局数组 */
var AJSON = '';
AJSON = new Array();
var Stoperr = 0;
/**包含全部数据的数组 */
var get_json = new Array();
/**
 * 核心本体这个是数据获取器
 * @param {*} din_Timag  商品主图
 * @param {*} din_TimagN 商品缩略图
 * @param {*} din_title  标题
 * @param {*} din_idurl  链接
 * @param {*} din_id     ID
 * @param {*} dinis_GC   搜索关键词(如果有)
 * @param {*} dinis_LY   入店来源
 * @param {*} dinis_YIN  访客位置
 * @param {*} dinis_YDM  访问时间
 * @param {*} dinis_YINR 访问时间+访客编号
 * @param {*} dinis_YMU  访客编号
 * @param {*} Nt         制表符
 */
function getGO_HM(din_Timag, din_TimagN, din_title, din_idurl, din_id, dinis_GC, dinis_LY, dinis_YIN, dinis_YDM, dinis_YINR, dinis_YMU, Nt) {
	AJSON = '';
	AJSON = new Array();
	Nt = "\t"; //制表符分隔
	var YMD =  HM_Time();
	[din_Timag, din_TimagN, din_title, din_idurl, din_id, dinis_GC, dinis_LY, dinis_YIN, dinis_YDM, dinis_YINR, dinis_YMU] = '';
	var diom = document.querySelectorAll(" .table-container.table-container-2  table  tbody tr");
		diom=document.querySelectorAll("#visitor-detail .oui-card-content  table   tbody tr");
		for (let i = 0; i < diom.length; i++) {
			let n = diom[i].querySelectorAll('td');
			// n=循环主目录
			let [SORT,UVPage,Source,Region,PVTime,Serial] =[n[0],n[1],n[2],n[3],n[4],n[5]];
				if(UVPage){
				if(UVPage.querySelector('.sycm-goods-td a')){
				  din_Timag  =MAXimg(UVPage.querySelector('.sycm-goods-td img').src);
				  din_TimagN = `![img](${din_Timag}_20x20.jpg)`;
				  din_idurl  = UVPage.querySelector('.sycm-goods-td a').href;
				  if(din_idurl.match(/[\?&]id=(\d+)/)){
					  din_id = '#'+din_idurl.match(/[\?&]id=(\d+)/)[1];
				  }
				  din_title =UVPage.querySelector('.sycm-goods-td a').title
				}else {
					din_id =	UVPage.innerText.replace(/[\s \t\n]+/g,'')
				}}
				if(Source){
					if(Source.querySelector('span .keyword')){
					dinis_GC=Source.querySelector('span .keyword').innerText;
					dinis_LY=Source.innerText.replace(/[\s \t\n]+/g,'');
					let newsrc= new RegExp(`${dinis_GC}$`);
					dinis_LY=dinis_LY.replace(newsrc,'')

				}else{
					// 没有内容就是纯入店来源
						dinis_LY=Source.innerText.replace(/[\s \t\n]+/g,'');
				}}
				if(Region){dinis_YIN=Region.innerText.replace(/[\s \t\n]+/g,'')}
				if(PVTime){dinis_YDM=PVTime.innerText.replace(/[\s \t\n]+/g,'')}
				if(Serial){dinis_YMU=Serial.innerText.replace(/[\s \t\n]+/g,'')}
				if(dinis_YMU){dinis_YINR=HM_Time()+'-'+dinis_YDM+"-"+dinis_YMU}

				var AJSONNU = ((YMD + Nt + dinis_YDM + Nt + din_TimagN + Nt + din_id + Nt + dinis_LY + Nt + dinis_GC + Nt + din_title + Nt + dinis_YIN + Nt + dinis_YMU + Nt + din_Timag + Nt + din_idurl + Nt + dinis_YINR + '\n')
				.replace(/undefined/igm, '')
				.replace(/,/igm, ',')
				.replace(/\t/igm, ','));
	// 		/*输出给用户的是逗号分隔文件 */
	// 		// 我需要的格式  日期   访问时间    商品缩略图   商品ID/来源 搜索来源    关键词 标题  IP地址    访客编号    商品主图    商品链接    访客唯一编号
			AJSON.push(AJSONNU);
            // 清空数据防止下行有问题,小bug懒得找反正要重构了
            [din_Timag, din_TimagN, din_title, din_idurl, din_id, dinis_GC, dinis_LY, dinis_YIN, dinis_YDM, dinis_YINR, dinis_YMU] = '';
		}
}
/**顺序数值编号器 参数:开始数字,位数(2=01,3=001) */
function MIU_NUM(num, n) {
	return (Array(n).join(0) + num).slice(- n);
};
/**复制本页 */
function copy_thwxNN() {
	getGO_HM();
	let text =AJSON.join('').replace(/,/img,'\t');
	GM_setClipboard(text);
	Qmsg.info("已复制可粘贴到表格增量")
	HM_get_new();
	AJSON = '';
	AJSON = new Array();
}

/**下载本页,下载后会自动删除内存中的数据不叠加下一页 */
function download_HM_CSV_At_present() {
	getGO_HM();
	download_HM_CSV();
	HM_get_new();
	AJSON = '';
	AJSON = new Array();
}
/**下载数据的函数 */
function download_HM_CSV(u, f) {
	let NAJSON;
	if (!u) {
		NAJSON = Do_not_repeat_HM(AJSON);
	} if (u) {
		NAJSON = Do_not_repeat_HM(u);
	}
	let blob = new Blob(NAJSON, {
		type: "text/plain;charset=utf-8"
	});

	if (f) { saveAs(blob, "合集_生意参谋访客数据_" + HM_Time() + ".csv"); } else {
		saveAs(blob,HM_Time()+"_"+"生意参谋访客数据_" +MIU_NUM(MIU_NUMX,2)+ ".csv");
	}MIU_NUMX =MIU_NUMX+1;
	/**清空储存中的数据 */

}
/**
 * 随机数值
 * @param {*} Min 最小
 * @param {*} Max 最大
 */
function GetRandomNum(Min, Max) {
	var Range = Max - Min;
	var Rand = Math.random();
	return (Min + Math.round(Rand * Range));
}

/**自动执行下载 */
function Automatic_download() {
	Qmsg.loading(`已开启自动下载,关闭此消息停止`, {
		autoClose: true,
		showClose: true
	});
	var idnf = setInterval(function () {
		document.querySelector("#visitor-detail > div.oui-card-header-wrapper > div.oui-card-header > div.oui-card-header-item.oui-card-header-item-pull-right > button").click();
		setTimeout(function () { if (document.querySelector('.qmsg-content')) { download_HM_CSV_At_present(); } }, 800);
		if (!document.querySelector('.qmsg-content')) { clearInterval(idnf); console.log('已停止') }
	}, (GetRandomNum(32000, 60000)));

}
/**声明这个函数在本脚本任意地方可执行 */
var NHM_idn;
var HM_get_newALLgoget_=[];

/**下载全部:网页显示有多少次就下载多少次 下一页时间为1秒到3秒防止性能占用过多 因为是整页自动添加表头 下载完成延时(5秒)删除数据中的全部数据*/
// function HM_HY_ALLgo(params) {
// 	Qmsg.info("该功能特别复杂,还在恢复中")
// }
async function  HM_HY_ALLgo() {
	HM_off_html(0);
    // 获取多少页
  let next=  document.querySelector("#visitor-detail .ant-pagination-next");
        // 下一页前面是总页数
  let  Countlength =next.parentElement.querySelectorAll('li').length-2;
  let  Count =  next.parentElement.querySelectorAll('li')[Countlength];
  if(Count)
  if(Count.innerText.match(/\d+/)){
    Count=Count.innerText.match(/\d+/)[0]*1;
  }else{return 	Qmsg.info("可能是网站更新了无法获取全部数据")}
  dasfsagdshsgag= Qmsg.loading(`正在下载中请勿关闭网页...`, {
    autoClose: true,
    showClose: true
});


  for(let i=0;i<Count;i++){
    getGO_HM();
    await sleep(200);
    HM_get_newALLgoget_.push(AJSON)
    // 随机异步阻塞
    await sleep(GetRandomNum(800,3000));
    next.click();
    AJSON=[];

}
// 下载

await sleep(200);
let data =Do_not_repeat_HM(HM_get_newALLgoget_)

let newdata =[];
for (let s = 0; s < data.length; s++) {
    const i = data[s];

    for (let c = 0; c < i.length; c++) {
        const v = i[c];
        newdata.push(v)
    }

}


await sleep(200);



// console.log(data)
// 敲代码就是要敷衍变量名也是不懒编程干嘛
// <= <=
//   __
dasfsagdshsgag.close();

	let blob = new Blob(newdata, {
		type: "text/plain;charset=utf-8"
	});
   let name= `${HM_Time()}_生意参谋访客数据_${MIU_NUM(MIU_NUMX,2)}.csv`
    saveAs(blob,name);
   delete data,HM_get_newALLgoget_,AJSON;
   HM_off_html(1)
   Qmsg.info("下载完成")
}

let keyMAXM=1;
/**按钮点击器 */
function HM_get_new() {

     document.querySelector("#visitor-detail .ant-pagination-next").click();
	 if( document.querySelector("#visitor-detail .ant-pagination-next").classList.toString().match("ant-pagination-disabled"))
	 return {type:"Success"}
}


/**这个是用于弹窗的库 没必要使用未压缩文本*//**
 * gitee地址:https://gitee.com/jesseqin/JavaScript_base
 */
;(function(root,Msg){
    if(typeof exports === 'object' && typeof module !== 'undefined'){
        module.exports = Msg
    }else if(typeof define === 'function' && define.amd){
        define([],function () { 
            return Msg(root); 
        });
    }else{
        root.Qmsg = Msg(root);
    }
})(this,function(global){
    'use srtict';
 
    //assign 兼容处理
    if (typeof Object.assign != 'function') {   
        Object.assign = function(target) {
        if (target == null) {
            throw new TypeError('Cannot convert undefined or null to object');
        }
    
        target = Object(target);
        for (var index = 1; index < arguments.length; index++) {
            var source = arguments[index];
            if (source != null) {
            for (var key in source) {
                if (Object.prototype.hasOwnProperty.call(source, key)) {
                target[key] = source[key];
                }
            }
            }
        }
        return target;
     } 
    };
 
    // 'classList' 兼容处理
    var isClsList = 'classList' in HTMLElement.prototype;
    if(!isClsList) {
        Object.defineProperty(HTMLElement.prototype,'classList',{
            get:function(){
                // add, remove ,contains,toggle
                // this  - > 
                var _self = this;
                return {
                    add:function(cls){
                        if(!this.contains(cls)){
                            _self.className +=' ' + cls;
                        }
                    },
                    remove:function(cls){
                        if(this.contains(cls)){ 
                            var reg= new RegExp(cls);   
                            _self.className =  _self.className.replace(reg,'');
                        }
                    },
                    contains:function(cls){      
                    var index =  _self.className.indexOf(cls);
                        return  index!=-1 ? true : false;
                    },
                    toggle:function(cls){
                        if(this.contains(cls)){ 
                            this.remove(cls)
                        } else {
                            this.add(cls)
                        }
                    }
                }
            }
        })
    }
 
    /**
     * 声明插件名称
     */
    var PLUGIN_NAME = "qmsg";
 
    /**
     * 命名空间 用于css和事件
     */
    var NAMESPACE = global && global.QMSG_GLOBALS && global.QMSG_GLOBALS.NAMESPACE || PLUGIN_NAME;
 
    /**
     * 状态 & 动画
     * 显示中,显示完成,关闭中
     */
    var STATES = {
        opening : 'MessageMoveIn',
        done : '',
        closing : 'MessageMoveOut'
    }
 
    /**
     * 全局默认配置
     * 可在引入js之前通过QMSG_GLOBALS.DEFAULTS进行配置
     * position {String} 位置,仅支持'center','right','left',默认'center'
     * type {String} 类型,支持'info','warning','success','error','loading'
     * showClose {Boolean} 是否显示关闭图标,默认为false不显示
     * timeout {Number} 多久后自动关闭,单位ms,默认2500
     * autoClose {Boolean} 是否自动关闭,默认true,注意在type为loading的时候自动关闭为false
     * content {String} 提示的内容
     * onClose {Function} 关闭的回调函数
     */
    var DEFAULTS = Object.assign({
        position:'center',
        type:"info", 
        showClose:false,
        timeout:2500,
        animation:true,
        autoClose:true,
        content:"",
        onClose:null,
        maxNums:5,
        html:false
    },global && global.QMSG_GLOBALS && global.QMSG_GLOBALS.DEFAULTS)
 
     /**
     * 设置icon html代码
     */
    var ICONS = {
        info:'<svg width="16" height="16" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="48" height="48" fill="white" fill-opacity="0.01"/><path d="M24 44C29.5228 44 34.5228 41.7614 38.1421 38.1421C41.7614 34.5228 44 29.5228 44 24C44 18.4772 41.7614 13.4772 38.1421 9.85786C34.5228 6.23858 29.5228 4 24 4C18.4772 4 13.4772 6.23858 9.85786 9.85786C6.23858 13.4772 4 18.4772 4 24C4 29.5228 6.23858 34.5228 9.85786 38.1421C13.4772 41.7614 18.4772 44 24 44Z" fill="#1890ff" stroke="#1890ff" stroke-width="4" stroke-linejoin="round"/><path fill-rule="evenodd" clip-rule="evenodd" d="M24 11C25.3807 11 26.5 12.1193 26.5 13.5C26.5 14.8807 25.3807 16 24 16C22.6193 16 21.5 14.8807 21.5 13.5C21.5 12.1193 22.6193 11 24 11Z" fill="#FFF"/><path d="M24.5 34V20H23.5H22.5" stroke="#FFF" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M21 34H28" stroke="#FFF" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>',
        warning:'<svg width="16" height="16" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="48" height="48" fill="white" fill-opacity="0.01"/><path d="M24 44C29.5228 44 34.5228 41.7614 38.1421 38.1421C41.7614 34.5228 44 29.5228 44 24C44 18.4772 41.7614 13.4772 38.1421 9.85786C34.5228 6.23858 29.5228 4 24 4C18.4772 4 13.4772 6.23858 9.85786 9.85786C6.23858 13.4772 4 18.4772 4 24C4 29.5228 6.23858 34.5228 9.85786 38.1421C13.4772 41.7614 18.4772 44 24 44Z" fill="#faad14" stroke="#faad14" stroke-width="4" stroke-linejoin="round"/><path fill-rule="evenodd" clip-rule="evenodd" d="M24 37C25.3807 37 26.5 35.8807 26.5 34.5C26.5 33.1193 25.3807 32 24 32C22.6193 32 21.5 33.1193 21.5 34.5C21.5 35.8807 22.6193 37 24 37Z" fill="#FFF"/><path d="M24 12V28" stroke="#FFF" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>',
        error:'<svg width="16" height="16" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="48" height="48" fill="white" fill-opacity="0.01"/><path d="M24 44C35.0457 44 44 35.0457 44 24C44 12.9543 35.0457 4 24 4C12.9543 4 4 12.9543 4 24C4 35.0457 12.9543 44 24 44Z" fill="#f5222d" stroke="#f5222d" stroke-width="4" stroke-linejoin="round"/><path d="M29.6569 18.3431L18.3432 29.6568" stroke="#FFF" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M18.3432 18.3431L29.6569 29.6568" stroke="#FFF" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>',
        success:'<svg width="16" height="16" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="48" height="48" fill="white" fill-opacity="0.01"/><path d="M24 4L29.2533 7.83204L35.7557 7.81966L37.7533 14.0077L43.0211 17.8197L41 24L43.0211 30.1803L37.7533 33.9923L35.7557 40.1803L29.2533 40.168L24 44L18.7467 40.168L12.2443 40.1803L10.2467 33.9923L4.97887 30.1803L7 24L4.97887 17.8197L10.2467 14.0077L12.2443 7.81966L18.7467 7.83204L24 4Z" fill="#52c41a" stroke="#52c41a" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M17 24L22 29L32 19" stroke="#FFF" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>',
        loading:'<svg class="animate-turn" width="16" height="16" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="48" height="48" fill="white" fill-opacity="0.01"/><path d="M4 24C4 35.0457 12.9543 44 24 44V44C35.0457 44 44 35.0457 44 24C44 12.9543 35.0457 4 24 4" stroke="#1890ff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M36 24C36 17.3726 30.6274 12 24 12C17.3726 12 12 17.3726 12 24C12 30.6274 17.3726 36 24 36V36" stroke="#1890ff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>',
        close:'<svg width="16" height="16" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="48" height="48" fill="white" fill-opacity="0.01"/><path d="M14 14L34 34" stroke="#909399" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M14 34L34 14" stroke="#909399" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>',
    }
 
     /**
     * 是否支持动画属性
     * @type {Boolean}
     */
    var CAN_ANIMATION = (function() {
        var style = document.createElement('div').style;
        return style.animationName !== undefined ||
          style.WebkitAnimationName !== undefined ||
          style.MozAnimationName !== undefined ||
          style.msAnimationName !== undefined ||
          style.OAnimationName !== undefined;
    })();
 
    /**
     * 生成带插件名的名称
     * @param {...String}
     * @returns {String}
     */
    function namespacify(){
        var res = NAMESPACE;
        for(var i = 0; i < arguments.length; ++i){
            res += '-' + arguments[i];
        }
        return res;
    }
 
    /**
     * 每条消息的构造函数
     * @param {Objetc} opts 配置参数,参考DEFAULTS
     */
    function Msg(opts){
        var oMsg = this;
        oMsg.settings = Object.assign({},DEFAULTS,opts||{});
        oMsg.id = Qmsg.instanceCount;
        var timeout = oMsg.settings.timeout;
        timeout = timeout && parseInt(timeout>=0) & parseInt(timeout)<=Math.NEGATIVE_INFINITY ?parseInt(timeout):DEFAULTS.timeout;
        oMsg.timeout = timeout;
        oMsg.settings.timeout = timeout;
        oMsg.timer = null;
        var $elem = document.createElement("div");
        var $svg = ICONS[oMsg.settings.type || 'info'];
        var contentClassName = namespacify("content-"+oMsg.settings.type || 'info');
        contentClassName +=oMsg.settings.showClose ?' '+ namespacify('content-with-close'):''
        var content = oMsg.settings.content || '';
        var $closeSvg = ICONS['close'];
        var $closeIcon = oMsg.settings.showClose ? '<i class="qmsg-icon qmsg-icon-close">'+$closeSvg+'</i>':'';
        var $span = document.createElement("span");
        if(oMsg.settings.html){
            $span.innerHTML = content;
        }else{
            $span.innerText = content;
        }
        $elem.innerHTML = '<div class="qmsg-content">\
            <div class="'+contentClassName+'">\
                <i class="qmsg-icon">'+$svg+'</i>'+$span.outerHTML + $closeIcon +
                '</div>\
        </div>';
 
        $elem.classList.add(namespacify('item'));
        $elem.style.textAlign = oMsg.settings.position;
        var $wrapper = document.querySelector('.'+NAMESPACE);
        if(!$wrapper){
            $wrapper =  document.createElement("div");
            $wrapper.classList.add(NAMESPACE,namespacify('wrapper'),namespacify('is-initialized'));
            document.body.appendChild($wrapper);
        }
        $wrapper.appendChild($elem);
        oMsg.$wrapper = $wrapper;
        oMsg.$elem = $elem;
        setState(oMsg,'opening');
        if(oMsg.settings.showClose){ //关闭按钮绑定点击事件
            $elem.querySelector(".qmsg-icon-close").addEventListener('click',function(){
                oMsg.close();
            }.bind($elem))
        }
        $elem.addEventListener("animationend", function(e) {   // 监听动画完成
            var target = e.target,animationName = e.animationName;
            if(animationName == STATES['closing']){
                clearInterval(this.timer);
                this.destroy();
            }
            target.style.animationName = '';
            target.style.webkitAnimationName = '';
        }.bind(oMsg))
        if(oMsg.settings.autoClose){ // 自动关闭
            var intvMs = 10; // 定时器频率
            oMsg.timer = setInterval(function(){
                this.timeout -= intvMs;
                if(this.timeout <= 0){
                    clearInterval(this.timer)
                    this.close();
                }
            }.bind(oMsg),intvMs);
            oMsg.$elem.addEventListener('mouseover',function(){
                clearInterval(this.timer)
            }.bind(oMsg))
            oMsg.$elem.addEventListener('mouseout',function(){
                if(this.state!='closing'){ // 状态为关闭则不重启定时器
                    this.timer = setInterval(function(){
                        this.timeout -= intvMs;
                        if(this.timeout <= 0){
                            clearInterval(this.timer);
                            this.close();
                        }
                    }.bind(oMsg),intvMs);
                }
            }.bind(oMsg))
        }
    }
 
    function setState(inst,state){
        if(!state || !STATES[state]) return;
        inst.state = state;
        inst.$elem.style.animationName = STATES[state];
    }
 
    /**
     * 直接销毁元素,不会触发关闭回调函数
     */
    Msg.prototype.destroy = function(){
        this.$elem.parentNode && this.$elem.parentNode.removeChild(this.$elem);
        clearInterval(this.timer);
        Qmsg.remove(this.id);
    }
    /**
     * 关闭,支持动画则会触发动画事件
     */
    Msg.prototype.close = function(){
        setState(this,'closing');
        if(!CAN_ANIMATION){ // 不支持动画
            this.destroy();
        }else{
            Qmsg.remove(this.id);
        }
        var callback = this.settings.onClose;
        if(callback && callback instanceof Function){
            callback.call(this);
        }
    }
 
    /**
     * 设置消息数量统计
     * @private
     */
    function setMsgCount(oMsg){
        var countClassName = namespacify('count');
        var $content = oMsg.$elem.querySelector("."+namespacify('content')),
        $count = $content.querySelector('.'+countClassName);
        if(!$count){
            $count = document.createElement("span");
            $count.classList.add(countClassName);
            $content.appendChild($count);
        }
        $count.innerHTML = oMsg.count;
        $count.style.animationName = "";
        $count.style.animationName = "MessageShake";
        oMsg.timeout = oMsg.settings.timeout || DEFAULTS.timeout;
    }
 
    /**
     * 合并参数为配置信息,用于创建Msg实例
     * @param {String} txt 文本内容
     * @param {Object} config 配置
     * @private
     */
    function mergeArgs(txt,config){
        var opts = Object.assign({},DEFAULTS);
        if(arguments.length===0){
            return opts;
        }
        if(txt instanceof Object){
            return Object.assign(opts,txt);
        }else{
            opts.content = txt.toString();
        }
        if(config instanceof Object){
            return Object.assign(opts,config)
        }
        return opts;
    }
 
    /**
     * 通过配置信息 来判断是否为同一条消息,并返回消息实例
     * @param {Object} params 配置项
     * @private
     */
    function judgeReMsg(params){
        params = params || {};
        var opt = JSON.stringify(params)
        var oInx = -1;
        var oMsg ;
        for(var i in this.oMsgs){
            var oMsgItem = this.oMsgs[i];
            if(oMsgItem.config == opt) {
                oInx = i;
                oMsg = oMsgItem.inst;
                break;
            }
        }
        if(oInx < 0){
            this.instanceCount ++;
            var oItem = {};
            oItem.id = this.instanceCount;
            oItem.config = opt;
            oMsg = new Msg(params);
            oMsg.id = this.instanceCount;
            oMsg.count = '';
            oItem.inst = oMsg;
            this.oMsgs[this.instanceCount] = oItem;
            var len = this.oMsgs.length;
            var maxNums = this.maxNums;
            /**
             * 关闭多余的消息
            */
            if(len > maxNums){
                var oIndex = 0;
                var oMsgs = this.oMsgs;
                for(oIndex;oIndex<len-maxNums;oIndex++){
                    oMsgs[oIndex] && oMsgs[oIndex].inst.settings.autoClose && oMsgs[oIndex].inst.close();
                }
            }
        }else{
            oMsg.count = !oMsg.count ? 2 : oMsg.count>=99 ? oMsg.count : oMsg.count+1;
            setMsgCount(oMsg);
        }
        oMsg.$elem.setAttribute("data-count",oMsg.count);
        return oMsg;
    }
 
 
    var Qmsg = {
        version:'0.0.1',
        instanceCount:0,
        oMsgs:[],
        maxNums:DEFAULTS.maxNums || 5,
        config:function(cfg){
            DEFAULTS = cfg && cfg instanceof Object ? Object.assign(DEFAULTS,cfg):DEFAULTS;
            this.maxNums = DEFAULTS.maxNums && DEFAULTS.maxNums > 0 ? parseInt(DEFAULTS.maxNums) : 3;
        },
        info:function(txt,config){
            var params = mergeArgs(txt,config);
            params.type = 'info';
           return judgeReMsg.call(this,params);
        },
        warning:function(txt,config){
            var params = mergeArgs(txt,config);
            params.type = 'warning';
           return judgeReMsg.call(this,params);
        },
        success:function(txt,config){
            var params = mergeArgs(txt,config);
            params.type = 'success';
           return judgeReMsg.call(this,params);
        },
        error:function(txt,config){
            var params = mergeArgs(txt,config);
            params.type = 'error';
           return judgeReMsg.call(this,params);
        },
        loading:function(txt,config){
            var params = mergeArgs(txt,config);
            params.type = 'loading';
            params.autoClose = false;
           return judgeReMsg.call(this,params);
        },
        remove:function(id){
            this.oMsgs[id] && delete this.oMsgs[id];
        },
        closeAll:function(){
            for(var i in this.oMsgs){
                this.oMsgs[i] && this.oMsgs[i].inst.close();
            }
        }
    }
 
    return Qmsg;
})


})();