diff --git a/src/alipay/index.ts b/src/alipay/index.ts new file mode 100644 index 0000000..f2d050e --- /dev/null +++ b/src/alipay/index.ts @@ -0,0 +1,78 @@ +/* eslint-disable ts/no-unsafe-assignment */ +/* eslint-disable ts/no-unsafe-member-access */ + +import { yellow } from 'kolorist' +import type { Browser, ElementHandle, Page } from 'puppeteer' +import puppeteer from 'puppeteer' +import type { Ora } from 'ora' +import ora from 'ora' +import prompts from 'prompts' +import { ALIPAY_URL, VIEWPORT, __DEV__ } from '../constants' +import { pathResolve, showQrCodeToTerminal } from '../utils' +import type { IBrand } from './type' + +let browser: Browser +let page: Page + +let spinner: Ora +let options: InputOptions + +async function getLoginScanCode() { + spinner = ora('正在获取登录二维码...').start() + browser = await puppeteer.launch({ headless: __DEV__ ? false : options.headless }) + page = await browser.newPage() + await page.setViewport(VIEWPORT) + await page.goto(ALIPAY_URL) + const qrWrapper = await page.waitForSelector('.authcenter-body-login') + const qrCodePath = pathResolve('../cache/login-qr-alipay.png') + await qrWrapper?.screenshot({ path: qrCodePath }) + spinner.succeed(yellow('请使用支付宝扫描二维码登录')) + console.log(await showQrCodeToTerminal(qrCodePath)) + await page.waitForSelector('.title___UNcmz') + spinner.succeed('支付宝登录成功') +} + +async function getBrandList(): Promise { + const brandList: IBrand[] = [] + let nextBtn: ElementHandle | null = null + spinner.start('获取品牌列表') + return new Promise((resolve) => { + // eslint-disable-next-line ts/no-misused-promises + page.on('response', async (response) => { + const url = response.url() + if (url.includes('https://developerportal.alipay.com/app/appPageQuery.json') && url.includes('appType=TINYAPP_NORMAL')) { + const result: any = await response.json() + const list: IBrand[] = result.data.rows + brandList.push(...list) + if (result.data.pageInfo.pageNum * result.data.pageInfo.pageSize < result.data.pageInfo.total) { + nextBtn = nextBtn ?? await page.waitForSelector('#rc-tabs-0-panel-TINYAPP_NORMAL > div > div.ant-table-wrapper > div > div > ul > li.ant-pagination-next > button') + void nextBtn?.click() + } + else { + page.off('response') + resolve(brandList) + spinner.succeed('获取品牌列表成功') + } + } + }) + }) +} + +export async function alipayRobot(opts: InputOptions) { + options = opts + await getLoginScanCode() + const brandList = await getBrandList() + const result = await prompts({ + type: 'multiselect', + name: 'brand', + message: '请选择要登录的支付宝账号', + choices: brandList.map((item) => { + return { + title: item.appName, + value: item.appId, + description: item.lastVersion, + } + }), + }) + console.log(result) +} diff --git a/src/alipay/type.ts b/src/alipay/type.ts new file mode 100644 index 0000000..1d374ed --- /dev/null +++ b/src/alipay/type.ts @@ -0,0 +1,23 @@ +export interface IBrand { + hasAlipayOnline: boolean + showIteration: boolean + gmtCreate: number + gmtModified: number + appId: string + appName: string + appDesc: string + appType: string + logoUrl: string + oid: string + pid: string + status: string + masterName: string + masterAccount: string + lastVersion?: string + lastVersionStatus?: string + allowBind: boolean + bindStatus: string + currentRole: { + [index: string]: string + } +} diff --git a/src/cache/login-qr-alipay.png b/src/cache/login-qr-alipay.png new file mode 100644 index 0000000..6fdd501 Binary files /dev/null and b/src/cache/login-qr-alipay.png differ diff --git a/src/constants/index.ts b/src/constants/index.ts index 52c6a82..1a1dda8 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -4,6 +4,7 @@ import type { Viewport } from 'puppeteer' export { description, version, name } from '../../package.json' export const WEIXIN_URL = 'https://mp.weixin.qq.com/' +export const ALIPAY_URL = 'https://auth.alipay.com/login/ant_sso_index.htm?goto=https%3A%2F%2Fopen.alipay.com%2Fdevelop%2Fmanage' export enum PLATFORM { WEIXIN = 'weixin', diff --git a/src/core/index.ts b/src/core/index.ts index 5627f05..769749f 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -1,8 +1,9 @@ -import { bgGreen, blue, green, red, reset } from 'kolorist' +import { blue, green, red, reset } from 'kolorist' import prompts from 'prompts' import { ACTION, PLATFORM } from '../constants' import weixinRobot from '../weixin' import { isEmpty } from '../utils' +import { alipayRobot } from '../alipay' export default async function main(options: InputOptions) { const result: prompts.Answers< @@ -43,5 +44,5 @@ export default async function main(options: InputOptions) { if (opts.platform === PLATFORM.WEIXIN) await weixinRobot(opts) else - console.log(bgGreen('正在开发中...')) + await alipayRobot(opts) }