first commit

This commit is contained in:
cieanyau committed 2026-11-06 00:04:38 +08:00
commit db5762abd4
687 files changed
+171307

No files matched your search

+856
View File
@@ -0,0 +1,856 @@
import CryptoJS from "crypto-js";
import { defineStore } from "pinia";
import { navigateTo, useRuntimeConfig } from "#app";
import { computed, ref } from "vue";
var ce = [
[/产品类型错误.{0,30}安全组[^\n]*/g, `该商品未接入安全组`],
[/商品未关联.{0,20}模块接口/g, `该商品暂不可用`],
[/未关联.{0,12}模块接口/g, `该商品暂不可用`],
[/尚未接入.{0,12}模块/g, `该商品暂不可用`],
];
var le = [
[/快快云-弹性云|弹性云/g, ``],
[/快快云|快快/g, ``],
[/魔方云|魔方财务|智简魔方|智简/g, ``],
[/美得云|美德云|meidecloud/gi, ``],
[/dwvps[a-z0-9_]*/gi, ``],
[/miloce[a-z0-9_]*/gi, ``],
[/jinghanyun[a-z0-9_]*/gi, ``],
[/kkidc[a-z0-9_]*/gi, ``],
[/kky[a-z0-9_]*/gi, ``],
[/idcsmart[a-z0-9_]*/gi, ``],
[/mf[_-]?cloud[a-z0-9_]*/gi, ``],
[/mf[_-]?dcim[a-z0-9_]*/gi, ``],
[/common[_-]?cloud[a-z0-9_]*/gi, ``],
[/pve[_-]?cloud[a-z0-9_]*/gi, ``],
];
var ue =
/模块接口|自定义配置|模块未关联|模块标识|上游|第三方云|[a-z]{2,}[_-][a-z0-9_]+|\bDCIM\b|whmcs|reserver|https?:\/\//i;
function W(e) {
let t = typeof e == `string` ? e : ``;
if (!t) return ``;
let n = t;
for (let [e, t] of ce) n = n.replace(e, t);
for (let [e, t] of le) n = n.replace(e, t);
return (
(n = n
.replace(/\s{2,}/g, ` `)
.replace(/[,,、]{2,}/g, `,`)
.replace(/^[\s,,、::;;-]+|[\s,,、::;;-]+$/g, ``)
.trim()),
n.length < 2 || ue.test(n) ? `操作失败,请稍后重试或联系客服` : n
);
}
function de(e) {
let t = typeof e == `string` ? e : ``;
return /^\s*上游熔断解除[::]/u.test(t)
? `服务连接已恢复正常`
: /^\s*上游熔断[::]/u.test(t)
? `服务连接暂时异常,请稍后重试`
: t;
}
var fe = 32;
var pe = 200;
var me = 6e4;
var G = new Map();
var he = Symbol(`uninitialized`);
var ge = 0;
function _e() {
(ge++, G.clear());
}
function ve() {
return ge;
}
function ye(e, t, n = ``) {
return JSON.stringify([e, n, t], (e, t) =>
t && typeof t == `object` && !Array.isArray(t)
? Object.fromEntries(
Object.keys(t)
.sort()
.map((e) => [e, t[e]]),
)
: t,
);
}
function be(e) {
return JSON.parse(JSON.stringify(e));
}
function xe(e, t, n = Date.now()) {
he !== e && (_e(), (he = e));
for (let [e, t] of G) t.expires <= n && G.delete(e);
let r = G.get(t);
if (r) return (G.delete(t), G.set(t, r), be(r.data));
}
function Se(e, t, n, r, i = Date.now()) {
if (e === he && r === ge) {
if (!Array.isArray(n.list) || n.list.length > pe) {
G.delete(t);
return;
}
try {
let e = be(n);
(G.delete(t),
G.size >= fe && G.delete(G.keys().next().value),
G.set(t, {
data: e,
expires: i + me,
}));
} catch {
G.delete(t);
}
}
}
var Ce = 2147483647;
function K(e, t) {
let n =
typeof e == `number`
? e
: typeof e == `string` && /^\d+$/.test(e)
? Number(e)
: NaN;
if (!Number.isSafeInteger(n) || n < t || n > Ce)
throw Error(`购买信息无效,请重新确认后重试`);
return n;
}
function we(e) {
if (!e || typeof e != `object` || Array.isArray(e))
throw Error(`购买信息无效,请重新确认后重试`);
return e;
}
function Te(e) {
let t = we(e);
return {
product_id: K(t.product_id, 1),
qty: K(t.qty, 1),
};
}
function Ee(e, t, n) {
if (e === `POST` && t === `/product/settle`)
return {
mode: `single`,
...Te(n),
};
if (e === `POST` && t === `/cart`) {
let e = we(n);
if (e.products !== void 0) {
if (
!Array.isArray(e.products) ||
!e.products.length ||
e.products.length > 1e3
)
throw Error(`购买信息无效,请重新确认后重试`);
return {
mode: `cart_add`,
products: e.products.map(Te),
};
}
return {
mode: `cart_add`,
...Te(e),
};
}
if (e === `POST` && t === `/cart/settle`) {
let e = we(n);
if (!Array.isArray(e.positions) || !e.positions.length)
throw Error(`请选择要结算的商品`);
return {
mode: `cart_settle`,
positions: [...new Set(e.positions.map((e) => K(e, 0)))],
};
}
let r = e === `PUT` ? /^\/cart\/(\d+)(\/qty)?$/.exec(t) : null;
if (r) {
let e = we(n);
return {
mode: `cart_update`,
position: K(r[1], 0),
qty: K(e.qty, 1),
...(r[2]
? {}
: {
product_id: K(e.product_id, 1),
}),
};
}
return null;
}
function De(e) {
if (!e || typeof e != `object` || Array.isArray(e)) return !1;
let t = e;
return (
typeof t.allowed == `boolean` &&
typeof t.message == `string` &&
(t.allowed || !!t.message.trim())
);
}
class ApiError extends Error {
status;
data;
constructor(status, message, data) {
super(message);
this.status = status;
this.data = data;
this.name = "ApiError";
}
}
const DEFAULT_REQUEST_TIMEOUT_MS = 30_000;
const FILE_TRANSFER_TIMEOUT_MS = 120_000;
function requestTimeoutError() {
return new ApiError(408, "请求超时,请稍后重试");
}
async function withRequestDeadline(
operation,
timeoutMs = DEFAULT_REQUEST_TIMEOUT_MS,
controller = new AbortController(),
) {
const duration =
Number.isFinite(timeoutMs) && timeoutMs > 0 && timeoutMs <= 2_147_483_647
? timeoutMs
: DEFAULT_REQUEST_TIMEOUT_MS;
let timer;
const deadline = new Promise((_, reject) => {
timer = setTimeout(() => {
controller.abort();
reject(requestTimeoutError());
}, duration);
});
try {
// The deadline also covers response-body decoding and any purchase preflight.
return await Promise.race([
Promise.resolve().then(() => operation(controller.signal)),
deadline,
]);
} finally {
clearTimeout(timer);
}
}
function assertRequestActive(signal) {
if (signal.aborted) throw requestTimeoutError();
}
function normalizeRequestError(error) {
return error instanceof ApiError
? error
: new ApiError(0, "网络异常,请检查网络后重试");
}
function useApi() {
const config = useRuntimeConfig();
const auth = useAuth();
function clearUnauthorizedSession(requestToken) {
if (
!requestToken ||
localStorage.getItem("jwt") !== requestToken ||
auth.token !== requestToken
)
return;
auth.clear();
if (window.location.pathname === "/login") return;
const redirect = window.location.pathname + window.location.search;
try {
void Promise.resolve(
navigateTo({
path: "/login",
query: redirect === "/" ? undefined : { redirect },
}),
).catch(() => {});
} catch {}
}
function responseObject(value) {
return value && typeof value === "object" && !Array.isArray(value)
? value
: {};
}
function responseError(response, payload, requestToken, fallbackMessage) {
const envelope = responseObject(payload);
const status =
response.status === 401
? 401
: typeof envelope.status === "number" && envelope.status !== 200
? envelope.status
: response.status;
if (status === 401) clearUnauthorizedSession(requestToken);
return new ApiError(
status,
W(envelope.msg || envelope.message) || fallbackMessage,
envelope.data,
);
}
async function decodeResponse(
response,
requestToken,
fallbackMessage,
signal,
allowStatuslessDataArray = false,
) {
const payload = await response.json().catch(() => null);
assertRequestActive(signal);
const envelope = responseObject(payload);
if (response.ok && envelope.status === 200) return payload;
if (
response.ok &&
allowStatuslessDataArray &&
!("status" in envelope) &&
Array.isArray(envelope.data)
) {
return { status: 200, msg: "", data: envelope.data };
}
throw responseError(response, payload, requestToken, fallbackMessage);
}
function apiUrl(path, query, keepEmpty = false) {
let url = `${String(config.public.apiBase ?? "")}/console/v1${path}`;
const search = new URLSearchParams();
for (const [key, value] of Object.entries(query ?? {})) {
if (value == null || (value === "" && !keepEmpty)) continue;
if (Array.isArray(value)) {
for (const item of value) {
if (item != null && item !== "")
search.append(`${key}[]`, String(item));
}
} else {
search.append(key, String(value));
}
}
if (search.size) url += `?${search}`;
return url;
}
async function request(method, path, options = {}) {
// Capture identity before the first await, including when logout clears it immediately.
const requestToken = auth.token;
const headers = { Accept: "application/json" };
if (requestToken) headers.Authorization = `Bearer ${requestToken}`;
if (options.body !== undefined)
headers["Content-Type"] = "application/json";
try {
const serializedBody =
options.body === undefined ? undefined : JSON.stringify(options.body);
return await withRequestDeadline(async (signal) => {
if (requestToken) {
let purchase;
try {
purchase = Ee(method, path, options.body);
} catch (error) {
throw new ApiError(
422,
error instanceof Error
? error.message
: "购买信息无效,请重新确认后重试",
);
}
if (purchase) {
const authToken = auth.token;
const permission = await request("POST", "/purchase_limit/check", {
body: purchase,
timeoutMs: options.timeoutMs ?? 15_000,
});
assertRequestActive(signal);
if (
localStorage.getItem("jwt") !== requestToken ||
auth.token !== authToken
) {
throw new ApiError(409, "登录状态已变化,请重新确认后重试");
}
if (JSON.stringify(options.body) !== serializedBody) {
throw new ApiError(409, "购买信息已变化,请重新确认后重试");
}
if (!De(permission))
throw new ApiError(502, "限购验证暂不可用,请稍后重试");
if (!permission.allowed)
throw new ApiError(422, permission.message);
}
}
assertRequestActive(signal);
const response = await fetch(
apiUrl(path, options.query, options.keepEmpty),
{
method,
headers,
body: serializedBody,
signal,
},
);
assertRequestActive(signal);
const envelope = await decodeResponse(
response,
requestToken,
response.ok
? "响应格式异常,请稍后重试"
: `请求失败(HTTP ${response.status})`,
signal,
options.allowStatuslessDataArray,
);
assertRequestActive(signal);
if (
method !== "GET" &&
path !== "/purchase_limit/check" &&
!/^\/product\/\d+\/config_option$/.test(path)
) {
_e();
}
return options.raw ? envelope : envelope.data;
}, options.timeoutMs);
} catch (error) {
throw normalizeRequestError(error);
}
}
async function upload(file) {
const body = new FormData();
body.append("file", file);
const headers = { Accept: "application/json" };
const requestToken = auth.token;
if (requestToken) headers.Authorization = `Bearer ${requestToken}`;
try {
return await withRequestDeadline(async (signal) => {
const response = await fetch(apiUrl("/upload"), {
method: "POST",
headers,
body,
signal,
});
assertRequestActive(signal);
const envelope = await decodeResponse(
response,
requestToken,
"上传失败",
signal,
);
assertRequestActive(signal);
return envelope.data;
}, FILE_TRANSFER_TIMEOUT_MS);
} catch (error) {
throw normalizeRequestError(error);
}
}
async function download(path, data, filename = "export.xlsx", options = {}) {
const method = options.method ?? "GET";
const headers = { Accept: "*/*" };
const requestToken = auth.token;
if (requestToken) headers.Authorization = `Bearer ${requestToken}`;
if (method === "POST") headers["Content-Type"] = "application/json";
try {
await withRequestDeadline(async (signal) => {
const response = await fetch(
apiUrl(path, method === "GET" ? data : undefined),
{
method,
headers,
...(method === "POST" ? { body: JSON.stringify(data ?? {}) } : {}),
signal,
},
);
assertRequestActive(signal);
const isJson = /\bapplication\/(?:[\w.-]+\+)?json\b/i.test(
response.headers.get("content-type") || "",
);
if (!response.ok || isJson) {
const payload = await response
.clone()
.json()
.catch(() => null);
assertRequestActive(signal);
const envelope = responseObject(payload);
if (
!response.ok ||
(typeof envelope.status === "number" && envelope.status !== 200)
) {
throw responseError(
response,
payload,
requestToken,
`下载失败(HTTP ${response.status})`,
);
}
}
const disposition = response.headers.get("content-disposition") || "";
const match = /filename\*?=(?:UTF-8'')?"?([^";]+)"?/i.exec(disposition);
if (match?.[1]) {
try {
filename = decodeURIComponent(match[1]);
} catch {
filename = match[1];
}
}
const blob = await response.blob();
assertRequestActive(signal);
const objectUrl = URL.createObjectURL(blob);
const link = document.createElement("a");
try {
link.href = objectUrl;
link.download = filename;
document.body.appendChild(link);
link.click();
} finally {
link.remove();
URL.revokeObjectURL(objectUrl);
}
}, options.timeoutMs ?? FILE_TRANSFER_TIMEOUT_MS);
} catch (error) {
throw normalizeRequestError(error);
}
}
return {
identity: () => auth.token,
request,
upload,
download,
get: (path, query, keepEmpty = false, options = {}) =>
request("GET", path, {
...options,
query,
keepEmpty,
}),
getRaw: (path, query, options = {}) =>
request("GET", path, {
...options,
query,
raw: true,
}),
post: (path, body, raw = false, options = {}) =>
request("POST", path, {
...options,
body,
raw,
}),
put: (path, body, query) => request("PUT", path, { body, query }),
del: (path, query, body) => request("DELETE", path, { query, body }),
};
}
var ot = CryptoJS.enc.Utf8.parse(`idcsmart.finance`);
var st = CryptoJS.enc.Utf8.parse(`9311019310287172`);
function ct(e) {
return CryptoJS.AES.encrypt(e, ot, {
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
iv: st,
}).toString();
}
function lt(e, t = `登录失败,请稍后重试`) {
let n = e && typeof e == `object` ? e : {},
r = typeof n.message == `string` ? n.message.trim() : ``,
i = n.data && typeof n.data == `object` ? n.data : {};
return i.need_security_verify || i.ip_exception_verify
? `本次登录需要额外的安全验证,请联系客服协助完成验证。`
: n.status === 429
? `登录尝试过于频繁,请稍后再试`
: n.status === 408 || /超时|timeout/i.test(r)
? `登录请求超时,请检查网络后重试`
: n.status === 0 ||
/网络异常|Failed to fetch|NetworkError|Load failed/i.test(r)
? `网络连接失败,请检查网络后重试`
: (n.status ?? 0) >= 500 ||
/页面错误|响应格式异常|Internal Server Error|Bad Gateway|Service Unavailable/i.test(
r,
)
? `登录服务暂时异常,请稍后重试;若持续失败,请联系客服。`
: !r ||
/<[^>]+>|SQLSTATE|\b(?:TypeError|ReferenceError|Exception)\b/.test(
r,
)
? t
: r;
}
function ut(e) {
return (
typeof e == `string` && e.length > 0 && e.length <= 8192 && !/\s/.test(e)
);
}
function dt(e) {
if (!e || typeof e != `object`) return null;
let t = e,
n = [t, t.data, t.error, t.response];
for (let e of n) {
if (!e || typeof e != `object`) continue;
let t = e,
n = t.data && typeof t.data == `object` ? t.data : t;
if (
n.need_security_verify === !0 ||
n.need_security_verify === 1 ||
n.need_security_verify === `1` ||
(Array.isArray(n.available_methods) && n.available_methods.length > 0)
)
return n;
}
return null;
}
function ft(e) {
let t = dt(e);
if (t)
throw Object.assign(Error(`安全验证尚未完成,请重试`), {
data: t,
});
}
var pt = {
operate_password: `操作密码`,
email_code: `邮箱验证码`,
phone_code: `手机验证码`,
certification: `实名认证`,
};
function mt(e) {
return (
Array.isArray(e.available_methods) ? e.available_methods : []
).flatMap((t) => {
let n =
typeof t == `string`
? {
value: t,
}
: t && typeof t == `object`
? t
: {},
r = String(n.value ?? ``);
return pt[r]
? [
{
value: r,
label: pt[r],
tip: String(n.tip ?? ``),
account: String(n.account ?? ``),
phone_code: String(n.phone_code ?? ``),
security_verify_token: String(
n.security_verify_token ?? e.security_verify_token ?? ``,
),
},
]
: [];
});
}
const useAuth = defineStore("auth", () => {
const token = ref(localStorage.getItem("jwt"));
const overview = ref(null);
const loading = ref(false);
const legacyLoginPending = ref(false);
const isLoggedIn = computed(() => !!token.value);
let overviewPromise = null;
let sessionVersion = 0;
let legacySession = null;
function loginWithJwt(jwt) {
if (!ut(jwt))
throw Error("登录响应无效,请重新登录;若持续失败,请联系客服。");
resetSessionState();
token.value = jwt;
localStorage.setItem("jwt", jwt);
}
function prepareLegacyLogin(jwt = localStorage.getItem("jwt")) {
clear();
legacySession = {
jwt: ut(jwt) ? jwt : null,
version: sessionVersion,
controller: null,
promise: null,
};
legacyLoginPending.value = true;
}
function cancelLegacyLogin() {
legacySession?.controller?.abort();
legacySession = null;
legacyLoginPending.value = false;
}
function verifyLegacyLogin() {
const session = legacySession;
if (!session?.jwt) {
return Promise.reject(
Error("缺少有效登录凭证,请返回原平台重新进入,或使用账号登录。"),
);
}
if (session.promise) return session.promise;
const apiBase = String(useRuntimeConfig().public.apiBase ?? "");
const controller = new AbortController();
session.controller = controller;
const isCurrentSession = () =>
legacySession === session && sessionVersion === session.version;
const promise = withRequestDeadline(
async (signal) => {
let response;
try {
response = await fetch(`${apiBase}/console/v1/index`, {
headers: {
Accept: "application/json",
Authorization: `Bearer ${session.jwt}`,
},
credentials: "omit",
cache: "no-store",
referrerPolicy: "no-referrer",
signal,
});
} catch {
throw Error("网络连接失败或验证超时,请检查网络后重试。");
}
const envelope = await response.json().catch(() => null);
assertRequestActive(signal);
if (!isCurrentSession()) throw Error("登录状态已变化,请重新进入。");
if (response.status === 401 || envelope?.status === 401) {
throw Error("登录凭证已失效,请返回原平台重新进入,或使用账号登录。");
}
const account = envelope?.data?.account;
if (
!response.ok ||
envelope?.status !== 200 ||
!account ||
typeof account !== "object" ||
!Number.isSafeInteger(account.id) ||
account.id <= 0
)
throw Error("暂时无法验证登录身份,请稍后重试。");
loginWithJwt(session.jwt);
overview.value = account;
},
15_000,
controller,
)
.catch((error) => {
if (error instanceof ApiError && error.status === 408) {
throw Error("网络连接失败或验证超时,请检查网络后重试。");
}
throw error;
})
.finally(() => {
if (isCurrentSession()) {
session.controller = null;
session.promise = null;
}
});
session.promise = promise;
return promise;
}
async function login(
account,
password,
captcha = "",
captchaToken = "",
type = "password",
code = "",
phoneCode = "86",
verification,
) {
if (type === "code" && account.includes("@"))
throw Error("验证码登录仅支持手机号");
const api = useApi();
const version = sessionVersion;
loading.value = true;
try {
const result = await api.post(
"/login",
{
type,
account,
...(account.includes("@") ? {} : { phone_code: phoneCode }),
code,
password: type === "password" ? ct(password) : "",
remember_password: "0",
captcha,
token: captchaToken,
...(verification || {}),
},
false,
{ timeoutMs: 15_000 },
);
if (version !== sessionVersion) throw Error("登录状态已变化,请重试");
ft(result);
if (!ut(result?.jwt))
throw Error("登录响应无效,请重新登录;若持续失败,请联系客服。");
loginWithJwt(result.jwt);
} finally {
loading.value = false;
}
}
function loadOverview() {
if (!overviewPromise) {
const version = sessionVersion;
const promise = useApi()
.get("/index", undefined, false, { timeoutMs: 10_000 })
.then((result) => {
if (version !== sessionVersion) throw Error("登录状态已变化,请重试");
overview.value = result.account;
return result.account;
})
.finally(() => {
if (overviewPromise === promise) overviewPromise = null;
});
overviewPromise = promise;
}
return overviewPromise;
}
async function fetchOverview() {
return overview.value ?? loadOverview();
}
async function refreshOverview() {
return loadOverview();
}
function logout() {
// request() captures the original Bearer synchronously; remote revocation never owns local logout.
const revocation = useApi().post("/logout");
clear();
void revocation.catch(() => {});
}
function resetSessionState() {
_e();
cancelLegacyLogin();
sessionVersion += 1;
overview.value = null;
overviewPromise = null;
}
function clear() {
resetSessionState();
token.value = null;
localStorage.removeItem("jwt");
}
return {
token,
overview,
loading,
isLoggedIn,
login,
loginWithJwt,
fetchOverview,
refreshOverview,
logout,
clear,
legacyLoginPending,
prepareLegacyLogin,
verifyLegacyLogin,
cancelLegacyLogin,
};
});
export {
lt as loginErrorMessage,
ApiError,
ye as apiCacheKey,
ve as apiCacheVersion,
W as sanitizeMessage,
de as operationMessage,
mt as securityMethods,
useApi,
Se as writeApiCache,
ft as assertSecurityComplete,
ut as isValidJwt,
xe as readApiCache,
dt as securityChallenge,
useAuth,
_e as clearApiCache,
};