Commit 8163427c by yexing

[yx]update

parent c1160bee
import { xlsx2csv } from "./xlsx.js";
import { Plan, createZip, checkResponse } from "./util.js";
import { createZip, checkResponse } from "./util.js";
import { Plan, makeLogEntry } from "./timezone.js";
import { uploadFile } from "./upload.js";
import { TABLE } from "./conf.js";
const checkOrigin = (u1, u2) => {
const checkURL = (u1, u2) => {
if (!u1 || !u2) return false;
return u1.startsWith(new URL(u2).origin);
}
return u1.startsWith(new URL(u2).origin) && !u1.includes("signin");
};
const sendTabMsg = (msg, callback) => {
const uri = msg.data.uri;
chrome.tabs.query({}, (tabs) => {
const tab = tabs.filter(x => checkOrigin(x.url, uri))[0];
const tab = tabs.filter(x => checkURL(x.url, uri))[0];
if (!tab) {
const errorMsg = `tab not found, msg: ${JSON.stringify(msg)}`
callback ? callback(errorMsg) : console.error(errorMsg);
chrome.notifications.create({
type: "basic",
title: "插件提醒",
message: "请重新打开页面!",
iconUrl: chrome.runtime.getURL('icon.png'),
requireInteraction: true,
});
return;
}
console.log(`send ${JSON.stringify(msg)} to ${tab.url}`);
......@@ -106,10 +114,7 @@ function startTask() {
const ackLen = logs.filter(x => x.message.includes("完成")).length;
chrome.runtime.sendMessage({ type: 'progress', logs });
if (ackLen === taskNum) {
logs.push({
time: new Date().toLocaleTimeString(),
message: "已全部完成"
});
logs.push(makeLogEntry("已全部完成"));
chrome.runtime.sendMessage({ type: 'progress', logs });
// copy logs
chrome.storage.local.set({ isRunning: false, logs });
......@@ -124,8 +129,8 @@ function startTask() {
const initTimedTask = () => {
for (const [key, { uri, params }] of Object.entries(TABLE)) {
const plan = new Plan(null, params);
const period = plan.get()?.period;
const when = plan.next().dt.getTime();
const period = plan.get();
const when = plan.next().dt.valueOf();
chrome.alarms.create(key, { when });
console.log(`[timedTask] uri: ${uri} period: ${period} when: ${when}`);
}
......@@ -135,9 +140,9 @@ chrome.alarms.onAlarm.addListener((alarm) => {
if (!Object.keys(TABLE).includes(key)) return;
const { uri, params } = TABLE[key];
const plan = new Plan(null, params);
const period = !fromDate || !toDate ? plan.get()?.period : [fromDate, toDate];
const period = !fromDate || !toDate ? plan.get() : [fromDate, toDate];
if (!when) {
when = plan.next().dt.getTime();
when = plan.next().dt.valueOf();
chrome.alarms.create(alarm.name, { when });
console.log(`[timedTask] uri: ${uri} period: ${period} when: ${when}`);
}
......
......@@ -24,10 +24,7 @@ const inventoryHealthCallback = async function (response) {
return response.blob();
}
const advertCallback = async function (response) {
let {
reportType = null, recommendationType = null,
startDate = null, endDate = null
} = this.options.body;
let { reportType = null, recommendationType = null, startDate = null, endDate = null } = this.options.body;
reportType ||= recommendationType;
const waitDone = async () => {
try {
......@@ -76,21 +73,22 @@ const advertCallback = async function (response) {
return waitDone();
}
const rrCallback = async function (response) {
const headers = this.options.headers;
const waitDone = async () => {
let url = new URL(`${this.uri}${this.names.apiName}`);
url.search = new URLSearchParams({
"reportType": "ORDER",
"reportVersion": "v1",
"page": "1",
"limit": "10"
reportType: "ORDER",
reportVersion: "v1",
page: "1",
limit: "10"
}).toString();
console.log(`GET ${url}`);
await sleep(DELAY * 30); // 60s
response = await fetch(url, { headers: this.options.headers });
response = await fetch(url, { headers: headers });
console.log(response);
let data = await response.json();
if (data.requests) {
const request = data.requests.find(item => item.requestId === requestId);
const request = data.requests.find((item) => item.requestId === requestId);
if (request && request.requestStatus === "READY") {
return;
}
......@@ -134,7 +132,7 @@ const rrCallback = async function (response) {
return null;
}
const gqlCallback = async function (response) {
const uri = this.uri, method = "POST", body = this.options.body, [fromDate, toDate] = this.options.period;
const uri = this.uri, method = "POST", body = this.options.body, headers = this.options.headers, [fromDate, toDate] = this.options.period;
async function getID(json) {
const { campaignReports = null, pagination = null } = json.data.get_coop_campaigns;
if (!campaignReports?.length) {
......@@ -155,23 +153,61 @@ const gqlCallback = async function (response) {
}
async function getData(campaignId, pageNumber) {
const body = JSON.stringify({
"query": "\n query get_coop_campaign($itemLevelSummary: ItemLevelSummaryReportRequest!) {\n get_coop_campaign(itemLevelSummary: $itemLevelSummary) {\n pagination {\n pageNo\n pageSize\n totalCount\n totalPages\n }\n itemLevelReports {\n id\n name\n imageUrl\n status\n offerPrice\n competitorPrice\n offerId\n sku\n olqScore\n productId\n demand\n googlePrice\n sameSeller14Day {\n gmv\n roas\n }\n traffic {\n clicks\n ctr\n cpc\n adspend\n impressions\n }\n url\n }\n }\n}\n ",
"query": `
query get_coop_campaign($itemLevelSummary: ItemLevelSummaryReportRequest!) {
get_coop_campaign(itemLevelSummary: $itemLevelSummary) {
pagination {
pageNo
pageSize
totalCount
totalPages
}
itemLevelReports {
id
name
imageUrl
status
offerPrice
competitorPrice
offerId
sku
olqScore
productId
demand
googlePrice
sameSeller14Day {
gmv
roas
}
issues
traffic {
clicks
ctr
cpc
adspend
impressions
}
url
}
}
}
`,
"variables": {
"itemLevelSummary": {
itemLevelSummary: {
campaignId,
"sort": {
"attributionType": "same_seller",
"sortBy": "adspend",
"sortOrder": "DESC"
sort: {
attributionType: "same_seller",
sortBy: "adspend",
sortOrder: "DESC",
},
"startDate": fromDate,
"endDate": toDate,
"page": {
startDate: fromDate,
endDate: toDate,
page: {
pageNumber,
"limit": 10
}
}
}
limit: 10,
},
},
},
});
response = await fetch(uri, { headers, method, body });
console.log(response);
......@@ -186,7 +222,7 @@ const gqlCallback = async function (response) {
ItemID: itemLevelReport.id,
SKU: itemLevelReport.sku,
Spend: itemLevelReport.traffic?.adspend || 0
}
};
});
data.push(...item);
const { pageNo, totalPages } = pagination;
......@@ -205,6 +241,10 @@ const gqlCallback = async function (response) {
}
const newJson = { status: "OK", data }
newJson.__route = "search_engine_marketing";
if (this.params.requestType === "OPEN_CYCLE") {
newJson["payCycleStatus"] = "open";
this.names.showName += " open";
}
newJson["walmartid"] = this.partnerId;
newJson["Starttime"] = fromDate;
newJson["Endtime"] = toDate;
......@@ -236,16 +276,14 @@ const getPeriods = async (options = {}) => {
console.error(`response 获取失败: ${JSON.stringify(data)}`);
throw new Error(response);
}
response.shift();
const { start = 0, end = 3, monthly = false } = options;
// response.shift();
const { start = 0, end = 3, isBimester = false } = options;
let periods;
if (monthly) {
const prevMouth = fmt0(getMouth(null, -1)).slice(0, -3);
if (isBimester) {
const prevMouth = getMouth(null, -1);
const curMouth = fmt0(new Date()).slice(0, -3);
const reg = new RegExp(`^${prevMouth}|^${curMouth}`);
periods = response.filter(
x => reg.test(x.payPeriodFromDate) || reg.test(x.settleDate)
);
periods = response.filter((x) => reg.test(x.payPeriodFromDate) || reg.test(x.settleDate));
} else {
periods = response.slice(start, end);
}
......@@ -265,7 +303,7 @@ const createAdvertTask = function (sign, bodyArgs, options = {}) {
return {
method: 'POST',
body: {
"format": "gzip",
format: "gzip",
advertiserId,
...bodyArgs,
},
......@@ -274,7 +312,7 @@ const createAdvertTask = function (sign, bodyArgs, options = {}) {
}
}
const aids = decodeState2(options.initialState)?.advertisers.map(x => x.id) || [];
const aids = decodeState2(options.initialState)?.advertisers.map((x) => x.id) || [];
const names = {
apiName: "campaigns",
showName: `Advert ${sign}`,
......@@ -284,67 +322,62 @@ const createAdvertTask = function (sign, bodyArgs, options = {}) {
request: options.request || "/v1/snapshot/report"
}
if (aids.length > 1) {
return new TaskGroup(aids.map(aid => {
return new Task(names, params, getTaskOptions(aid));
}), { unique: true });
return new TaskGroup(
aids.map((aid) => {
return new Task(names, params, getTaskOptions(aid));
}), { unique: true });
} else {
return new Task(names, params, getTaskOptions());
}
}
const createOrderTask = function (sign, bodyArgs, options = {}) {
const { fromDate, toDate } = bodyArgs;
return new Task({
apiName: "reportRequests",
apiName2: "downloadReport",
showName: options.showName
}, {
"reportType": "ORDER",
"reportVersion": "v1",
"isDSV": "false",
"bizRole": "MP"
}, {
method: 'POST',
body: {
"rowFilters": [
{
"type": "enumFilter",
"values": [
"All"
],
"columnName": "orderGroups"
},
{
"type": "enumFilter",
"values": [
sign
],
"columnName": "fulfilmentTypes"
},
{
"type": "rangeFilter",
"columnName": "orderDate",
"from": fromDate,
"to": toDate
}
],
"additionalInfo": {
"reportSummary": `${sign} Fulfilled - ${fmt2(fromDate)} to ${fmt2(toDate)}`
},
"excludeColumns": [
"Order Type",
"Service PO#",
"Service Status",
"Total Service Cost",
"Service Scheduled Date"
]
return new Task(
{
apiName: "reportRequests",
apiName2: "downloadReport",
showName: options.showName,
},
headers: {
...rrHeaders(),
{
reportType: "ORDER",
reportVersion: "v1",
isDSV: "false",
bizRole: "MP",
},
callback: rrCallback,
ext: "xlsx"
});
}
{
method: "POST",
body: {
rowFilters: [
{
type: "enumFilter",
values: ["All"],
columnName: "orderGroups",
},
{
type: "enumFilter",
values: [sign],
columnName: "fulfilmentTypes",
},
{
type: "rangeFilter",
columnName: "orderDate",
from: fromDate,
to: toDate,
},
],
additionalInfo: {
reportSummary: `${sign} Fulfilled - ${fmt2(fromDate)} to ${fmt2(toDate)}`,
},
excludeColumns: ["Order Type", "Service PO#", "Service Status", "Total Service Cost", "Service Scheduled Date"],
},
headers: {
...rrHeaders(),
},
callback: rrCallback,
ext: "xlsx",
}
);
};
export async function createTasks(uri, period) {
if (!uri.startsWith(location.origin)) {
return [];
......@@ -359,51 +392,62 @@ export async function createTasks(uri, period) {
switch (uri) {
case TABLE.PAYMENT.uri:
{
const periods = await retry(
getPeriods,
{ isThrow: false },
[{ monthly: true }]
) || [];
const periods = (await retry(getPeriods, { isThrow: false }, [{ isBimester: true }])) || [];
await sleep(DELAY);
const tasks = [];
Task.uri = uri;
for (const period of periods) {
fromDate = period.payPeriodFromDate;
toDate = period.payPeriodToDate;
const settleDate = period.settleDate;
const { settleDate, payCycleStatus: requestType } = period;
const reportDate = fmt3(settleDate);
Task.desc = `${fromDate}_${toDate}`;
if (requestType !== "OPEN_CYCLE") {
tasks.push(
new Task(
{
apiName: "report/reconreport/v1/reconFile",
showName: "Payments new report",
},
{
reportDate,
},
{
ext: "zip",
}
),
new Task(
{
apiName: "report/reconreport/reconFile",
showName: "Payments legacy report",
},
{
reportDate,
},
{
ext: "zip",
}
)
);
}
tasks.push(
new Task({
apiName: "report/reconreport/v1/reconFile",
showName: "Payments new report",
}, {
reportDate
}, {
ext: "zip"
}),
new Task({
apiName: "report/reconreport/reconFile",
showName: "Payments legacy report",
}, {
reportDate
}, {
ext: "zip"
}),
new Task({
apiName: "auroraPaymentsSettlementService/payment/settlementDetails",
showName: "Export This Page",
}, {
settleDate,
fromDate,
toDate,
requestType: "SETTLED_CYCLE"
}, {
ext: "json",
callback: jsonCallback,
next: true,
}),
new Task(
{
apiName: "auroraPaymentsSettlementService/payment/settlementDetails",
showName: "Export This Page",
},
{
settleDate,
fromDate,
toDate,
requestType,
},
{
ext: "json",
callback: jsonCallback,
next: true,
}
)
);
}
return tasks;
......@@ -411,39 +455,84 @@ export async function createTasks(uri, period) {
case TABLE.GQL.uri:
{
const body = {
"query": "\n query get_coop_campaigns($campaignSummary: CampaignSummaryRequest!) {\n get_coop_campaigns(campaignSummary: $campaignSummary) {\n pagination {\n pageNo\n pageSize\n totalCount\n totalPages\n }\n campaignReports {\n id\n name\n startDate\n endDate\n status\n labels\n budget\n targetRoas\n sameSeller14Day {\n gmv\n roas\n }\n traffic {\n clicks\n adspend\n cpc\n impressions\n ctr\n }\n }\n }\n}\n ",
"variables": {
"campaignSummary": {
"startDate": fromDate,
"endDate": toDate,
"name": "",
"statuses": [
"RUNNING",
"COMPLETED",
"STOPPED",
"ERROR",
"PAUSED"
],
"page": {
"limit": 10,
"pageNumber": 0
}
}
}
}
query: `
query get_coop_campaigns($campaignSummary: CampaignSummaryRequest!) {
get_coop_campaigns(campaignSummary: $campaignSummary) {
pagination {
pageNo
pageSize
totalCount
totalPages
}
campaignReports {
id
name
startDate
endDate
status
labels
budget
dailyBudget
targetRoas
sameSeller14Day {
gmv
roas
}
traffic {
clicks
adspend
cpc
impressions
ctr
}
biddingStrategyType
campaignRecommendations {
type
subType
recommendedValue
status
}
creationType
}
}
}
`,
variables: {
campaignSummary: {
startDate: fromDate,
endDate: toDate,
name: "",
statuses: ["RUNNING", "COMPLETED", "STOPPED", "ERROR", "PAUSED"],
page: {
limit: 10,
pageNumber: 0,
},
sort: {
sortBy: "status",
sortOrder: "ASC",
attributionType: "same_seller",
},
},
},
};
return [
new Task({
apiName: "",
showName: "Search Engine Marketing",
}, {}, {
method: 'POST',
ext: 'json',
body,
period,
callback: gqlCallback,
next: true,
})
]
new Task(
{
apiName: "",
showName: "Search Engine Marketing",
},
{},
{
method: "POST",
ext: "json",
body,
period,
headers: rrHeaders(),
callback: gqlCallback,
next: true,
}
),
];
}
case TABLE.ORDER.uri:
return [
......@@ -455,135 +544,193 @@ export async function createTasks(uri, period) {
case TABLE.ADVERT.uri:
{
const initialState = await chrome.runtime.sendMessage({ type: "executeScript", data: "initialState" });
const initialUrl = performance.getEntriesByType('navigation')[0]?.name || location.href;
const initialUrl = performance.getEntriesByType("navigation")[0]?.name || location.href;
Task.partnerId = getValue("partner_id", initialUrl, "&");
Task.uri = uri;
return [
createAdvertTask("Keyword Performance", {
"startDate": fromDate,
"endDate": toDate,
"reportType": "keyword",
"attributionWindow": "days3",
"extraFields": ["noDate"],
}, { initialState }),
createAdvertTask("Placement Performance", {
"startDate": fromDate,
"endDate": toDate,
"reportType": "placement",
"attributionWindow": "days3",
"extraFields": ["noDate"],
}, { initialState }),
createAdvertTask("Item Keyword Performance", {
"startDate": fromDate,
"endDate": toDate,
"reportType": "itemKeyword",
"attributionWindow": "days3",
"extraFields": ["noDate"],
}, { initialState }),
createAdvertTask("Item Performance", {
"startDate": fromDate,
"endDate": toDate,
"reportType": "adItem",
"attributionWindow": "days3",
"extraFields": ["noDate", "splitAttribution"],
}, { initialState }),
createAdvertTask("Keyword Recommendations", {
"recommendationType": "keywordRecommendations"
}, {
request: "/v1/snapshot/recommendations",
initialState
}),
createAdvertTask(
"Keyword Performance",
{
startDate: fromDate,
endDate: toDate,
reportType: "keyword",
attributionWindow: "days3",
extraFields: ["noDate"],
},
{ initialState }
),
createAdvertTask(
"Placement Performance",
{
startDate: fromDate,
endDate: toDate,
reportType: "placement",
attributionWindow: "days3",
extraFields: ["noDate"],
},
{ initialState }
),
createAdvertTask(
"Item Keyword Performance",
{
startDate: fromDate,
endDate: toDate,
reportType: "itemKeyword",
attributionWindow: "days3",
extraFields: ["noDate"],
},
{ initialState }
),
createAdvertTask(
"Item Performance",
{
startDate: fromDate,
endDate: toDate,
reportType: "adItem",
attributionWindow: "days3",
extraFields: ["noDate", "splitAttribution"],
},
{ initialState }
),
createAdvertTask(
"Keyword Recommendations",
{
recommendationType: "keywordRecommendations",
},
{
request: "/v1/snapshot/recommendations",
initialState,
}
),
];
}
default:
{
const cutOffDate = await retry(
getCutOffDate,
{ isThrow: false },
) || "";
const [s, cut] = cutDate([fromDate, toDate], cutOffDate);
const cutOffDate = (await retry(getCutOffDate, { isThrow: false })) || "";
const [se, cut] = cutDate([fromDate, toDate], cutOffDate);
Task.uri = uri;
return [
new Task({
apiName: "salesReport",
showName: "WFS Orders"
}, {
fromDate,
toDate,
}, { ext: 'json' }),
new Task({
apiName: "salesReport",
showName: "WFS Multchannel_Fulfillment_Details"
}, {
fromDate,
toDate,
type: "MCS"
}, { ext: 'json' }),
new TaskGroup([
new Task({
apiName: "returnsReport",
showName: "Customer returns"
}, {
new Task(
{
apiName: "salesReport",
showName: "WFS Orders",
},
{
fromDate,
toDate,
},
{ ext: "json" }
),
new Task(
{
apiName: "salesReport",
showName: "WFS Multchannel_Fulfillment_Details",
},
{
fromDate,
toDate: cut ? cutOffDate : toDate,
}, { ext: 'json' }),
new Task({
apiName: "customerReturnsReportDca",
showName: "New customer returns"
}, {
fromDate: cut ? cutOffDate : fromDate,
toDate,
}, { ext: 'json' }),
].slice(...s)),
type: "MCS",
},
{ ext: "json" }
),
new TaskGroup(
[
new Task(
{
apiName: "returnsReport",
showName: "Customer returns",
},
{
fromDate,
toDate: cut ? cutOffDate : toDate,
},
{ ext: "json" }
),
new Task(
{
apiName: "customerReturnsReportDca",
showName: "New customer returns",
},
{
fromDate: cut ? cutOffDate : fromDate,
toDate,
},
{ ext: "json" }
),
].slice(...se)
),
new Task({
apiName: "inventoryReconciliation",
showName: "Inventory reconciliation"
}, {
fromDate,
toDate,
}),
new Task({
apiName: "poAudit",
showName: "Inbound receipts"
}, {
fromDate,
toDate,
gtin: ""
}),
new Task({
apiName: "feeDetailReport",
showName: "Settlement"
}, {
startDate: fromDate,
endDate: toDate,
}),
new Task({
apiName: "storageFeeReport",
showName: "Storage"
}, {
startDate: fromDate,
endDate: toDate,
}),
new Task({
apiName: "inboundTransportationReport",
showName: "Inbound transportation"
}, {
startDate: fromDate,
endDate: toDate,
}),
new Task(
{
apiName: "inventoryReconciliation",
showName: "Inventory reconciliation",
},
{
fromDate,
toDate,
}
),
new Task(
{
apiName: "poAudit",
showName: "Inbound receipts",
},
{
fromDate,
toDate,
gtin: "",
}
),
new Task(
{
apiName: "feeDetailReport",
showName: "Settlement",
},
{
startDate: fromDate,
endDate: toDate,
}
),
new Task(
{
apiName: "storageFeeReport",
showName: "Storage",
},
{
startDate: fromDate,
endDate: toDate,
}
),
new Task(
{
apiName: "inboundTransportationReport",
showName: "Inbound transportation",
},
{
startDate: fromDate,
endDate: toDate,
}
),
new Task({
apiName: "inventoryHealthReport",
showName: "Inventory health"
}, {}, { callback: inventoryHealthCallback }),
new Task({
apiName: "inventoryHealthReport",
showName: "Inventory health mcs"
}, {
reportType: "multichannel"
}, { callback: inventoryHealthCallback }),
new Task(
{
apiName: "inventoryHealthReport",
showName: "Inventory health",
},
{},
{ callback: inventoryHealthCallback }
),
new Task(
{
apiName: "inventoryHealthReport",
showName: "Inventory health mcs",
},
{
reportType: "multichannel",
},
{ callback: inventoryHealthCallback }
),
];
}
}
......
......@@ -3,13 +3,13 @@ const p1 = [
[`11 ${hour}:`, ["01", "10"]],
[`21 ${hour}:`, ['11', '20']],
[`01 ${hour}:`, ['21', 0]],
[`03 00:`, ['01', 0]]
];
const p2 = [
[`11 ${hour}:`, ["01", "10"]],
[`21 ${hour}:`, ['11', '20']],
[`03 00:`, ['01', 0]]
[`05 00:`, ['01', 0]]
];
// const p2 = [
// [`11 ${hour}:`, ["01", "10"]],
// [`21 ${hour}:`, ['11', '20']],
// [`05 00:`, ['01', 0]]
// ];
export const TABLE = {
WFS: {
name: "WFS",
......@@ -19,7 +19,7 @@ export const TABLE = {
PAYMENT: {
name: "放款表",
uri: "https://seller.walmart.com/aurora/v1/",
params: p2
params: p1
},
GQL: {
name: "营销表",
......
import { sleep, xpath, createZip, fmt0, addLog } from "./util.js";
import { sleep, xpath, createZip, fmt0 } from "./util.js";
import { addLog } from "./timezone.js";
import { createTasks } from "./base.js";
import { Task } from "./task.js";
import { uploadFile } from "./upload.js";
......@@ -21,7 +22,9 @@ async function run(options = {}) {
const [key, { name }] = Object.entries(TABLE).find((item) => item[1].uri === uri);
let tasks = await createTasks(uri, period);
tasks = sn ? [tasks.at(sn)] : tasks;
let moment = 3000, idx = 0, len = tasks.length;
// 在季度周期过滤掉月度任务
// tasks = tasks.filter((x)=>!x.isMonthly);
let moment = 2000, idx = 0, len = tasks.length;
const allData = [], allFn = [], zipFn = `${Task.partnerId} #${key}# ${fromDate}_${toDate}.zip`;
for (const task of tasks) {
const pf = `${++idx}/${len}`;
......
......@@ -10,6 +10,80 @@ dayjs.extend(isSameOrBefore);
const CST = "Asia/Shanghai";
const PT = "America/Los_Angeles";
export class Plan {
constructor(dt, params) {
this.dt = dayjs.tz(dt ?? new Date(), CST);
this.setHandler();
this.table = new Proxy({}, this.handler);
this.params = [];
params?.forEach(param => this._addParam(...param));
}
setHandler() {
this.handler = {
dt: this.dt,
order: [], // 逆序
get(obj, prop) {
if (prop in obj) return obj[prop];
const idx = this.order.find(x => prop - x >= 0);
return obj[idx];
},
set(obj, prop, value) {
const result = Reflect.set(...arguments);
this.order = Object.keys(obj).sort((a, b) => b - a);
let [x1, x2] = value.period, dt = this.dt;
if (this.dt.date() < parseInt(x2) || x2 === 0) {
dt = this.dt.subtract(1, "month");
}
let year = dt.year();
let month = dt.month() + 1;
x2 = x2 === 0 ? dt.daysInMonth() : x2;
month = (month + '').padStart(2, "0");
value.period = [
`${year}-${month}-${x1}`,
`${year}-${month}-${x2}`
];
return result;
}
};
}
get(day = null) {
const it = day ? this.table[day] : this.table[this.dt.date()];
return it?.period;
}
next() {
let dt = this.dt;
const order = this.handler.order;
const idx = (
order.indexOf(this.get().dt.date() + '') - 1 + order.length // 向上
) % order.length;
if (idx == order.length - 1) {
dt = dt.add(1, "month");
}
let year = dt.year();
let month = dt.month();
dt = this.table[order[idx]].dt
.set("year", year)
.set("month", month);
return new Plan(dt, this.params);
}
_addParam(execTime, period) {
// MM-dd HH:mm:ss
const dt = dayjs.tz(new Date(), CST)
.set("date", +execTime.substring(0, 2))
.set("hour", +execTime.substring(3, 5));
this.table[dt.date()] = { period, dt };
this.params.push(arguments);
}
}
export const makeLogEntry = (message) => {
return {
time: dayjs.tz(new Date(), CST).format("HH:mm:ss"),
message
}
};
export const addLog = (message, push) => chrome.runtime.sendMessage({ type: "addLog", data: makeLogEntry(message), push });
const checkTime = (time) => {
if (!time.isValid()) throw new Error("无效时间");
}
......@@ -38,7 +112,7 @@ export function isLatestDate(dt) {
const time = dayjs.tz(dt ?? new Date(), PT);
checkTime(time);
const now = dayjs.tz(undefined, PT);
return time.isSame(now, "day")
return time.isSame(now, "day")
|| time.isSame(now.subtract(1, "day"), "day")
|| time.isSame(now.add(1, "day"), "day");
}
......
......@@ -131,70 +131,6 @@ export function downloadFile(fn, blob) {
a.remove();
URL.revokeObjectURL(url);
}
export class Plan {
constructor(dt, params) {
this.dt = dt = dt && new Date(dt) || new Date();
this.handler = {
order: [], // 逆序
get(obj, prop) {
if (prop in obj) return obj[prop];
const idx = this.order.find(x => prop - x >= 0);
return obj[idx];
},
set(obj, prop, value) {
const result = Reflect.set(...arguments);
this.order = Object.keys(obj).sort((a, b) => b - a);
let [x1, x2] = value.period;
let year = dt.getFullYear();
let month = dt.getMonth();
if (dt.getDate() < parseInt(x2) || x2 === 0) {
month = month == 0 ? 11 : month - 1;
year = month == 0 ? year - 1 : year;
}
month++;
const endDate = new Date(year, month, 0).getDate() + '';
x2 = x2 === 0 ? endDate : x2;
month = (month + '').padStart(2, '0');
value.period = [
`${year}-${month}-${x1}`,
`${year}-${month}-${x2}`
];
return result;
}
}
this.table = new Proxy({}, this.handler);
this.params = [];
params?.forEach(args => this._addParam(...args));
}
get(day = null) {
return day ? this.table[day] : this.table[this.dt.getDate()];
}
next() {
let year = this.dt.getFullYear();
let month = this.dt.getMonth() + 1;
const order = this.handler.order;
const idx = (
order.indexOf(this.get().day) - 1 + order.length // 向上
) % order.length;
if (idx == order.length - 1) {
month = month == 12 ? 1 : month + 1;
year = month == 12 ? year + 1 : year;
}
const info = this.table[order[idx]];
return new Plan(new Date(`${year}-${month}-${info.day} ${info.time}`), this.params);
}
_addParam(execTime, period) {
// MM-dd HH:mm:ss
const dt = new Date(`01-${execTime}`);
this.table[dt.getDate()] = {
period,
day: dt.getDate() + '',
time: `${dt.toTimeString().substring(0, 8)}`,
};
this.params.push(arguments);
}
}
export function fmt0(d1, diff = 0) {
const dt1 = new Date(d1);
dt1.setDate(d1.getDate() + diff);
......@@ -224,10 +160,3 @@ export function ffmt1(d1, d2) {
const dt2 = new Date(d2);
return `${dt1.getMonth() + 1}${dt1.getDate()}-${dt2.getDate()}`;
}
export const addLog = (message, push) => {
const logEntry = {
time: new Date().toLocaleTimeString(),
message
};
chrome.runtime.sendMessage({ type: "addLog", data: logEntry, push });
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment