# 運動中心 api 邏輯: 某一頁可以找到場地的 Object : providers 利用 Template7 先將 BODY 建立一個 屬於外掛的 DOM,給予 ID,由於頁面本身有 Jqeury 所以直接引用。接著綁定按鈕事件, reload 跟 原始網頁的 method 預約 再跑一次 providers 迴圈,將變數塞入物件,建立實例,因為後段一次只吃一個場地的參數,所以依次將 ID 塞到 job 陣列裡面。 建立完畢之後 doJob,每次將 job 的陣列吐出一個 value, 塞入 run 中,run 建立一個 Promise,代表這個場地資料取得完畢,並且 render dom。結束之後繼續把 job 變數重複傳遞,直到 job 變成空陣列為止 class 物件:主要包裝了兩個 load、send #### load 根據 actionInit 去針對後端寫入場地參數 接著 actionGetDateList 去要每日的時段列表 讀取資料 render 到 dom 中 #### send 根據 actionInit 去針對後端寫入場地參數 呼叫原生網頁的 API 送 日期 (date) 時間(time) => 跳轉 ## Fetch 版本 ```javascript // ==UserScript== // @name sport_auto_api // @namespace http://mesak.tw // @version 1.0 // @description Help order sport place // @author Mesak // @match https://pzsc.17fit.com/service-flow-sp // @icon https://www.google.com/s2/favicons?sz=64&domain=17fit.com // @require https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.3/moment.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/template7/1.4.1/template7.min.js // ==/UserScript== const dataFormat = "YYYY/MM/DD"; const allowDates = [moment(), moment().add(1, "days"), moment().add(2, "days"), moment().add(3, "days")]; const bodyTemplate = `<section class="container" id="plugin_order_place"> <div class="row"> {{#each this}} <div class="col-md-6"> <div id="place_{{member_id}}" data-key="{{@key}}" class="panel panel-primary"> <div class="panel-heading"><span>{{member_name}}</span> <button type="button" class="refresh close" data-id="{{member_id}}"> <span class="glyphicon glyphicon-refresh" aria-hidden="true"></span> </button> </div> <div class="panel-body text-center"></div> </div> </div> {{/each}} </div> </section>`; const dateTemplate = ` <div class="row"> {{#each list}} <div class="col-md-3"> <h4>{{title}}</h4> {{#each times}} <div style="margin-bottom:6px"> <a class="btn btn-warning btn-block" rel="pick_up_time" data-id="{{@root.id}}" data-time="{{time}}" data-date="{{date}}">{{time}}</a> </div> {{else}} <div style="text-align: center; "> 本日已額滿,請選擇其它日期 </div> {{/each}} </div> {{/each}} </div> `; const loadTemplate = ` <div class="loader triangle"> <svg viewBox="0 0 86 80"> <path d="M40 65L5.35899 4.99999L74.641 5L40 65Z"/> </svg> </div> ` class place { constructor(name, member_id, role_relationships_id) { this.member_id = member_id; this.role_relationships_id = role_relationships_id; this.level_price = 0; this.member_name = name; this.dates = new Map(); this.$node = $(`#place_${member_id}`); } actionInit() { return new Promise((resolve, _reject) => { fetch('https://pzsc.17fit.com/service-flow-dt',{ method : 'POST', headers:{ 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ member_id: this.member_id, //場點 ID role_relationships_id: this.role_relationships_id, //場地 ID member_name: this.member_name, //場地名稱 level_price: this.level_price, }) }) .then(function(response) { resolve(); }) }); } actionGetDateList() { const datePromise = []; allowDates.forEach((moment, index) => { let date = moment.format(dataFormat); datePromise.push( fetch('https://pzsc.17fit.com/getServiceProviderDateTimeApi',{ method : 'POST', headers:{ 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ date: moment.format(dataFormat), }) }).then( (response) => response.json() ).then( (data) => { this.setDate(date, data); }) ); }); return new Promise((resolve, _reject) => { Promise.all(datePromise).then((result) => { resolve(result); }); }); } setDate(date, data) { this.dates.set(date, data); } load(){ return new Promise((resolve, _reject) => { this.$node.find('.panel-body').html(Template7.compile(loadTemplate)); this.actionInit().then(() => { this.actionGetDateList().then((data) => { this.render(); resolve(data) }); }); }); } send(date,time) { this.actionInit().then(() => { $17.formPost({ url: "https://pzsc.17fit.com/service-flow-confirm", params: { is_cash: 0, selected_day: date, selected_time: time }, }); }); } render() { let data = { id: this.member_id, list: [], }; allowDates.forEach((moment, index) => { let date = moment.format(dataFormat); let dateTimes = this.dates.get(date); let dateData = { title: date, times: Array.from(dateTimes.values()), }; dateData.hasTimes = dateData.times.length > 0; data.list.push(dateData); }); this.$node.find('.panel-body').html(Template7.compile(dateTemplate)(data)); } } (function () { "use strict"; //$('body').append('<div id="plugin_order_place"></div>') providers = providers.filter( item => item.member_id != 0); $("body").append(Template7.compile(bodyTemplate)(providers)); const service = new Map(); const jobs = []; let test_id ; providers.forEach((item, index) => { service.set( `member_${item.member_id}`, new place(item.member_name, item.member_id, item.role_relationships_id)); jobs.push( `member_${item.member_id}` ); test_id = `member_${item.member_id}` }); $('#plugin_order_place').on('click','a[rel="pick_up_time"]' , (e) => { $17.swal({ title: `預約時間 ${e.currentTarget.dataset.date} ${e.currentTarget.dataset.time}`, text: '是否要預約?', type: 'success', }, () => { const member_id = e.currentTarget.dataset.id const activeService = service.get(`member_${member_id}`); activeService.send(e.currentTarget.dataset.date,e.currentTarget.dataset.time) }); }).on('click','.refresh' , (e) => { const member_id = e.currentTarget.dataset.id run( `member_${member_id}` ) }) function run( id ) { const activeService = service.get(id); return activeService.load(); } function doJob(jobs){ if( jobs.length ){ run( jobs.shift() ).then(()=>{ doJob(jobs) }) } } doJob( jobs ) //run( test_id ) })(); ```