mirror of
https://github.com/primedigitaltech/azon_seeker.git
synced 2026-02-08 16:37:01 +08:00
feat: enhance waitForPageLoaded
This commit is contained in:
parent
6f15a8bcb5
commit
cb249dba87
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "azon-seeker",
|
"name": "azon-seeker",
|
||||||
"displayName": "Azon Seeker v0.7.1.2-beta",
|
"displayName": "Azon Seeker v0.7.1.4-beta",
|
||||||
"version": "0.7.2",
|
"version": "0.7.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "Starter modify by honestfox101 and PetrichorFun",
|
"description": "Starter modify by honestfox101 and PetrichorFun",
|
||||||
|
|||||||
@ -10,6 +10,8 @@ export function useLongTask() {
|
|||||||
try {
|
try {
|
||||||
result = await task();
|
result = await task();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
|
||||||
console.error('Task failed:', error);
|
console.error('Task failed:', error);
|
||||||
}
|
}
|
||||||
isRunning.value = false;
|
isRunning.value = false;
|
||||||
|
|||||||
@ -15,6 +15,7 @@ export function isForbiddenUrl(url: string): boolean {
|
|||||||
export const isFirefox = navigator.userAgent.includes('Firefox');
|
export const isFirefox = navigator.userAgent.includes('Firefox');
|
||||||
|
|
||||||
// export const remoteHost = __DEV__ ? '127.0.0.1:8000' : '47.251.4.191:8000';
|
// export const remoteHost = __DEV__ ? '127.0.0.1:8000' : '47.251.4.191:8000';
|
||||||
export const remoteHost = __DEV__ ? '127.0.0.1:18000' : 'vm8nc3zr-18000.usw2.devtunnels.ms';
|
// export const remoteHost = __DEV__ ? '127.0.0.1:18000' : 'vm8nc3zr-18000.usw2.devtunnels.ms';
|
||||||
|
export const remoteHost = __DEV__ ? '127.0.0.1:18000' : '47.251.4.191:8000';
|
||||||
|
|
||||||
// export const remoteHost = '47.251.4.191:8000';
|
// export const remoteHost = '47.251.4.191:8000';
|
||||||
|
|||||||
@ -48,6 +48,11 @@ export async function exec<T, P extends Record<string, unknown>>(
|
|||||||
): Promise<T> {
|
): Promise<T> {
|
||||||
const { timeout = 30000 } = options;
|
const { timeout = 30000 } = options;
|
||||||
return new Promise<T>(async (resolve, reject) => {
|
return new Promise<T>(async (resolve, reject) => {
|
||||||
|
// 基本刷新
|
||||||
|
// await browser.tabs.reload(tabId);
|
||||||
|
// console.log('exec', browser.tabs.get(tabId), tabId);
|
||||||
|
|
||||||
|
// console.log('exec', func, (await browser.tabs.get(tabId)).url);
|
||||||
for (let i = 0; i < 50; i++) {
|
for (let i = 0; i < 50; i++) {
|
||||||
await new Promise<void>((r) => setTimeout(r, 200));
|
await new Promise<void>((r) => setTimeout(r, 200));
|
||||||
const tab = await browser.tabs.get(tabId);
|
const tab = await browser.tabs.get(tabId);
|
||||||
@ -55,7 +60,24 @@ export async function exec<T, P extends Record<string, unknown>>(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setTimeout(() => reject('脚本运行超时'), timeout);
|
|
||||||
|
const tab = await browser.tabs.get(tabId);
|
||||||
|
if (tab.status !== 'complete') {
|
||||||
|
console.log('waitForPageLoaded');
|
||||||
|
|
||||||
|
await browser.tabs.reload(tabId);
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 2000)); // 等待刷新开始
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < 50; i++) {
|
||||||
|
await new Promise<void>((r) => setTimeout(r, 200));
|
||||||
|
const tab = await browser.tabs.get(tabId);
|
||||||
|
if (tab.status === 'complete') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => reject(`脚本运行超时, foucs on ${func}`), timeout);
|
||||||
try {
|
try {
|
||||||
const injectResults = await browser.scripting.executeScript({
|
const injectResults = await browser.scripting.executeScript({
|
||||||
target: { tabId },
|
target: { tabId },
|
||||||
|
|||||||
@ -6,24 +6,177 @@ export class AmazonSearchPageInjector extends BaseInjector {
|
|||||||
await new Promise((resolve) => setTimeout(resolve, 500 + ~~(500 * Math.random())));
|
await new Promise((resolve) => setTimeout(resolve, 500 + ~~(500 * Math.random())));
|
||||||
while (true) {
|
while (true) {
|
||||||
const targetNode = document.querySelector('.s-pagination-next');
|
const targetNode = document.querySelector('.s-pagination-next');
|
||||||
window.scrollBy(0, ~~(Math.random() * 500) + 500);
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, ~~(Math.random() * 50) + 500));
|
await new Promise((resolve) => setTimeout(resolve, ~~(Math.random() * 50) + 500));
|
||||||
|
|
||||||
|
const h = Math.max(
|
||||||
|
document.documentElement.scrollHeight,
|
||||||
|
document.body.scrollHeight,
|
||||||
|
document.documentElement.offsetHeight,
|
||||||
|
document.body.offsetHeight,
|
||||||
|
document.documentElement.clientHeight,
|
||||||
|
);
|
||||||
|
|
||||||
|
await modernScrollTo({ top: h * (0.4 + Math.random() * 0.2), behavior: 'smooth' });
|
||||||
|
|
||||||
if (targetNode || document.readyState === 'complete') {
|
if (targetNode || document.readyState === 'complete') {
|
||||||
targetNode?.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
// await new Promise((resolve) => setTimeout(resolve, ~~(Math.random() * 50) + 250));
|
||||||
|
|
||||||
|
// 第一段:滚到中下部
|
||||||
|
// window.scrollTo({
|
||||||
|
// top: h * (1 - ~~(Math.random() * 50)),
|
||||||
|
// behavior: 'smooth'
|
||||||
|
// });
|
||||||
|
await modernScrollTo({ top: h * (0.9 + Math.random() * 0.08), behavior: 'smooth' });
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, ~~(Math.random() * 50) + 250));
|
||||||
|
|
||||||
|
// targetNode?.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||||
|
await scrollIntoViewAndWait(targetNode as HTMLElement, {
|
||||||
|
behavior: 'smooth',
|
||||||
|
block: 'center',
|
||||||
|
});
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, ~~(Math.random() * 50) + 250));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (true) {
|
while (true) {
|
||||||
await new Promise((resolve) => setTimeout(resolve, 500 + ~~(500 * Math.random())));
|
await new Promise((resolve) => setTimeout(resolve, 500 + ~~(500 * Math.random())));
|
||||||
const spins = Array.from(document.querySelectorAll<HTMLElement>('.a-spinner')).filter(
|
// const spins = Array.from(document.querySelectorAll<HTMLElement>('.a-spinner')).filter(
|
||||||
(e) => e.getClientRects().length > 0,
|
// (e) => e.getClientRects().length > 0,
|
||||||
);
|
// );
|
||||||
if (spins.length === 0) {
|
// if (spins.length === 0) {
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const spins = Array.from(document.querySelectorAll('.a-carousel-card-empty'))
|
||||||
|
// if (spins.length === 0) {
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
|
const pagination = document.querySelectorAll('.rhf-sign-in-button');
|
||||||
|
if (pagination.length > 0) {
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 500 + ~~(500 * Math.random())));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 平滑滚动并等待滚动结束
|
||||||
|
* @param options 原生 ScrollToOptions 接口 (包含 top, left, behavior)
|
||||||
|
*/
|
||||||
|
async function modernScrollTo(options: ScrollToOptions): Promise<void> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
// 1. 针对已经处于目标位置的情况做兜底处理
|
||||||
|
// 如果目标位置与当前位置一致,部分浏览器可能不会触发 scrollend
|
||||||
|
const targetTop = options.top ?? window.scrollY;
|
||||||
|
const targetLeft = options.left ?? window.scrollX;
|
||||||
|
|
||||||
|
if (targetTop === window.scrollY && targetLeft === window.scrollX) {
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 监听原生滚动结束事件
|
||||||
|
// 注意:scrollend 是 2023-2024 年起普及的标准,2026 年已是主流
|
||||||
|
document.addEventListener(
|
||||||
|
'scrollend',
|
||||||
|
() => {
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
{ once: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
// 3. 执行滚动
|
||||||
|
window.scrollTo(options);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将元素滚动到视野中心并等待动画结束
|
||||||
|
* @param element 目标 DOM 元素
|
||||||
|
* @param options 滚动配置
|
||||||
|
*/
|
||||||
|
async function scrollIntoViewAndWait(
|
||||||
|
element: HTMLElement,
|
||||||
|
options: ScrollIntoViewOptions = { behavior: 'smooth', block: 'center' },
|
||||||
|
): Promise<void> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
// 监听滚动结束事件
|
||||||
|
// scrollend 会在滚动圆满完成或被中断时触发
|
||||||
|
document.addEventListener(
|
||||||
|
'scrollend',
|
||||||
|
() => {
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
{ once: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
// 触发滚动
|
||||||
|
element.scrollIntoView(options);
|
||||||
|
|
||||||
|
// 兼容性兜底:如果元素已经在视野内,浏览器可能不触发滚动
|
||||||
|
// 可以在此处检查位置,若无位移则直接 resolve
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// public waitForPageLoaded() {
|
||||||
|
// return this.run(async () => {
|
||||||
|
// await new Promise((resolve) => setTimeout(resolve, 500 + ~~(500 * Math.random())));
|
||||||
|
|
||||||
|
// // 第一个 while 循环:添加 12 秒超时刷新机制
|
||||||
|
// const timeoutMs = 12000; // 12 秒
|
||||||
|
// let startTime = Date.now();
|
||||||
|
// let refreshCount = 0;
|
||||||
|
// const maxRefresh = 1; // 最多刷新 1 次
|
||||||
|
// console.log('waitForPageLoaded');
|
||||||
|
|
||||||
|
// while (true) {
|
||||||
|
// const targetNode = document.querySelector('.s-pagination-next');
|
||||||
|
// window.scrollBy(0, ~~(Math.random() * 500) + 500);
|
||||||
|
// await new Promise((resolve) => setTimeout(resolve, ~~(Math.random() * 50) + 500));
|
||||||
|
|
||||||
|
// if (targetNode || document.readyState === 'complete') {
|
||||||
|
// targetNode?.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 检查是否超时
|
||||||
|
// if (Date.now() - startTime > timeoutMs) {
|
||||||
|
// if (refreshCount < maxRefresh) {
|
||||||
|
// // 刷新页面
|
||||||
|
// console.log('检查是否超时,刷新页面');
|
||||||
|
|
||||||
|
// browser.tabs.query({ active: true, currentWindow: true }).then(tabs => {
|
||||||
|
// browser.tabs.reload(tabs[0].id);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// await new Promise((resolve) => setTimeout(resolve, 2000)); // 等待刷新开始
|
||||||
|
|
||||||
|
// // 重置计时器和刷新计数
|
||||||
|
// refreshCount++;
|
||||||
|
// startTime = Date.now();
|
||||||
|
// continue; // 重新从 while 循环开始
|
||||||
|
// } else {
|
||||||
|
// // 已刷新过一次,仍然超时,抛出错误
|
||||||
|
// throw new Error('等待页面加载超时(已尝试刷新)');
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 第二个 while 循环:等待 spinner 消失
|
||||||
|
// while (true) {
|
||||||
|
// await new Promise((resolve) => setTimeout(resolve, 500 + ~~(500 * Math.random())));
|
||||||
|
// const spins = Array.from(document.querySelectorAll('.a-spinner')).filter(
|
||||||
|
// (e) => e.getClientRects().length > 0
|
||||||
|
// );
|
||||||
|
// if (spins.length === 0) {
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
public async getPagePattern() {
|
public async getPagePattern() {
|
||||||
return this.run(async () => {
|
return this.run(async () => {
|
||||||
@ -118,32 +271,32 @@ export class AmazonSearchPageInjector extends BaseInjector {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
/**
|
||||||
// * 检测当前亚马逊搜索页面是否有下一页,并自动点击翻页按钮。
|
* 检测当前亚马逊搜索页面是否有下一页,并自动点击翻页按钮。
|
||||||
// *
|
*
|
||||||
// * 该方法在页面上下文中执行,查找亚马逊标准分页按钮('.s-pagination-next'),
|
* 该方法在页面上下文中执行,查找亚马逊标准分页按钮('.s-pagination-next'),
|
||||||
// * 检查按钮是否未被禁用('s-pagination-disabled' 类),然后模拟用户点击。
|
* 检查按钮是否未被禁用('s-pagination-disabled' 类),然后模拟用户点击。
|
||||||
// * 点击前会随机等待 500-1000 毫秒以避免被识别为机器人。
|
* 点击前会随机等待 500-1000 毫秒以避免被识别为机器人。
|
||||||
// *
|
*
|
||||||
// * @returns `true` 表示有下一页且已点击翻页按钮,页面正在加载下一页内容;
|
* @returns `true` 表示有下一页且已点击翻页按钮,页面正在加载下一页内容;
|
||||||
// * `false` 表示没有下一页(按钮不存在或被禁用)。
|
* `false` 表示没有下一页(按钮不存在或被禁用)。
|
||||||
// */
|
*/
|
||||||
// public async determineHasNextPage() {
|
public async determineHasNextPage() {
|
||||||
// return this.run(async () => {
|
return this.run(async () => {
|
||||||
// const nextButton = document.querySelector<HTMLLinkElement>('.s-pagination-next');
|
const nextButton = document.querySelector<HTMLLinkElement>('.s-pagination-next');
|
||||||
// if (nextButton) {
|
if (nextButton) {
|
||||||
// if (!nextButton.classList.contains('s-pagination-disabled')) {
|
if (!nextButton.classList.contains('s-pagination-disabled')) {
|
||||||
// await new Promise((resolve) => setTimeout(resolve, 500 + ~~(500 * Math.random())));
|
await new Promise((resolve) => setTimeout(resolve, 500 + ~~(500 * Math.random())));
|
||||||
// nextButton.click();
|
nextButton.click();
|
||||||
// return true;
|
return true;
|
||||||
// } else {
|
} else {
|
||||||
// return false;
|
return false;
|
||||||
// }
|
}
|
||||||
// } else {
|
} else {
|
||||||
// return false;
|
return false;
|
||||||
// }
|
}
|
||||||
// });
|
});
|
||||||
// }
|
}
|
||||||
// /**
|
// /**
|
||||||
// * 检测并执行亚马逊搜索页面翻页,等待页面刷新完成。
|
// * 检测并执行亚马逊搜索页面翻页,等待页面刷新完成。
|
||||||
// * @returns 能否翻页(true=翻页成功,false=没有下一页或翻页失败)
|
// * @returns 能否翻页(true=翻页成功,false=没有下一页或翻页失败)
|
||||||
@ -178,51 +331,51 @@ export class AmazonSearchPageInjector extends BaseInjector {
|
|||||||
* 检测并执行亚马逊搜索页面翻页,通过 URL 变化确认刷新完成。
|
* 检测并执行亚马逊搜索页面翻页,通过 URL 变化确认刷新完成。
|
||||||
* @returns 能否翻页(true=已翻页,false=已是最后一页)
|
* @returns 能否翻页(true=已翻页,false=已是最后一页)
|
||||||
*/
|
*/
|
||||||
public async determineHasNextPage(): Promise<boolean> {
|
// public async determineHasNextPage(): Promise<boolean> {
|
||||||
return this.run(async () => {
|
// return this.run(async () => {
|
||||||
const nextButton = document.querySelector<HTMLLinkElement>('.s-pagination-next');
|
// const nextButton = document.querySelector<HTMLLinkElement>('.s-pagination-next');
|
||||||
|
|
||||||
if (nextButton && !nextButton.classList.contains('s-pagination-disabled')) {
|
// if (nextButton && !nextButton.classList.contains('s-pagination-disabled')) {
|
||||||
// 1. 记录当前 URL
|
// // 1. 记录当前 URL
|
||||||
const initialUrl = window.location.href;
|
// const initialUrl = window.location.href;
|
||||||
|
|
||||||
// 2. 随机等待后点击
|
// // 2. 随机等待后点击
|
||||||
await new Promise((resolve) => setTimeout(resolve, 500 + ~~(500 * Math.random())));
|
// await new Promise((resolve) => setTimeout(resolve, 500 + ~~(500 * Math.random())));
|
||||||
nextButton.click();
|
// nextButton.click();
|
||||||
|
|
||||||
// 3. 等待 URL 变化(表示页面已开始导航)
|
// // 3. 等待 URL 变化(表示页面已开始导航)
|
||||||
await new Promise<void>((resolve) => {
|
// await new Promise<void>((resolve) => {
|
||||||
const checkUrl = () => {
|
// const checkUrl = () => {
|
||||||
if (window.location.href !== initialUrl) {
|
// if (window.location.href !== initialUrl) {
|
||||||
resolve();
|
// resolve();
|
||||||
} else {
|
// } else {
|
||||||
setTimeout(checkUrl, 100);
|
// setTimeout(checkUrl, 100);
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
checkUrl();
|
// checkUrl();
|
||||||
});
|
// });
|
||||||
|
|
||||||
// 4. 等待页面稳定(document.readyState === 'complete')
|
// // 4. 等待页面稳定(document.readyState === 'complete')
|
||||||
await new Promise<void>((resolve) => {
|
// await new Promise<void>((resolve) => {
|
||||||
const checkReadyState = () => {
|
// const checkReadyState = () => {
|
||||||
if (document.readyState === 'complete') {
|
// if (document.readyState === 'complete') {
|
||||||
resolve();
|
// resolve();
|
||||||
} else {
|
// } else {
|
||||||
setTimeout(checkReadyState, 100);
|
// setTimeout(checkReadyState, 100);
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
checkReadyState();
|
// checkReadyState();
|
||||||
});
|
// });
|
||||||
|
|
||||||
// 5. 额外等待确保内容加载
|
// // 5. 额外等待确保内容加载
|
||||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
// await new Promise((resolve) => setTimeout(resolve, 500));
|
||||||
|
|
||||||
return true;
|
// return true;
|
||||||
}
|
// }
|
||||||
|
|
||||||
return false;
|
// return false;
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AmazonDetailPageInjector extends BaseInjector {
|
export class AmazonDetailPageInjector extends BaseInjector {
|
||||||
|
|||||||
@ -5,7 +5,14 @@ import { usePageWorker } from '~/page-worker';
|
|||||||
import MulInputModal from '~/sidepanel/views/components/MulInputModal.vue';
|
import MulInputModal from '~/sidepanel/views/components/MulInputModal.vue';
|
||||||
const message = useMessage();
|
const message = useMessage();
|
||||||
const showModal = ref(false);
|
const showModal = ref(false);
|
||||||
const initKeysCount = ref(0);
|
|
||||||
|
const initKeysCount = ref(keywordsList.value.length);
|
||||||
|
const currentIndex = computed(() => {
|
||||||
|
if (timelines.value.length === 0) return null;
|
||||||
|
if (keywordsList.value.length === 0) return null;
|
||||||
|
return initKeysCount.value - keywordsList.value.length + 1;
|
||||||
|
});
|
||||||
|
const isRestarting = ref(false);
|
||||||
//#region Initial Page Worker
|
//#region Initial Page Worker
|
||||||
const worker = usePageWorker('amazon', { objects: ['search'] });
|
const worker = usePageWorker('amazon', { objects: ['search'] });
|
||||||
worker.on('error', ({ message: msg }) => {
|
worker.on('error', ({ message: msg }) => {
|
||||||
@ -31,6 +38,8 @@ const timelines = ref<Timeline[]>([]);
|
|||||||
|
|
||||||
const launch = async () => {
|
const launch = async () => {
|
||||||
const kws = unref(keywordsList);
|
const kws = unref(keywordsList);
|
||||||
|
console.log(isRestarting.value);
|
||||||
|
|
||||||
timelines.value = [
|
timelines.value = [
|
||||||
{
|
{
|
||||||
type: 'info',
|
type: 'info',
|
||||||
@ -40,7 +49,7 @@ const launch = async () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
// timelines.value.push();
|
// timelines.value.push();
|
||||||
initKeysCount.value = kws.length;
|
// initKeysCount.value = kws.length;
|
||||||
await worker.runSearchPageTask(kws, {
|
await worker.runSearchPageTask(kws, {
|
||||||
progress: (remains) => {
|
progress: (remains) => {
|
||||||
if (remains.length > 0) {
|
if (remains.length > 0) {
|
||||||
@ -60,6 +69,23 @@ const launch = async () => {
|
|||||||
time: new Date().toLocaleString(),
|
time: new Date().toLocaleString(),
|
||||||
content: `搜索任务结束`,
|
content: `搜索任务结束`,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (keywordsList.value.length === 0) {
|
||||||
|
message.success('所有关键词数据采集完成!');
|
||||||
|
} else {
|
||||||
|
if (!isRestarting.value) return;
|
||||||
|
console.info('5秒后重新采集!');
|
||||||
|
message.info('5秒后重新采集!');
|
||||||
|
timelines.value.push({
|
||||||
|
type: 'info',
|
||||||
|
title: '重新采集',
|
||||||
|
time: new Date().toLocaleString(),
|
||||||
|
content: `5秒后重新采集!`,
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
handleStart();
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleStart = async () => {
|
const handleStart = async () => {
|
||||||
@ -80,6 +106,7 @@ const clickInputButton = (e: MouseEvent) => {
|
|||||||
|
|
||||||
const handleModalConfirm = (keys: string[]) => {
|
const handleModalConfirm = (keys: string[]) => {
|
||||||
keywordsList.value = keys;
|
keywordsList.value = keys;
|
||||||
|
initKeysCount.value = keys.length;
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -92,11 +119,11 @@ const handleModalConfirm = (keys: string[]) => {
|
|||||||
<span style="display: inline-block"> 当前剩余关键词数量: {{ keywordsList.length }} 条</span>
|
<span style="display: inline-block"> 当前剩余关键词数量: {{ keywordsList.length }} 条</span>
|
||||||
<span style="display: inline-block">
|
<span style="display: inline-block">
|
||||||
现在爬到第
|
现在爬到第
|
||||||
{{
|
{{ currentIndex ?? '--' }} 条</span
|
||||||
initKeysCount - keywordsList.length + 1 ? '---' : initKeysCount - keywordsList.length + 1
|
|
||||||
}}
|
|
||||||
条</span
|
|
||||||
>
|
>
|
||||||
|
<span style="display: inline-block">
|
||||||
|
是否自动重新采集: <n-switch v-model:value="isRestarting" />
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="interactive-section">
|
<div class="interactive-section">
|
||||||
<n-infinite-scroll style="max-height: 40vh; padding-right: 16px" :distance="10">
|
<n-infinite-scroll style="max-height: 40vh; padding-right: 16px" :distance="10">
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useWebExtensionStorage } from '~/composables/useWebExtensionStorage';
|
import { useWebExtensionStorage } from '~/composables/useWebExtensionStorage';
|
||||||
|
|
||||||
export const keywordsList = useWebExtensionStorage<string[]>('keywordsList', ['']);
|
export const keywordsList = useWebExtensionStorage<string[]>('keywordsList', []);
|
||||||
|
|
||||||
export const detailAsinInput = useWebExtensionStorage<string>('detailAsinInputText', '');
|
export const detailAsinInput = useWebExtensionStorage<string>('detailAsinInputText', '');
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user