// ==UserScript==
// @name 数银_全链路分析
// @namespace http://tampermonkey.net/
// @version 0.2
// @description 数银扩展工具
// @author siji-Xian
// @match *://databank.tmall.com*
// @icon https://www.google.com/s2/favicons?domain=oceanengine.com
// @grant none
// @license MIT
// @require https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/3.2.1/jquery.min.js
// @require https://cdn.bootcss.com/moment.js/2.20.1/moment.min.js
// @require https://greasyfork.org/scripts/404478-jsonexportexcel-min/code/JsonExportExcelmin.js?version=811266
// @require https://greasyfork.org/scripts/455576-qmsg/code/Qmsg.js?version=1122361
// ==/UserScript==
(function () {
"use strict";
if (
location.href.startsWith(
"https://databank.tmall.com/#/fullLinkDistribution"
)
) {
var new_element = document.createElement("link");
new_element.setAttribute("rel", "stylesheet");
new_element.setAttribute(
"href",
"https://qmsg.refrain.xyz/message.min.css"
);
const button = document.createElement("div");
button.textContent = "导出数据";
Object.assign(button.style, {
height: "34px",
lineHeight: "var(--line-height, 34px)",
alignItems: "center",
color: "white",
background:
"linear-gradient(90deg, rgba(0, 239, 253), rgba(64, 166, 254))",
borderRadius: "5px",
marginLeft: "10px",
fontSize: "13px",
padding: "0 10px",
cursor: "pointer",
fontWeight: "500",
});
button.addEventListener("click", urlClick);
const button2 = document.createElement("div");
button2.textContent = "创建WS连接";
Object.assign(button2.style, {
height: "34px",
lineHeight: "var(--line-height, 34px)",
alignItems: "center",
color: "white",
background:
"linear-gradient(90deg, rgba(0, 239, 253), rgba(64, 166, 254))",
borderRadius: "5px",
marginLeft: "10px",
fontSize: "13px",
padding: "0 10px",
cursor: "pointer",
fontWeight: "500",
});
button2.addEventListener("click", wsClick);
const getRequestOptions = {
method: "GET",
redirect: "follow",
};
async function fetchFun(url, data, requestOptions = getRequestOptions) {
const params = new URLSearchParams(data).toString();
try {
const response = await fetch(`${url}?${params}`, requestOptions);
if (response.ok) {
const result = await response.json();
return result;
} else {
throw new Error(`Fetch failed: ${response.status}`);
}
} catch (error) {
loadingMsg.close();
Qmsg.error({
content: `网络请求错误: ${error.message}`,
timeout: 5000,
});
throw error;
}
}
function appendDoc() {
const likeComment = document.querySelector(".databank-ceiling-bar");
if (likeComment) {
document.body.appendChild(new_element);
likeComment.append(button2);
likeComment.append(button);
return;
}
setTimeout(appendDoc, 1000);
}
appendDoc();
function getCrowdIdFromHash() {
let url = new URL(window.location.href);
let hash = url.hash;
hash = hash.slice(23);
let searchParams = new URLSearchParams(hash);
let crowdId = searchParams.get("crowdId");
return crowdId;
}
// 消息队列
let tableList = [];
let zongList = []
//处理日期
async function getDateRange(startDate, endDate) {
const dateArray = [];
const currentDate = moment(startDate);
const lastDate = moment(endDate);
while (currentDate <= lastDate) {
dateArray.push(currentDate.format("YYYYMMDD"));
currentDate.add(1, "days");
}
return dateArray;
}
let dates = [];
async function getData(thedate) {
const zong = await fetchFun(
"https://databank.tmall.com/api/ecapi",
{
thedate,
path: '/datatable/fulllink/'
}
);
return zong?.data[1].uv
}
async function wsClick() {
try {
let res = prompt(
"日期,例: 20230511,20230521 (起始页和结束页中间用英文逗号分隔)"
);
if (res) {
let [startPage, endPage] = res.split(",");
let startPageInt = parseInt(startPage);
let endPageInt = parseInt(endPage);
if (isNaN(startPageInt) || isNaN(endPageInt) || endPage < startPage) {
throw new Error("日期格式错误!");
}
dates = await getDateRange(startPage, endPage);
}
} catch (err) {
Qmsg.error(err.message);
}
// 调用函数获取 crowdId 的值
tableList = [];
// 获取总数值数据
zongList = await Promise.all(dates.map(async v=>{
return {key:v,value:await getData(v)}
}))
let data = {
method: "/queryDataService/queryDataOnWidget",
headers: { rid: "1694746656769012", type: "PULL" },
body: {
args: {
referer: "databank-fullLinkDistribution",
id: "892669",
isMock: 0,
whatIfParam: { widgetParamList: [], customParamList: [] },
widgetSelections: null,
selections: [
{
dimensionName: "cateId",
restrictList: [{ hide: 1, oper: "eq", value: "-99" }],
eq: [{ hide: 1, oper: "eq", value: "-99" }],
lt: null,
gt: null,
ge: null,
le: null,
ne: null,
showText: "-99",
},
{
dimensionName: "brandId",
restrictList: [{ hide: 1, oper: "eq", value: "3949661" }],
eq: [{ hide: 1, oper: "eq", value: "3949661" }],
lt: null,
gt: null,
ge: null,
le: null,
ne: null,
showText: "3949661",
},
{
dimensionName: "searchKeyword",
restrictList: [{ hide: 1, oper: "eq", value: "" }],
eq: [{ hide: 1, oper: "eq", value: "" }],
lt: null,
gt: null,
ge: null,
le: null,
ne: null,
showText: "",
},
{
dimensionName: "buyRecency",
restrictList: [
{ hide: 1, oper: "eq", value: "1", showName: "<=1天" },
],
eq: [{ hide: 1, oper: "eq", value: "1", showName: "<=1天" }],
lt: null,
gt: null,
ge: null,
le: null,
ne: null,
showText: "<=1天",
},
{
dimensionName: "statusId",
restrictList: [
{ hide: 1, oper: "eq", value: "1020", showName: "兴趣" },
],
eq: [{ hide: 1, oper: "eq", value: "1020", showName: "兴趣" }],
lt: null,
gt: null,
ge: null,
le: null,
ne: null,
showText: "兴趣",
},
{
dimensionName: "theDate",
restrictList: [{ hide: 1, oper: "eq", value: "20230914" }],
eq: [{ hide: 1, oper: "eq", value: "20230914" }],
lt: null,
gt: null,
ge: null,
le: null,
ne: null,
showText: "20230914",
},
{
dimensionName: "ds",
restrictList: [
{ hide: 1, oper: "le", value: "20230914" },
{ hide: 1, oper: "ge", value: "undefined" },
],
eq: null,
lt: null,
gt: null,
ge: [{ hide: 1, oper: "ge", value: "undefined" }],
le: [{ hide: 1, oper: "le", value: "20230914" }],
ne: null,
showText: "20230914, undefined",
},
{
dimensionName: "isAll",
restrictList: [{ hide: 1, oper: "eq", value: "1" }],
eq: [{ hide: 1, oper: "eq", value: "1" }],
lt: null,
gt: null,
ge: null,
le: null,
ne: null,
showText: "1",
},
{
dimensionName: "level1TouchId",
restrictList: [
{ hide: 1, oper: "eq", value: "8", showName: "付费广告" },
],
eq: [{ hide: 1, oper: "eq", value: "8", showName: "付费广告" }],
lt: null,
gt: null,
ge: null,
le: null,
ne: null,
showText: "付费广告",
},
{
dimensionName: "departmentType",
restrictList: [
{ hide: 1, oper: "eq", value: "EC", showName: "部门版本" },
],
eq: [
{ hide: 1, oper: "eq", value: "EC", showName: "部门版本" },
],
lt: null,
gt: null,
ge: null,
le: null,
ne: null,
showText: "部门版本",
},
{
dimensionName: "commodityAnalysis",
restrictList: [
{ hide: 1, oper: "eq", value: "true", showName: "商品权限" },
],
eq: [
{ hide: 1, oper: "eq", value: "true", showName: "商品权限" },
],
lt: null,
gt: null,
ge: null,
le: null,
ne: null,
showText: "商品权限",
},
{
dimensionName: "env",
restrictList: [
{ hide: 1, oper: "eq", value: "//databank.tmall.com" },
],
eq: [{ hide: 1, oper: "eq", value: "//databank.tmall.com" }],
lt: null,
gt: null,
ge: null,
le: null,
ne: null,
showText: "//databank.tmall.com",
},
{
dimensionName: "itemTag",
restrictList: [
{ hide: 1, showName: "全部", value: "-999", oper: "eq" },
],
eq: [{ hide: 1, showName: "全部", value: "-999", oper: "eq" }],
lt: null,
gt: null,
ge: null,
le: null,
ne: null,
showText: "全部",
},
],
rdPathInfoList: [],
appId: "6",
},
},
};
// 创建 WebSocket 连接
const socket = new WebSocket("wss://ws-insight-engine.tmall.com/");
// 监听连接成功事件
socket.onopen = function (event) {
console.log("WebSocket 连接已建立", new Date());
Qmsg.info("WebSocket 连接已建立");
// 在连接成功后发送消息
dates.forEach((v) => {
data.headers.rid = v;
data.body.args.selections[5].restrictList[0].value = v;
data.body.args.selections[5].eq[0].value = v;
data.body.args.selections[5].showText = v;
data.body.args.selections[6].restrictList[0].value = v;
data.body.args.selections[6].le[0].value = v;
socket.send(JSON.stringify(data));
});
};
// 监听接收消息事件
socket.onmessage = function (event) {
let eventData = JSON.parse(event.data);
if (eventData?.body?.axises.length==1 && eventData?.body?.datas.length==2 ) {
tableList.push(eventData);
}
};
// 监听连接关闭事件
socket.onclose = function (event) {
console.log("WebSocket 连接已关闭", new Date());
// 在此处进行连接关闭后的处理
Qmsg.info("WebSocket 连接已关闭");
};
// 监听发生错误事件
socket.onerror = function (error) {
console.error("WebSocket 发生错误:", error);
// 在此处处理错误
Qmsg.info("WebSocket 发生错误");
};
}
//message.js
let loadingMsg = null;
function expExcel(e) {
console.log(e)
let mapData = new Map(
e.map((item) => {
let value = item.body.axises[0].values.map((v, i) => {
return {
key: v.showName,
value: [
item.body.datas[0].values[i],
item.body.datas[1].values[i],
],
};
});
return [item.headers.rid, value];
})
);
let mapData2 = new Map(
zongList.map((v) => {
return [v.key,v.value]
})
)
console.log(mapData2)
let expData = dates.map((v) => {
return {
key: v,
value: mapData2.get(v),
value1: mapData.get(v)[0].value[0],
value2: mapData.get(v)[0].value[1],
};
});
let contrast = {
日期: "key",
num:'value',
搜索占比: "value1",
行业均值: "value2",
};
let option = {};
option.fileName = "数银_全链路分析"; //文件名
option.datas = [
{
sheetName: "",
sheetData: expData,
sheetHeader: Object.keys(contrast),
sheetFilter: Object.values(contrast),
columnWidths: [], // 列宽
},
];
var toExcel = new ExportJsonExcel(option);
toExcel.saveExcel();
loadingMsg.close();
}
function urlClick() {
if (tableList.length) {
loadingMsg = Qmsg.loading("正在导出,请勿重复点击!");
expExcel(tableList);
}else{
Qmsg.warning("请先创建ws链接!");
}
}
}
})();