iphone-xudale 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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)
|