// ==UserScript== // @name 卡世界数据导出器 // @namespace http://tampermonkey.net/ // @license Apache-2.0 // @version 0.5.1 // @author byhgz // @description 卡世界功能拓展 // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @noframes // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @grant GM_addStyle // @grant GM_registerMenuCommand // @match https://ksjhaoka.com/* // @require https://cdn.jsdelivr.net/npm/vue@2 // @require https://unpkg.com/element-ui/lib/index.js // ==/UserScript== "use strict"; !function(t){"use strict";const e=new class{#t={events:{},futures:{}};#e={events:{},callbackInterval:1500};on(t,e){const n=this.#t.events;if(n[t])return void n[t].push(e);n[t]=[],n[t].push(e);const a=this.#t.futures;if(a[t]){for(const n of a[t])e(...n);delete a[t]}}once(t,e){const n=(...a)=>{e(...a),this.#n(t,n)};this.on(t,n)}handler(t,e){const n=this.#e.events;if(n[t])throw new Error("该事件名已经存在,请更换事件名");n[t]=e}invoke(t,...e){return new Promise((n=>{const a=this.#e.events;if(a[t])return void n(a[t](...e));const l=setInterval((()=>{a[t]&&(clearInterval(l),n(a[t](...e)))}),this.#e.callbackInterval)}))}send(t,...e){const n=this.#t,a=n.events[t];if(a){for(const t of a)t(...e);return}const l=n.futures;l[t]||(l[t]=[]),l[t].push(e)}#n(t,e){const n=this.#t.events;n[t]&&(n[t]=n[t].filter((t=>t!==e)));const a=this.#e.events;a[t]&&(a[t]=a[t].filter((t=>t!==e)))}off(t){const e=this.#t.events;if(e[t])return delete e[t],!0;const n=this.#e.events;return!!n[t]&&(delete n[t],!0)}setInvokeInterval(t){this.#e.callbackInterval=t}getEvents(){return{regularEvents:this.#t,callbackEvents:this.#e}}},n={template:'\n
\n \n \n \n 取 消\n 确 定\n \n \n\n
',data:()=>({dialogVisible:!1,content:""}),methods:{handleClose(t){this.$confirm("确认关闭?").then((e=>{t()})).catch((t=>{}))}},created(){e.on("展示内容对话框",(t=>{this.content=t,this.$message("已更新内容"),this.dialogVisible=!0}))}};var a=async(t,e={})=>{try{e={...{doc:document,interval:1e3,timeout:-1},...e};const n=await function(t,e={}){const n={doc:document,interval:1e3,timeout:-1};return e={...n,...e},new Promise(((n,a)=>{const l=setInterval((()=>{const a=e.doc.querySelector(t);a&&(n(a),clearInterval(l))}),e.interval);e.timeout>0&&setTimeout((()=>{clearInterval(l),a(null)}),e.timeout)}))}(t,e);return-1===e.timeout?n:{state:!0,data:n}}catch(t){return{state:!1,data:t}}},l=async(t,e={})=>{e={...{doc:document,interval:1e3,timeout:-1},...e};try{const n=await function(t,e={}){const n={doc:document,interval:1e3,timeout:-1};return e={...n,...e},new Promise(((n,a)=>{const l=setInterval((()=>{const a=e.doc.querySelectorAll(t);a.length>0&&(n(Array.from(a)),clearInterval(l))}),e.interval);e.timeout>0&&setTimeout((()=>{clearInterval(l),a(null)}),e.timeout)}))}(t,e);return-1===e.timeout?n:{state:!0,data:n}}catch(t){return{state:!1,data:t}}};const o=new class{#a=new Map;addEvent(t,e,n,a=!1){const l=this.#a;l.has(t)||l.set(t,{events:[],attrs:[]});const{events:o,attrs:s}=l.get(t);!a&&s.includes(e)||(s.push(e),o.push({eventName:e,callback:n}),t.setAttribute("gz-event",JSON.stringify(s)),t.addEventListener(e,n))}hasEventName(t,e){const n=this.#a;if(n.has(t))return!0;const{attrs:a}=n.get(t);return a.includes(e)}},s=async()=>{const t=await l(".app-main .el-row>div"),e=[];for(const n of t){const t={};t["运营商"]=n.querySelector(".goods-header-title").textContent.match(/运营商:(.+)/)[1],t["上架时间"]=n.querySelector(".goods-header-time").textContent.match(/上架时间:(.+)/)[1];const a=n.querySelector(".overflow-ellipsis").textContent;t["卡名"]=a.substring(2,a.indexOf("卡")+1),t["原始标题"]=a;const l=a.substring(a.indexOf("卡")+1),o=l.indexOf("元");let s,i;-1!==o?(s=l.substring(0,o),i=l.substring(o+1,l.length)):(s="未描述",i="获取失败"),t["主要参数"]=i,t["月租"]=s;const r=n.querySelectorAll(".goods-tab>span"),c=r[0].textContent;let d;t["归属地"]=c.includes("归属地")?c.match(/(.+)归属地/)[1]:c,t["是否支持选号"]=i.includes("支持选号")?"是":"未知",t["是否永久套餐"]=i.includes("永久套餐")?"是":"未知",t["是否支持结转"]=i.includes("支持结转")?"是":"未知",t["是否长期套餐"]=i.includes("长期套餐")?"是":"未知",t["快递"]=r[1].textContent,t["合约"]=r[2].textContent,t["年龄要求"]=r[3].textContent,d=5===r.length?r[4].textContent:"未描述",t["激活方案"]=d,t["佣金"]=n.querySelector(".goods-brokerage div").textContent;for(const e of n.querySelectorAll(".goods-info-ul>.goods-info-li")){const n=e.querySelector(".goods-info-value").textContent.split(":");t[n[0]]=n[1]}t.img=n.querySelector(".goods-img").src;for(const e in t)t[e]=t[e].trim();t["下单地址"]="https://ym.ksjhaoka.com/show?s=mNgPsRk2118639&id="+t["产品ID"],e.push(t)}return e};var i=(t=window.location.href)=>t.endsWith("ksjhaoka.com/#/goods/sale"),r=async t=>{const e=await s(),n=[],a=t.length;for(let a of e)t.some((t=>t["产品ID"]===a["产品ID"]))||n.push(a);for(let e of n)t.push(e);return a{const t=await l(".el-row .goods-list"),e=[];for(const n of t){const t={};let a=n.querySelector(".goods-header-title").textContent.trim();a=a.split(":"),t[a[0]]=a[1];let l=n.querySelector(".goods-header-time").textContent.trim();l=l.split(":"),t[l[0]]=l[1],t.img=n.querySelector("img.goods-img").src;const o=[];t.title=n.querySelector("h3.overflow-ellipsis").textContent;for(let t of n.querySelectorAll(".goods-box>.goods-tab>span"))o.push(t.textContent);t.tag=o;try{t["佣金"]=n.querySelector(".goods-brokerage>div").textContent.trim()}catch(e){t["佣金"]="未描述"}const s=n.querySelectorAll(".goods-info-li>div.goods-info-value");for(let e of s){const n=e.textContent.split(":");t[n[0]]=n[1]}e.push(t)}return e},u=()=>{let t;a(".app-container .type-box").then((n=>{o.addEvent(n,"click",(n=>{const a=n.target,l=a.textContent.trim();"type-activate"===a.className&&t!==l&&(t=l,e.send("产品管理子标签切换",l))}))}))};var m=(t,e)=>{const n=document.createElement("a");n.setAttribute("href","data:text/plain;charset=utf-8,"+encodeURIComponent(t)),n.setAttribute("download",e),n.style.display="none",document.body.appendChild(n),n.click(),document.body.removeChild(n)},h=t=>{const e=new URL(t),n=e.pathname.split("/").filter((t=>""!==t)),a=new URLSearchParams(e.search.slice(1)),l={};for(const[t,e]of a.entries())l[t]=e;return{protocol:e.protocol,hostname:e.hostname,port:e.port,pathname:e.pathname,pathSegments:n,search:e.search,queryParams:l,hash:e.hash}},p=(t,e,n=!1)=>{const a=new Set,l=t.filter((t=>{const n=t[e];return!a.has(n)&&(a.add(n),!0)}));return n&&t.splice(0,t.length,...l),l};const v={props:{dataList:{type:Array,default:()=>[]},fileName:{type:String,default:"列表数据"}},template:'\n
\n \n \n 导出(JSON文件)\n 导出(控制台)\n \n
',data:()=>({}),methods:{outToJsonFIleBut(){const t=this.dataList.length;0!==t?(m(JSON.stringify(this.dataList,null,4),`${this.fileName}-${t}个.json`),this.$alert("已执行导出json文件类型,请留意浏览器下载操作")):this.$message("未有数据可供导出")},outToConsoleBut(){if(0===this.dataList.length)return void this.$message("未有数据可供导出");console.info(this.fileName+"数据=======start");const t=JSON.stringify(this.dataList);console.info(JSON.parse(t)),console.info(t),console.info(this.fileName+"数据=======end"),this.$alert("已输出到控制台,可通过f12导出")}}},f={template:'\n
\n \n 数据信息\n \n 数据\n \n \n \n 获取{{ butTxt }}列表数据(当前页)\n 查看数据\n 清空数据\n \n \n
',props:{dataList:{type:Array,default:()=>[]},fileName:{type:String,default:"列表数据"},butTxt:{type:String,default:"列表"}},components:{out_data_vue:v},data:()=>({}),methods:{lookDataBut(){e.send("lookData",this.dataList)}},created(){}},g={template:'\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
',components:{promotion_center_vue:{template:'\n
\n \n
',components:{data_mode_vue:f},data:()=>({dataList:[]}),methods:{async getPromotionCenterDataBut(){if(!i())return void this.$message("当前页面不是推广中心页面");if(await e.invoke("isAppendMode")){await r(this.dataList)?this.$message("已追加成功!"):this.$message("追加失败,数据未变化")}else this.dataList=await c();await e.invoke("isViewMode")&&e.send("lookData",this.dataList)},clearDataBut(){this.dataList=[],this.$message("已清空数据!")}}},data_mode_vue:f},data:()=>({isAppendMode:!0,isViewMode:!1,not_available_data_list:[],available_data_list:[],tabsActiveName:"推广中心"}),methods:{async getListDataBut(t){const n=this.$loading({lock:!0,text:`${t}数据获取中...`}),a=await d(),l=await e.invoke("isAppendMode");let o;n.close();let s="未上架"===t?this.not_available_data_list:this.available_data_list;l?(o=p([...s,...a],"产品ID"),this.$message("已追加成功!")):o=a,"未上架"===t?this.not_available_data_list=o:this.available_data_list=o},clearDataBut(t){"未上架"===t?this.not_available_data_list=[]:this.available_data_list=[],this.$message("已清空数据!")}},created(){e.handler("isAppendMode",(()=>this.isAppendMode)),e.handler("isViewMode",(()=>this.isViewMode)),e.on("lookData",(t=>{this.$message("获取成功!"),e.send("展示内容对话框",JSON.stringify(t,null,4))})),e.on("产品管理子标签切换",(t=>{this.tabsActiveName=t}))}};var b=(t,e,n=null)=>GM_registerMenuCommand(t,e,n),y=(t,e)=>{GM_setValue(t,e)},w=(t,e)=>GM_getValue(t,e);const _={template:'\n
\n \n 读取存储账号密码\n 存储账号密码\n 读取右侧编辑框号密\n \n \n \n \n \n \n \n \n \n
\n 填写右侧号密信息\n
\n
',data:()=>({inputName:"",inputPwd:""}),methods:{readRightInputKeyInfoBut(){const t=document.querySelector('input[name="username"].el-input__inner')?.value||null;if(null===t)return void this.$message("读取用户名或手机号失败");this.inputName=t;const e=document.querySelector('input[name="password"].el-input__inner')?.value||null;null!==e?(this.inputPwd=e,this.$alert("读取成功!")):this.$message("读取密码失败")},readMKKeyInfoToInputBut(){const t=w("info",null);null!==t?(this.inputName=t.name,this.inputPwd=t.pwd,this.$alert("读取成功!")):this.$message("读取失败")},saveMKKeyInfoBut(){""!==this.inputName.trim()&&""!==this.inputPwd.trim()?(y("info",{name:this.inputName,pwd:this.inputPwd}),this.$alert("保存成功!")):this.$message("请输入账号密码")},writeRightInputKeyInfoBut(){if(""===this.inputName.trim()||""===this.inputPwd.trim())return void this.$message("请输入账号密码");const t=document.querySelector('input[name="username"].el-input__inner'),e=document.querySelector('input[name="password"].el-input__inner');null!==t&&null!==e?(t.value=this.inputName,e.value=this.inputPwd,this.$alert("写入成功!")):this.$message("读取输入框失败")}},created(){const t=w("info",null);null!==t&&(this.inputName=t.name,this.inputPwd=t.pwd)}},k=t=>{const e=t.querySelectorAll(".disply-flex>span"),n={};for(let t of e){const e=t.textContent.trim().split(":");n[e[0]]=e[1].trim()}return n},x=t=>{const e={};for(let n=0;n\n \n 数据信息\n \n 数据\n \n \n \n \n 获取列表数据(当前页)\n \n ',components:{out_data_vue:v},data:()=>({dataList:[]}),methods:{getListDataBut(){(async()=>{const t=(await a(".el-table__body-wrapper.is-scrolling-left>table")).querySelectorAll("tbody>tr"),e=[];let n={};for(let a of t){if("el-table__row expanded"===a.className){const t=k(a);for(let e in t)n[e]=t[e];continue}const t=Array.from(a.querySelectorAll(".expand-column"));for(let e=0;ediv");if(4!==e)if(0!==e){if(3===e){const t=a.querySelector(".el-button"),e=t.getAttribute("aria-describedby"),l=t.querySelector("span");l&&(n["短信时间"]=l.textContent.trim());const o=document.querySelector(`#${e}`);o&&(n["短信"]=o.textContent.trim())}if(1!==e&&2!==e&&3!==e)4!==e?5===e&&(n["商家备注"]=a.textContent.trim()):n["失败原因"]=a.textContent.trim();else for(let t of l){const e=t.textContent.trim();let a=e.includes(":")?e.split(":"):e.split(":");n[a[0]]=a[1].trim()}}else{const t=x(l);for(let e in t)n[e]=t[e]}}e.push(n),n={}}return e})().then((t=>{this.dataList=t,this.$alert("获取当前页订单成功")}))}}},C=document.createElement("div");if(C.style.position="fixed",C.style.left="0",C.style.top="0",C.style.width="100%",C.style.height="100%",document.body.appendChild(C),null===document.head.querySelector("#element-ui-css")){const t=document.createElement("link");t.rel="stylesheet",t.href="https://unpkg.com/element-ui/lib/theme-chalk/index.css",t.id="element-ui-css",document.head.appendChild(t),console.log("挂载element-ui样式成功")}new t({el:C,template:'\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
',components:{look_content_dialog_vue:n,product_management_vue:g,login_vue:_,order_management_vue:S},data:()=>({drawer:!0,login_show:!1,tabsActiveName:"产品管理"}),methods:{},created(){e.on("主面板开关",(()=>{this.drawer=!this.drawer})),e.on("登录选项卡显隐",(t=>{this.login_show=t})),e.on("切换标签页",(t=>{this.tabsActiveName=t})),e.on("el-msg",(t=>{this.$message(t)}))}});const I=document.createElement("style");I.innerHTML="body {\n overflow: hidden;\n}\n\n\n.el-vertical-center {\n display: flex;\n justify-content: center;\n}\n\n\n.el-horizontal-center {\n display: flex;\n align-items: center;\n}\n\n\n.el-horizontal-right {\n display: flex;\n justify-content: flex-end;\n}\n\n\n.el-horizontal-left {\n display: flex;\n justify-content: flex-start;\n}\n",document.head.appendChild(I);var E=(t=window.location.href,n=document.title)=>{const a=h(t);if(console.log("静态路由:",t,a),t.includes("ksjhaoka.com/#/login"))return e.send("登录选项卡显隐",!0),void e.send("切换标签页","登录");i(t)&&u()},N=()=>{let t=window.location.href;setInterval((()=>{const e=window.location.href;if(t===e)return;t=e;const a=document.title;n(e,a)}),1e3);const n=(t,n)=>{const a=h(t);console.log("动态路由:",a,t,n),t.includes("ksjhaoka.com/#/login")||e.send("登录选项卡显隐",!1),i()&&(e.send("切换标签页","产品管理"),u())}};window.addEventListener("load",(()=>{console.log("卡世界页面加载完成"),E(),N(),a(".floating").then((t=>{t.remove(),e.send("el-msg","已移除页面右下角悬浮广告")}))})),document.addEventListener("keydown",(function(t){"`"===t.key&&e.send("主面板开关")})),b("主面板开关展示",(()=>{e.send("主面板开关")})),b("获取当前产品页面列表",(async()=>{if(!i())return void alert("当前页面不是产品管理");const t=c();console.log("===========当前页面产品列表==========="),console.log(t),console.log("===========当前页面产品列表==========="),alert("已打印在控制台上")}))}(Vue);