From e2139135a74b9df9abd976c063e18e3d186de012 Mon Sep 17 00:00:00 2001 From: cxOrz Date: Thu, 25 May 2023 22:56:07 +0800 Subject: [PATCH] =?UTF-8?q?=E7=9B=91=E5=90=AC=E6=A8=A1=E5=BC=8F=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=A4=9A=E4=BD=8D=E7=BD=AE=E5=B0=9D=E8=AF=95=E7=AD=BE?= =?UTF-8?q?=E5=88=B0=EF=BC=88=E6=9A=82=E4=B8=8D=E6=94=AF=E6=8C=81=E4=BB=8E?= =?UTF-8?q?Web=E5=90=AF=E7=94=A8=E7=9B=91=E5=90=AC=E7=9A=84=E6=83=85?= =?UTF-8?q?=E5=86=B5=EF=BC=89=EF=BC=9B=E6=89=8B=E5=8A=A8=E7=AD=BE=E5=88=B0?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BD=8D=E7=BD=AE=E5=88=97=E8=A1=A8=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/server/src/configs/prompts.ts | 120 +++++++++++++++++++++++ apps/server/src/functions/location.ts | 134 ++++++++++++++++++++------ apps/server/src/index.ts | 53 ++++++++-- apps/server/src/monitor.ts | 115 ++-------------------- 4 files changed, 274 insertions(+), 148 deletions(-) create mode 100644 apps/server/src/configs/prompts.ts diff --git a/apps/server/src/configs/prompts.ts b/apps/server/src/configs/prompts.ts new file mode 100644 index 0000000..2e75494 --- /dev/null +++ b/apps/server/src/configs/prompts.ts @@ -0,0 +1,120 @@ +import { red } from 'kolorist'; +import prompts from 'prompts'; + +export const PromptsOptions = { + onCancel: () => { + console.log(red('✖') + ' 操作取消'); + process.exit(0); + }, +}; + +// 最多保存10个位置,签到失败则轮流尝试 +export const addressPrompts = async () => { + const presetAddress = []; + for (let i = 0; i < 10; i++) { + let { lon_lat_address } = await prompts({ + type: 'text', + name: 'lon_lat_address', + message: `位置参数预设#${i + 1}(经纬度/地址)`, + initial: '113.516288,34.817038/河南省郑州市万科城大学软件楼', + }, PromptsOptions); + lon_lat_address = lon_lat_address.match(/([\d.]*),([\d.]*)\/(\S*)/); + console.log(`#${i + 1} 经度: ${lon_lat_address?.[1]} 纬度: ${lon_lat_address?.[2]} 地址: ${lon_lat_address?.[3]}`); + presetAddress.push({ + lon: lon_lat_address?.[1], + lat: lon_lat_address?.[2], + address: lon_lat_address?.[3] + }); + // 到10个就不再询问继续 + if (i < 9) { + const { next } = await prompts({ + type: () => i === 9 ? null : 'confirm', + name: 'next', + message: '是否继续添加', + initial: true, + }, PromptsOptions); + if (!next) break; + } + } + return presetAddress; +}; + +/** + * 监听模式问题数组 + */ +export const monitorPromptsQuestions: Array = [ + { + type: 'number', + name: 'delay', + message: '签到延时(单位:秒)', + initial: 0, + }, + { + type: 'confirm', + name: 'mail', + message: '是否启用邮件通知?', + initial: false, + }, + { + type: (prev) => (prev ? 'text' : null), + name: 'host', + message: 'SMTP服务器', + initial: 'smtp.qq.com', + }, + { + type: (prev) => (prev ? 'confirm' : null), + name: 'ssl', + message: '是否启用SSL', + initial: true, + }, + { + type: (prev) => (prev ? 'number' : null), + name: 'port', + message: '端口号', + initial: 465, + }, + { + type: (prev) => (prev ? 'text' : null), + name: 'user', + message: '邮件账号', + initial: 'xxxxxxxxx@qq.com', + }, + { + type: (prev) => (prev ? 'text' : null), + name: 'pass', + message: '授权码(密码)', + }, + { + type: (prev) => (prev ? 'text' : null), + name: 'to', + message: '接收邮箱', + }, + { + type: 'confirm', + name: 'cq_enabled', + message: '是否连接到go-cqhttp服务?', + initial: false, + }, + { + type: (prev) => (prev ? 'text' : null), + name: 'ws_url', + message: 'Websocket 地址', + initial: 'ws://127.0.0.1:8080', + }, + { + type: (prev) => (prev ? 'select' : null), + name: 'target_type', + message: '选择消息的推送目标', + choices: [ + { title: '群组', value: 'group' }, + { title: '私聊', value: 'private' } + ], + }, + { + type: (prev) => (prev ? 'number' : null), + name: 'target_id', + message: '接收号码', + initial: 10001, + }, +]; + diff --git a/apps/server/src/functions/location.ts b/apps/server/src/functions/location.ts index 35788a4..d195ced 100644 --- a/apps/server/src/functions/location.ts +++ b/apps/server/src/functions/location.ts @@ -1,18 +1,54 @@ import { CHAT_GROUP, PPTSIGN } from '../configs/api'; +import { delay } from '../utils/helper'; import { cookieSerialize, request } from '../utils/request'; -export const LocationSign = async ( - args: BasicCookie & { name: string; address: string; activeId: string; lat: string; lon: string; fid: string; } -): Promise => { - const { name, address, activeId, lat, lon, fid, ...cookies } = args; - const url = `${PPTSIGN.URL}?name=${name}&address=${address}&activeId=${activeId}&uid=${cookies._uid}&clientip=&latitude=${lat}&longitude=${lon}&fid=${fid}&appType=15&ifTiJiao=1`; - const result = await request(url, { - secure: true, - headers: { - Cookie: cookieSerialize(cookies), - }, - }); - const msg = result.data === 'success' ? '[位置]签到成功' : `[位置]${result.data}`; +interface AddressItem { + lon: string; + lat: string; + address: string; +} +type PresetAddress = AddressItem[]; +type CookieWithAddressItemArgs = BasicCookie & AddressItem & { name: string; activeId: string; fid: string; }; +type CookieWithPresetAddressArgs = BasicCookie & { presetAddress: PresetAddress; name: string; activeId: string; fid: string; }; + +type LocationSignType = { + (arg1: CookieWithAddressItemArgs): Promise; + (arg1: CookieWithPresetAddressArgs): Promise; +}; + +export const LocationSign: LocationSignType = async (args): Promise => { + let msg = ''; + if ('address' in args) { + // 单个位置直接签 + const { name, address, activeId, lat, lon, fid, ...cookies } = args; + const url = `${PPTSIGN.URL}?name=${name}&address=${address}&activeId=${activeId}&uid=${cookies._uid}&clientip=&latitude=${lat}&longitude=${lon}&fid=${fid}&appType=15&ifTiJiao=1`; + const result = await request(url, { + secure: true, + headers: { + Cookie: cookieSerialize(cookies), + }, + }); + msg = result.data === 'success' ? '[位置]签到成功' : `[位置]${result.data}`; + } else { + // 多个位置尝试 + const { name, activeId, presetAddress, fid, ...cookies } = args; + for (let i = 0; i < presetAddress.length; i++) { + const url = `${PPTSIGN.URL}?name=${name}&address=${presetAddress[i].address}&activeId=${activeId}&uid=${cookies._uid}&clientip=&latitude=${presetAddress[i].lat}&longitude=${presetAddress[i].lon}&fid=${fid}&appType=15&ifTiJiao=1`; + const result = await request(url, { + secure: true, + headers: { + Cookie: cookieSerialize(cookies), + }, + }); + if (result.data === 'success') { + msg = '[位置]签到成功'; + break; + } else { + msg = `[位置]${result.data}`; + await delay(1); + } + } + } console.log(msg); return msg; }; @@ -20,25 +56,63 @@ export const LocationSign = async ( /** * 位置签到,无课程群聊版本 */ -export const LocationSign_2 = async ( - args: BasicCookie & { name: string; address: string; activeId: string; lat: string; lon: string; fid: string; } -): Promise => { - const { address, activeId, lat, lon, ...cookies } = args; - const formdata = `address=${encodeURIComponent(address)}&activeId=${activeId}&uid=${cookies._uid - }&clientip=&useragent=&latitude=${lat}&longitude=${lon}&fid=&ifTiJiao=1`; - const result = await request( - CHAT_GROUP.SIGN.URL, - { - secure: true, - method: 'POST', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', - Cookie: cookieSerialize(cookies), +export const LocationSign_2: LocationSignType = async (args): Promise => { + let msg = ''; + if ('address' in args) { + // 单个位置直接签 + const { address, activeId, lat, lon, ...cookies } = args; + const formdata = `address=${encodeURIComponent(address)}&activeId=${activeId}&uid=${cookies._uid}&clientip=&useragent=&latitude=${lat}&longitude=${lon}&fid=&ifTiJiao=1`; + const result = await request( + CHAT_GROUP.SIGN.URL, + { + secure: true, + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', + Cookie: cookieSerialize(cookies), + }, }, - }, - formdata - ); - const msg = result.data === 'success' ? '[位置]签到成功' : `[位置]${result.data}`; + formdata + ); + msg = result.data === 'success' ? '[位置]签到成功' : `[位置]${result.data}`; + } else { + // 多个位置尝试 + const { activeId, presetAddress, ...cookies } = args; + for (let i = 0; i < presetAddress.length; i++) { + const formdata = `address=${encodeURIComponent(presetAddress[i].address)}&activeId=${activeId}&uid=${cookies._uid}&clientip=&useragent=&latitude=${presetAddress[i].lat}&longitude=${presetAddress[i].lon}&fid=&ifTiJiao=1`; + const result = await request( + CHAT_GROUP.SIGN.URL, + { + secure: true, + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', + Cookie: cookieSerialize(cookies), + }, + }, + formdata + ); + if (result.data === 'success') { + msg = '[位置]签到成功'; + break; + } else { + msg = `[位置]${result.data}`; + await delay(1); + } + } + } console.log(msg); return msg; }; + +export const presetAddressChoices = (presetAddress: any[] = []) => { + const arr = []; + for (let i = 0; i < presetAddress.length; i++) { + arr.push({ + title: `${presetAddress[i].lon},${presetAddress[i].lat}/${presetAddress[i].address}`, + value: i, + }); + } + arr.push({ title: '手动添加', value: -1 }); + return [...arr]; +}; diff --git a/apps/server/src/index.ts b/apps/server/src/index.ts index b47754e..47fa7dc 100644 --- a/apps/server/src/index.ts +++ b/apps/server/src/index.ts @@ -2,7 +2,7 @@ import prompts from 'prompts'; import { blue, red } from 'kolorist'; import { getPPTActiveInfo, preSign, traverseCourseActivity } from './functions/activity'; import { GeneralSign } from './functions/general'; -import { LocationSign } from './functions/location'; +import { LocationSign, presetAddressChoices } from './functions/location'; import { getObjectIdFromcxPan, PhotoSign } from './functions/photo'; import { QRCodeSign } from './functions/qrcode'; import { getAccountInfo, getCourses, getLocalUsers, userLogin } from './functions/user'; @@ -72,14 +72,49 @@ const PromptsOptions = { case 4: { // 位置签到 console.log('[获取经纬度]https://api.map.baidu.com/lbsapi/getpoint/index.html'); - const defaultLngLat = configs.monitor ? `${configs.monitor.lon},${configs.monitor.lat}` : '113.516288,34.817038'; - const defaultAddress = configs.monitor ? configs.monitor.address : ''; - const { lnglat } = await prompts({ type: 'text', name: 'lnglat', message: '经纬度', initial: defaultLngLat }, PromptsOptions); - const { address } = await prompts({ type: 'text', name: 'address', message: '详细地址', initial: defaultAddress }); - const lat = lnglat.substring(lnglat.indexOf(',') + 1, lnglat.length); - const lon = lnglat.substring(0, lnglat.indexOf(',')); - await LocationSign({ ...activity, ...params, address, lat, lon, name, }); - configs.monitor = { lon, lat, address, delay: configs?.monitor?.delay || 0 }; + const { presetItem } = await prompts({ + type: 'select', + name: 'presetItem', + message: '详细地址', + choices: presetAddressChoices(configs.monitor.presetAddress), + initial: 0, + }, PromptsOptions); + let lon_lat_address: any; + if (presetItem === -1) { + // 手动添加 + const { lon_lat_address: result } = await prompts({ + type: 'text', + name: 'lon_lat_address', + message: '位置参数预设(经纬度/地址)', + initial: '113.516288,34.817038/河南省郑州市万科城大学软件楼', + }, PromptsOptions); + lon_lat_address = result.match(/([\d.]*),([\d.]*)\/(\S*)/); + configs.monitor.presetAddress.push({ + lon: result?.[1], + lat: result?.[2], + address: result?.[3] + } + ); + } else { + // 选取地址 + lon_lat_address = [ + '填充[0]', + configs.monitor.presetAddress[presetItem].lon, + configs.monitor.presetAddress[presetItem].lat, + configs.monitor.presetAddress[presetItem].address, + ]; + } + + // 构成预设位置对象 + const addressItem = { + lon: lon_lat_address?.[1], + lat: lon_lat_address?.[2], + address: lon_lat_address?.[3] + }; + await LocationSign({ ...activity, ...params, ...addressItem, name }); + + // 更新本地数据 + configs.monitor = { presetAddress: configs?.monitor.presetAddress, delay: configs?.monitor?.delay || 0 }; configs.mailing = configs.mailing ? configs.mailing : { enabled: false }; configs.cqserver = configs.cqserver ? configs.cqserver : { cq_enabled: false }; break; diff --git a/apps/server/src/monitor.ts b/apps/server/src/monitor.ts index 96ed7d4..aeff4e5 100644 --- a/apps/server/src/monitor.ts +++ b/apps/server/src/monitor.ts @@ -15,6 +15,7 @@ import { getIMParams, getLocalUsers, userLogin } from './functions/user'; import { getJsonObject, getStoredUser, storeUser } from './utils/file'; import { delay } from './utils/helper'; import { sendEmail } from './utils/mailer'; +import { PromptsOptions, addressPrompts, monitorPromptsQuestions } from './configs/prompts'; const JSDOM = new jsdom.JSDOM('', { url: 'https://im.chaoxing.com/webim/me' }); (globalThis.window as any) = JSDOM.window; (globalThis.WebSocket as any) = WebSocket; @@ -24,13 +25,6 @@ globalThis.location = JSDOM.window.location; // eslint-disable-next-line @typescript-eslint/no-var-requires const webIM = require('./utils/websdk3.1.4.js').default; -const PromptsOptions = { - onCancel: () => { - console.log(red('✖') + ' 操作取消'); - process.exit(0); - }, -}; - const WebIMConfig = { xmppURL: 'https://im-api-vip6-v2.easecdn.com/ws', apiURL: 'https://a1-vip6.easecdn.com', @@ -82,108 +76,15 @@ async function configure(phone: string) { } // 若不使用本地,则配置并写入本地 if (!local) { - const response = await prompts( - [ - { - type: 'text', - name: 'lon', - message: '位置签到经度', - initial: '113.516288', - }, - { - type: 'text', - name: 'lat', - message: '位置签到纬度', - initial: '34.817038', - }, - { - type: 'text', - name: 'address', - message: '详细地址', - }, - { - type: 'number', - name: 'delay', - message: '签到延时(单位:秒)', - initial: 0, - }, - { - type: 'confirm', - name: 'mail', - message: '是否启用邮件通知?', - initial: false, - }, - { - type: (prev) => (prev ? 'text' : null), - name: 'host', - message: 'SMTP服务器', - initial: 'smtp.qq.com', - }, - { - type: (prev) => (prev ? 'confirm' : null), - name: 'ssl', - message: '是否启用SSL', - initial: true, - }, - { - type: (prev) => (prev ? 'number' : null), - name: 'port', - message: '端口号', - initial: 465, - }, - { - type: (prev) => (prev ? 'text' : null), - name: 'user', - message: '邮件账号', - initial: 'xxxxxxxxx@qq.com', - }, - { - type: (prev) => (prev ? 'text' : null), - name: 'pass', - message: '授权码(密码)', - }, - { - type: (prev) => (prev ? 'text' : null), - name: 'to', - message: '接收邮箱', - }, - { - type: 'confirm', - name: 'cq_enabled', - message: '是否连接到go-cqhttp服务?', - initial: false, - }, - { - type: (prev) => (prev ? 'text' : null), - name: 'ws_url', - message: 'Websocket 地址', - initial: 'ws://127.0.0.1:8080', - }, - { - type: (prev) => (prev ? 'select' : null), - name: 'target_type', - message: '选择消息的推送目标', - choices: [ - { title: '群组', value: 'group' }, - { title: '私聊', value: 'private' } - ], - }, - { - type: (prev) => (prev ? 'number' : null), - name: 'target_id', - message: '接收号码', - initial: 10001, - }, - ], - PromptsOptions - ); + const presetAddress = await addressPrompts(); + const response = await prompts(monitorPromptsQuestions, PromptsOptions); const monitor: any = {}; const mailing: any = {}; const cqserver: any = {}; monitor.delay = response.delay; monitor.lon = response.lon; monitor.lat = response.lat; - monitor.address = response.address; + monitor.presetAddress = presetAddress; mailing.enabled = response.mail; mailing.host = response.host; mailing.ssl = response.ssl; @@ -236,10 +137,8 @@ async function Sign(realname: string, params: UserCookieType & { tuid: string; } case 'location': { result = await LocationSign_2({ name: realname, - address: config.address, + presetAddress: config.presetAddress, activeId: activity.activeId, - lat: config.lat, - lon: config.lon, ...params, }); break; @@ -266,10 +165,8 @@ async function Sign(realname: string, params: UserCookieType & { tuid: string; } // 位置签到 result = await LocationSign({ name: realname, - address: config.address, + presetAddress: config.presetAddress, activeId: activity.activeId, - lat: config.lat, - lon: config.lon, ...params, }); break;