mirror of
https://github.com/smallfawn/QLScriptPublic.git
synced 2026-11-06 06:46:48 +08:00
315 lines
11 KiB
JavaScript
315 lines
11 KiB
JavaScript
/*
|
|
------------------------------------------
|
|
@Author: sm
|
|
@Date: 2026.06.09
|
|
@Description: OPPO 小程序会员查询/积分签到
|
|
cron: 21 8 * * *
|
|
------------------------------------------
|
|
变量名:oppo
|
|
变量值:wx_server 里的 openid,多账号用 & 或换行
|
|
|
|
依赖变量:
|
|
wx_server_url 默认 http://192.168.31.196:8787
|
|
wx_auth 必填,wx_server 鉴权值
|
|
------------------------------------------
|
|
*/
|
|
|
|
const { Env } = require("../tools/env.js");
|
|
const axios = require("axios");
|
|
|
|
const $ = new Env("OPPO");
|
|
|
|
const CK_NAME = "oppo";
|
|
const APP = {
|
|
name: "OPPO",
|
|
appid: "wxe705c556754a1de2",
|
|
version: 361,
|
|
};
|
|
const WX_SERVER_URL = (process.env.wx_server_url || "http://192.168.31.196:8787").replace(/\/$/, "");
|
|
const WX_AUTH = process.env.wx_auth || "";
|
|
const MINI_API = "https://omoapplet-api-cn.heytap.com";
|
|
const H5_API = "https://hd.opposhop.cn";
|
|
const SIGN_ACTIVITY_ID = "2061050217641549824";
|
|
const CREDITS_ADD_ACTION_ID = "1788913e6d9e4683b8b9ab0088733560";
|
|
const BUSINESS = 1;
|
|
const SIGN_PAGE =
|
|
"https://hd.opposhop.cn/bp/b371ce270f7509f0?nightModelEnable=true&utm_source=huiyuanwx&utm_medium=me_qiandao";
|
|
const USER_AGENT =
|
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF";
|
|
|
|
function splitAccounts(value = "") {
|
|
return String(value)
|
|
.split(/\n|&/)
|
|
.map((item) => item.trim())
|
|
.filter(Boolean);
|
|
}
|
|
|
|
function short(value, max = 500) {
|
|
if (value === undefined || value === null) return "";
|
|
const text = typeof value === "string" ? value : JSON.stringify(value);
|
|
return text.length > max ? `${text.slice(0, max)}...` : text;
|
|
}
|
|
|
|
function parseAccount(raw = "") {
|
|
const text = String(raw || "").trim();
|
|
if (!text) return {};
|
|
if (text.startsWith("{")) {
|
|
const data = JSON.parse(text);
|
|
return {
|
|
openid: data.openid || data.openId || "",
|
|
remark: data.remark || data.name || "",
|
|
};
|
|
}
|
|
const [openid, remark] = text.split("#").map((item) => item.trim());
|
|
return { openid, remark };
|
|
}
|
|
|
|
function awardTypeName(type) {
|
|
const map = {
|
|
0: "无奖励",
|
|
1: "积分",
|
|
2: "优惠券",
|
|
3: "抽奖机会",
|
|
};
|
|
return map[Number(type)] || `类型${type}`;
|
|
}
|
|
|
|
function todayText() {
|
|
const now = new Date();
|
|
const y = now.getFullYear();
|
|
const m = String(now.getMonth() + 1).padStart(2, "0");
|
|
const d = String(now.getDate()).padStart(2, "0");
|
|
return `${y}-${m}-${d}`;
|
|
}
|
|
|
|
async function request(options) {
|
|
const res = await axios.request({
|
|
timeout: 25000,
|
|
validateStatus: () => true,
|
|
...options,
|
|
headers: {
|
|
"User-Agent": USER_AGENT,
|
|
Accept: "application/json, text/plain, */*",
|
|
...(options.headers || {}),
|
|
},
|
|
});
|
|
return { status: res.status, headers: res.headers || {}, data: res.data };
|
|
}
|
|
|
|
async function getWxCode(openid) {
|
|
if (!WX_AUTH) throw new Error("未配置 wx_auth,无法从 wx_server 获取 code");
|
|
const { status, data } = await request({
|
|
method: "POST",
|
|
url: `${WX_SERVER_URL}/wx/code`,
|
|
headers: {
|
|
auth: WX_AUTH,
|
|
"content-type": "application/json",
|
|
Referer: `https://servicewechat.com/${APP.appid}/${APP.version}/page-frame.html`,
|
|
},
|
|
data: { appid: APP.appid, openid },
|
|
});
|
|
const code = data?.data?.code || data?.code;
|
|
if (status !== 200 || !code) throw new Error(`获取 code 失败 HTTP ${status}: ${short(data)}`);
|
|
return code;
|
|
}
|
|
|
|
class OppoTask {
|
|
constructor(rawAccount, index) {
|
|
this.index = index;
|
|
this.account = parseAccount(rawAccount);
|
|
this.sessionId = "";
|
|
this.encryptedSession = "";
|
|
this.openId = "";
|
|
this.memberInfo = {};
|
|
this.baseInfo = {};
|
|
}
|
|
|
|
log(message) {
|
|
$.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${message}`);
|
|
}
|
|
|
|
miniHeaders(extra = {}) {
|
|
return {
|
|
"content-type": "application/json",
|
|
s_channel: "oppo",
|
|
source_type: "2",
|
|
s_version: "010000",
|
|
spCallSource: "oppohy",
|
|
Referer: `https://servicewechat.com/${APP.appid}/${APP.version}/page-frame.html`,
|
|
sessionId: this.sessionId || "",
|
|
NEWOPPOSID: this.encryptedSession || "",
|
|
openid: this.openId || "",
|
|
sa_distinct_id: this.openId || "",
|
|
constToken: this.sessionId || "",
|
|
...extra,
|
|
};
|
|
}
|
|
|
|
h5Headers(extra = {}) {
|
|
return {
|
|
"content-type": "application/json",
|
|
Origin: H5_API,
|
|
Referer: SIGN_PAGE,
|
|
sessionId: this.sessionId || "",
|
|
NEWOPPOSID: this.encryptedSession || "",
|
|
openid: this.openId || "",
|
|
sa_distinct_id: this.openId || "",
|
|
constToken: this.sessionId || "",
|
|
Cookie: [
|
|
`NEWOPPOSID=${encodeURIComponent(this.encryptedSession || "")}`,
|
|
`sessionId=${encodeURIComponent(this.sessionId || "")}`,
|
|
`openid=${encodeURIComponent(this.openId || "")}`,
|
|
].join("; "),
|
|
...extra,
|
|
};
|
|
}
|
|
|
|
async miniRequest(method, path, data = {}) {
|
|
const upperMethod = method.toUpperCase();
|
|
const { status, data: result } = await request({
|
|
method: upperMethod,
|
|
url: `${MINI_API}${path}`,
|
|
headers: this.miniHeaders(),
|
|
params: upperMethod === "GET" ? data : undefined,
|
|
data: upperMethod === "GET" ? undefined : data,
|
|
});
|
|
if (status !== 200) throw new Error(`${path} HTTP ${status}: ${short(result)}`);
|
|
if (result?.ret && String(result.ret) !== "1") {
|
|
throw new Error(`${path} 失败: ${result.errMsg || result.message || short(result)}`);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
async h5Request(method, path, data = {}) {
|
|
const upperMethod = method.toUpperCase();
|
|
const { status, data: result } = await request({
|
|
method: upperMethod,
|
|
url: `${H5_API}${path}`,
|
|
headers: this.h5Headers(),
|
|
params: upperMethod === "GET" ? data : undefined,
|
|
data: upperMethod === "GET" ? undefined : data,
|
|
});
|
|
if (status !== 200) throw new Error(`${path} HTTP ${status}: ${short(result)}`);
|
|
if (Number(result?.code) !== 200 && result?.succeed !== true) {
|
|
throw new Error(`${path} 失败: ${result?.message || result?.errorMessage || short(result)}`);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
async login() {
|
|
if (!this.account.openid) throw new Error("账号格式错误,请配置 wx_server 里的 openid");
|
|
const code = await getWxCode(this.account.openid);
|
|
const { status, data } = await request({
|
|
method: "POST",
|
|
url: `${MINI_API}/user/pre/auth`,
|
|
headers: {
|
|
"content-type": "application/json",
|
|
Referer: `https://servicewechat.com/${APP.appid}/${APP.version}/page-frame.html`,
|
|
},
|
|
data: { code },
|
|
});
|
|
if (status !== 200 || String(data?.ret) !== "1") throw new Error(`登录失败 HTTP ${status}: ${short(data)}`);
|
|
const info = data.data || {};
|
|
this.sessionId = info.sessionId || "";
|
|
this.encryptedSession = info.encryptedSession || "";
|
|
this.openId = info.openId || "";
|
|
if (!this.sessionId) throw new Error(`登录响应缺少 sessionId: ${short(data)}`);
|
|
this.log(`登录成功 openId=${this.openId || "未知"}`);
|
|
}
|
|
|
|
async queryMember() {
|
|
const member = await this.miniRequest("GET", "/member/info", { sessionId: this.sessionId });
|
|
const base = await this.miniRequest("GET", "/member/baseInfo", { sessionId: this.sessionId }).catch(() => ({}));
|
|
this.memberInfo = member.data || {};
|
|
this.baseInfo = base.data || {};
|
|
const userName = this.memberInfo.userName || this.baseInfo.userName || "未知";
|
|
const phone = this.baseInfo.pnumber ? `,手机号: ${this.baseInfo.pnumber}` : "";
|
|
this.log(
|
|
`用户信息: ${userName}${phone},积分: ${this.memberInfo.pointAmount ?? 0},成长值: ${
|
|
this.memberInfo.growthValue ?? 0
|
|
},等级: ${this.memberInfo.gradeCode || "未知"}`
|
|
);
|
|
}
|
|
|
|
async queryEntrance() {
|
|
const result = await this.miniRequest("GET", "/activity/signIn/entrance", { sessionId: this.sessionId });
|
|
const data = result.data || {};
|
|
this.log(`签到入口: ${data.signInIsStarted ? "已开启" : "未开启"},连续/累计天数: ${data.signInDays ?? "-"}`);
|
|
}
|
|
|
|
async getSignDetail() {
|
|
const result = await this.h5Request("GET", "/api/cn/oapi/marketing/cumulativeSignIn/getSignInDetail", {
|
|
activityId: SIGN_ACTIVITY_ID,
|
|
creditsAddActionId: CREDITS_ADD_ACTION_ID,
|
|
business: BUSINESS,
|
|
});
|
|
return result.data || {};
|
|
}
|
|
|
|
todayAward(detail = {}) {
|
|
const today = todayText();
|
|
const awards = Array.isArray(detail.baseAwards) ? detail.baseAwards : [];
|
|
return awards.find((item) => String(item.signTime || "").slice(0, 10) === today) || awards[0] || {};
|
|
}
|
|
|
|
async querySignDetail() {
|
|
const detail = await this.getSignDetail();
|
|
const award = this.todayAward(detail);
|
|
const signed = Number(award.status) === 1;
|
|
this.log(
|
|
`签到详情: ${signed ? "今日已签" : "今日未签"},已签天数: ${detail.signInDayNum ?? 0},今日奖励: ${
|
|
award.awardValue ?? "-"
|
|
}${award.awardType !== undefined ? awardTypeName(award.awardType) : ""}`
|
|
);
|
|
return { detail, signed };
|
|
}
|
|
|
|
async signIn() {
|
|
const { signed } = await this.querySignDetail();
|
|
if (signed) return this.log("签到结果: 今日已签到,跳过");
|
|
const result = await this.h5Request("POST", "/api/cn/oapi/marketing/cumulativeSignIn/signIn", {
|
|
activityId: SIGN_ACTIVITY_ID,
|
|
captchaCode: "",
|
|
creditsAddActionId: CREDITS_ADD_ACTION_ID,
|
|
business: BUSINESS,
|
|
});
|
|
const data = result.data || {};
|
|
if (data.receiveStatus === false) {
|
|
this.log(`签到结果: 失败,${data.receiveFailMsg || result.message || "未知原因"}`);
|
|
return;
|
|
}
|
|
this.log(`签到结果: 成功,获得 ${data.awardValue ?? "-"}${awardTypeName(data.awardType)}`);
|
|
await this.querySignDetail();
|
|
}
|
|
|
|
async run() {
|
|
try {
|
|
this.log(`开始执行 ${APP.name}`);
|
|
await this.login();
|
|
await this.queryMember();
|
|
await this.queryEntrance();
|
|
await this.signIn();
|
|
await this.queryMember();
|
|
} catch (e) {
|
|
this.log(`执行失败: ${e.message || e}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
async function main() {
|
|
$.checkEnv(CK_NAME);
|
|
if (!$.userCount) {
|
|
$.log(`未找到变量 ${CK_NAME}`);
|
|
return;
|
|
}
|
|
for (let i = 0; i < $.userList.length; i++) {
|
|
const task = new OppoTask($.userList[i], i + 1);
|
|
await task.run();
|
|
if (i < $.userList.length - 1) await $.wait(1500, 3000);
|
|
}
|
|
}
|
|
|
|
main()
|
|
.catch((e) => $.log(`脚本异常: ${e.message || e}`))
|
|
.finally(() => $.done());
|