您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Banishment this world!
当前为
// ==UserScript== // @name ACGN-stock營利統計外掛 // @namespace http://tampermonkey.net/ // @version 4.05.01 // @description Banishment this world! // @author SoftwareSing // @match http://acgn-stock.com/* // @match https://acgn-stock.com/* // @match https://test.acgn-stock.com/* // @match https://museum.acgn-stock.com/* // @grant none // ==/UserScript== //I love Hatsune Miku. //版本號為'主要版本號 + "." + 次要版本號 + 錯誤修正版本號,ex 8.31.39 //修復導致功能失效的錯誤或更新重大功能提升主要或次要版本號 //優化UI,優化效能,優化小錯誤更新錯誤版本號 //本腳本修改自 "ACGN股票系統每股營利外掛 2.200 by papago89" //這邊記一下每個storage的格式 //local_scriptAD_UpdateTime local //date //local_scriptAD local //{"adLinkType": ["_self", "_blank"], // "adLink": ["/company/detail/NJbJuXaJxjJpzAJui", "https://www.google.com.tw/"], // "adData": [" message ", "miku"], // "adFormat": ["a", "aLink"]} //local_CsDatas_UpdateTime local //date //local_CsDatas規格 local //{"companyID": String, "companyName": String, // "companyPrice": Number, "companyStock": Number, "companyProfit": Number, // "companySalary": Number, "companyNextSeasonSalary": Number, "companyBonus": Number, // "companyEmployeesNumber": Number, "companyNextSeasonEmployeesNumber": Number} //userStcokInfo的格式 session //{"userID": "CWgfhqxbrJMxsknrb", // "userCompany": [{"companyID": aaa, "userHold": number}, {}] // "userManage": [{"companyID": aaa}, {}] // "userEmployee": {"companyID": aaa} } /*************************************/ /**************DebugMode**************/ const debugMode = false; //debugMode == true 的時候,會console更多資訊供debug function debugConsole(msg) { if (debugMode) console.log(msg); } /**************DebugMode**************/ /*************************************/ /*************************************/ /***************import****************/ const {alertDialog} = require("./client/layout/alertDialog.js"); /***************import****************/ /*************************************/ /*************************************/ /************GlobalVariable***********/ //會跨2區以上使用的全域變數放在這裡 //如從stockSummary跨到accountInfo用的變數 var serverType = "normal"; var myID = null; //當前登入的使用者ID var myHoldStock = []; //當前登入的使用者持有的股票, 在股市總覽可以直接抓到全部 var myOrders = []; //當前登入的使用者未完成交易的買賣單, 在股市總覽可以直接抓到全部 var othersScript = []; /************GlobalVariable***********/ /*************************************/ /*************************************/ /*********ACGNListenerScript**********/ //本區監測事件搬運自"ACGN股票系統每股營利外掛 ver2.810" //https://github.com/frozenmouse/acgn-stock-user-script/blob/master/acgn-stock.user.js (function() { startEvent(); observeLoadingOverlay(); })(); // 觀察頁面是否進入或離開載入狀態(是否正在轉圈圈) function observeLoadingOverlay() { // 頁面處於載入狀態時會出現的蓋版元素(俗稱「轉圈圈」) const loadingOverlay = $("#loading .loadingOverlay")[0]; // 觀察 loadingOverlay 的 class attribute 是否變動 new MutationObserver(mutations => { mutations.filter(m => m.attributeName === "class").forEach(m => { if (m.target.classList.contains("d-none")) { // 轉圈圈隱藏 => 已脫離載入狀態 onPageLoaded(); } else { // 顯示轉圈圈 => 正處於載入狀態 onPageLoading(); } }); }).observe(loadingOverlay, { attributes: true }); } // 頁面在載入狀態時進行此回呼 function onPageLoading() { console.log(""); console.log(""); console.log(`Page loading: ${document.location.href}`); } // 頁面離開載入狀態時進行此回呼 function onPageLoaded() { const currentUrl = document.location.href; console.log(`Page loaded: ${currentUrl}`); console.log(""); console.log(""); // 頁面 url 樣式的回呼表 const urlPatternCallbackTable = [ { pattern: /company\/[0-9]+/, callback: onStockSummaryPageLoaded }, { pattern: /company\/detail/, callback: onCompanyDetailPageLoaded }, { pattern: /accountInfo/, callback: onAccountInfoPageLoaded }, { pattern: /foundation\/[0-9]+/, callback: onFoundationPlanPageLoaded }, { pattern: /arenaInfo/, callback: onArenaInfoPageLoaded }, ]; // 匹配當前頁面 url 的樣式並進行對應的回呼 urlPatternCallbackTable.forEach(({ pattern, callback }) => { if (currentUrl.match(pattern)) { // loadingOverlay 消失後,需要給點時間讓頁面的載入全部跑完 setTimeout(callback, 100); } }); } // 當「股市總覽」頁面已載入時進行的回呼 function onStockSummaryPageLoaded() { setTimeout(stockSummaryEvent, 39); } // 當「公司資訊」頁面已載入時進行的回呼 function onCompanyDetailPageLoaded() { setTimeout(companyEvent, 390); } // 當「帳號資訊」頁面已載入時進行的回呼 function onAccountInfoPageLoaded() { setTimeout(accountInfoEvent, 200); //checkUserInfo(); } // 當「新創計劃」頁面已載入時進行的回呼 function onFoundationPlanPageLoaded() { } //當「最萌亂鬥大賽」頁面已載入時進行的回呼 function onArenaInfoPageLoaded() { setTimeout(arenaInfoEvent, 39); } /*********ACGNListenerScript**********/ /*************************************/ /*************StartScript*************/ /*************************************/ //本區StartFunction startEvent() function startEvent() { checkSeriousError(); setTimeout(checkScriptEvent, 0); //前2項十分重要,需最優先執行 checkServer(); setTimeout(checkCsDatasUpdateTime, 1000); setTimeout(checkScriptVIPUpdateTime, 1500); setTimeout(checkVIPstate, 2000); setTimeout(checkScriptADUpdateTime, 2500); setTimeout(checkOthersScript, 2500); setTimeout(checkUserID, 3900); setTimeout(addShowVIPbutton, 3900); setTimeout(addPluginDropdownMenuEvent, 5000); setTimeout(checkOthersScript, 180000); } function checkServer() { const currentServer = document.location.href; const serverTypeTable = [ { type: /museum.acgn-stock.com/, callback: museumScript }, { type: /test.acgn-stock.com/, callback: testScript }, ]; // 匹配當前連接 server 的樣式並進行對應的回呼 serverTypeTable.forEach(({ type, callback }) => { if (currentServer.match(type)) { setTimeout(callback, 1); } }); } function museumScript() { console.log("start museumScript()"); serverType = "museum"; companies_jsonDB = museum_companies_jsonDB; companies_jsonDB_updatetime = museum_companies_jsonDB_updatetime; console.log("end museumScript()"); } function testScript() { console.log("start testScript()"); serverType = "test"; console.log("end testScript()"); } function checkUserID() { myID = String(Meteor.connection._userId); console.log("userID: " + myID); if (myID === "null") setTimeout(checkUserID, 15000); else setTimeout(checkUserID, 300000); } /*************StartScript*************/ /*************************************/ /*************************************/ /**********ResetLocalStorage**********/ //本區StartFunction checkSeriousError() function checkSeriousError() { //這個function將會清空所有由本插件控制的localStorage //用於如果上一版發生嚴重錯誤導致localStorage錯亂,以致插件無法正常啟動時 //或是用於當插件更新時,需要重設localStorage var seriousErrorVersion = 3.701; //seriousErrorVersion會輸入有問題的版本號,當發生問題時我會增加本數字,或是於更新需要時亦會增加 //使用者本地的數字紀錄如果小於這個數字將會清空所有localStorage var lastErrorVersion = 0 !== window.localStorage.getItem ("lastErrorVersion") ? Number(JSON.parse(window.localStorage.getItem ("lastErrorVersion"))) : 0; //lastErrorVersion = 0; //你如果覺得現在就有問題 可以把這行的註解取消掉來清空localStorage if (Number.isNaN(lastErrorVersion)) { lastErrorVersion = 0; console.log("reset lastErrorVersion as 0"); } else { console.log("localStorage of lastErrorVersion is work"); } if (lastErrorVersion < seriousErrorVersion) { console.log("last version has serious error, start remove all localStorage"); window.localStorage.removeItem("local_CsDatas_UpdateTime"); window.localStorage.removeItem("local_CsDatas"); window.localStorage.removeItem("local_scriptAD_UpdateTime"); window.localStorage.removeItem("local_scriptAD"); window.localStorage.removeItem("local_dataSearch"); window.localStorage.removeItem("local_scriptAD_use"); window.localStorage.removeItem("local_scriptVIP_UpdateTime"); window.localStorage.removeItem("local_scriptVIP"); window.localStorage.removeItem("lastErrorVersion"); lastErrorVersion = seriousErrorVersion; window.localStorage.setItem("lastErrorVersion", JSON.stringify(lastErrorVersion)); } } /**********ResetLocalStorage**********/ /*************************************/ /*************************************/ /************UpdateScript*************/ //本區StartFunction checkScriptEvent() function checkScriptEvent() { var myVersion = GM_info.script.version; var oReq = new XMLHttpRequest(); oReq.addEventListener("load", checkScriptVersion); oReq.open("GET", "https://gf.qytechs.cn/scripts/33542.json"); oReq.send(); } function checkScriptVersion() { var obj = JSON.parse(this.responseText); var myVersion = GM_info.script.version; console.log(obj.version.substr(0, 4) + "," + myVersion.substr(0, 4) + "," + (obj.version.substr(0, 4) > myVersion.substr(0, 4))); if(obj.version.substr(0, 4) > myVersion.substr(0, 4)) $('<li class="nav-item"><a class="nav-link btn btn-primary" href="https://gf.qytechs.cn/zh-TW/scripts/33542" id="UpdateDividendScript" target="Blank">' + Dict[lan].updateDividendScript + '</a></li>').insertAfter($('.nav-item')[$('.nav-item').length - 1]); else setTimeout(checkScriptEvent, 600000); } /************UpdateScript*************/ /*************************************/ /*************************************/ /**********CheckOthersScript**********/ //本區StartFunction checkOthersScript() //檢查是否有安裝其他腳本 function checkOthersScript() { console.log("start checkOthersScript()"); const papago89 = check_papago89_Script(); if (papago89) addToScriptList("papago89"); console.log("complete checkOthersScript()"); } function addToScriptList(scriptName) { const scriptIndex = othersScript.findIndex(n => n == scriptName); if (scriptIndex === -1) othersScript.push(scriptName); } //檢查是否有安裝papago89的腳本 function check_papago89_Script() { const papago89_Script = $('#about-script').length; if (papago89_Script > 0) { console.log("-----found papago89 script"); return true; } else return false; } /**********CheckOthersScript**********/ /*************************************/ /*************************************/ /***********GetDataBaseData***********/ //所有外連DB的function都寫在這裡 //所有可以用網頁呈現的DB都用這個去call function getWebData(url) { let webObjCache = null; const webUrl = String(url); const request = new XMLHttpRequest(); request.open("GET", webUrl); // 非同步 GET request.addEventListener("load", () => { debugConsole("got webData"); try { webObjCache = JSON.parse(request.responseText); } catch(err) { webObjCache = request.responseText; } }); request.send(); return (callback) => { // 若快取資料存在,則直接回傳快取 if (webObjCache !== null) { callback(webObjCache); return; } // 若無快取資料,則加入事件監聽,等載入後再回傳資料 request.addEventListener("load", function() { callback(webObjCache); }); }; } //連上web來取得資料 /** * 以非同步方式取得另外整理過的公司資料 json * * 考慮資料更新週期極長,若是已經取得過資料,就將之前取得的資料快取回傳 * * 使用方法: * const getData = getWebData("https://www.google.com"); //這邊請把google換成你要連的網址 * getData(a => { * // 這裡的 a 即為該 json 物件 * console.log(a); * }); * * //有呼叫const的function請務必用setTimeout執行,以防錯誤,即使0秒也行 * setTimeout(fun_a, 0); * function fun_a() { * getData(a => { * console.log(a); * } * } */ const normal_AD_jsonDB = "https://acgnstock-data.firebaseio.com/ACGNstock-scriptAD/AD.json"; const normal_AD_jsonDB_updatetime = "https://acgnstock-data.firebaseio.com/ACGNstock-scriptAD/updateTime.json"; const normal_companies_jsonDB = "https://acgnstock-data.firebaseio.com/ACGNstock-company/companys.json"; const normal_companies_jsonDB_updatetime = "https://acgnstock-data.firebaseio.com/ACGNstock-company/updateTime.json"; const museum_companies_jsonDB = "https://acgnstock-data.firebaseio.com/ACGNstock-museum/script/company/companys.json"; const museum_companies_jsonDB_updatetime = "https://acgnstock-data.firebaseio.com/ACGNstock-museum/script/company/updateTime.json"; const normal_scriptVIP_jsonDB = "https://acgnstock-data.firebaseio.com/ACGNstock-normal/scriptVIP/VIPproducts.json"; const normal_scriptVIP_jsonDB_updatetime = "https://acgnstock-data.firebaseio.com/ACGNstock-normal/scriptVIP/updateTime.json"; var companies_jsonDB = normal_companies_jsonDB; var companies_jsonDB_updatetime = normal_companies_jsonDB_updatetime; var AD_jsonDB = normal_AD_jsonDB; var AD_jsonDB_updatetime = normal_AD_jsonDB_updatetime; var scriptVIP_jsonDB = normal_scriptVIP_jsonDB; var scriptVIP_jsonDB_updatetime = normal_scriptVIP_jsonDB_updatetime; /***********GetDataBaseData***********/ /*************************************/ /*************************************/ /************updateCsDatas************/ //本區StartFunction checkCsDatasUpdateTime() function checkCsDatasUpdateTime() { console.log("start checkCsDatasUpdateTime()"); var CsDatas_UpdateTime = JSON.parse(window.localStorage.getItem ("local_CsDatas_UpdateTime")) || "null"; const get_companies_jsonDB_updatetime = getWebData(companies_jsonDB_updatetime); get_companies_jsonDB_updatetime(json_updateTime => { console.log("json_updateTime === CsDatas_UpdateTime : " + (json_updateTime === CsDatas_UpdateTime)); if (json_updateTime === CsDatas_UpdateTime) { console.log("dont need update " + CsDatas_UpdateTime); } else { console.log("server update time: " + json_updateTime); console.log("local update time: " + CsDatas_UpdateTime); console.log("start update data"); setTimeout(updateCsDatas, 1, json_updateTime); } }); console.log("complete checkCsDatasUpdateTime()"); } function updateCsDatas(updateTime) { console.log("start updateCsDatas()"); var CsDatas = []; const get_companies_jsonDB = getWebData(companies_jsonDB); get_companies_jsonDB(jsonData => { for (let n = 0 ; n < jsonData.length ; n++) { //local_CsDatas規格 local //{"companyID": String, "companyName": String, // "companyPrice": Number, "companyStock": Number, "companyProfit": Number, // "companySalary": Number, "companyNextSeasonSalary": Number, "companyBonus": Number, // "companyEmployeesNumber": Number, "companyNextSeasonEmployeesNumber": Number} const thisCompany = jsonData[n]; CsDatas.push({ "companyID": String(thisCompany.companyID), "companyName": String(thisCompany.companyName), "companyPrice": Number(thisCompany.companyPrice), "companyStock": Number(thisCompany.companyStock), "companyProfit": Number(thisCompany.companyProfit), "companySalary": Number(thisCompany.companySalary), "companyNextSeasonSalary": Number(thisCompany.companyNextSeasonSalary), "companyBonus": Number(thisCompany.companyBonus), "companyEmployeesNumber": Number(thisCompany.companyEmployeesNumber), "companyNextSeasonEmployeesNumber": Number(thisCompany.companyNextSeasonEmployeesNumber) }); //debugConsole("push success") } window.localStorage.setItem ("local_CsDatas", JSON.stringify(CsDatas)); if (updateTime === null || updateTime === undefined) { window.localStorage.setItem ("local_CsDatas_UpdateTime", JSON.stringify("no data")); } else { window.localStorage.setItem ("local_CsDatas_UpdateTime", JSON.stringify(updateTime)); } console.log("complete updateCsDatas()"); }); } /************updateCsDatas************/ /*************************************/ /*************************************/ /**************scriptAD***************/ //本區StartFunction checkScriptADUpdateTime() function checkScriptADUpdateTime() { console.log("start checkScriptADUpdateTime()"); var scriptAD_UpdateTime = JSON.parse(window.localStorage.getItem ("local_scriptAD_UpdateTime")) || "null"; const get_AD_jsonDB_updatetime = getWebData(AD_jsonDB_updatetime); get_AD_jsonDB_updatetime(json_updateTime => { console.log("json_updateTime === scriptAD_UpdateTime : " + (json_updateTime === scriptAD_UpdateTime)); if (json_updateTime === scriptAD_UpdateTime) { console.log("dont need update " + scriptAD_UpdateTime); setTimeout(addAD, 1); } else { console.log("server update time: " + json_updateTime); console.log("local update time: " + scriptAD_UpdateTime); console.log("start update AD data"); setTimeout(updateScriptAD, 1, json_updateTime); } }); console.log("complete checkScriptADUpdateTime()"); } function updateScriptAD(updateTime) { console.log("start updateScriptAD()"); const get_AD_jsonDB = getWebData(AD_jsonDB); get_AD_jsonDB(jsonData => { window.localStorage.setItem ("local_scriptAD", JSON.stringify(jsonData)); if (updateTime === null || updateTime === undefined) { window.localStorage.setItem ("local_scriptAD_UpdateTime", JSON.stringify("no data")); } else { window.localStorage.setItem ("local_scriptAD_UpdateTime", JSON.stringify(updateTime)); } setTimeout(addAD, 1); console.log("complete updateScriptAD()"); }); } function addAD() { console.log("start add script AD"); const scriptAD_use = window.localStorage.getItem("local_scriptAD_use") || "true"; if (scriptAD_use !== "false") { const scriptADData = JSON.parse(window.localStorage.getItem ("local_scriptAD")) || "null"; var data, adNumber, link, linkNumber = 0, linkType; $('<a class="scriptAD float-left" id="scriptAD-0"> </a>').insertAfter($('.text-danger.float-left')); if (scriptADData !== "null") { console.log("ADnumber:" + scriptADData.adFormat.length); for (let adF = 0 ; adF < scriptADData.adFormat.length ; ++adF) { console.log("adding AD"); adNumber = Number($('.scriptAD').length); data = scriptADData.adData[adF]; if (scriptADData.adFormat[adF] == "a") { $('<a class="scriptAD float-left" id="scriptAD-' + adNumber + '">' + data + '</a>') .insertAfter($('#scriptAD-' + (adNumber - 1))); } else if (scriptADData.adFormat[adF] == "aLink") { link = scriptADData.adLink[linkNumber]; linkType = scriptADData.adLinkType[linkNumber]; //console.log(linkType); //console.log((linkType != "_blank")); if ((linkType != "_blank") && (linkType != "_parent") && (linkType != "_top")) linkType = ""; //linkType = ""; $('<a class="scriptAD float-left" id="scriptAD-' + adNumber + '" href="' + link + '" target="' + linkType + '">' + data + '</a>').insertAfter($('#scriptAD-' + (adNumber - 1))); linkNumber += 1; } } } else { console.log("!!!error: can not get local_scriptAD"); } } console.log("success add script AD"); } /**************scriptAD***************/ /*************************************/ /*************************************/ /**********pluginDropdownMenu*********/ //本區StartFunction addPluginDropdownMenuEvent() function addPluginDropdownMenuEvent() { setTimeout(addMostStockDropdownMenu, 100); } function addMostStockDropdownMenu() { console.log("start addMostStockDropdownMenu()"); // 所有按鍵插入在原來的第三個按鍵(主題配置)之後 // 按鍵需要以倒序插入,後加的按鍵會排在左邊 const insertionTarget = $(".note")[2]; const mostStockDropDown = $(` <div class="note"> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" href="#" data-toggle="dropdown">${t("mostStockDropDown")}</a> <div class="dropdown-menu px-3" aria-labelledby="navbarDropdownMenuLink" style="display: none;" id="stock-menu"> <h6 class="dropdown-header" style="padding: 0.5rem 0rem" id="company-list">${t("mostStockDropDown")}</h6> </div> </li> </div> `); mostStockDropDown.insertAfter(insertionTarget); setTimeout(addMostStockDropdownMenuDetail, 10); console.log("end addMostStockDropdownMenu()"); } function addMostStockDropdownMenuDetail() { if (myHoldStock.length > 0) { console.log("start addMostStockDropdownMenuDetail()"); const top = $('#company-list'); const CsDatas = JSON.parse(window.localStorage.getItem ("local_CsDatas")) || []; //local_CsDatas規格 local //{"companyID": String, "companyName": String, // "companyPrice": Number, "companyStock": Number, "companyProfit": Number, // "companySalary": Number, "companyNextSeasonSalary": Number, "companyBonus": Number, // "companyEmployeesNumber": Number, "companyNextSeasonEmployeesNumber": Number} var myStockRanked = myHoldStock; myStockRanked = myStockRanked.sort(function(a, b) { debugConsole("-----addMostStockDropdownMenuDetail()-myStockRanked.sort"); //排序 const aIndex = CsDatas.findIndex(x => x.companyID == a.companyId); const bIndex = CsDatas.findIndex(y => y.companyID == b.companyId); debugConsole("------myStockRanked.sort a: " + a.companyId); debugConsole("------myStockRanked.sort b: " + b.companyId); if ((aIndex !== -1) && (bIndex !== -1)) { //當2間公司都有資料,可以計算之間的排序 const aPercent = Number(a.stocks) / Number(CsDatas[aIndex].companyStock); const bPercent = Number(b.stocks) / Number(CsDatas[bIndex].companyStock); return (bPercent - aPercent); } else if (aIndex !== -1) { //只有a有資料,a排前面 return -1; } else if (bIndex !== -1) { //只有b有資料,b排前面 return 1; } else { //都沒資料,不動排序 return 0; } }); debugConsole("-----end addMostStockDropdownMenuDetail()-myStockRanked.sort"); let i = 0, j = 0; let list = ""; while ((i < 10000) && (myStockRanked.length > i) && (j < 30)) { debugConsole("-----addMostStockDropdownMenuDetail()-addButton"); const aIndex = CsDatas.findIndex(x => x.companyID == myStockRanked[i].companyId); if (aIndex !== -1) { list += (`<a class="nav-link" href="/company/detail/${myStockRanked[i].companyId}" id="company-link"> ${CsDatas[aIndex].companyName}</a>`); j += 1; } i += 1; } $(list).insertAfter(top); console.log("end addMostStockDropdownMenuDetail()"); } else { console.log("myHoldStock not ready, restart addMostStockDropdownMenuDetail() after 10s"); setTimeout(addMostStockDropdownMenuDetail, 10000); } } /**********pluginDropdownMenu*********/ /*************************************/ /*************************************/ /************stockSummary*************/ //本區StartFunction stockSummaryEvent() function stockSummaryEvent() { //setTimeout(getBasicUserData, 500, 0); getBasicUserData(0); setTimeout(useCompaniesDatasEvent, 600); } function getBasicUserData(runNumber) { console.log("start getBasicUserData()"); var restart = false; if (runNumber < 10) { runNumber += 1; if (Meteor.connection._mongo_livedata_collections.directors.find().fetch().length > 0) myHoldStock = Meteor.connection._mongo_livedata_collections.directors.find().fetch(); else restart = true; if (Meteor.connection._mongo_livedata_collections.orders.find().fetch().length > 0) myOrders = Meteor.connection._mongo_livedata_collections.orders.find().fetch(); else restart = true; } /*if (restart) setTimeout(getBasicUserData, 1000, runNumber);*/ console.log("complete getBasicUserData()"); console.log(""); } function useCompaniesDatasEvent() { var companiesDatas = Meteor.connection._mongo_livedata_collections.companies.find().fetch(); if (companiesDatas.length > 0) { console.log("start useCompaniesDatasEvent()"); var profit, price, ID, release, earnPerShare, manager, hold, name; var bonus = 5, salary = 0; const CsDatas = JSON.parse(window.localStorage.getItem ("local_CsDatas")) || []; //local_CsDatas規格 local //{"companyID": String, "companyName": String, // "companyPrice": Number, "companyStock": Number, "companyProfit": Number, // "companySalary": Number, "companyNextSeasonSalary": Number, "companyBonus": Number, // "companyEmployeesNumber": Number, "companyNextSeasonEmployeesNumber": Number} //如果執行的function需要存值,放在這裡 var value_computeProfit = 0; var value_BatchAddCsDatasLocalStorage_1 = JSON.parse(window.localStorage.getItem ("local_CsDatas")) || []; var value_BatchAddCsDatasLocalStorage_2 = false; var value_BatchAddCsDatasLocalStorage = [value_BatchAddCsDatasLocalStorage_1, value_BatchAddCsDatasLocalStorage_2]; var value_isEnd = false; for (let i = 0; i < companiesDatas.length; ++i) { let thisCompany = companiesDatas[i]; profit = Number(thisCompany.profit); price = Number(thisCompany.listPrice); ID = String(thisCompany._id); release = Number(thisCompany.totalRelease); earnPerShare = Number((profit * 0.8) / release); manager = String(thisCompany.manager); name = String(thisCompany.companyName); const CDindex = CsDatas.findIndex(c => c.companyID == ID); if (CDindex !== -1) { bonus = Number(CsDatas[CDindex].companyBonus); salary = Number(CsDatas[CDindex].companySalary); if (CsDatas[CDindex].companyEmployeesNumber > 0) earnPerShare = Number((profit * (0.8 - (bonus * 0.01))) / release); } const MHSindex = myHoldStock.findIndex(a => a.companyId == ID); if (MHSindex === -1) hold = 0; else hold = Number(myHoldStock[MHSindex].stocks); console.log(String(ID + "---" + name + "---" + price + "---" + release + "---" + profit + "---" + earnPerShare + "---" + hold + "---" + manager)); //需要執行的function放在這 value_computeProfit = computeProfit(ID, earnPerShare, hold, value_computeProfit); value_isEnd = (i + 1 >= companiesDatas.length); value_BatchAddCsDatasLocalStorage = BatchAddCsDatasLocalStorage(ID, name, profit, price, release, value_BatchAddCsDatasLocalStorage, value_isEnd); const papago89_Script = othersScript.findIndex(n => n == "papago89"); if (papago89_Script === -1) SSAddSomeInfo(ID, earnPerShare, price, hold, manager, profit); console.log(""); } console.log("complete computeProfit()"); console.log(""); } else { console.log("companiesDatas not ready, restart useCompaniesDatasEvent() after 2s"); setTimeout(useCompaniesDatasEvent, 2000); } } //總獲利計算--加入分紅計算 function computeProfit(ID, earnPerShare, hold, sumProfit) { console.log("---start computeProfit()"); var classProfit; sumProfit += earnPerShare * hold; console.log("-----預計分紅: " + sumProfit); classProfit = $("#totalProfitNumber"); if (classProfit.length === 0) { $('<div class="media company-summary-item border-grid-body" id = "totalProfit"><div class="col-6 text-right border-grid" id = "totalProfitTitle"><h2>' + Dict[lan].totalProfitInThisPage + '</h2></div></div>').insertAfter($('.card-title')[0]); $('<div class="col-6 text-right border-grid" id = "totalProfitNumber"><h2>$ ' + sumProfit.toFixed() + '</h2></div>').insertAfter($('#totalProfitTitle')[0]); } else { $("#totalProfitNumber")[0].innerHTML = "<h2>$ " + sumProfit.toFixed() + "</h2>"; } console.log("---complete computeProfit()"); return sumProfit; } //批量將公司資料加入localStorage function BatchAddCsDatasLocalStorage(ID, name, profit, price, release, inputValue, isEnd) { console.log("---start BatchAddCsDatasLocalStorage()"); var CsDatas = inputValue[0]; var isChange = inputValue[1]; //local_CsDatas規格 local //{"companyID": String, "companyName": String, // "companyPrice": Number, "companyStock": Number, "companyProfit": Number, // "companySalary": Number, "companyNextSeasonSalary": Number, "companyBonus": Number, // "companyEmployeesNumber": Number, "companyNextSeasonEmployeesNumber": Number} let index = CsDatas.findIndex(x => x.companyID == ID); if (index != -1) { if ((CsDatas[index].companyPrice == price) && (CsDatas[index].companyStock == release) && (CsDatas[index].companyStock == profit)) { debugConsole("-----dont need update LocalStorage"); } else { isChange = true; const salary = CsDatas[index].companySalary; const nextSeasonSalary = CsDatas[index].companyNextSeasonSalary; const bonus = CsDatas[index].companyBonus; const employeesNumber = CsDatas[index].companyEmployeesNumber; const nextSeasonEmployeesNumber = CsDatas[index].companyNextSeasonEmployeesNumber; CsDatas.splice(index, 1); debugConsole("-----AddCsDatasLocalStorage---splice"); CsDatas.push({ "companyID": ID, "companyName": name, "companyPrice": Number(price), "companyStock": Number(release), "companyProfit": Number(profit), "companySalary": Number(salary), "companyNextSeasonSalary": Number(nextSeasonSalary), "companyBonus": Number(bonus), "companyEmployeesNumber": Number(employeesNumber), "companyNextSeasonEmployeesNumber": Number(nextSeasonEmployeesNumber) }); debugConsole("-----Add local_CsDatas LocalStorage!!"); } } else { isChange = true; CsDatas.push({ "companyID": ID, "companyName": name, "companyPrice": Number(price), "companyStock": Number(release), "companyProfit": Number(profit), "companySalary": Number(1000), "companyNextSeasonSalary": Number(1000), "companyBonus": Number(5), "companyEmployeesNumber": Number(0), "companyNextSeasonEmployeesNumber": Number(0) }); debugConsole("-----AddCsDatasLocalStorage!!"); } debugConsole("-----BatchAddCsDatasLocalStorage()---isChange: " + isChange + "---isEnd: " + isEnd + "---"); if (isChange && isEnd) { window.localStorage.setItem ("local_CsDatas", JSON.stringify(CsDatas)); debugConsole("-----setItem---local_CsDatas"); } outputValue = [CsDatas, isChange]; console.log("---complete BatchAddCsDatasLocalStorage()"); return outputValue; } function SSAddSomeInfo(ID, earnPerShare, price, hold, manager, profit) { if($(".col-12.col-md-6.col-lg-4.col-xl-3").length > 0) { //會加入 本益比 股價總值 現金股利 經理薪水 console.log("---start SSAddSomeInfo()"); var classInfo; var PE, stockWorth, stockProfit, managerSalary; PE = price / earnPerShare; PE = PE.toFixed(3); stockWorth = price * hold; stockProfit = (earnPerShare * hold).toFixed(); managerSalary = (profit * 0.05).toFixed(); let i = 0; for (i = 0 ; i < $('.title a').length ; i++) { if (ID == String($('.title a')[i].href.match(/\/company\/detail\/([^]+)/)[1])) break; } debugConsole("-----SSAddSomeInfo()---" + ID + "---" + i + "---" + PE + "---" + stockWorth + "---" + stockProfit + "---" + managerSalary + "---"); classInfo = $("#stockPEInfo_" + i); if (classInfo.length === 0) { if (myID == manager) $('<div name="stockPEInfo" class="row row-info d-flex justify-content-between" id="stockManagerSalaryInfo_' + i + '"><p>' + Dict[lan].stockManagerSalaryInfo + '</p><p>' + managerSalary + '</p></div>').insertAfter($('.company-card')[i].children[6]); $('<div name="stockPEInfo" class="row row-info d-flex justify-content-between" id="stockProfitInfo_' + i + '"><p>' + Dict[lan].stockProfitInfo + '</p><p>' + stockProfit + '</p></div>').insertAfter($('.company-card')[i].children[6]); $('<div name="stockPEInfo" class="row row-info d-flex justify-content-between" id="stockWorthInfo_' + i + '"><p>' + Dict[lan].stockWorthInfo + '</p><p>' + stockWorth + '</p></div>').insertAfter($('.company-card')[i].children[6]); $('<div name="stockPEInfo" class="row row-info d-flex justify-content-between" id="stockPEInfo_' + i + '"><p>' + Dict[lan].stockPEInfo + '</p><p>' + PE + '</p></div>').insertAfter($('.company-card')[i].children[6]); } console.log("---complete SSAddSomeInfo()"); } } /************stockSummary*************/ /*************************************/ /*************************************/ /**************company****************/ //本區StartFunction companyEvent() function companyEvent() { setTimeout(company_AddCsDatasLocalStorage, 1); setTimeout(checkUserOwnedProducts, 2); } function company_AddCsDatasLocalStorage() { const companiesDatas = Meteor.connection._mongo_livedata_collections.companies.find().fetch(); const employeesDatas = Meteor.connection._mongo_livedata_collections.employees.find().fetch(); if (companiesDatas.length > 0) { console.log("start company_AddCsDatasLocalStorage()"); var profit, price, ID, release, earnPerShare, manager, hold, name; var salary, nextSeasonSalary, bonus; var employeesNumber = 0, nextSeasonEmployeesNumber = 0; let thisCompany = companiesDatas[0]; profit = Number(thisCompany.profit); price = Number(thisCompany.listPrice); ID = String(thisCompany._id); release = Number(thisCompany.totalRelease); earnPerShare = (Number(thisCompany.profit) * 0.8 / Number(thisCompany.totalRelease)); manager = String(thisCompany.manager); name = String(thisCompany.companyName); salary = Number(thisCompany.salary); nextSeasonSalary = Number(thisCompany.nextSeasonSalary); bonus = Number(thisCompany.seasonalBonusPercent); for (let empData of employeesDatas) { if ((empData.employed) && (empData.companyId === ID)) employeesNumber += 1; else if ((empData.employed === false) && (empData.companyId === ID) && (empData.resigned === false)) nextSeasonEmployeesNumber += 1; } if (employeesNumber > 0) earnPerShare = Number((profit * (0.8 - (bonus * 0.01))) / release); console.log("---" + ID + "---" + name + "---"); //debugConsole(String("---" + ID + "---" + name + "---")); debugConsole(String("price: " + price + " release: " + release + " profit: " + profit)); debugConsole(String("salary: " + salary + " nextSeasonSalary: " + nextSeasonSalary + " bonus: " + bonus)); debugConsole(String("employeesNumber: " + employeesNumber + " nextSeasonEmployeesNumber: " + nextSeasonEmployeesNumber)); var CsDatas = JSON.parse(window.localStorage.getItem ("local_CsDatas")) || []; //local_CsDatas規格 local //{"companyID": String, "companyName": String, // "companyPrice": Number, "companyStock": Number, "companyProfit": Number, // "companySalary": Number, "companyNextSeasonSalary": Number, "companyBonus": Number, // "companyEmployeesNumber": Number, "companyNextSeasonEmployeesNumber": Number} inputData = { "companyID": ID, "companyName": name, "companyPrice": Number(price), "companyStock": Number(release), "companyProfit": Number(profit), "companySalary": Number(salary), "companyNextSeasonSalary": Number(nextSeasonSalary), "companyBonus": Number(bonus), "companyEmployeesNumber": Number(employeesNumber), "companyNextSeasonEmployeesNumber": Number(nextSeasonEmployeesNumber) }; //如果先前紀錄過該公司,則刪除重記 const index = CsDatas.findIndex(x => x.companyID == ID); if (index != -1) { if (CsDatas[index] === inputData) { debugConsole("dont need update cookie"); } else { CsDatas.splice(index, 1); debugConsole("AddCsDatasCookie---splice"); CsDatas.push(inputData); window.localStorage.setItem ("local_CsDatas", JSON.stringify(CsDatas)); debugConsole("Add CsDatas localStorage!!"); } } else { CsDatas.push(inputData); window.localStorage.setItem ("local_CsDatas", JSON.stringify(CsDatas)); debugConsole("AddCsDatasLocalStorage!!"); } console.log("complete company_AddCsDatasLocalStorage()"); console.log(""); } else { console.log("companiesDatas not ready, restart company_AddCsDatasLocalStorage() after 2s"); setTimeout(company_AddCsDatasLocalStorage, 2000); } } /**************company****************/ /*************************************/ /*************************************/ /*************accountInfo*************/ //本區StartFunction accountInfoEvent() function accountInfoEvent() { checkUserInfo(); setTimeout(checkUserOwnedProducts, 2); } function checkUserInfo() { console.log("start checkUserInfo()"); const userID = String(document.location.href.match(/accountInfo\/([0-z]+)/)[1]); console.log("-----checkUserInfo() userID = " + userID); var userStockInfo = JSON.parse(window.sessionStorage.getItem ("userStockInfo")) || []; //userStcokInfo的格式: //{"userID": "CWgfhqxbrJMxsknrb", // "userCompany": [{"companyID": aaa, "userHold": number}, {}] // "userManage": [{"companyID": aaa}, {}] // "userEmployee": {"companyID": aaa} } // userEmployee暫時用不到 var userIndex = userStockInfo.findIndex(a => a.userID == userID); debugConsole("-----checkUserInfo() userIndex = " + userIndex); if (userIndex == -1) { userStockInfo.push({"userID": userID, "userCompany": [], "userManage": [], "userEmployee": {"companyID": null} }); userIndex = userStockInfo.findIndex(a => a.userID == userID); debugConsole("-----checkUserInfo() userIndex = " + userIndex); window.sessionStorage.setItem ("userStockInfo", JSON.stringify(userStockInfo)); } if ($('.card-title').length > 0) { var managerSalary = Number(computeManagerSalary(userID)); var employeeBonus = Number(computeEmployeeBonus()); debugConsole("-----checkUserInfo() userID = " + userID + " , myID = " + myID + " , userID == myID : " + (userID == myID)); if ((userID == myID) && (myHoldStock.length > 0)) { checkMyHoldStock(); addUserProfitInfo(userID, managerSalary, employeeBonus); } checkUserHoldStock(userID, 0, managerSalary, employeeBonus); addUserProfitInfo(userID, managerSalary, employeeBonus); } else { console.log("$('.card-title') is not ready, restart checkUserInfo() after 2s"); setTimeout(checkUserInfo, 2000); } console.log("complete checkUserInfo()"); console.log(""); } function computeManagerSalary(userID) { console.log("---start computeManagerSalary()"); var profit, managerSalary = 0; const companyTitleView = $('.nav-link.active')[0].text; var userStockInfo = JSON.parse(window.sessionStorage.getItem ("userStockInfo")) || []; const userIndex = userStockInfo.findIndex(a => a.userID == userID); //userStcokInfo的格式: //{"userID": "CWgfhqxbrJMxsknrb", // "userCompany": [{"companyID": aaa, "userHold": number}, {}] // "userManage": [{"companyID": aaa}, {}] // "userEmployee": {"companyID": aaa} } const CsDatas = JSON.parse(window.localStorage.getItem ("local_CsDatas")) || []; //local_CsDatas規格 local //{"companyID": String, "companyName": String, // "companyPrice": Number, "companyStock": Number, "companyProfit": Number, // "companySalary": Number, "companyNextSeasonSalary": Number, "companyBonus": Number, // "companyEmployeesNumber": Number, "companyNextSeasonEmployeesNumber": Number} console.log("-----computeManagerSalary()-----companyTitleView === \"經理人\": " + (companyTitleView === "經理人")); if (companyTitleView === "經理人") //可以獲得經理資訊,更新userStockInfo { const companiesDatas = Meteor.connection._mongo_livedata_collections.companies.find().fetch(); debugConsole("-----computeManagerSalary()-----companiesDatas.length: " + companiesDatas.length); for (let i = 0 ; i < companiesDatas.length ; i++) { const ID = companiesDatas[i]._id; const companyIndex = userStockInfo[userIndex].userManage.findIndex(a => a.companyID == ID); debugConsole("-----computeManagerSalary()-----manage: " + ID + " index: " + companyIndex); if (companyIndex === -1) { userStockInfo[userIndex].userManage.push({"companyID": ID}); debugConsole("-----computeManagerSalary()-----add into userStockInfo"); } } window.sessionStorage.setItem ("userStockInfo", JSON.stringify(userStockInfo)); } //使用userStockInfo的資訊 計算managerSalary console.log("-----computeManagerSalary()-----userManage.length: " + userStockInfo[userIndex].userManage.length); for (let i = 0 ; i < userStockInfo[userIndex].userManage.length ; i++) { const ID = userStockInfo[userIndex].userManage[i].companyID; const companyIndex = CsDatas.findIndex(a => a.companyID == ID); if (companyIndex === -1) { debugConsole("-----computeManagerSalary()-----not found company " + ID); } else { profit = CsDatas[companyIndex].companyProfit; debugConsole("-----computeManagerSalary()-----" + ID + "-----" + profit + "-----"); managerSalary += Number(profit * 0.05); debugConsole("-----computeManagerSalary()-----" + managerSalary); } } //完成後自動開始新增資訊 //但如果沒有經理薪水就不會新增 console.log("-----computeManagerSalary()-----" + managerSalary); if (managerSalary > 0) addManagerSalaryInfo(managerSalary); console.log("---complete computeManagerSalary()"); return managerSalary; } function addManagerSalaryInfo(managerSalary) { console.log("---start addManagerSalaryInfo()"); managerSalary = Number(managerSalary); var classManagerSalaryInfo = $("#managerSalaryInfoNumber"); if(classManagerSalaryInfo.length === 0) { $('<div class="media account-info-item border-grid-body" id = "managerSalaryInfo"><div class="col-6 text-right border-grid" id = "managerSalaryInfoTitle"><h2>' + Dict[lan].managerTotalSalary + '</h2></div></div>').insertAfter($('.card-title')[0]); $('<div class="col-6 text-right border-grid" id = "managerSalaryInfoNumber"><h2>$ ' + managerSalary.toFixed() + '</h2></div>').insertAfter($('#managerSalaryInfoTitle')[0]); } else { $("#managerSalaryInfoNumber")[0].innerHTML = "<h2>$ " + managerSalary.toFixed() + "</h2>"; } console.log("---complete addManagerSalaryInfo()"); } function computeEmployeeBonus() { console.log("---start computeEmployeeBonus()"); const CsDatas = JSON.parse(window.localStorage.getItem ("local_CsDatas")) || []; //local_CsDatas規格 local //{"companyID": String, "companyName": String, // "companyPrice": Number, "companyStock": Number, "companyProfit": Number, // "companySalary": Number, "companyNextSeasonSalary": Number, "companyBonus": Number, // "companyEmployeesNumber": Number, "companyNextSeasonEmployeesNumber": Number} const employeesDatas = Meteor.connection._mongo_livedata_collections.employees.find().fetch(); var employeeBonus = 0; for (let emp of employeesDatas) { if (emp.employed) { const companyIndex = CsDatas.findIndex(c => c.companyID === emp.companyId); if (companyIndex !== -1) { debugConsole("-----computeEmployeeBonus()-----" + emp.companyId + "-----"); debugConsole("-----computeEmployeeBonus()-----" + CsDatas[companyIndex].companyProfit + "-----" + CsDatas[companyIndex].companyBonus + "-----" + CsDatas[companyIndex].companyEmployeesNumber + "-----"); let bonus = 0; if (Number(CsDatas[companyIndex].companyEmployeesNumber) > 0) bonus = Number(CsDatas[companyIndex].companyProfit * Number(CsDatas[companyIndex].companyBonus * 0.01) / Number(CsDatas[companyIndex].companyEmployeesNumber)); employeeBonus += bonus; debugConsole("-----computeEmployeeBonus()-----" + employeeBonus + "-----"); } } } console.log("-----computeEmployeeBonus()-----" + employeeBonus); if (employeeBonus > 0) addEmployeeBonusInfo(employeeBonus); console.log("---complete computeEmployeeBonus()"); return employeeBonus; } function addEmployeeBonusInfo(employeeBonus) { console.log("---start addEmployeeBonusInfo()"); employeeBonus = Number(employeeBonus); var classEmployeeBonusInfo = $("#employeeBonusInfoNumber"); if(classEmployeeBonusInfo.length === 0) { $('<div class="media account-info-item border-grid-body" id = "employeeBonusInfo"><div class="col-6 text-right border-grid" id = "employeeBonusInfoTitle"><h2>' + Dict[lan].employeeTotalBonus + '</h2></div></div>').insertAfter($('.card-title')[0]); $('<div class="col-6 text-right border-grid" id = "employeeBonusInfoNumber"><h2>$ ' + employeeBonus.toFixed() + '</h2></div>').insertAfter($('#employeeBonusInfoTitle')[0]); } else { $("#employeeBonusInfoNumber")[0].innerHTML = "<h2>$ " + employeeBonus.toFixed() + "</h2>"; } console.log("---complete addEmployeeBonusInfo()"); } function checkUserHoldStock(userID, CUHS_runNumber, managerSalary, employeeBonus) { const directors = Meteor.connection._mongo_livedata_collections.directors.find().fetch(); if (directors.length > 0) { console.log("---start checkUserHoldStock()"); /*if ($("[data-toggle-panel=stock]").parent().next().children().last().length > 0) addNotCompleteMessage();*/ console.log("-----userID: " + userID + " CUHS_runNumber: " + CUHS_runNumber + " managerSalary: " + managerSalary + " employeeBonus: " + employeeBonus); var userStockInfo = JSON.parse(window.sessionStorage.getItem ("userStockInfo")) || []; //userStcokInfo的格式: //{"userID": "CWgfhqxbrJMxsknrb", // "userCompany": [{"companyID": aaa, "userHold": number}, {}] // "userManage": [{"companyID": aaa}, {}] // "userEmployee": {"companyID": aaa} } const userIndex = userStockInfo.findIndex(a => a.userID == userID); var ID, hold; var isChange = false; for (let i = 0 ; i < directors.length ; i++) { ID = String(directors[i].companyId); hold = Number(directors[i].stocks); debugConsole("-----" + ID + "-----" + hold + "-----"); const companyIndex = userStockInfo[userIndex].userCompany.findIndex(b => b.companyID == ID); if (companyIndex != -1) { if (Number(userStockInfo[userIndex].userCompany[companyIndex].userHold) == hold) { //debugConsole("dont need update this company"); } else { isChange = true; userStockInfo[userIndex].userCompany.splice(companyIndex, 1); userStockInfo[userIndex].userCompany.push({"companyID": ID, "userHold": hold}); } } else { isChange = true; userStockInfo[userIndex].userCompany.push({"companyID": ID, "userHold": hold}); } } //怕是資料還沒更新完成就開始執行,如果完全沒有變化會再次執行,共確認3次 //目前將確認3次的部分暫時移除,僅做一次更新 if (isChange) { window.sessionStorage.setItem ("userStockInfo", JSON.stringify(userStockInfo)); //addCompleteMessage(); //setTimeout(addUserProfitInfo, 10, userID, managerSalary, employeeBonus); } else { /*if (CUHS_runNumber < 3) setTimeout(checkUserHoldStock, 100, userID, CUHS_runNumber+1, managerSalary); else { addCompleteMessage(); setTimeout(addUserProfitInfo, 10, userID, managerSalary); }*/ //addCompleteMessage(); //setTimeout(addUserProfitInfo, 10, userID, managerSalary, employeeBonus); } console.log("---complete checkUserHoldStock()"); } } function addCompleteMessage() { var pageNum = "1"; if (($(".page-item.active")[1] !== undefined) && ($(".page-item.active")[1] !== null)) pageNum = $(".page-item.active")[1].textContent; if ($("#CompleteMessage").length === 0) { $(`<button class="btn btn-danger btn-sm" type="button" disabled="disabled" id="CompleteMessage">第${pageNum}頁統計完成</button>`) .insertAfter($("[data-toggle-panel=stock]").parent().next().children().last()); } else { $("#CompleteMessage")[0].innerHTML = `第${pageNum}頁統計完成`; } } function addNotCompleteMessage() { //const pageNum = $(".page-item.active").text(); if ($("#CompleteMessage").length === 0) { $(`<button class="btn btn-danger btn-sm" type="button" disabled="disabled" id="CompleteMessage">還沒有統計完成</button>`) .insertAfter($("[data-toggle-panel=stock]").parent().next().children().last()); if ($("#clear-asset-message-btn").length > 0) //為了將訊息移動到正確的位置 { $("#clear-asset-message-btn").click(); if ($("#compute-btn").length > 0) $("#compute-btn").click(); } } else { $("#CompleteMessage")[0].innerHTML = `還沒有統計完成`; } } function checkMyHoldStock() { console.log("---start checkMyHoldStock()"); var userStockInfo = JSON.parse(window.sessionStorage.getItem ("userStockInfo")) || []; //userStcokInfo的格式: //{"userID": "CWgfhqxbrJMxsknrb", // "userCompany": [{"companyID": aaa, "userHold": number}, {}] // "userManage": [{"companyID": aaa}, {}] // "userEmployee": {"companyID": aaa} } const userID = myID; const userIndex = userStockInfo.findIndex(a => a.userID == userID); var ID, hold; const directors = myHoldStock; //避免重複不斷的更新 if (directors.length != userStockInfo[userIndex].userCompany.length) { for (let i = 0 ; i < directors.length ; i++) { ID = String(directors[i].companyId); hold = Number(directors[i].stocks); debugConsole("-----" + ID + "-----" + hold + "-----"); const companyIndex = userStockInfo[userIndex].userCompany.findIndex(b => b.companyID == ID); if (companyIndex != -1) { if (Number(userStockInfo[userIndex].userCompany[companyIndex].userHold) == hold) { //console.log("dont need update this company"); } else { userStockInfo[userIndex].userCompany.splice(companyIndex, 1); userStockInfo[userIndex].userCompany.push({"companyID": ID, "userHold": hold}); } } else { userStockInfo[userIndex].userCompany.push({"companyID": ID, "userHold": hold}); } } window.sessionStorage.setItem ("userStockInfo", JSON.stringify(userStockInfo)); } console.log("---complete checkMyHoldStock()"); } function addUserProfitInfo(userID, managerSalary, employeeBonus) { console.log("---start addUserProfitInfo()"); const userStockInfo = null !== window.sessionStorage.getItem ("userStockInfo") ? JSON.parse(window.sessionStorage.getItem ("userStockInfo")) : []; //userStcokInfo的格式: //{"userID": "CWgfhqxbrJMxsknrb", // "userCompany": [{"companyID": aaa, "userHold": number}, {}] // "userManage": [{"companyID": aaa}, {}] // "userEmployee": {"companyID": aaa} } const userIndex = userStockInfo.findIndex(a => a.userID == userID); //理論上到這邊userIndex就不可能是-1了啦..... const users = Meteor.connection._mongo_livedata_collections.users.find().fetch(); debugConsole("-----userID: " + userID); const users_i = users.findIndex(u => u._id == String(userID)); debugConsole("-----user_i: " + users_i); //for debug const CsDatas = JSON.parse(window.localStorage.getItem ("local_CsDatas")) || []; //local_CsDatas規格 local //{"companyID": String, "companyName": String, // "companyPrice": Number, "companyStock": Number, "companyProfit": Number, // "companySalary": Number, "companyNextSeasonSalary": Number, "companyBonus": Number, // "companyEmployeesNumber": Number, "companyNextSeasonEmployeesNumber": Number} const cash = Number(users[users_i].profile.money); var classUserProfitInfo, userAssets = 0, userProfit = 0, userCompanyNumber = 0; var price, earnPerShare; for (let k = 0 ; k < userStockInfo[userIndex].userCompany.length ; k++) { price = 0; earnPerShare = 0; const companyIndex = CsDatas.findIndex(b => b.companyID == userStockInfo[userIndex].userCompany[k].companyID); if (companyIndex != -1) { price = Number(CsDatas[companyIndex].companyPrice); if (CsDatas[companyIndex].employeesNumber > 0) earnPerShare = Number(CsDatas[companyIndex].companyProfit * (0.8 - (CsDatas[companyIndex].companyBonus * 0.01)) / CsDatas[companyIndex].companyStock); else earnPerShare = Number(CsDatas[companyIndex].companyProfit * 0.8 / CsDatas[companyIndex].companyStock); } userAssets += price * userStockInfo[userIndex].userCompany[k].userHold; userProfit += earnPerShare * userStockInfo[userIndex].userCompany[k].userHold; userCompanyNumber += 1; } var usingCash = 0; //正在用於買單的錢 var sellingStockWorth = 0; //正在賣的股票價值,以參考價計算 if (userID == myID) { const orders = myOrders; const orderType_buy = "購入"; const orderType_sell = "賣出"; for (let j = 0 ; j < orders.length ; j++) { const amount = Number(orders[j].amount); const done = Number(orders[j].done); if (orders[j].orderType === orderType_buy) { const unitPrice = Number(orders[j].unitPrice); usingCash += (unitPrice * (amount - done)); } else if (orders[j].orderType === orderType_sell) { const companyIndex = CsDatas.findIndex(b => b.companyID == String(orders[j].companyId)); if (companyIndex === -1) price = 0; else price = Number(CsDatas[companyIndex].companyPrice); sellingStockWorth += (price * (amount - done)); } else { console.log("-----未完成買賣單發生嚴重錯誤: 不是買單也不是賣單,你怎麼做到的......"); } } debugConsole("-----usingCash: " + usingCash); debugConsole("-----sellingStockWorth: " + sellingStockWorth); var classUserUsingCashInfo = $("#userUsingCashInfoNumber"); if(classUserUsingCashInfo.length === 0) { debugConsole("-----start add using cash info"); $('<div class="media account-info-item border-grid-body" id = "userSellingStockInfo"><div class="col-6 text-right border-grid" id = "userSellingStockInfoTitle"><h2>' + Dict[lan].userTotalSellingStock + '</h2></div></div>').insertAfter($('.card-title')[0]); $('<div class="col-6 text-right border-grid" id = "userSellingStockInfoNumber"><h2>$ ' + sellingStockWorth + '</h2></div>').insertAfter($('#userSellingStockInfoTitle')[0]); $('<div class="media account-info-item border-grid-body" id = "userUsingCashInfo"><div class="col-6 text-right border-grid" id = "userUsingCashInfoTitle"><h2>' + Dict[lan].userTotalUsingCash + '</h2></div></div>').insertAfter($('.card-title')[0]); $('<div class="col-6 text-right border-grid" id = "userUsingCashInfoNumber"><h2>$ ' + usingCash + '</h2></div>').insertAfter($('#userUsingCashInfoTitle')[0]); } else { debugConsole("-----start update using cash info"); $("#userSellingStockInfoNumber")[0].innerHTML = "<h2>$ " + sellingStockWorth + "</h2>"; $("#userUsingCashInfoNumber")[0].innerHTML = "<h2>$ " + usingCash + "</h2>"; } } debugConsole("-----call compute tax"); const tax = computeTax((userAssets + userProfit + managerSalary + employeeBonus + cash + usingCash + sellingStockWorth)); var classUserTaxInfo = $("#userTaxInfoNumber"); if(classUserTaxInfo.length === 0) { debugConsole("-----start add tax info"); $('<div class="media account-info-item border-grid-body" id = "userTaxInfo"><div class="col-6 text-right border-grid" id = "userTaxInfoTitle"><h2>' + Dict[lan].userTotalTax + '</h2></div></div>').insertAfter($('.card-title')[0]); $('<div class="col-6 text-right border-grid" id = "userTaxInfoNumber"><h2>$ ' + tax + '</h2></div>').insertAfter($('#userTaxInfoTitle')[0]); } else { debugConsole("-----start update tax info"); $("#userTaxInfoNumber")[0].innerHTML = "<h2>$ " + tax + "</h2>"; } classUserProfitInfo = $("#userProfitInfoNumber"); if(classUserProfitInfo.length === 0) { debugConsole("-----start add info"); $('<div class="media account-info-item border-grid-body" id = "userProfitInfo"><div class="col-6 text-right border-grid" id = "userProfitInfoTitle"><h2>' + Dict[lan].userTotalProfit + '</h2></div></div>').insertAfter($('.card-title')[0]); $('<div class="col-6 text-right border-grid" id = "userProfitInfoNumber"><h2>$ ' + userProfit.toFixed() + '</h2></div>').insertAfter($('#userProfitInfoTitle')[0]); $('<div class="media account-info-item border-grid-body" id = "userAssetsInfo"><div class="col-6 text-right border-grid" id = "userAssetsInfoTitle"><h2>' + Dict[lan].userTotalAssets + '</h2></div></div>').insertAfter($('.card-title')[0]); $('<div class="col-6 text-right border-grid" id = "userAssetsInfoNumber"><h2>$ ' + userAssets + '</h2></div>').insertAfter($('#userAssetsInfoTitle')[0]); $('<div class="media account-info-item border-grid-body" id = "userCompanyNumberInfo"><div class="col-6 text-right border-grid" id = "userCompanyNumberInfoTitle"><h2>' + Dict[lan].userTotalCompanyNumber + '</h2></div></div>').insertAfter($('.card-title')[0]); $('<div class="col-6 text-right border-grid" id = "userCompanyNumberInfoNumber"><h2> ' + userCompanyNumber + '</h2></div>').insertAfter($('#userCompanyNumberInfoTitle')[0]); } else { debugConsole("-----start update info"); $("#userProfitInfoNumber")[0].innerHTML = "<h2>$ " + userProfit.toFixed() + "</h2>"; $("#userAssetsInfoNumber")[0].innerHTML = "<h2>$ " + userAssets + "</h2>"; $("#userCompanyNumberInfoNumber")[0].innerHTML = "<h2> " + userCompanyNumber + "</h2>"; } console.log("---complete addUserProfitInfo()"); } // 稅率表:資產上限、稅率、累進差額 function computeTax(input) { debugConsole("---start computeTax()"); debugConsole("-----computeTax() input: " + input); const taxRateTable = [ { asset: 10000, rate: 0.00, adjustment: 0 }, { asset: 100000, rate: 0.03, adjustment: 300 }, { asset: 500000, rate: 0.06, adjustment: 3300 }, { asset: 1000000, rate: 0.09, adjustment: 18300 }, { asset: 2000000, rate: 0.12, adjustment: 48300 }, { asset: 3000000, rate: 0.15, adjustment: 108300 }, { asset: 4000000, rate: 0.18, adjustment: 198300 }, { asset: 5000000, rate: 0.21, adjustment: 318300 }, { asset: 6000000, rate: 0.24, adjustment: 468300 }, { asset: 7000000, rate: 0.27, adjustment: 648300 }, { asset: 8000000, rate: 0.30, adjustment: 858300 }, { asset: 9000000, rate: 0.33, adjustment: 1098300 }, { asset: 10000000, rate: 0.36, adjustment: 1368300 }, { asset: 11000000, rate: 0.39, adjustment: 1668300 }, { asset: 12000000, rate: 0.42, adjustment: 1998300 }, { asset: 13000000, rate: 0.45, adjustment: 2358300 }, { asset: 14000000, rate: 0.48, adjustment: 2748300 }, { asset: 15000000, rate: 0.51, adjustment: 3168300 }, { asset: 16000000, rate: 0.54, adjustment: 3618300 }, { asset: 17000000, rate: 0.57, adjustment: 4098300 }, { asset: Infinity, rate: 0.60, adjustment: 4608300 }, ]; const { rate, adjustment } = taxRateTable.find(e => input < e.asset); const output = Math.ceil(input * rate - adjustment); debugConsole("-----computeTax() output: " + output); debugConsole("-----complete computeTax()"); return output; } //個人持股表格 //這邊抄了新的方法來實作,做為第一次測試,之後再重構其他的 // 判斷直到 condition 符合之後再執行 action function waitUntil(condition, action) { setTimeout(function check() { if (condition()) { action(); } else { setTimeout(check, 0); } }, 0); } // 控制 持股表格 資料夾是否展開的 ReactiveVar const userHaveStockInfo_FolderExpandedVar = new ReactiveVar(false); // 加入持股表格資料夾 Template.accountInfo.onRendered(() => { console.log("accountInfo.onRendered()"); const instance = Template.instance(); const userHaveStockInfo_FolderHead = $(` <div class="col-12 border-grid"> <a class="d-block h4" href="" data-toggle-panel="userHaveStockInfo"> ${t("userHaveStockInfo")} <i class="fa fa-folder"/> </a> </div> `); const userHaveStockInfo_FolderIcon = userHaveStockInfo_FolderHead.find("i.fa"); const userHaveStockInfo_FolderBody = $(` <div class="col-12 text-right border-grid"> <table border="1" id="userHaveStockInfo_Table"> <tr> <th width="390px"> 公司名稱 </th> <th> 公司股價 </th> <th> 每股分紅 </th> <th> 持有股數 </th> <th> 持有比例 </th> <th> 股票總值 </th> <th> 預估分紅 </th> <th> 本益比 </th> </tr> </table> </div> `); waitUntil( () => instance.$(".card-block:last() .row").length > 0, () => instance.$(".card-block:last() .row.border-grid-body").append(userHaveStockInfo_FolderHead)); instance.autorun(() => { const userHaveStockInfo_FolderExpanded = userHaveStockInfo_FolderExpandedVar.get(); if (userHaveStockInfo_FolderExpanded) { setTimeout(() => { userHaveStockInfo_FolderIcon.addClass("fa-folder-open").removeClass("fa-folder"); userHaveStockInfo_FolderBody.insertAfter(userHaveStockInfo_FolderHead); setTimeout(add_userHaveStockInfo_Table, 10); }, 0); } else { setTimeout(() => { userHaveStockInfo_FolderIcon.addClass("fa-folder").removeClass("fa-folder-open"); userHaveStockInfo_FolderBody.detach(); }); } }); }); function add_userHaveStockInfo_Table() { console.log("---start add_userHaveStockInfo_Table()"); const userID = String(document.location.href.match(/accountInfo\/([0-z]+)/)[1]); debugConsole("-----userID: " + userID); const userStockInfo = null !== window.sessionStorage.getItem ("userStockInfo") ? JSON.parse(window.sessionStorage.getItem ("userStockInfo")) : []; //userStcokInfo的格式: //{"userID": "CWgfhqxbrJMxsknrb", // "userCompany": [{"companyID": aaa, "userHold": number}, {}] // "userManage": [{"companyID": aaa}, {}] // "userEmployee": {"companyID": aaa} } const userIndex = userStockInfo.findIndex(a => a.userID == userID); debugConsole("-----userIndex: " + userIndex); debugConsole("-----//如果是-1 下一步應該跳出本function"); //到這邊如果是-1那後面的就不用做了,會跳出function if (userID !== -1) { const CsDatas = JSON.parse(window.localStorage.getItem ("local_CsDatas")) || []; //local_CsDatas規格 local //{"companyID": String, "companyName": String, // "companyPrice": Number, "companyStock": Number, "companyProfit": Number, // "companySalary": Number, "companyNextSeasonSalary": Number, "companyBonus": Number, // "companyEmployeesNumber": Number, "companyNextSeasonEmployeesNumber": Number} $(`tr[companyID]`).remove(); for (let k = 0 ; k < userStockInfo[userIndex].userCompany.length ; k++) { const companyID = userStockInfo[userIndex].userCompany[k].companyID; let price = 0; let earnPerShare = 0; let name = "error:404 not found"; let release = 0; const hold = userStockInfo[userIndex].userCompany[k].userHold; const companyIndex = CsDatas.findIndex(b => b.companyID == companyID); if (companyIndex != -1) { name = String(CsDatas[companyIndex].companyName); price = Number(CsDatas[companyIndex].companyPrice); release = Number(CsDatas[companyIndex].companyStock); if (CsDatas[companyIndex].employeesNumber > 0) earnPerShare = Number(CsDatas[companyIndex].companyProfit * (0.8 - (CsDatas[companyIndex].companyBonus * 0.01)) / CsDatas[companyIndex].companyStock); else earnPerShare = Number(CsDatas[companyIndex].companyProfit * 0.8 / CsDatas[companyIndex].companyStock); } debugConsole(String("")); if ($(`tr[companyID="${companyID}"]`).length < 1) { $("#userHaveStockInfo_Table").append(` <tr companyID="${companyID}"> <td title="companyID" width="390px"> <a href="/company/detail/${companyID}">${name}</a> </td> <td title="price">${price}</td> <td title="earnPerShare">${earnPerShare.toFixed(2)}</td> <td title="hold">${hold}</td> <td title="holdPercentage">${(hold / release * 100).toFixed(2)} %</td> <td title="stockWorth">${(price * hold)}</td> <td title="dividend">${(earnPerShare * hold).toFixed(0)}</td> <td title="PE">${(price / earnPerShare).toFixed(3)}</td> </tr> `); } else { $(`tr[companyID="${companyID}"]`).find(`td[title="price"]`)[0].innerHTML = ` ${price} `; $(`tr[companyID="${companyID}"]`).find(`td[title="earnPerShare"]`)[0].innerHTML = ` ${earnPerShare.toFixed(2)} `; $(`tr[companyID="${companyID}"]`).find(`td[title="hold"]`)[0].innerHTML = ` ${hold} `; $(`tr[companyID="${companyID}"]`).find(`td[title="holdPercentage"]`)[0].innerHTML = ` ${(hold / release * 100).toFixed(2)} % `; $(`tr[companyID="${companyID}"]`).find(`td[title="stockWorth"]`)[0].innerHTML = ` ${(price * hold)} `; $(`tr[companyID="${companyID}"]`).find(`td[title="dividend"]`)[0].innerHTML = ` ${(earnPerShare * hold).toFixed(0)} `; $(`tr[companyID="${companyID}"]`).find(`td[title="PE"]`)[0].innerHTML = ` ${(price / earnPerShare).toFixed(3)} `; } } } console.log("---end add_userHaveStockInfo_Table()"); } Template.accountInfo.events({ "click [data-toggle-panel=userHaveStockInfo]"(event) { event.preventDefault(); console.log("click_userHaveStockInfo"); userHaveStockInfo_FolderExpandedVar.set(!userHaveStockInfo_FolderExpandedVar.get()); }, }); /*************accountInfo*************/ /*************************************/ /*************************************/ /**************arenaInfo**************/ function arenaInfoEvent() { checkFighterInfo(); addMyArenaButton(); addRemoveButtton(); } function Fighter(fID, fManager, fHP, fSP, fATK, fDEF, fAGI) { this.ID = fID; this.manager = fManager; this.money = { "total": Number(fHP + fSP + fATK + fDEF + fAGI), "hp": fHP, "sp": fSP, "atk": fATK, "def": fDEF, "agi": fAGI }; this.hp = Number(Math.floor(fHP/200) + 50); this.sp = Number(Math.floor(fSP/1000) + 5); this.atk = Number(Math.floor(fATK/1000) + 1); this.def = Number(Math.floor(fDEF/1000)); this.agi = Number(Math.floor(fAGI/1000)); debugConsole("=====new Fighter ID: " + this.ID); debugConsole("=====new Fighter total money: " + this.money.total); } function checkFighterInfo() { console.log("start checkFighterInfo()"); var fighters = []; const dbFighters = Meteor.connection._mongo_livedata_collections.arenaFighters.find().fetch(); debugConsole("-----for of dbFighters"); for (let f of dbFighters) { debugConsole("-----new Fighter input: " + f.companyId + f.manager + f.hp + f.sp + f.atk + f.def + f.agi); let thisFighter = new Fighter(f.companyId, f.manager, f.hp, f.sp, f.atk, f.def, f.agi); fighters.push(thisFighter); } addFighterMoneyInfo(fighters); //consoleMoney(fighters); console.log("end checkFighterInfo()"); } function addFighterMoneyInfo(fighters) { console.log("---start addFighterMoneyInfo()"); const moneyInfoTitle = $(` <th class="text-center text-truncate" style="width: 100px; min-width: 100px;cursor: pointer;" title="投資額" id="moneyInfoTitle" > 投資額 </th> `); debugConsole("-----th[title=投資額].length: " + $('th[title="投資額"]').length); if ($('th[title="投資額"]').length < 1) { moneyInfoTitle.insertAfter($('th[title="名次"]')[0]); } debugConsole("-----for of fighters"); for (let thisFighter of fighters) { const fID = thisFighter.ID; debugConsole("-----fID: " + fID); debugConsole("-----tr[data-id=fID].length: " + $(`tr[data-id=${fID}]`).length); $(`tr[data-id=${fID}]`).append(` <td class="text-center px-1 text-truncate" style="width: 100px; min-width: 100px;"> ${thisFighter.money.total} </td> `); } console.log("---end addFighterMoneyInfo()"); } function consoleMoney(fighters) { fighters.sort(function(a, b) { return b.money.total - a.money.total; }); const CsDatas = JSON.parse(window.localStorage.getItem ("local_CsDatas")) || []; //local_CsDatas規格 local //{"companyID": String, "companyName": String, // "companyPrice": Number, "companyStock": Number, "companyProfit": Number, // "companySalary": Number, "companyNextSeasonSalary": Number, "companyBonus": Number, // "companyEmployeesNumber": Number, "companyNextSeasonEmployeesNumber": Number} for (let f = 0; f < 100; f += 1) { const thisFighter = fighters[f]; const cIndex = CsDatas.findIndex(c => c.companyID == thisFighter.ID); console.log("rank: " + f); console.log("ID: " + thisFighter.ID); if (cIndex != -1) console.log("name: " + CsDatas[cIndex].companyName); console.log("manager: " + thisFighter.manager); console.log("money: " + thisFighter.money.total); console.log("HP: " + thisFighter.hp); console.log(""); console.log(""); } } function removeNotFighter() { console.log("start removeNotFighter()"); const dbFighters = Meteor.connection._mongo_livedata_collections.arenaFighters.find().fetch(); for (let f of dbFighters) { const money = f.hp + f.sp + f.atk + f.def + f.agi; if (money < 10000) { debugConsole("id: " + f.companyId + " money: " + money); $(`tr[data-id=${f.companyId}]`).remove(); } } console.log("end removeNotFighter()"); } function addRemoveButtton() { if ($(`button[id="removeNotFighter"]`).length < 1) { const buttonRemove = $(` <button class="btn btn-primary btn-sm" type="button" id="removeNotFighter"> 移除沒資格的參賽者 </button> `); buttonRemove.insertAfter($(`h1[class="card-title mb-1"]`)[0]); $('#removeNotFighter')[0].addEventListener("click", function() { removeNotFighter(); }); } } //Dark function //don't see, don't use, don't ask var my_virtual_fighters = []; var battleTime = 0; function removeMyArenaButton() { $(`[objectGroup="myArena"]`).remove(); } function addMyArenaButton() { console.log("start addMyArenaButton()"); removeMyArenaButton(); if (checkAttackSequence()) { if ($('#startMyArena').length < 1) { const buttonMyArena = $(` <button class="btn btn-danger btn-sm" type="button" id="startMyArena" objectGroup="myArena"> 使用進階功能 </button> `); buttonMyArena.insertAfter($(`h1[class="card-title mb-1"]`)[0]); $('#startMyArena')[0].addEventListener("click", function() { $('#startMyArena').remove(); myArena(); } ); } } console.log("end addMyArenaButton()"); } function myArena() { console.log("start myArena()"); console.log("-----ready to start fightSimulatorCreater"); addInputID(); fightSimulatorCreater(); addFindInfoButton(); addStartFightSimulatorButton(); addFindBattleLogButton(); console.log("end myArena()"); } function checkAttackSequence() { console.log("---start checkAttackSequence()"); let checkReturn = false; const dbFighters = Meteor.connection._mongo_livedata_collections.arenaFighters.find().fetch(); if (dbFighters.length > 0) { checkReturn = true; for (let f of dbFighters) { if (f.attackSequence.length === 0) { checkReturn = false; break; } } } return checkReturn; } function VirtualFighter(fID, fName, fManager, fHP, fSP, fATK, fDEF, fAGI, fspCost, fcreatedAt, fattackSequence) { this.ID = fID; this.name = fName; this.manager = fManager; this.money = { "total": Number(fHP + fSP + fATK + fDEF + fAGI), "hp": fHP, "sp": fSP, "atk": fATK, "def": fDEF, "agi": fAGI, "killBonus": 0 }; this.hp = Number(Math.floor(fHP/200) + 50); this.sp = Number(Math.floor(fSP/1000) + 5); this.atk = Number(Math.floor(fATK/1000) + 1); this.def = Number(Math.floor(fDEF/1000)); this.agi = Number(Math.floor(fAGI/1000)); this.spCost = Number(fspCost); this.createdAt = Date.parse(fcreatedAt); this.attackSequence = fattackSequence; this.attackIndex = -1; var notFound = 999999; while (notFound !== -1) { this.attackIndex += 1; notFound = this.attackSequence.findIndex(x => x === this.attackIndex); } this.battleLog = []; this.battleLog.push(`【聲明】模擬戰鬥僅使用現有數值進行模擬,與 最終結果 並不會相同`); debugConsole("=====new Fighter ID: " + this.ID); debugConsole("=====new Fighter total money: " + this.money.total); } function fightSimulatorCreater() { battleTime = 0; const dbFighters = Meteor.connection._mongo_livedata_collections.arenaFighters.find().fetch(); var vFighters = []; const CsDatas = JSON.parse(window.localStorage.getItem ("local_CsDatas")) || []; //local_CsDatas規格 local //{"companyID": String, "companyName": String, // "companyPrice": Number, "companyStock": Number, "companyProfit": Number, // "companySalary": Number, "companyNextSeasonSalary": Number, "companyBonus": Number, // "companyEmployeesNumber": Number, "companyNextSeasonEmployeesNumber": Number} debugConsole("-----for of dbFighters"); for (let f of dbFighters) { const fName = (CsDatas.find(c => c.companyID === f.companyId)).companyName; debugConsole("-----new Fighter input: " + f.companyId + fName + f.manager + f.hp + f.sp + f.atk + f.def + f.agi + f.spCost + f.createdAt + f.attackSequence.length); let thisFighter = new VirtualFighter(f.companyId, fName, f.manager, f.hp, f.sp, f.atk, f.def, f.agi, f.spCost, f.createdAt, f.attackSequence); vFighters.push(thisFighter); } //刪除不到10000的北七 debugConsole("-----start delete money < 10000"); var deleteList = []; for (let i=0; i<vFighters.length; i+=1) { if (vFighters[i].money.total < 10000) { const thisFighterAttackIndex = vFighters[i].attackIndex; debugConsole("-----delete ID: " + vFighters[i].ID + " attackIndex: " + thisFighterAttackIndex); debugConsole("-----delete Name: " + vFighters[i].name); debugConsole(""); vFighters.splice(i, 1); deleteList.push(thisFighterAttackIndex); i -= 1; //因為刪除會導致順序改變,因此i要往回1個 } } const sampleAttackSequence = vFighters[0].attackSequence; if (sampleAttackSequence.length !== (dbFighters.length-1)) { //當亂鬥已經結束時,不符合參賽資格的公司會被從列表刪除,但會留在攻擊名單內 //因此要把這些公司從參加者的攻擊名單中刪除 for (let d of sampleAttackSequence) { if ((vFighters.findIndex(f => f.attackIndex === d)) === -1) { deleteList.push(d); } } } for (let j=0; j<vFighters.length; j+=1) { for (let k of deleteList) { const thisI = vFighters[j].attackSequence.findIndex(f => f === k); vFighters[j].attackSequence.splice(thisI, 1); } } //排攻擊順序 vFighters.sort(function(a, b) { if ((b.agi - a.agi) === 0) return a.createdAt - b.createdAt; else return b.agi - a.agi; }); my_virtual_fighters = vFighters; const moneyInfoTitle = $(` <th class="text-center text-truncate" style="width: 150px; min-width: 150px; cursor: pointer;" title="預估戰鬥獎勵" id="moneyInfoTitle" objectGroup="myArena" > 預估戰鬥獎勵 </th> `); if ($('th[title="預估戰鬥獎勵"]').length < 1) { moneyInfoTitle.insertAfter($('th[title="投資額"]')[0]); } debugConsole("-----for of fighters"); for (let thisFighter of vFighters) { const fID = thisFighter.ID; debugConsole("-----fID: " + fID); debugConsole("-----tr[data-id=fID].length: " + $(`tr[data-id=${fID}]`).length); $(`tr[data-id=${fID}]`).append(` <td class="text-center px-1 text-truncate" style="width: 150px; min-width: 150px;"> ${thisFighter.money.killBonus} </td> `); } } function fightSimulator(vFighters) { console.log("---start fightSimulator()"); battleTime += 1; const topSP = 6; // spCost>這個數值 則視為100%發動 const topAGI = 30; // 雙方AGI差距<這個數值 則視為100%命中 var vLog = []; const statementLog = `【聲明】模擬戰鬥僅使用現有數值進行模擬,與 最終結果 並不會相同`; console.log(statementLog); vLog.push(statementLog); for (let i=0; i<vFighters.length; i+=1) { debugConsole("-----i: " + i); debugConsole("-----vFighters[i].hp: " + vFighters[i].hp); if (vFighters[i].hp > 0) { const randomSp = Math.floor((Math.random() * 10) + 1); const randomAgi = Math.floor((Math.random() * 100) + 1); debugConsole("-----randomSp: " + randomSp); debugConsole("-----randomAgi: " + randomAgi); //決定攻擊目標 debugConsole("-----決定攻擊目標"); var targetHP = 0; var targetIndex = -1; var t = -1; debugConsole("-----while()"); while (targetHP < 1) { t += 1; debugConsole("-----t: " + t); const targetI = vFighters[i].attackSequence[t]; debugConsole("-----targetI: " + targetI); targetIndex = vFighters.findIndex(f => f.attackIndex === targetI); debugConsole("-----targetIndex: " + targetIndex); targetHP = vFighters[targetIndex].hp; debugConsole("-----targetHP: " + targetHP); } debugConsole("-----targetIndex: " + targetIndex); //開始攻擊 debugConsole("-----開始攻擊"); if (((vFighters[i].spCost > topSP) || (vFighters[i].spCost >= randomSp)) && (vFighters[i].sp >= vFighters[i].spCost)) { vFighters[targetIndex].hp -= vFighters[i].atk; vFighters[i].sp -= vFighters[i].spCost; const thisLog = `【第${battleTime}回合】${vFighters[i].name} 使用SP攻擊對 ${vFighters[targetIndex].name} 造成${vFighters[i].atk}傷害,血量變為${vFighters[targetIndex].hp}`; console.log(thisLog); vFighters[i].battleLog.push(thisLog); vFighters[targetIndex].battleLog.push(thisLog); vLog.push(thisLog); } else { const agiAGI = vFighters[targetIndex].agi - vFighters[i].agi; if ((agiAGI < topAGI) || ((agiAGI-randomAgi) <= 0) || (randomAgi > 95)) { let atkNumber = vFighters[i].atk - vFighters[targetIndex].def; if (atkNumber < 1) { atkNumber = 1; } vFighters[targetIndex].hp -= atkNumber; const thisLog = `【第${battleTime}回合】${vFighters[i].name} 使用普通攻擊對 ${vFighters[targetIndex].name} 造成${atkNumber}傷害,血量變為${vFighters[targetIndex].hp}`; console.log(thisLog); vFighters[i].battleLog.push(thisLog); vFighters[targetIndex].battleLog.push(thisLog); vLog.push(thisLog); } else { const thisLog = `【第${battleTime}回合】${vFighters[i].name} 攻擊 ${vFighters[targetIndex].name} ,但AGI差距${agiAGI}點而被閃開了`; console.log(thisLog); vFighters[i].battleLog.push(thisLog); vFighters[targetIndex].battleLog.push(thisLog); vLog.push(thisLog); } } //計算是否擊倒 debugConsole("-----計算是否擊倒"); if (vFighters[targetIndex].hp <= 0) { vFighters[i].money.killBonus += vFighters[targetIndex].money.total; const thisLog = `【第${battleTime}回合】${vFighters[i].name} 擊倒了 ${vFighters[targetIndex].name} ,獲得了${vFighters[targetIndex].money.total}的獎金`; console.log(thisLog); vFighters[i].battleLog.push(thisLog); vFighters[targetIndex].battleLog.push(thisLog); vLog.push(thisLog); } } } //戰鬥結束 回復SP for (let i=0; i<vFighters.length; i+=1) { debugConsole("-----i: " + i); if (vFighters[i].hp > 0) { vFighters[i].sp += 1; } } my_virtual_fighters = vFighters; addFightSimulatorData(vFighters); addBattleLogTable(vLog); console.log("---end fightSimulator()"); } function addFightSimulatorData(vFighters) { console.log("---start addFightSimulatorData()"); for (let thisFighter of vFighters) { debugConsole("ID: " + thisFighter.ID + " hp sp killBonus: " + thisFighter.hp + thisFighter.sp + thisFighter.money.killBonus); $(`tr[data-id=${thisFighter.ID}]`).find('td')[2].innerText = thisFighter.hp; $(`tr[data-id=${thisFighter.ID}]`).find('td')[3].innerText = thisFighter.sp; $(`tr[data-id=${thisFighter.ID}]`).find('td')[9].innerText = thisFighter.money.killBonus; } console.log("---end addFightSimulatorData()"); } function addBattleLogTable(vLog) { $(`table[id=findArenaOutput_Table]`).remove(); const outListTable = $(` <table border="1" id="findArenaOutput_Table"> <tr> <td> 紀錄 </td> </tr> </table> `); outListTable.insertAfter($(`input[id=inputID]`)[0]); for (let thisLog of vLog) { $("#findArenaOutput_Table").append(` <tr> <td> ${thisLog} </td> </tr> `); } } function addStartFightSimulatorButton() { const buttonFS = $(` <button class="btn btn-danger btn-sm" type="button" id="startFS" objectGroup="myArena"> 模擬戰鬥 </button> `); buttonFS.insertAfter($(`h1[class="card-title mb-1"]`)[0]); $('#startFS')[0].addEventListener("click", function() {fightSimulator(my_virtual_fighters); }); } function findBattleLog(fID) { const outListTable = $(` <table border="1" id="findArenaOutput_Table"> <tr> <td> 紀錄 </td> </tr> </table> `); outListTable.insertAfter($(`input[id=inputID]`)[0]); const thisFighter = my_virtual_fighters.find(f => f.ID === fID); for (let thisLog of thisFighter.battleLog) { $("#findArenaOutput_Table").append(` <tr> <td> ${thisLog} </td> </tr> `); } } function addFindBattleLogButton() { const buttonFindBattleLog = $(` <button class="btn btn-info btn-sm" type="button" id="findBattleLog" objectGroup="myArena"> 搜尋模擬戰鬥紀錄 </button> `); buttonFindBattleLog.insertAfter($(`h1[class="card-title mb-1"]`)[0]); $('#findBattleLog')[0].addEventListener("click", function() { $(`table[id=findArenaOutput_Table]`).remove(); const tID = $(`input[id=inputID]`)[0].value; findBattleLog(tID); }); } function findAttackList(fID) { const printNumber = 100; const thisFighter = my_virtual_fighters.find(x => x.ID === fID); const CsDatas = JSON.parse(window.localStorage.getItem ("local_CsDatas")) || []; //local_CsDatas規格 local //{"companyID": String, "companyName": String, // "companyPrice": Number, "companyStock": Number, "companyProfit": Number, // "companySalary": Number, "companyNextSeasonSalary": Number, "companyBonus": Number, // "companyEmployeesNumber": Number, "companyNextSeasonEmployeesNumber": Number} const outListTable = $(` <table border="1" id="findArenaOutput_Table"> <tr> <td> 攻擊序 </td> <td width="390px"> 公司名稱 </td> </tr> </table> `); outListTable.insertAfter($(`input[id=inputID]`)[0]); for (let i=0; i<printNumber; i+=1) { const a_index = thisFighter.attackSequence[i]; const a_fighter = my_virtual_fighters.find(x => x.attackIndex === a_index); const a_company = CsDatas.find(c => c.companyID === a_fighter.ID); console.log("attack: " + i + " " + a_company.companyName); $("#findArenaOutput_Table").append(` <tr> <td> ${(i+1)} </td> <td width="390px"> <a href="/company/detail/${a_company.companyID}">${a_company.companyName}</a> </td> </tr> `); } } function findAttackMe(myID) { const fs = my_virtual_fighters; const myF = fs.find(f => f.ID === myID); const myIndex = myF.attackIndex; const findNumberIn = 39; const CsDatas = JSON.parse(window.localStorage.getItem ("local_CsDatas")) || []; //local_CsDatas規格 local //{"companyID": String, "companyName": String, // "companyPrice": Number, "companyStock": Number, "companyProfit": Number, // "companySalary": Number, "companyNextSeasonSalary": Number, "companyBonus": Number, // "companyEmployeesNumber": Number, "companyNextSeasonEmployeesNumber": Number} const outListTable = $(` <table border="1" id="findArenaOutput_Table"> <tr> <td> 攻擊序 </td> <td width="390px"> 公司名稱 </td> </tr> </table> `); outListTable.insertAfter($(`input[id=inputID]`)[0]); for (let f of fs) { const xIndex = f.attackSequence.findIndex(x => x === myIndex); if (xIndex < findNumberIn) { const thatcompany = CsDatas.find(c => c.companyID === f.ID); console.log("ID: " + f.ID); console.log("name: " + thatcompany.companyName); console.log("attackIndex: " + xIndex); //console.log(f); console.log(""); if (xIndex !== -1) { $("#findArenaOutput_Table").append(` <tr> <td> ${xIndex + 1} </td> <td width="390px"> <a href="/company/detail/${f.ID}">${thatcompany.companyName}</a> </td> </tr> `); } } } } function addInputID() { const inputID = $(` <input class="form-control" type="text" name="inputID" id="inputID" objectGroup="myArena" maxlength="200" placeholder="請輸入公司ID,如 初音未來 為 oeQuXvDBoHYTAZ7ei" > `); inputID.insertAfter($(`h1[class="card-title mb-1"]`)[0]); } function addFindInfoButton() { const buttonAttackList = $(` <button class="btn btn-warning btn-sm" type="button" id="findAttackList" objectGroup="myArena"> 搜尋攻擊清單 </button> `); buttonAttackList.insertAfter($(`h1[class="card-title mb-1"]`)[0]); $('#findAttackList')[0].addEventListener("click", function() { $(`table[id=findArenaOutput_Table]`).remove(); const tID = $(`input[id=inputID]`)[0].value; findAttackList(tID); }); const buttonAttackMe = $(` <button class="btn btn-warning btn-sm" type="button" id="findAttackMe" objectGroup="myArena"> 搜尋敵人清單 </button> `); buttonAttackMe.insertAfter($(`h1[class="card-title mb-1"]`)[0]); $('#findAttackMe')[0].addEventListener("click", function() { $(`table[id=findArenaOutput_Table]`).remove(); const tID = $(`input[id=inputID]`)[0].value; findAttackMe(tID); }); const buttonRemoveTable = $(` <button class="btn btn-info btn-sm" type="button" id="removeTable" objectGroup="myArena"> 移除table </button> `); buttonRemoveTable.insertAfter($(`h1[class="card-title mb-1"]`)[0]); $('#removeTable')[0].addEventListener("click", function() { $(`table[id=findArenaOutput_Table]`).remove(); }); } /**************arenaInfo**************/ /*************************************/ /*************************************/ /**************scriptVIP**************/ function checkVIPstate() { if (!isVIP()) { const useAD = true; window.localStorage.setItem("local_scriptAD_use", useAD); } } function addShowVIPbutton() { console.log("start addShowVIPbutton()"); const showButton = $(` <li class="nav-item" name="scriptVIP"> <a class="nav-link" href="#" name="showVIP">外掛VIP</a> </li> `); $(`<hr name="script" id="0">`).insertAfter($(`li[class="nav-item"]`).find($(`a[href="/fscStock"`))); showButton.insertAfter($(`hr[name="script"][id="0"]`)[0]); $(`a[name="showVIP"]`)[0].addEventListener("click", function() { setTimeout(showVIPpage, 0); }); console.log("end addShowVIPbutton()"); } function showVIPpage() { console.log("start showVIPpage()"); //暴力移除目前頁面 $(".card-block").remove(); //改為VIP功能資訊 $(".card").append(` <div class="card-block" name="VIP"> <div class="col-5"> <h1 class="card-title mb-1">SoftwareScript</h1> <h1 class="card-title mb-1"> VIP功能</h1> </div> <div class="col-5">您是我的恩客嗎?</div> <div class="col-12"> <hr> <p>要離開本頁面記得點進來的那一頁以外的其他頁面</p> <hr> <h2 name="becomeVIP">成為VIP</h2> <hr> <h2 name="VIPscriptAD">外掛廣告</h2> <hr> <h2 name="VIPdataSearch">資料搜尋</h2> <hr> <p>如VIP功能發生問題,請至Discord股市群聯絡SoftwareSing</p> </div> </div> `); vipInfo(); vipAD(); vipDataSearch(); console.log("end showVIPpage()"); } function vipInfo() { console.log("---start vipInfo()"); const scriptVIP_UpdateTime = JSON.parse(window.localStorage.getItem ("local_scriptVIP_UpdateTime")) || "null"; const userVIP = isVIP(); const info = (` <p>VIP條件更新時間: ${scriptVIP_UpdateTime}</p> <p>您目前的VIP狀態: ${userVIP}</p> <p>VIP權限: </P> <ul name="vipCanDo"> <li>關閉外掛廣告</li> <li>使用資料搜尋功能</li> </ul> <p>為成為VIP需要購買以下商品</p> <ul name="needProduct"></ul> `); let productList = ""; const products = JSON.parse(window.localStorage.getItem ("local_scriptVIP")) || []; for (let p of products) { productList += (`<li><a href="${p.link}" target="_self">${p.description}</a></li>`); } $(info).insertAfter($(`h2[name="becomeVIP"]`)); $(`ul[name="needProduct"]`).append($(productList)); console.log("---end vipInfo()"); } function vipAD() { console.log("---start vipAD()"); const scriptADData = JSON.parse(window.localStorage.getItem ("local_scriptAD")) || "null"; const scriptAD_UpdateTime = JSON.parse(window.localStorage.getItem ("local_scriptAD_UpdateTime")) || "null"; let ADinfo = ""; if (scriptADData !== "null") { let linkNumber = 0; let adNumber = 0; console.log("ADnumber:" + scriptADData.adFormat.length); for (let adF = 0 ; adF < scriptADData.adFormat.length ; ++adF) { console.log("adding AD"); adNumber += 1; data = scriptADData.adData[adF]; if (scriptADData.adFormat[adF] == "a") { ADinfo += ('<a class="scriptAD float-left" id="scriptAD-' + adNumber + '">' + data + '</a>'); } else if (scriptADData.adFormat[adF] == "aLink") { link = scriptADData.adLink[linkNumber]; linkType = scriptADData.adLinkType[linkNumber]; //console.log(linkType); //console.log((linkType != "_blank")); if ((linkType != "_blank") && (linkType != "_parent") && (linkType != "_top")) linkType = ""; //linkType = ""; ADinfo += ('<a class="scriptAD float-left" id="scriptAD-' + adNumber + '" href="' + link + '" target="' + linkType + '">' + data + '</a>'); linkNumber += 1; } } } const info = (` <p>目前的廣告更新時間: ${scriptAD_UpdateTime}</p> <p>目前的廣告內容: </p> <p>${ADinfo} </p> <p> <button class="btn btn-info btn-sm" name="openAD">開啟外掛廣告</button> <button class="btn btn-danger btn-sm" name="closeAD">關閉外掛廣告</button> </p> <p> <font color="red">設定會於下次開啟時生效</font> </p> `); if ($(`button[name="closeAD"]`).length < 1) { $(info).insertAfter($(`h2[name="VIPscriptAD"]`)); } if (!isVIP()) { debugConsole("-----user is VIP."); $(`button[name="closeAD"]`)[0].disabled = true; } else { $(`button[name="closeAD"]`)[0].addEventListener("click", function() { const useAD = false; window.localStorage.setItem("local_scriptAD_use", useAD); }); } $(`button[name="openAD"]`)[0].addEventListener("click", function() { const useAD = true; window.localStorage.setItem("local_scriptAD_use", useAD); }); console.log("---end vipAD()"); } function isVIP() { console.log("---start isVIP()"); let products = JSON.parse(window.localStorage.getItem ("local_scriptVIP")) || []; let VIP = true; debugConsole("-----for of products"); for (let scriptP of products) { debugConsole("=====scriptP: "); debugConsole(scriptP); if (scriptP.check === false) { VIP = false; debugConsole("=====break"); break; } } debugConsole("------end for of products"); console.log("-----VIP: " + VIP); console.log("---end isVIP()"); return VIP; } function checkUserOwnedProducts() { console.log("start checkUserOwnedProducts()"); const userID = myID; let products = JSON.parse(window.localStorage.getItem ("local_scriptVIP")) || []; const {dbUserOwnedProducts} = require("./db/dbUserOwnedProducts"); //檢查每個VIP要求的產品是否已經有買到 debugConsole("-----for of products"); for (let scriptP of products) { debugConsole("=====scriptP: "); debugConsole(scriptP); const p = dbUserOwnedProducts.find({productId: scriptP.productID, userId: userID}).fetch(); debugConsole("=====p: "); debugConsole(p); if (p.length > 0) { //已經確定有該產品,確認數量 if (p[0].amount >= scriptP.needAmount) { scriptP.check = true; } } debugConsole(""); } debugConsole("------end for of products"); window.localStorage.setItem ("local_scriptVIP", JSON.stringify(products)); console.log("end checkUserOwnedProducts()"); } function checkScriptVIPUpdateTime() { console.log("start checkScriptVIPUpdateTime()"); const scriptVIP_UpdateTime = JSON.parse(window.localStorage.getItem ("local_scriptVIP_UpdateTime")) || "null"; const get_scriptVIP_jsonDB_updatetime = getWebData(scriptVIP_jsonDB_updatetime); get_scriptVIP_jsonDB_updatetime(json_updateTime => { console.log("json_updateTime === CsDatas_UpdateTime : " + (json_updateTime === scriptVIP_UpdateTime)); if (json_updateTime === scriptVIP_UpdateTime) { console.log("dont need update " + scriptVIP_UpdateTime); } else { console.log("server update time: " + json_updateTime); console.log("local update time: " + scriptVIP_UpdateTime); console.log("start update data"); setTimeout(updateScriptVIP, 1, json_updateTime); } console.log("complete checkScriptVIPUpdateTime()"); }); } function updateScriptVIP(updateTime) { console.log("start updateScriptVIP()"); const get_scriptVIP_jsonDB = getWebData(scriptVIP_jsonDB); get_scriptVIP_jsonDB(jsonData => { window.localStorage.setItem ("local_scriptVIP", JSON.stringify(jsonData)); if (updateTime === null || updateTime === undefined) { window.localStorage.setItem ("local_scriptVIP_UpdateTime", JSON.stringify("no data")); } else { window.localStorage.setItem ("local_scriptVIP_UpdateTime", JSON.stringify(updateTime)); } console.log("end updateScriptVIP()"); }); } function vipDataSearch() { console.log("start vipDataSearch()"); const CsDatas_UpdateTime = JSON.parse(window.localStorage.getItem ("local_CsDatas_UpdateTime")) || "null"; const info = (` <p> VIP可以用此功能搜尋公司資料<br /> 公司資料為 從雲端同步 或 於瀏覽股市時自動更新,因此可能與最新資料有所落差<br /> 目前的雲端資料更新時間: ${CsDatas_UpdateTime}<br /> (每次重新載入股市時,會確認雲端是否有更新資料) </p> <p> </p> <p>各項數值名稱對照表(不在表中的數值無法使用): <table border="1" name="valueNameTable"> <tr name="companyID"> <td>公司ID</td> <td>ID</td> </tr> <tr name="companyName"> <td>公司名稱</td> <td>name</td> </tr> <tr name="companyPrice"> <td>股價</td> <td>price</td> </tr> <tr name="companyStock"> <td>總釋股量</td> <td>stock</td> </tr> <tr name="companyProfit"> <td>總營收</td> <td>profit</td> </tr> <tr name="companySalary"> <td>本季員工薪水</td> <td>salary</td> </tr> <tr name="companyNextSeasonSalary"> <td>下季員工薪水</td> <td>nextSeasonSalary</td> </tr> <tr name="companyBonus"> <td>員工分紅%數</td> <td>bonus</td> </tr> <tr name="companyEmployeesNumber"> <td>本季員工人數</td> <td>employeesNumber</td> </tr> <tr name="companyNextSeasonEmployeesNumber"> <td>下季員工人數</td> <td>nextSeasonEmployeesNumber</td> </tr> </table> </p> <p>常用函式: <table border="1" name="valueNameTable"> <tr name="等於"> <td bgcolor="yellow">等於 (請用2或3個等號)</td> <td bgcolor="yellow">==</td> </tr> <tr name="OR"> <td>x OR(或) y</td> <td>(x || y)</td> </tr> <tr name="AND"> <td>x AND y</td> <td>(x && y)</td> </tr> <tr name="toFixed()"> <td>把x四捨五入至小數點y位</td> <td>x.toFixed(y)</td> </tr> <tr name="Math.ceil(price * 1.15)"> <td>計算漲停價格</td> <td>Math.ceil(price * 1.15)</td> </tr> <tr name="Math.ceil(price * 0.85)"> <td>計算跌停價格</td> <td>Math.ceil(price * 0.85)</td> </tr> <tr name="本益比"> <td>本益比</td> <td>(price * stock) / profit</td> </tr> <tr name="益本比"> <td>益本比</td> <td>profit / (price * stock)</td> </tr> </table> </p> <p> </p> <p> <select class="form-control" style="width: 300px;" name="dataSearchList"></select> <button class="btn btn-info btn-sm" name="createTable">建立新的搜尋表</button> <button class="btn btn-danger btn-sm" name="deleteTable">刪除這個搜尋表</button> <button class="btn btn-danger btn-sm" name="deleteAllTable">刪除所有</button> </p> <p name="showTableName"> 表格名稱: <span class="text-info" name="tableName"></span></p> <p name="showTableFilter"> 過濾公式:<input class="form-control" type="text" name="tableFilter" placeholder="請輸入過濾公式,如: (price>1000)"> <button class="btn btn-info btn-sm" name="addTableFilter">儲存過濾公式</button> <button class="btn btn-danger btn-sm" name="deleteTableFilter">刪除過濾公式</button> </p> <p name="showTableSort"> 排序依據:<input class="form-control" type="text" name="tableSort" placeholder="請輸入排序公式,如: (price),小到大請加負號: -(price)"> <button class="btn btn-info btn-sm" name="addTableSort">儲存排序公式</button> <button class="btn btn-danger btn-sm" name="deleteTableSort">刪除排序公式</button> </p> <p> </p> <p name"showTableColumn">表格欄位<br /> <button class="btn btn-info btn-sm" name="addTableColumn">新增欄位</button> <table border="1" name"tableColumn"> <thead> <th>名稱</th> <th>公式</th> <th>操作</th> </thead> <tbody name="tableColumn"> </tbody> </table> </p> <p> </p> <p> <button class="btn btn-info" name="outputTable">輸出結果</button> <button class="btn btn-warning" name="clearOutputTable">清空輸出</button> </p> <p name="outputTable"></p> <p> </p> `); $(info).insertAfter($(`h2[name="VIPdataSearch"]`)); $(`button[name="deleteAllTable"]`)[0].addEventListener("click", ()=>{ alertDialog.confirm({ title: '刪除所有搜尋表', message: `您確定要刪除所有的表格嗎? <br /> (建議發生嚴重錯誤至無法操作時 再這麼做)`, callback: (result) => { if (result) { window.localStorage.removeItem("local_dataSearch"); //有些錯誤會造成addEventListener加入失敗,因此直接重載入網頁 setTimeout(showVIPpage, 10); } } }); }); $(`button[name="createTable"]`)[0].addEventListener("click", ()=>{ alertDialog.dialog({ type: 'prompt', title: '新建搜尋表', message: `請輸入表格名稱(如有重複將直接覆蓋)`, inputType: 'text', customSetting: ``, callback: function(result) { if (result) { addTable(result); addDataSearchList(); $(`select[name="dataSearchList"]`)[0].value = stripscript(result); showTableInfo(); } } }); }); $(`button[name="deleteTable"]`)[0].addEventListener("click", ()=>{ const tableName = $(`select[name="dataSearchList"]`)[0].value; alertDialog.confirm({ title: '刪除搜尋表', message: `您確定要刪除表格 ${tableName} 嗎?`, callback: (result) => { if (result) { deleteTable(tableName); addDataSearchList(); showTableInfo(); } } }); }); addDataSearchList(); if ($(`select[name="dataSearchList"]`)[0].value !== "") { showTableInfo(); } $(`button[name="addTableFilter"]`)[0].addEventListener("click", ()=>{ const tableName = $(`select[name="dataSearchList"]`)[0].value; const filter = $(`input[name="tableFilter"]`)[0].value; addTableFilter(tableName, filter); }); $(`button[name="deleteTableFilter"]`)[0].addEventListener("click", ()=>{ const tableName = $(`select[name="dataSearchList"]`)[0].value; deleteTableFilter(tableName); $(`input[name="tableFilter"]`)[0].value = ""; }); $(`button[name="addTableSort"]`)[0].addEventListener("click", ()=>{ const tableName = $(`select[name="dataSearchList"]`)[0].value; const sort = $(`input[name="tableSort"]`)[0].value; addTableSort(tableName, sort); }); $(`button[name="deleteTableSort"]`)[0].addEventListener("click", ()=>{ const tableName = $(`select[name="dataSearchList"]`)[0].value; deleteTableSort(tableName); $(`input[name="tableSort"]`)[0].value = ""; }); $(`button[name="addTableColumn"]`)[0].addEventListener("click", ()=>{ const tableName = $(`select[name="dataSearchList"]`)[0].value; alertDialog.dialog({ type: 'prompt', title: '新增欄位', message: `請輸入新的欄位名稱`, inputType: 'text', customSetting: `placeholder="請輸入欄位名稱,如: 本益比"`, callback: function(newName) { if (newName) { alertDialog.dialog({ type: 'prompt', title: '新增欄位', message: `請輸入新的公式`, inputType: 'text', customSetting: `placeholder="請輸入欄位公式,如: (profit / (price * stock))"`, callback: function(newRule) { if (newRule) { addTableColumn(tableName, newName, newRule); showTableColumn(tableName); } } }); } } }); }); $(`button[name="outputTable"]`)[0].addEventListener("click", ()=>{ if (isVIP()) { const tableName = $(`span[name="tableName"]`)[0].innerText; if (tableName !== "") { const filter = $(`input[name="tableFilter"]`)[0].value; addTableFilter(tableName, filter); const sort = $(`input[name="tableSort"]`)[0].value; addTableSort(tableName, sort); outputTable(tableName); } } else { alertDialog.alert("你不是VIP!(怒)"); } }); $(`button[name="clearOutputTable"]`)[0].addEventListener("click", ()=>{ $(`table[name=outputTable]`).remove(); }); console.log("end vipDataSearch()"); } function addDataSearchList() { console.log("---start addDataSearchList()"); $(`option[name="dataSearchList"]`).remove(); const dataSearch = JSON.parse(window.localStorage.getItem ("local_dataSearch")) || []; for (let t of dataSearch) { const item = $(`<option name="dataSearchList" value="${t.tableName}">${t.tableName}</option>`); $(`select[name="dataSearchList"]`).append(item); } $(`select[name="dataSearchList"]`)[0].addEventListener("change", ()=>{ $(`table[name=outputTable]`).remove(); showTableInfo(); }); console.log("---end addDataSearchList()"); } function showTableInfo() { console.log("---start showTableInfo"); const selectValue = $(`select[name="dataSearchList"]`)[0].value; if (selectValue) { const dataSearch = JSON.parse(window.localStorage.getItem ("local_dataSearch")) || []; const thisTable = dataSearch.find(t => t.tableName === selectValue); $(`span[name="tableName"]`)[0].innerText = thisTable.tableName; $(`input[name="tableFilter"]`)[0].value = thisTable.filter; $(`input[name="tableSort"]`)[0].value = thisTable.sort; showTableColumn(thisTable.tableName); } else { $(`span[name="tableName"]`)[0].innerText = ""; $(`input[name="tableFilter"]`)[0].value = ""; $(`input[name="tableSort"]`)[0].value = ""; $(`tr[name="tableColumn"]`).remove(); } console.log("---end showTableInfo"); } function showTableColumn(tableName) { console.log("---start showTableColumn()"); $(`tr[name="tableColumn"]`).remove(); const dataSearch = JSON.parse(window.localStorage.getItem ("local_dataSearch")) || []; const thisTable = dataSearch.find(t => t.tableName === tableName); for (let c of thisTable.column) { const t = (` <tr name="tableColumn"> <td>${c.columnName}</td> <td>${String(c.rule)}</td> <td> <button class="btn btn-warning btn-sm" name="changeTableColumn" id="${c.columnName}">修改</button> <button class="btn btn-danger btn-sm" name="deleteTableColumn" id="${c.columnName}">刪除</button> </td> </tr> `); $(`tbody[name="tableColumn"]`).append(t); $(`button[name="changeTableColumn"][id="${c.columnName}"]`)[0].addEventListener("click", ()=>{ alertDialog.dialog({ type: 'prompt', title: '修改欄位', message: `請輸入新的欄位名稱`, inputType: 'text', defaultValue: c.columnName, customSetting: ``, callback: function(newName) { if (newName) { alertDialog.dialog({ type: 'prompt', title: '修改欄位', message: `請輸入新的公式`, inputType: 'text', defaultValue: String(c.rule), customSetting: ``, callback: function(newRule) { if (newRule) { changeTableColumn(tableName, c.columnName, newRule, newName); showTableColumn(tableName); } } }); } } }); }); $(`button[name="deleteTableColumn"][id="${c.columnName}"]`)[0].addEventListener("click", ()=>{ alertDialog.confirm({ title: `刪除 ${tableName} 的欄位`, message: `您確定要刪除欄位 ${c.columnName} 嗎?`, callback: (result) => { if (result) { deleteTableColumn(tableName, c.columnName); showTableColumn(tableName); } } }); }); } console.log("---end showTableColumn()"); } function outputTable(tableName) { console.log("start outputTable()"); $(`table[name=outputTable]`).remove(); const dataSearch = JSON.parse(window.localStorage.getItem ("local_dataSearch")) || []; const t = dataSearch.find(x => x.tableName === tableName); const CsDatas = JSON.parse(window.localStorage.getItem ("local_CsDatas")) || []; let outputCompanies = []; try { if (t.filter) { for (let c of CsDatas) { if (doInputFunction(c, t.filter)) { outputCompanies.push(c); } } } else { outputCompanies = CsDatas; } } catch (e) { alertDialog.alert("計算失敗!過濾公式出錯"); return; } try { if (t.sort) { outputCompanies.sort((a, b) => doInputFunction(b, t.sort) - doInputFunction(a, t.sort)); } } catch (e) { alertDialog.alert("計算失敗!排序公式出錯"); return; } let outputList = []; let debugColumnName = ""; try { for (let c of outputCompanies) { let row = {}; for (let column of t.column) { debugColumnName = column.columnName; row[column.columnName] = doInputFunction(c, column.rule); } outputList.push(row); } } catch (e) { alertDialog.alert(`計算失敗!欄位 ${debugColumnName} 公式出錯`); return; } let thead = ""; for (let column of t.column) { thead += `<th style="max-width: 390px;">${column.columnName}</th>`; } const output = (` <table border="1" name="outputTable"> <thead name="outputTable"> ${thead} </thead> <tbody name="outputTable"> </tbody> </table> `); ($(`p[name="outputTable"]`)).append(output); for (let row of outputList) { let outputRow = `<tr>`; for (let column of t.column) { outputRow += `<td style="max-width: 390px;">${row[column.columnName]}</td>`; } outputRow += `</tr>`; $(`tbody[name="outputTable"]`).append(outputRow); } console.log("end outputTable()"); } function addTable(newTableName) { const tableName = stripscript(newTableName); let dataSearch = JSON.parse(window.localStorage.getItem ("local_dataSearch")) || []; const newTable = {"tableName": tableName , "filter": null , "sort": null , "column": []}; if (dataSearch.findIndex(t => t.tableName === tableName) === -1) { dataSearch.push(newTable); } else { dataSearch.find(t => t.tableName === tableName) = newTable; } window.localStorage.setItem ("local_dataSearch", JSON.stringify(dataSearch)); const companyLink = '(`<a name="companyName" id="${ID}" href="/company/detail/${ID}">${name}</a>`)'; addTableColumn(tableName, "公司名稱", companyLink); } function deleteTable(tableName) { let dataSearch = JSON.parse(window.localStorage.getItem ("local_dataSearch")) || []; const i = dataSearch.findIndex(t => t.tableName === tableName); dataSearch.splice(i, 1); if (dataSearch.length > 0) { window.localStorage.setItem ("local_dataSearch", JSON.stringify(dataSearch)); } else { window.localStorage.removeItem("local_dataSearch"); } } function addTableSort(tableName, sort) { let dataSearch = JSON.parse(window.localStorage.getItem ("local_dataSearch")) || []; (dataSearch.find(d => d.tableName === tableName)).sort = sort; window.localStorage.setItem ("local_dataSearch", JSON.stringify(dataSearch)); } function deleteTableSort(tableName) { let dataSearch = JSON.parse(window.localStorage.getItem ("local_dataSearch")) || []; (dataSearch.find(d => d.tableName === tableName)).sort = null; window.localStorage.setItem ("local_dataSearch", JSON.stringify(dataSearch)); } function addTableFilter(tableName, filter) { let dataSearch = JSON.parse(window.localStorage.getItem ("local_dataSearch")) || []; (dataSearch.find(d => d.tableName === tableName)).filter = filter; window.localStorage.setItem ("local_dataSearch", JSON.stringify(dataSearch)); } function deleteTableFilter(tableName) { let dataSearch = JSON.parse(window.localStorage.getItem ("local_dataSearch")) || []; (dataSearch.find(d => d.tableName === tableName)).filter = null; window.localStorage.setItem ("local_dataSearch", JSON.stringify(dataSearch)); } function addTableColumn(tableName, columnName, rule) { let dataSearch = JSON.parse(window.localStorage.getItem ("local_dataSearch")) || []; (dataSearch.find(d => d.tableName === tableName)).column.push({"columnName": stripscript(columnName), "rule": rule}); window.localStorage.setItem ("local_dataSearch", JSON.stringify(dataSearch)); } function changeTableColumn(tableName, columnName, rule, newColumnName) { let dataSearch = JSON.parse(window.localStorage.getItem ("local_dataSearch")) || []; let tableColumn = (dataSearch.find(d => d.tableName === tableName)).column; (tableColumn.find(col => col.columnName === columnName)).rule = rule; (tableColumn.find(col => col.columnName === columnName)).columnName = stripscript(newColumnName); (dataSearch.find(d => d.tableName === tableName)).column = tableColumn; window.localStorage.setItem ("local_dataSearch", JSON.stringify(dataSearch)); } function deleteTableColumn(tableName, columnName) { let dataSearch = JSON.parse(window.localStorage.getItem ("local_dataSearch")) || []; const tableColumn = (dataSearch.find(d => d.tableName === tableName)).column; (dataSearch.find(d => d.tableName === tableName)).column.splice(tableColumn.findIndex(c => c.columnName === columnName), 1); window.localStorage.setItem ("local_dataSearch", JSON.stringify(dataSearch)); } function doInputFunction(company, fun) { const ID = company.companyID; const id = company.companyID; const name = company.companyName; const price = company.companyPrice; const stock = company.companyStock; const profit = company.companyProfit; const salary = company.companySalary; const nextSeasonSalary = company.companyNextSeasonSalary; const bonus = company.companyBonus; const employeesNumber = company.companyEmployeesNumber; const nextSeasonEmployeesNumber = company.companyNextSeasonEmployeesNumber; debugConsole("=====do=" + fun); return eval(fun); } function stripscript(s) { const pattern = new RegExp("[`~!@#$^&*()=|{}':;',\\[\\].<>/?~!@#¥……&*()——|{}【】‘;:”“'。,、?]"); let rs = ""; for (let i = 0; i < s.length; i++) { rs = rs+s.substr(i, 1).replace(pattern, ''); } return rs; } /**************scriptVIP**************/ /*************************************/ /*************************************/ /**************Language***************/ var lan = ""; lan = null !== window.localStorage.getItem ("PM_language") ? window.localStorage.getItem ("PM_language") : "tw"; // 目前的語言 let currentLanguage = window.localStorage.getItem("PM_language") || "tw"; // 翻譯米糕 function t(key) { return Dict[currentLanguage][key]; } /*function ChangeLanguage(l){ if(lan === l)return; lan = l; window.localStorage.setItem ("PM_language",l); window.location.reload(); }*/ const Dict = { tw: { totalProfitInThisPage: "本頁預計分紅:", updateDividendScript: "更新預估分紅腳本", userTotalAssets: "使用者股票總值:", userTotalProfit: "預估股票分紅:", userTotalCompanyNumber: "持有公司總數:", managerTotalSalary: "預估經理薪水:", employeeTotalBonus: "預估員工分紅:", userTotalTax: "預估本季稅金:", PEratio: "本益比排行", stockPEInfo: "本益比", stockManagerSalaryInfo: "經理薪水", stockProfitInfo: "現金股利", stockWorthInfo: "股票總值", userHaveStockInfo: "持股資訊總表", userTotalUsingCash: "買單現金總值:", userTotalSellingStock: "賣單股票總值:", mostStockDropDown: "最多持股公司", }, en: { totalProfitInThisPage: "Total profit in this page :", updateDividendScript: "Update Dividend Script", userTotalAssets: "User stock worth:", userTotalProfit: "Estimated stock dividends:", userTotalCompanyNumber: "Hold the total number of companies:", managerTotalSalary: "Estimated manager salary:", employeeTotalBonus: "預估員工分紅:", userTotalTax: "Estimated tax for this season:", PEratio: "PE ratio", stockPEInfo: "PE", stockManagerSalaryInfo: "Manager salary", stockProfitInfo: "Dividend", stockWorthInfo: "Stock worth", userHaveStockInfo: "持股資訊總表", userTotalUsingCash: "買單現金總值:", userTotalSellingStock: "賣單股票總值:", mostStockDropDown: "最多持股公司", }, jp: { totalProfitInThisPage: "本ページ利回り総額:", updateDividendScript: "更新預估分紅腳本", userTotalAssets: "使用者股票總值:", userTotalProfit: "預估股票分紅:", userTotalCompanyNumber: "持有公司總數:", managerTotalSalary: "預估經理薪水:", employeeTotalBonus: "預估員工分紅:", userTotalTax: "預估本季稅金:", PEratio: "本益比排行", stockPEInfo: "本益比", stockManagerSalaryInfo: "經理薪水", stockProfitInfo: "現金股利", stockWorthInfo: "股票總值", userHaveStockInfo: "持股資訊總表", userTotalUsingCash: "買單現金總值:", userTotalSellingStock: "賣單股票總值:", mostStockDropDown: "最多持股公司", }, marstw: { totalProfitInThisPage: "這ㄘ可yee拿ㄉ$$:", updateDividendScript: "有★★★版", userTotalAssets: "股票ㄉ$$:", userTotalProfit: "這ㄘ會拿ㄉ$$:", userTotalCompanyNumber: "偶ㄐ間公ㄙ:", managerTotalSalary: "雞李ㄉ西水:", employeeTotalBonus: "預估員工分紅:", userTotalTax: "ㄋ要交ㄉ茄:", PEratio: "ㄅyee逼排行", stockPEInfo: "ㄅyee逼", stockManagerSalaryInfo: "ㄐ李溪水", stockProfitInfo: "會給ㄉ前", stockWorthInfo: "股票ㄓˊ", userHaveStockInfo: "持股資訊總表", userTotalUsingCash: "買單現金總值:", userTotalSellingStock: "賣單股票總值:", mostStockDropDown: "最多持股公司", } }; /**************Language***************/ /*************************************/
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址