iphone-xudale 0.2.9
Sign up to get free protection for your applications and to get access to all the features.
- package/.eslintrc.json +3 -0
- package/app/(pages)/options/page.tsx +720 -0
- package/app/(pages)/popup/page.tsx +166 -0
- package/app/(pages)/tips/page.tsx +40 -0
- package/app/components/DropListBox.tsx +157 -0
- package/app/components/SVGPlay.tsx +14 -0
- package/app/favicon.ico +0 -0
- package/app/globals.css +27 -0
- package/app/layout.tsx +15 -0
- package/app/page.tsx +3 -0
- package/app/scripts/content/checkoutSteps.ts +341 -0
- package/app/scripts/content/doFroApplePages.ts +206 -0
- package/app/scripts/content/getPageInitInfo.ts +49 -0
- package/app/scripts/content/getStoreCanPickInfo.ts +251 -0
- package/app/scripts/content/goOrderSteps.ts +179 -0
- package/app/scripts/content/index.ts +56 -0
- package/app/scripts/content/playSystemNotifacation.ts +39 -0
- package/app/scripts/content/sendSelfNotificatioin.ts +27 -0
- package/app/scripts/inject/index.ts +18 -0
- package/app/shared/constants.ts +236 -0
- package/app/shared/interface.ts +25 -0
- package/app/shared/location/city.json +1774 -0
- package/app/shared/location/county.json +17115 -0
- package/app/shared/location/province.json +94 -0
- package/app/shared/util.ts +93 -0
- package/buildAfter.js +86 -0
- package/bunBuild.ts +54 -0
- package/extension/content-script.js +7 -0
- package/extension/favicon.ico +0 -0
- package/extension/icons/icon128.png +0 -0
- package/extension/icons/icon16.png +0 -0
- package/extension/icons/icon19-disable.png +0 -0
- package/extension/icons/icon19.png +0 -0
- package/extension/icons/icon32.png +0 -0
- package/extension/icons/icon38.png +0 -0
- package/extension/icons/icon48.png +0 -0
- package/extension/inject-script.js +1 -0
- package/extension/manifest.json +38 -0
- package/extension/service-worker.js +62 -0
- package/extension.next.config.js +25 -0
- package/icon_generator.py +30 -0
- package/middleware.ts +21 -0
- package/next.config.js +15 -0
- package/package.json +67 -0
- package/postcss.config.js +6 -0
- package/public/assets/images/SCR-20230916-nbkz.png +0 -0
- package/public/assets/images/SCR-20230916-nbyv.png +0 -0
- package/public/assets/images/SCR-20230916-ncte.png +0 -0
- package/public/assets/images/SCR-20230916-ndgw.png +0 -0
- package/public/assets/images/SCR-20230916-ndks.png +0 -0
- package/public/assets/images/SCR-20230916-neaa.png +0 -0
- package/public/assets/images/SCR-20230916-neeq.jpeg +0 -0
- package/public/assets/images/SCR-20230916-nfkt.png +0 -0
- package/public/assets/images/SCR-20230919-ulfn.png +0 -0
- package/public/assets/images/SCR-20230919-ulzd.png +0 -0
- package/public/assets/images/SCR-20230919-uocr.png +0 -0
- package/public/icon_original.png +0 -0
- package/public/next.svg +1 -0
- package/public/vercel.svg +1 -0
- package/tailwind.config.ts +20 -0
- package/tsconfig.json +27 -0
- package/types/global.d.ts +19 -0
@@ -0,0 +1,251 @@
|
|
1
|
+
import { IPHONEORDER_CONFIG } from '@/app/shared/interface'
|
2
|
+
import { applePageUrl, iPhoneModels, fetchHeaders, defaultAres } from '@/app/shared/constants'
|
3
|
+
import { sleep, randomSleep } from '@/app/shared/util'
|
4
|
+
import crossfetch from 'cross-fetch'
|
5
|
+
import { each as _each, map as _map } from 'lodash'
|
6
|
+
|
7
|
+
const fetch = crossfetch.bind(this)
|
8
|
+
|
9
|
+
/*
|
10
|
+
* @partNumber iPhone 型号
|
11
|
+
* @isNoWait 是否等待,不等待表示纯粹调用接口
|
12
|
+
*/
|
13
|
+
interface IGetStoreCanPickInfoProps {
|
14
|
+
x_aos_stk: string
|
15
|
+
partNumber: string
|
16
|
+
isNoWait?: boolean
|
17
|
+
iPhoneOrderConfig: IPHONEORDER_CONFIG
|
18
|
+
}
|
19
|
+
const getStoreCanPickInfo = async ({
|
20
|
+
x_aos_stk,
|
21
|
+
partNumber,
|
22
|
+
isNoWait,
|
23
|
+
iPhoneOrderConfig,
|
24
|
+
}: IGetStoreCanPickInfoProps) => {
|
25
|
+
storeSearchInPage({ iPhoneOrderConfig })
|
26
|
+
let pickupStoreInfo: Record<string, any> = {}
|
27
|
+
const { host, protocol } = window.location || {}
|
28
|
+
// let url = `${protocol}//www.apple.com.cn/shop/fulfillment-messages`
|
29
|
+
let url = `/shop/checkoutx?_a=search&_m=checkout.fulfillment.pickupTab.pickup.storeLocator`
|
30
|
+
|
31
|
+
const districtName = iPhoneOrderConfig.districtName || defaultAres.districtName
|
32
|
+
const provinceName = iPhoneOrderConfig.provinceName || defaultAres.provinceName
|
33
|
+
const cityName = iPhoneOrderConfig.cityName || defaultAres.cityName
|
34
|
+
let reqQuery = {
|
35
|
+
'parts.0': partNumber, // 型号 `MQ8G3CH/A`,
|
36
|
+
'mts.0': `regular`,
|
37
|
+
pl: true,
|
38
|
+
location: `${provinceName} ${cityName} ${districtName}`,
|
39
|
+
geoLocated: false,
|
40
|
+
state: provinceName,
|
41
|
+
city: cityName,
|
42
|
+
district: districtName,
|
43
|
+
}
|
44
|
+
|
45
|
+
const querystring = _map(reqQuery, (value, key) => {
|
46
|
+
return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
|
47
|
+
}).join(`&`)
|
48
|
+
|
49
|
+
let dataString = '',
|
50
|
+
data = []
|
51
|
+
const provinceCityDistrict =
|
52
|
+
provinceName == cityName ? cityName + ' ' + districtName : provinceName + ' ' + cityName + ' ' + districtName
|
53
|
+
data = [
|
54
|
+
`checkout.fulfillment.pickupTab.pickup.storeLocator.showAllStores=false`,
|
55
|
+
`checkout.fulfillment.pickupTab.pickup.storeLocator.selectStore=`,
|
56
|
+
`checkout.fulfillment.pickupTab.pickup.storeLocator.searchInput=${encodeURIComponent(
|
57
|
+
provinceName + ' ' + cityName + ' ' + districtName
|
58
|
+
)}`,
|
59
|
+
`checkout.fulfillment.pickupTab.pickup.storeLocator.address.stateCitySelectorForCheckout.city=${encodeURIComponent(
|
60
|
+
cityName
|
61
|
+
)}`,
|
62
|
+
`checkout.fulfillment.pickupTab.pickup.storeLocator.address.stateCitySelectorForCheckout.state=${encodeURIComponent(
|
63
|
+
provinceName
|
64
|
+
)}`,
|
65
|
+
`checkout.fulfillment.pickupTab.pickup.storeLocator.address.stateCitySelectorForCheckout.provinceCityDistrict=${encodeURIComponent(
|
66
|
+
provinceCityDistrict
|
67
|
+
)}`,
|
68
|
+
`checkout.fulfillment.pickupTab.pickup.storeLocator.address.stateCitySelectorForCheckout.countryCode=CN`,
|
69
|
+
`checkout.fulfillment.pickupTab.pickup.storeLocator.address.stateCitySelectorForCheckout.district=${encodeURIComponent(
|
70
|
+
districtName
|
71
|
+
)}`,
|
72
|
+
]
|
73
|
+
dataString = data.join(`&`)
|
74
|
+
|
75
|
+
let options = {
|
76
|
+
method: 'POST',
|
77
|
+
headers: {
|
78
|
+
...fetchHeaders,
|
79
|
+
referer: applePageUrl.buyiPhone,
|
80
|
+
'X-Aos-Model-Page': 'checkoutPage',
|
81
|
+
'X-Aos-Stk': x_aos_stk,
|
82
|
+
},
|
83
|
+
credentials: 'include' as RequestCredentials,
|
84
|
+
body: dataString,
|
85
|
+
}
|
86
|
+
|
87
|
+
console.log(`getStoreCanPickInfo options`, options)
|
88
|
+
try {
|
89
|
+
let resResult = (await fetch(url, options)) as Record<string, any>
|
90
|
+
|
91
|
+
let pickupResults: any = {}
|
92
|
+
|
93
|
+
// 如果请求失败, 表示被封禁
|
94
|
+
if (![200, 301, 302].includes(Number(resResult?.status))) {
|
95
|
+
if (!isNoWait) {
|
96
|
+
console.log(`********** GMfetch failed, stepWait add 1 sec **********`)
|
97
|
+
const resText = await resResult.text()
|
98
|
+
// console.log(`resText`, resText)
|
99
|
+
iPhoneOrderConfig.stepWait = iPhoneOrderConfig.stepWait + 1
|
100
|
+
if (resText?.indexOf(`503 Service Temporarily Unavailable`) > -1) {
|
101
|
+
console.log(`********** and wait 1 min **********`)
|
102
|
+
// 换一个型号调用,让apple认为是正常请求
|
103
|
+
const iPhoneProAll = iPhoneModels.iPhone15Pro
|
104
|
+
const randomPartNumberiPhonePro =
|
105
|
+
iPhoneProAll[Math.floor(Math.random() * iPhoneProAll.length)]?.model
|
106
|
+
await getStoreCanPickInfo({
|
107
|
+
x_aos_stk,
|
108
|
+
partNumber: randomPartNumberiPhonePro,
|
109
|
+
isNoWait: true,
|
110
|
+
iPhoneOrderConfig,
|
111
|
+
})
|
112
|
+
await sleep(60)
|
113
|
+
}
|
114
|
+
} else {
|
115
|
+
console.log(`********** GMfetch failed, NoWait failed **********`)
|
116
|
+
}
|
117
|
+
} else {
|
118
|
+
const resJson = await resResult.json()
|
119
|
+
console.log(`resJson`, resJson)
|
120
|
+
pickupResults =
|
121
|
+
resJson?.body?.checkout?.fulfillment?.pickupTab?.pickup?.storeLocator?.searchResults?.d || {}
|
122
|
+
}
|
123
|
+
|
124
|
+
let partPickupStores = pickupResults?.retailStores || [],
|
125
|
+
pickupNumbers = ''
|
126
|
+
_each(partPickupStores, store => {
|
127
|
+
const {
|
128
|
+
retailAddress,
|
129
|
+
storeDisabled,
|
130
|
+
pickupMessages,
|
131
|
+
availability,
|
132
|
+
storeId: storeNumber,
|
133
|
+
storeName,
|
134
|
+
} = store || {}
|
135
|
+
const { availableNowForAllLines } = availability || {}
|
136
|
+
const { city } = retailAddress || {}
|
137
|
+
// 有时候会搜出周边城市,这里用于排除周边城市
|
138
|
+
const isInCity = city == cityName
|
139
|
+
if (isInCity && pickupMessages?.length && (!storeDisabled || availableNowForAllLines)) {
|
140
|
+
pickupStoreInfo = {
|
141
|
+
...pickupStoreInfo,
|
142
|
+
storeNumber,
|
143
|
+
storeName,
|
144
|
+
availableNowForAllLines,
|
145
|
+
}
|
146
|
+
return false
|
147
|
+
}
|
148
|
+
})
|
149
|
+
} catch (e) {
|
150
|
+
console.log(e)
|
151
|
+
if (!isNoWait) {
|
152
|
+
console.log(`********** GMfetch failed, stepWait add 1 sec, and wait 1 min **********`)
|
153
|
+
iPhoneOrderConfig.stepWait = iPhoneOrderConfig.stepWait + 1
|
154
|
+
// 换一个型号调用,让apple认为是正常请求
|
155
|
+
const iPhoneProAll = iPhoneModels.iPhone15Pro
|
156
|
+
const randomPartNumberiPhonePro = iPhoneProAll[Math.floor(Math.random() * iPhoneProAll.length)]?.model
|
157
|
+
await getStoreCanPickInfo({
|
158
|
+
x_aos_stk,
|
159
|
+
partNumber: randomPartNumberiPhonePro,
|
160
|
+
isNoWait: true,
|
161
|
+
iPhoneOrderConfig,
|
162
|
+
})
|
163
|
+
await sleep(10)
|
164
|
+
} else {
|
165
|
+
console.log(`********** GMfetch failed, NoWait failed **********`)
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
console.log(`pickupStoreInfo`, pickupStoreInfo)
|
170
|
+
return pickupStoreInfo
|
171
|
+
}
|
172
|
+
|
173
|
+
export default getStoreCanPickInfo
|
174
|
+
|
175
|
+
interface IStoreSearchInPageProps {
|
176
|
+
iPhoneOrderConfig: IPHONEORDER_CONFIG
|
177
|
+
}
|
178
|
+
|
179
|
+
const randomRange = 3
|
180
|
+
const storeSearchInPage = async ({ iPhoneOrderConfig }: IStoreSearchInPageProps) => {
|
181
|
+
const storeSearchDataAutom = `fulfillment-pickup-store-search-button`
|
182
|
+
const storeSearchBtn = document.querySelector(`button[data-autom="${storeSearchDataAutom}"]`)
|
183
|
+
if (!storeSearchBtn) return
|
184
|
+
const { cityName, districtName, provinceName } = iPhoneOrderConfig
|
185
|
+
|
186
|
+
if (!cityName || !districtName || !provinceName) return
|
187
|
+
|
188
|
+
// 已纠正的情况下,不需要重复点击了
|
189
|
+
if (storeSearchBtn.textContent) {
|
190
|
+
if (storeSearchBtn.textContent.includes(districtName) && storeSearchBtn.textContent.includes(provinceName)) {
|
191
|
+
return
|
192
|
+
}
|
193
|
+
}
|
194
|
+
|
195
|
+
await randomSleep({ min: 0, max: randomRange })
|
196
|
+
const isSelectionOpen = document.querySelectorAll(`li[role="listitem"]>button`)?.length > 0
|
197
|
+
|
198
|
+
if (!isSelectionOpen) {
|
199
|
+
;(storeSearchBtn as HTMLButtonElement).click()
|
200
|
+
}
|
201
|
+
|
202
|
+
await randomSleep({ min: 0, max: randomRange })
|
203
|
+
|
204
|
+
const provinceTabBtn = document.getElementById(
|
205
|
+
'checkout.fulfillment.pickupTab.pickup.storeLocator.address.stateCitySelectorForCheckout.state'
|
206
|
+
)
|
207
|
+
provinceTabBtn?.click()
|
208
|
+
|
209
|
+
let hasTheProvince = false
|
210
|
+
if (provinceName) {
|
211
|
+
const provinceItems = document.querySelectorAll(`li[role="listitem"]>button`)
|
212
|
+
_each(provinceItems, p_item => {
|
213
|
+
if (p_item?.textContent?.includes(provinceName)) {
|
214
|
+
;(p_item as HTMLButtonElement)?.click()
|
215
|
+
hasTheProvince = true
|
216
|
+
return false
|
217
|
+
}
|
218
|
+
})
|
219
|
+
await randomSleep({ min: 0, max: randomRange })
|
220
|
+
}
|
221
|
+
|
222
|
+
const cityTabBtn = document.getElementById(
|
223
|
+
`checkout.fulfillment.pickupTab.pickup.storeLocator.address.stateCitySelectorForCheckout.city`
|
224
|
+
)
|
225
|
+
cityTabBtn?.click()
|
226
|
+
if (hasTheProvince && cityName && cityName != provinceName && cityTabBtn) {
|
227
|
+
const cityItems = document.querySelectorAll(`li[role="listitem"]>button`)
|
228
|
+
_each(cityItems, p_item => {
|
229
|
+
if (p_item?.textContent?.includes(cityName)) {
|
230
|
+
;(p_item as HTMLButtonElement)?.click()
|
231
|
+
return false
|
232
|
+
}
|
233
|
+
})
|
234
|
+
await randomSleep({ min: 0, max: randomRange })
|
235
|
+
}
|
236
|
+
|
237
|
+
const districtTabBtn = document.getElementById(
|
238
|
+
`checkout.fulfillment.pickupTab.pickup.storeLocator.address.stateCitySelectorForCheckout.district`
|
239
|
+
)
|
240
|
+
districtTabBtn?.click()
|
241
|
+
if (districtName && districtTabBtn) {
|
242
|
+
const districtItems = document.querySelectorAll(`li[role="listitem"]>button`)
|
243
|
+
_each(districtItems, p_item => {
|
244
|
+
if (p_item?.textContent?.includes(districtName)) {
|
245
|
+
;(p_item as HTMLButtonElement)?.click()
|
246
|
+
return false
|
247
|
+
}
|
248
|
+
})
|
249
|
+
await randomSleep({ min: 0, max: randomRange })
|
250
|
+
}
|
251
|
+
}
|
@@ -0,0 +1,179 @@
|
|
1
|
+
import getStoreCanPickInfo from './getStoreCanPickInfo'
|
2
|
+
import checkoutSteps from './checkoutSteps'
|
3
|
+
import type { IPHONEORDER_CONFIG } from '@/app/shared/interface'
|
4
|
+
import { CHECKOUT_STEPS, BILL_OPTIONS_TYPE } from '@/app/shared/constants'
|
5
|
+
import { sleep } from '@/app/shared/util'
|
6
|
+
import { isEmpty as _isEmpty, each as _each, some as _some } from 'lodash'
|
7
|
+
import { iframeMessagePass } from '@/app/shared/constants'
|
8
|
+
|
9
|
+
interface IGoOrderSteps {
|
10
|
+
partNumber: string
|
11
|
+
x_aos_stk: string
|
12
|
+
count?: number
|
13
|
+
iPhoneOrderConfig: IPHONEORDER_CONFIG
|
14
|
+
}
|
15
|
+
|
16
|
+
const goOrderSteps = async ({ partNumber, x_aos_stk, count, iPhoneOrderConfig }: IGoOrderSteps) => {
|
17
|
+
count = count || 1 // 重试次数
|
18
|
+
const { afterCountThenReload = 50 } = iPhoneOrderConfig || {}
|
19
|
+
// ********** 发送消息给 tips page **********
|
20
|
+
const iframeWindow = (document?.getElementById(iframeMessagePass.iframeID) as HTMLIFrameElement)?.contentWindow
|
21
|
+
const message = { action: iframeMessagePass.messageAction, count: count, beforeReload: afterCountThenReload }
|
22
|
+
iframeWindow?.postMessage(message, '*')
|
23
|
+
|
24
|
+
// 获取可以提货的商店信息
|
25
|
+
let pickupStoreInfo = await getStoreCanPickInfo({ x_aos_stk, partNumber, iPhoneOrderConfig })
|
26
|
+
|
27
|
+
const { storeNumber, availableNowForAllLines } = pickupStoreInfo || {}
|
28
|
+
const { host, protocol } = location || {}
|
29
|
+
|
30
|
+
if (storeNumber) {
|
31
|
+
// 走第一步, 选店,获取提货时间
|
32
|
+
let canPickupTime = await checkoutSteps({
|
33
|
+
step: CHECKOUT_STEPS.selectStore,
|
34
|
+
x_aos_stk,
|
35
|
+
stepInfo: {
|
36
|
+
storeNumber,
|
37
|
+
},
|
38
|
+
iPhoneOrderConfig,
|
39
|
+
})
|
40
|
+
console.log(`firstStep:`, canPickupTime)
|
41
|
+
|
42
|
+
const timeSlot = canPickupTime?.timeSlot as Record<string, any>
|
43
|
+
const noNeedTimeSlot = canPickupTime?.noNeedTimeSlot
|
44
|
+
const canPickup = canPickupTime?.isSuccess
|
45
|
+
if (!canPickup) return
|
46
|
+
|
47
|
+
if (noNeedTimeSlot) {
|
48
|
+
// 所有时间可取货,直接走 checkoutFulfillment
|
49
|
+
let canCheckout = await checkoutSteps({
|
50
|
+
noNeedTimeSlot,
|
51
|
+
step: CHECKOUT_STEPS.checkoutFulfillment,
|
52
|
+
x_aos_stk,
|
53
|
+
stepInfo: {
|
54
|
+
storeNumber,
|
55
|
+
},
|
56
|
+
iPhoneOrderConfig,
|
57
|
+
})
|
58
|
+
|
59
|
+
if (!canCheckout?.isSuccess) return
|
60
|
+
} else {
|
61
|
+
// 第二步, 选日期时间
|
62
|
+
let pickupTimeInStore = await checkoutSteps({
|
63
|
+
step: CHECKOUT_STEPS.selectPickupTime,
|
64
|
+
noNeedTimeSlot,
|
65
|
+
x_aos_stk,
|
66
|
+
stepInfo: {
|
67
|
+
storeNumber,
|
68
|
+
...timeSlot,
|
69
|
+
},
|
70
|
+
iPhoneOrderConfig,
|
71
|
+
})
|
72
|
+
|
73
|
+
if (!pickupTimeInStore?.isSuccess) return
|
74
|
+
}
|
75
|
+
// 第三步 填写证件信息
|
76
|
+
let addContactResult = await checkoutSteps({
|
77
|
+
step: CHECKOUT_STEPS.pickupContact,
|
78
|
+
x_aos_stk,
|
79
|
+
stepInfo: {
|
80
|
+
lastName: iPhoneOrderConfig.lastName,
|
81
|
+
firstName: iPhoneOrderConfig.firstName,
|
82
|
+
emailAddress: iPhoneOrderConfig.appleId,
|
83
|
+
fullDaytimePhone: iPhoneOrderConfig.mobile,
|
84
|
+
nationalIdSelf: iPhoneOrderConfig.last4code,
|
85
|
+
},
|
86
|
+
iPhoneOrderConfig,
|
87
|
+
})
|
88
|
+
const { allBillingOptions } = addContactResult || {}
|
89
|
+
|
90
|
+
if (!addContactResult?.isSuccess) return
|
91
|
+
|
92
|
+
let selectBillType = BILL_OPTIONS_TYPE[iPhoneOrderConfig.payBill] || BILL_OPTIONS_TYPE.alipay
|
93
|
+
let selectBillValue = 'ALIPAY'
|
94
|
+
|
95
|
+
if (!_isEmpty(allBillingOptions)) {
|
96
|
+
_each(allBillingOptions, bill_option => {
|
97
|
+
const { label, labelImageAlt, a11yLabel, value } = bill_option || {}
|
98
|
+
const labelText = label || labelImageAlt || a11yLabel || ''
|
99
|
+
if (labelText.indexOf(selectBillType) > -1) {
|
100
|
+
selectBillValue = value || 'ALIPAY'
|
101
|
+
return false
|
102
|
+
}
|
103
|
+
})
|
104
|
+
}
|
105
|
+
// 第四步一, 选择付款方式
|
106
|
+
let addBill = await checkoutSteps({
|
107
|
+
step: CHECKOUT_STEPS.selectBill,
|
108
|
+
x_aos_stk,
|
109
|
+
stepInfo: {
|
110
|
+
billOption: selectBillValue,
|
111
|
+
billInstallment: iPhoneOrderConfig.payInstallment, // 分期
|
112
|
+
},
|
113
|
+
iPhoneOrderConfig,
|
114
|
+
})
|
115
|
+
|
116
|
+
if (!addBill?.isSuccess) return
|
117
|
+
|
118
|
+
if (iPhoneOrderConfig.payInstallment && iPhoneOrderConfig.payInstallment > 0) {
|
119
|
+
const { installmentOptions = [] } = addBill || {}
|
120
|
+
// 判断传入的分期是否合法
|
121
|
+
let isPayInstallmentValidated = _some(installmentOptions, item => {
|
122
|
+
return item?.value == iPhoneOrderConfig.payInstallment
|
123
|
+
})
|
124
|
+
if (!isPayInstallmentValidated) {
|
125
|
+
iPhoneOrderConfig.payInstallment = installmentOptions[installmentOptions?.length - 1]?.value || 0
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
let confirmBillStepsInfo: Record<string, any> = {
|
130
|
+
billOption: selectBillValue,
|
131
|
+
}
|
132
|
+
if (iPhoneOrderConfig.payInstallment) {
|
133
|
+
confirmBillStepsInfo = {
|
134
|
+
...confirmBillStepsInfo,
|
135
|
+
billInstallment: iPhoneOrderConfig.payInstallment, // 分期
|
136
|
+
}
|
137
|
+
}
|
138
|
+
// 第四步二,确认付款方式
|
139
|
+
let confirmBill = await checkoutSteps({
|
140
|
+
step: CHECKOUT_STEPS.checkoutBill,
|
141
|
+
x_aos_stk,
|
142
|
+
stepInfo: {
|
143
|
+
...confirmBillStepsInfo,
|
144
|
+
},
|
145
|
+
iPhoneOrderConfig,
|
146
|
+
})
|
147
|
+
|
148
|
+
if (!confirmBill?.isSuccess) return
|
149
|
+
|
150
|
+
// 最后下单
|
151
|
+
let placeOrderRes = await checkoutSteps({
|
152
|
+
step: CHECKOUT_STEPS.placeOrder,
|
153
|
+
x_aos_stk,
|
154
|
+
stepInfo: {},
|
155
|
+
iPhoneOrderConfig,
|
156
|
+
})
|
157
|
+
|
158
|
+
if (placeOrderRes?.isSuccess) {
|
159
|
+
let jumpUrl = `${protocol}//${host}/shop/checkout/interstitial`
|
160
|
+
if (placeOrderRes?.url) {
|
161
|
+
// `${protocol}//${host}/shop/checkout/status`
|
162
|
+
jumpUrl = `${protocol}//${host}${placeOrderRes.url || ''}`
|
163
|
+
}
|
164
|
+
|
165
|
+
location.href = jumpUrl
|
166
|
+
}
|
167
|
+
} else if (count >= afterCountThenReload) {
|
168
|
+
await sleep(1, `goOrderSteps failed over ${afterCountThenReload} times, then reload page`)
|
169
|
+
location.reload()
|
170
|
+
} else {
|
171
|
+
await sleep(
|
172
|
+
iPhoneOrderConfig.stepWait,
|
173
|
+
`goOrderSteps again, count: ${count}, limit times: ${afterCountThenReload}`
|
174
|
+
)
|
175
|
+
await goOrderSteps({ partNumber, x_aos_stk, count: count + 1, iPhoneOrderConfig })
|
176
|
+
}
|
177
|
+
}
|
178
|
+
|
179
|
+
export default goOrderSteps
|
@@ -0,0 +1,56 @@
|
|
1
|
+
import doFroApplePages from './doFroApplePages'
|
2
|
+
import { iframeMessagePass } from '@/app/shared/constants'
|
3
|
+
import playSystemNotification from './playSystemNotifacation'
|
4
|
+
|
5
|
+
// @ts-ignore
|
6
|
+
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
7
|
+
const { data, voiceInfo } = message || {}
|
8
|
+
const { text } = voiceInfo || {}
|
9
|
+
if (data == 'playSystemNotification' && text) {
|
10
|
+
playSystemNotification({ voiceInfo: voiceInfo })
|
11
|
+
}
|
12
|
+
})
|
13
|
+
|
14
|
+
const addTipsToPage = () => {
|
15
|
+
var extensionId = chrome.runtime.id
|
16
|
+
const iframe = document.createElement('iframe')
|
17
|
+
iframe.id = iframeMessagePass.iframeID
|
18
|
+
iframe.style.cssText = `
|
19
|
+
right: 0;
|
20
|
+
top: 50%;
|
21
|
+
width: 250px;
|
22
|
+
height: 160px;
|
23
|
+
`
|
24
|
+
iframe.src = `chrome-extension://${extensionId}/dist/tips.html`
|
25
|
+
document.documentElement.appendChild(iframe)
|
26
|
+
iframe.style.position = 'fixed'
|
27
|
+
console.log(`addTipsToPage`)
|
28
|
+
}
|
29
|
+
|
30
|
+
console.log(`this is content`)
|
31
|
+
const contentRun = async () => {
|
32
|
+
addTipsToPage()
|
33
|
+
|
34
|
+
// const orderEnabled = !!(await restoreFromStorage(storeKeys.orderEnabled))
|
35
|
+
// console.log(`orderEnabled`, orderEnabled)
|
36
|
+
// if (!orderEnabled) return
|
37
|
+
await doFroApplePages()
|
38
|
+
}
|
39
|
+
|
40
|
+
contentRun()
|
41
|
+
|
42
|
+
window.addEventListener('message', function (event) {
|
43
|
+
if (event.source === window && event.data.action === 'doFroApplePages') {
|
44
|
+
// 在这里执行你的方法逻辑
|
45
|
+
doFroApplePages(event.data.url)
|
46
|
+
}
|
47
|
+
})
|
48
|
+
|
49
|
+
// 监听页面的加载完成事件, 注入自定义脚本到页面中
|
50
|
+
window.addEventListener('load', function injectCustomScript() {
|
51
|
+
var script = document.createElement('script')
|
52
|
+
var extensionId = chrome.runtime.id
|
53
|
+
console.log(extensionId)
|
54
|
+
script.src = `chrome-extension://${extensionId}/inject-script.js`
|
55
|
+
document.documentElement.appendChild(script)
|
56
|
+
})
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import { VOICE_OBJ } from '@/app/shared/interface'
|
2
|
+
|
3
|
+
const defaultVoiceInfo = {
|
4
|
+
text: `抢到了`,
|
5
|
+
times: 1,
|
6
|
+
}
|
7
|
+
|
8
|
+
const playSystemNotification = async ({ voiceInfo }: { voiceInfo: VOICE_OBJ }) => {
|
9
|
+
let extensionId
|
10
|
+
if (typeof chrome !== 'undefined' && chrome?.runtime) {
|
11
|
+
extensionId = chrome.runtime.id
|
12
|
+
chrome.runtime.sendMessage({ data: 'bellring', extensionId, voiceInfo })
|
13
|
+
}
|
14
|
+
|
15
|
+
// 检查浏览器是否支持 Web Notifications API
|
16
|
+
if ('Notification' in window) {
|
17
|
+
const icon = extensionId ? `chrome-extension://${extensionId}/icons/icon38.png` : undefined
|
18
|
+
// 请求权限显示通知
|
19
|
+
Notification.requestPermission().then(permission => {
|
20
|
+
if (permission === 'granted') {
|
21
|
+
// 创建通知对象
|
22
|
+
const notification = new Notification('提醒', {
|
23
|
+
body: voiceInfo?.text || defaultVoiceInfo.text,
|
24
|
+
icon,
|
25
|
+
})
|
26
|
+
|
27
|
+
// 将通知点击时的行为处理逻辑添加在这里
|
28
|
+
notification.onclick = function () {
|
29
|
+
// 处理通知点击事件
|
30
|
+
console.log('通知被点击了')
|
31
|
+
}
|
32
|
+
}
|
33
|
+
})
|
34
|
+
} else {
|
35
|
+
console.log(`notification fail`)
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
export default playSystemNotification
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import { sleep } from '@/app/shared/util'
|
2
|
+
|
3
|
+
const sendSelfNotificatioin = async ({ url }: { url?: string }) => {
|
4
|
+
if (!url) return
|
5
|
+
|
6
|
+
return Promise.race([
|
7
|
+
sleep(5),
|
8
|
+
new Promise((resolve, reject) => {
|
9
|
+
const img = new Image()
|
10
|
+
img.src = url
|
11
|
+
img.style.display = 'none'
|
12
|
+
img.style.width = '1px'
|
13
|
+
img.style.height = '1px'
|
14
|
+
document.body.appendChild(img)
|
15
|
+
img.addEventListener('load', function () {
|
16
|
+
console.log('请求成功')
|
17
|
+
resolve(true)
|
18
|
+
})
|
19
|
+
img.addEventListener('error', function () {
|
20
|
+
console.log('请求失败')
|
21
|
+
resolve(false)
|
22
|
+
})
|
23
|
+
}),
|
24
|
+
])
|
25
|
+
}
|
26
|
+
|
27
|
+
export default sendSelfNotificatioin
|
@@ -0,0 +1,18 @@
|
|
1
|
+
;(function (history) {
|
2
|
+
var originalPushState = history.pushState
|
3
|
+
|
4
|
+
history.pushState = function (state, title, url) {
|
5
|
+
if (typeof history.onpushstate == 'function') {
|
6
|
+
history.onpushstate({ state: state })
|
7
|
+
}
|
8
|
+
|
9
|
+
// @ts-ignore
|
10
|
+
url = url && url.search(/^http/) > -1 ? url : ''
|
11
|
+
|
12
|
+
window.postMessage({ action: 'doFroApplePages', url: url }, '*')
|
13
|
+
// 调用原生的 history.pushState 方法
|
14
|
+
// @ts-ignore
|
15
|
+
return originalPushState.apply(history, arguments)
|
16
|
+
}
|
17
|
+
console.log(history.pushState)
|
18
|
+
})(history)
|