币商页面
This commit is contained in:
parent
1fc21860a2
commit
1a3984fb63
@ -36,7 +36,7 @@
|
||||
width: min(100%, var(--page-width));
|
||||
aspect-ratio: 1080 / 2410;
|
||||
margin: 0 auto;
|
||||
overflow: hidden;
|
||||
overflow: visible;
|
||||
background: var(--brown-990);
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: var(--brown-990);
|
||||
overflow: hidden;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.sr-only {
|
||||
@ -118,7 +118,141 @@
|
||||
left: 5.3704%;
|
||||
top: 63.0705%;
|
||||
width: 89.1667%;
|
||||
height: 11.4108%;
|
||||
height: auto;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.agency-list {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.agency-row {
|
||||
width: 100%;
|
||||
aspect-ratio: 963 / 275;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 0 24px;
|
||||
border: 1px solid var(--gold-line);
|
||||
border-radius: 2.9076% / 10.1818%;
|
||||
background: var(--panel-brown);
|
||||
box-shadow:
|
||||
inset 0 0 0 1px rgba(255, 214, 109, 0.16),
|
||||
0 6px 18px rgba(38, 11, 0, 0.35);
|
||||
}
|
||||
|
||||
.agency-avatar {
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
flex: 0 0 52px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid rgba(255, 220, 136, 0.78);
|
||||
background: rgba(46, 18, 0, 0.55);
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.agency-main {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.agency-name {
|
||||
display: block;
|
||||
color: #fff3cf;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
line-height: 1.15;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.agency-meta {
|
||||
margin-top: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
color: rgba(255, 238, 195, 0.74);
|
||||
font-size: 10px;
|
||||
line-height: 1.15;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.agency-flags {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.agency-flag {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid rgba(255, 238, 195, 0.62);
|
||||
object-fit: cover;
|
||||
background: rgba(46, 18, 0, 0.6);
|
||||
}
|
||||
|
||||
.agency-actions {
|
||||
flex: 0 0 78px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
justify-content: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.agency-action {
|
||||
appearance: none;
|
||||
width: 78px;
|
||||
height: 24px;
|
||||
margin: 0;
|
||||
padding: 0 7px;
|
||||
border: 1px solid rgba(255, 222, 126, 0.72);
|
||||
border-radius: 999px;
|
||||
font-size: 10px;
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
letter-spacing: 0;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
box-shadow: 0 2px 8px rgba(38, 11, 0, 0.3);
|
||||
}
|
||||
|
||||
.agency-action:active {
|
||||
transform: translateY(1px);
|
||||
}
|
||||
|
||||
.agency-action.whatsapp {
|
||||
border-color: rgba(159, 255, 185, 0.84);
|
||||
background: linear-gradient(180deg, #27c66a, #168a49);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.agency-action.profile {
|
||||
background: linear-gradient(180deg, #fff2a8, #efb43d);
|
||||
color: #552300;
|
||||
}
|
||||
|
||||
.agency-state {
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(255, 238, 195, 0.78);
|
||||
font-size: 13px;
|
||||
font-weight: 650;
|
||||
text-align: center;
|
||||
padding: 0 18px;
|
||||
aspect-ratio: 963 / 275;
|
||||
border: 1px solid var(--gold-line);
|
||||
border-radius: 2.9076% / 10.1818%;
|
||||
background: var(--panel-brown);
|
||||
@ -127,13 +261,15 @@
|
||||
.bottom-frame {
|
||||
position: absolute;
|
||||
left: 1.8056%;
|
||||
top: 91%;
|
||||
top: var(--bottom-frame-top, 91%);
|
||||
width: 96.1574%;
|
||||
height: 2.4066%;
|
||||
display: block;
|
||||
max-width: none;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
transform: scaleY(-1);
|
||||
transform-origin: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
@ -151,7 +287,11 @@
|
||||
|
||||
<img class="title-ribbon" src="../../assets/recharge-agency-list/title-ribbon.png" alt="Recharge Agency" />
|
||||
|
||||
<section class="content-panel" aria-label="Recharge agency list"></section>
|
||||
<section class="content-panel" aria-label="Recharge agency list">
|
||||
<div class="agency-list" data-agency-list>
|
||||
<div class="agency-state">Loading agencies...</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<svg class="bottom-frame" aria-hidden="true" viewBox="0 0 1038.5 58" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 58L9 49V28L34 8H193.5L200 17.5H840.5L845.5 8H1005.5L1031 28.5V49L1038.5 58V25.5L1010 0H840.5L834.5 11.5H204L197 0H30L0 25.5V58Z" fill="url(#bottom-frame-gradient)" />
|
||||
@ -166,6 +306,307 @@
|
||||
</svg>
|
||||
</div>
|
||||
</main>
|
||||
<script>
|
||||
(function () {
|
||||
const DEFAULT_API_BASE = "https://jvapi.haiyihy.com/";
|
||||
const DEFAULT_API_PREFIX = "/go";
|
||||
const ENDPOINT = "/app/h5/recharge-agency-list/sellers";
|
||||
const DEFAULT_AVATAR = "../../assets/defaultAvatar-CdxWBK1k.png";
|
||||
const query = new URLSearchParams(window.location.search || "");
|
||||
const hashQuery = new URLSearchParams((window.location.hash.split("?")[1] || "").split("#")[0]);
|
||||
const listNode = document.querySelector("[data-agency-list]");
|
||||
|
||||
function trimValue(value) {
|
||||
return String(value || "").trim();
|
||||
}
|
||||
|
||||
function readParam(names) {
|
||||
for (const name of names) {
|
||||
const fromQuery = trimValue(query.get(name));
|
||||
if (fromQuery) return fromQuery;
|
||||
const fromHash = trimValue(hashQuery.get(name));
|
||||
if (fromHash) return fromHash;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function normalizeBaseURL(base) {
|
||||
const value = trimValue(base) || DEFAULT_API_BASE;
|
||||
return value.endsWith("/") ? value : value + "/";
|
||||
}
|
||||
|
||||
function resolveAPIBase() {
|
||||
const override = readParam(["apiBase", "api_base"]);
|
||||
if (override) return normalizeBaseURL(override);
|
||||
if (typeof window.__RECHARGE_AGENCY_API_BASE__ === "string") {
|
||||
return normalizeBaseURL(window.__RECHARGE_AGENCY_API_BASE__);
|
||||
}
|
||||
return normalizeBaseURL(DEFAULT_API_BASE);
|
||||
}
|
||||
|
||||
function resolveAPIPrefix(apiBase) {
|
||||
const override = readParam(["apiPrefix", "api_prefix"]);
|
||||
if (override) return override;
|
||||
if (typeof window.__RECHARGE_AGENCY_API_PREFIX__ === "string") {
|
||||
return trimValue(window.__RECHARGE_AGENCY_API_PREFIX__);
|
||||
}
|
||||
try {
|
||||
return new URL(apiBase).origin === new URL(DEFAULT_API_BASE).origin ? DEFAULT_API_PREFIX : "";
|
||||
} catch (_) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function joinPath() {
|
||||
return "/" + Array.prototype.slice.call(arguments)
|
||||
.map((part) => trimValue(part).replace(/^\/+|\/+$/g, ""))
|
||||
.filter(Boolean)
|
||||
.join("/");
|
||||
}
|
||||
|
||||
function buildURL(path) {
|
||||
const apiBase = resolveAPIBase();
|
||||
const apiPrefix = resolveAPIPrefix(apiBase);
|
||||
const url = new URL(joinPath(apiPrefix, path).replace(/^\/+/, ""), apiBase);
|
||||
url.searchParams.set("cursor", readParam(["cursor"]) || "1");
|
||||
url.searchParams.set("limit", readParam(["limit"]) || "20");
|
||||
return url;
|
||||
}
|
||||
|
||||
function normalizeAuthorization(value) {
|
||||
const token = trimValue(value);
|
||||
if (!token) return "";
|
||||
return /^bearer\s+/i.test(token) ? token : "Bearer " + token;
|
||||
}
|
||||
|
||||
function readAuthorization() {
|
||||
const direct = readParam(["Authorization", "authorization"]);
|
||||
if (direct) return normalizeAuthorization(direct);
|
||||
const token = readParam(["token", "accessToken", "access_token"]);
|
||||
if (token) return normalizeAuthorization(token);
|
||||
if (typeof window.__RECHARGE_AGENCY_AUTHORIZATION__ === "string") {
|
||||
return normalizeAuthorization(window.__RECHARGE_AGENCY_AUTHORIZATION__);
|
||||
}
|
||||
try {
|
||||
return normalizeAuthorization(
|
||||
window.localStorage.getItem("Authorization") ||
|
||||
window.localStorage.getItem("authorization") ||
|
||||
window.localStorage.getItem("token") ||
|
||||
window.localStorage.getItem("accessToken")
|
||||
);
|
||||
} catch (_) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function clearList() {
|
||||
while (listNode.firstChild) listNode.removeChild(listNode.firstChild);
|
||||
}
|
||||
|
||||
function syncListLayout(count) {
|
||||
const safeCount = Math.max(1, Number(count) || 1);
|
||||
const listTop = 63.0705;
|
||||
const cardHeight = 11.4108;
|
||||
const cardGap = 1.16;
|
||||
const bottomGap = 3.95;
|
||||
const listHeight = safeCount * cardHeight + Math.max(0, safeCount - 1) * cardGap;
|
||||
const bottomTop = Math.max(91, listTop + listHeight + bottomGap);
|
||||
document.documentElement.style.setProperty("--bottom-frame-top", bottomTop.toFixed(4) + "%");
|
||||
}
|
||||
|
||||
function renderState(message) {
|
||||
syncListLayout(1);
|
||||
clearList();
|
||||
const node = document.createElement("div");
|
||||
node.className = "agency-state";
|
||||
node.textContent = message;
|
||||
listNode.appendChild(node);
|
||||
}
|
||||
|
||||
function compactNumber(value) {
|
||||
const number = Number(value || 0);
|
||||
if (!Number.isFinite(number) || number <= 0) return "";
|
||||
if (number >= 1000000) return (number / 1000000).toFixed(1).replace(/\.0$/, "") + "M";
|
||||
if (number >= 1000) return (number / 1000).toFixed(1).replace(/\.0$/, "") + "K";
|
||||
return String(Math.trunc(number));
|
||||
}
|
||||
|
||||
function createImage(className, src, fallback) {
|
||||
const img = document.createElement("img");
|
||||
img.className = className;
|
||||
img.alt = "";
|
||||
img.decoding = "async";
|
||||
img.loading = "lazy";
|
||||
img.src = trimValue(src) || fallback || "";
|
||||
img.onerror = function () {
|
||||
if (fallback && img.src.indexOf(fallback) === -1) {
|
||||
img.src = fallback;
|
||||
}
|
||||
};
|
||||
return img;
|
||||
}
|
||||
|
||||
function isInAppWebView() {
|
||||
return !!(
|
||||
window.FlutterPageControl &&
|
||||
typeof window.FlutterPageControl.postMessage === "function"
|
||||
);
|
||||
}
|
||||
|
||||
function sendToApp(message) {
|
||||
if (!isInAppWebView()) {
|
||||
console.warn("[AppBridge] FlutterPageControl is not available", message);
|
||||
return false;
|
||||
}
|
||||
window.FlutterPageControl.postMessage(String(message));
|
||||
return true;
|
||||
}
|
||||
|
||||
function openUserProfile(uid) {
|
||||
const safeUID = trimValue(uid).replace(/:/g, "");
|
||||
if (!safeUID) return false;
|
||||
return sendToApp("view_user_info:" + safeUID);
|
||||
}
|
||||
|
||||
function normalizeWhatsapp(value) {
|
||||
const raw = trimValue(value);
|
||||
if (!raw) return "";
|
||||
const linkMatch = raw.match(/(?:wa\.me\/|phone=)(\+?\d[\d\s().-]*)/i);
|
||||
const phoneSource = linkMatch ? linkMatch[1] : ((raw.match(/\+?\d[\d\s().-]{5,}\d/) || [raw])[0]);
|
||||
const digits = phoneSource.replace(/\D/g, "");
|
||||
return digits.length >= 6 ? digits : "";
|
||||
}
|
||||
|
||||
function buildWhatsappURL(value) {
|
||||
const raw = trimValue(value);
|
||||
if (/^https?:\/\/(?:wa\.me|api\.whatsapp\.com|www\.whatsapp\.com)\//i.test(raw)) {
|
||||
return raw;
|
||||
}
|
||||
const phone = normalizeWhatsapp(raw);
|
||||
return phone ? "https://wa.me/" + encodeURIComponent(phone) : "";
|
||||
}
|
||||
|
||||
function openWhatsapp(value) {
|
||||
const url = buildWhatsappURL(value);
|
||||
if (!url) return false;
|
||||
let opened = null;
|
||||
if (typeof window.open === "function") {
|
||||
opened = window.open(url, "_blank", "noopener");
|
||||
}
|
||||
if (!opened) {
|
||||
window.location.href = url;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function createRow(item) {
|
||||
const row = document.createElement("article");
|
||||
row.className = "agency-row";
|
||||
row.dataset.userId = trimValue(item.userId);
|
||||
|
||||
row.appendChild(createImage("agency-avatar", item.userAvatar, DEFAULT_AVATAR));
|
||||
|
||||
const main = document.createElement("div");
|
||||
main.className = "agency-main";
|
||||
|
||||
const name = document.createElement("span");
|
||||
name.className = "agency-name";
|
||||
name.textContent = item.userNickname || item.account || ("ID " + item.userId);
|
||||
main.appendChild(name);
|
||||
|
||||
const meta = document.createElement("div");
|
||||
meta.className = "agency-meta";
|
||||
const place = [item.countryName, item.regionCode].filter(Boolean).join(" / ");
|
||||
const count = compactNumber(item.transactionCount);
|
||||
const metaParts = [];
|
||||
if (place) metaParts.push(place);
|
||||
metaParts.push("ID " + (item.account || item.userId));
|
||||
if (count) metaParts.push(count + " orders");
|
||||
meta.textContent = metaParts.join(" · ");
|
||||
main.appendChild(meta);
|
||||
row.appendChild(main);
|
||||
|
||||
const flags = document.createElement("div");
|
||||
flags.className = "agency-flags";
|
||||
const flagValues = (Array.isArray(item.nationalFlag) ? item.nationalFlag : []).slice(0, 3).filter(Boolean);
|
||||
flagValues.forEach(function (flag) {
|
||||
flags.appendChild(createImage("agency-flag", flag, ""));
|
||||
});
|
||||
if (flagValues.length) row.appendChild(flags);
|
||||
|
||||
const actions = document.createElement("div");
|
||||
actions.className = "agency-actions";
|
||||
const whatsapp = item.whatsapp || item.whatsApp || item.contactInfo;
|
||||
if (normalizeWhatsapp(whatsapp)) {
|
||||
const whatsappButton = document.createElement("button");
|
||||
whatsappButton.type = "button";
|
||||
whatsappButton.className = "agency-action whatsapp";
|
||||
whatsappButton.textContent = "WhatsApp";
|
||||
whatsappButton.setAttribute("aria-label", "Open WhatsApp");
|
||||
whatsappButton.addEventListener("click", function (event) {
|
||||
event.stopPropagation();
|
||||
openWhatsapp(whatsapp);
|
||||
});
|
||||
actions.appendChild(whatsappButton);
|
||||
}
|
||||
|
||||
const profileButton = document.createElement("button");
|
||||
profileButton.type = "button";
|
||||
profileButton.className = "agency-action profile";
|
||||
profileButton.textContent = "Profile";
|
||||
profileButton.setAttribute("aria-label", "Open user profile");
|
||||
profileButton.addEventListener("click", function (event) {
|
||||
event.stopPropagation();
|
||||
openUserProfile(item.userId);
|
||||
});
|
||||
actions.appendChild(profileButton);
|
||||
row.appendChild(actions);
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
function normalizePayload(json) {
|
||||
const body = json && (json.body || json.data || json);
|
||||
return body && Array.isArray(body.records) ? body.records : [];
|
||||
}
|
||||
|
||||
async function fetchAgencies() {
|
||||
if (!listNode) return;
|
||||
const authorization = readAuthorization();
|
||||
if (!authorization) {
|
||||
renderState("Open in app to view agencies.");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const response = await fetch(buildURL(ENDPOINT).toString(), {
|
||||
cache: "no-store",
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
Authorization: authorization,
|
||||
},
|
||||
});
|
||||
const json = await response.json().catch(function () { return {}; });
|
||||
if (!response.ok || json.status === false) {
|
||||
throw new Error(json.errorMsg || json.message || "Unable to load agencies.");
|
||||
}
|
||||
const records = normalizePayload(json);
|
||||
if (!records.length) {
|
||||
renderState("No agencies available.");
|
||||
return;
|
||||
}
|
||||
syncListLayout(records.length);
|
||||
clearList();
|
||||
records.forEach(function (item) {
|
||||
listNode.appendChild(createRow(item || {}));
|
||||
});
|
||||
} catch (error) {
|
||||
renderState(error && error.message ? error.message : "Unable to load agencies.");
|
||||
}
|
||||
}
|
||||
|
||||
fetchAgencies();
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
35
h5/coin-seller/index.back.html
Normal file
35
h5/coin-seller/index.back.html
Normal file
@ -0,0 +1,35 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
|
||||
>
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
||||
<meta http-equiv="Pragma" content="no-cache">
|
||||
<meta http-equiv="Expires" content="0">
|
||||
<title>Yumi H5</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
window.__H5_ROUTE_PATH__ = "/coin-seller";
|
||||
</script>
|
||||
<script src="/assets/yumi-route-entry.js"></script>
|
||||
<script type="module" crossorigin src="/js/index-CIAVq8iD-1776148658686.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/css/index-VRlNQ74k-1776148661679.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,35 +1,19 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
|
||||
>
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
||||
<meta http-equiv="Pragma" content="no-cache">
|
||||
<meta http-equiv="Expires" content="0">
|
||||
<title>Yumi H5</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
window.__H5_ROUTE_PATH__ = "/coin-seller";
|
||||
</script>
|
||||
<script src="/assets/yumi-route-entry.js"></script>
|
||||
<script type="module" crossorigin src="/js/index-CIAVq8iD-1776148658686.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/css/index-VRlNQ74k-1776148661679.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
var target = new URL("https://h5.haiyihy.com/hyapp/recharge-center/index.html")
|
||||
var source = new URL(window.location.href)
|
||||
source.searchParams.forEach(function (value, key) {
|
||||
target.searchParams.set(key, value)
|
||||
})
|
||||
target.searchParams.set("h5v", "20260429-0335")
|
||||
window.location.replace(target.toString())
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
|
||||
<title>Recharge Center</title>
|
||||
<link rel="stylesheet" href="./style.css?v=20260429-0100" />
|
||||
<link rel="stylesheet" href="./style.css?v=20260430-0108" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="recharge-center" aria-label="Recharge Center" data-i18n-aria="page_label" data-loading="true">
|
||||
@ -28,6 +28,49 @@
|
||||
</nav>
|
||||
|
||||
<main class="content">
|
||||
<section class="card profile-card self-profile-card" aria-label="User profile" data-i18n-aria="profile_card">
|
||||
<div class="avatar-shell">
|
||||
<img class="avatar-image" id="selfAvatar" alt="" hidden />
|
||||
<span class="avatar-fallback" id="selfAvatarFallback">U</span>
|
||||
</div>
|
||||
<div class="profile-copy">
|
||||
<div class="name" id="selfName">-</div>
|
||||
<div class="meta" id="selfUid">UID: -</div>
|
||||
<div class="meta whatsapp-meta" id="selfWhatsappRow">
|
||||
<span class="whatsapp-icon" id="selfWhatsappIcon" aria-hidden="true" hidden>
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M6.2 18.2 4.8 21l3.2-1.1a8.2 8.2 0 1 0-1.8-1.7Z" />
|
||||
<path d="M9.4 8.4c.3-.3.8-.3 1 .1l.7 1.2c.2.4.1.8-.2 1.1l-.4.3c.5 1 1.4 1.8 2.4 2.3l.4-.5c.3-.3.7-.4 1.1-.2l1.2.7c.4.2.5.7.2 1-.5.8-1.2 1.1-2.1.9-2.8-.6-5.1-2.8-5.8-5.6-.2-.8.2-1.5 1.5-1.3Z" />
|
||||
</svg>
|
||||
</span>
|
||||
<span id="selfWhatsappText"></span>
|
||||
<button class="whatsapp-add-button" id="addWhatsappButton" type="button" data-whatsapp-open data-i18n="add_whatsapp">+ add whatsapp</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card balance-card" aria-label="Coins" data-i18n-aria="balance_title">
|
||||
<div class="balance-head">
|
||||
<div>
|
||||
<div class="balance-label" data-i18n="balance_title">Coins</div>
|
||||
</div>
|
||||
<button class="history-button" type="button" data-history-open aria-label="History" data-i18n-aria="history">
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M12 8v5l3 2" />
|
||||
<path d="M3.5 12a8.5 8.5 0 1 0 2.2-5.7" />
|
||||
<path d="M3.5 4.5v5h5" />
|
||||
</svg>
|
||||
<span data-i18n="history">History</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="balance-value">
|
||||
<span class="balance-coin gold-coin-icon" aria-hidden="true">
|
||||
<span class="gold-coin-shine"></span>
|
||||
</span>
|
||||
<strong id="selfBalance">0</strong>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card search-card">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
@ -59,28 +102,26 @@
|
||||
<div class="name" id="targetName">-</div>
|
||||
<div class="meta" id="targetUid">UID: -</div>
|
||||
</div>
|
||||
<button class="mini-action" type="button" data-change-target data-i18n="change">Change</button>
|
||||
<button class="mini-action mini-action-icon" type="button" data-change-target aria-label="Change" data-i18n-aria="change">X</button>
|
||||
</section>
|
||||
|
||||
<section class="card country-card" id="countryCard" hidden>
|
||||
<section class="card coin-recharge-card" id="coinRechargeCard" hidden>
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<div class="section-title" data-i18n="select_country">Select a country</div>
|
||||
<div class="section-subtitle" id="countrySubtitle">-</div>
|
||||
<div class="section-title" data-i18n="coin_recharge_title">Recharge coins</div>
|
||||
<div class="section-subtitle" data-i18n="coin_recharge_subtitle">Enter coins amount</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="country-list" id="countryList"></div>
|
||||
</section>
|
||||
|
||||
<section class="card payment-card" id="paymentCard" hidden>
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<div class="section-title" data-i18n="payment_methods">Payment methods</div>
|
||||
<div class="section-subtitle" data-i18n="select_package">Select a package</div>
|
||||
<form class="coin-recharge-form" id="coinRechargeForm" autocomplete="off">
|
||||
<div class="coin-input-shell">
|
||||
<span class="input-coin gold-coin-icon" aria-hidden="true">
|
||||
<span class="gold-coin-shine"></span>
|
||||
</span>
|
||||
<input id="coinAmountInput" type="text" inputmode="numeric" data-i18n-placeholder="coin_amount_placeholder" placeholder="Enter coins amount" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="payment-status" id="paymentStatus" role="status" hidden></div>
|
||||
<div class="channel-list" id="channelList"></div>
|
||||
<button id="confirmRechargeButton" type="submit" data-i18n="confirm_recharge">Confirm recharge</button>
|
||||
</form>
|
||||
<div class="form-status" id="coinRechargeStatus" role="status" hidden></div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
@ -94,13 +135,60 @@
|
||||
<div class="help-content">
|
||||
<h3 data-i18n="faq_title">FAQ</h3>
|
||||
<p data-i18n="faq_question_1">How to recharge?</p>
|
||||
<p data-i18n="faq_answer_1">Enter the user's ID, choose a package, then select a payment method.</p>
|
||||
<p data-i18n="faq_answer_1">Enter the user's ID, enter the coins amount, then confirm recharge.</p>
|
||||
<p data-i18n="faq_question_2">How to check recharge result?</p>
|
||||
<p data-i18n="faq_answer_2">After payment, return to the app and check the user's wallet balance.</p>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="history-modal" id="historyModal" hidden>
|
||||
<div class="modal-backdrop" data-history-close></div>
|
||||
<section class="modal-dialog history-dialog" role="dialog" aria-modal="true" aria-labelledby="historyTitle">
|
||||
<div class="modal-head">
|
||||
<h2 id="historyTitle" data-i18n="transaction_records">Transaction records</h2>
|
||||
<button class="modal-close" type="button" aria-label="Close" data-i18n-aria="close" data-history-close>×</button>
|
||||
</div>
|
||||
<div class="history-body">
|
||||
<form class="history-search-form" id="historySearchForm" autocomplete="off">
|
||||
<input id="historySearchInput" type="text" inputmode="text" data-i18n-placeholder="enter_user_id" placeholder="Enter user ID" />
|
||||
<button type="submit" data-i18n="search">Search</button>
|
||||
<button id="historyClearButton" class="history-clear-button" type="button" data-i18n="cancel">Cancel</button>
|
||||
</form>
|
||||
<div class="history-tabs" role="tablist" aria-label="Transaction type">
|
||||
<button type="button" class="history-tab is-active" data-history-tab="0" data-i18n="income">Income</button>
|
||||
<button type="button" class="history-tab" data-history-tab="1" data-i18n="expenditure">Expenditure</button>
|
||||
</div>
|
||||
<div class="history-status" id="historyStatus" role="status" hidden></div>
|
||||
<div class="history-list" id="historyList"></div>
|
||||
<button class="history-load-more" id="historyLoadMore" type="button" data-i18n="load_more" hidden>Load more</button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="whatsapp-modal" id="whatsappModal" hidden>
|
||||
<div class="modal-backdrop" data-whatsapp-close></div>
|
||||
<section class="modal-dialog whatsapp-dialog" role="dialog" aria-modal="true" aria-labelledby="whatsappTitle">
|
||||
<div class="modal-head">
|
||||
<h2 id="whatsappTitle" data-i18n="add_whatsapp_title">Add WhatsApp</h2>
|
||||
<button class="modal-close" type="button" aria-label="Close" data-i18n-aria="close" data-whatsapp-close>×</button>
|
||||
</div>
|
||||
<form class="whatsapp-form" id="whatsappForm" autocomplete="off">
|
||||
<div class="whatsapp-input-shell">
|
||||
<span class="whatsapp-input-icon" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M6.2 18.2 4.8 21l3.2-1.1a8.2 8.2 0 1 0-1.8-1.7Z" />
|
||||
<path d="M9.4 8.4c.3-.3.8-.3 1 .1l.7 1.2c.2.4.1.8-.2 1.1l-.4.3c.5 1 1.4 1.8 2.4 2.3l.4-.5c.3-.3.7-.4 1.1-.2l1.2.7c.4.2.5.7.2 1-.5.8-1.2 1.1-2.1.9-2.8-.6-5.1-2.8-5.8-5.6-.2-.8.2-1.5 1.5-1.3Z" />
|
||||
</svg>
|
||||
</span>
|
||||
<input id="whatsappInput" type="tel" inputmode="tel" data-i18n-placeholder="whatsapp_placeholder" placeholder="Enter WhatsApp" />
|
||||
</div>
|
||||
<button id="saveWhatsappButton" type="submit" data-i18n="save">Save</button>
|
||||
<div class="form-status" id="whatsappStatus" role="status" hidden></div>
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="home-indicator" aria-hidden="true"></div>
|
||||
<div class="loading-mask" id="loadingMask" role="status" aria-live="polite" aria-busy="true">
|
||||
<div class="runner-stick" aria-hidden="true">
|
||||
@ -112,11 +200,11 @@
|
||||
<span class="runner-leg runner-leg-back"></span>
|
||||
<span class="runner-ground"></span>
|
||||
</div>
|
||||
<div class="loading-copy">loading....</div>
|
||||
<div class="loading-copy" data-i18n="loading_mask">loading....</div>
|
||||
</div>
|
||||
|
||||
<div class="toast" id="toast" role="status" aria-live="polite" hidden></div>
|
||||
</div>
|
||||
<script src="./script.js?v=20260429-0100" defer></script>
|
||||
<script src="./script.js?v=20260430-0108" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -32,6 +32,44 @@
|
||||
|
||||
## APIs
|
||||
|
||||
### Get current user profile
|
||||
|
||||
`GET /team/member/profile`
|
||||
|
||||
Usage in new H5:
|
||||
- Loads the current logged-in user's account card before the recharge flow.
|
||||
- This is the same current-user profile source reused by the hyapp center pages.
|
||||
|
||||
Reusable fields:
|
||||
- `id`
|
||||
- `account`
|
||||
- `userNickname`
|
||||
- `name`
|
||||
- `userAvatar`
|
||||
- `ownSpecialId.account`
|
||||
|
||||
### Get current user coin balance
|
||||
|
||||
`GET /wallet/freight/balance`
|
||||
|
||||
Original Vue reference:
|
||||
- The old recharge agency / coin seller page imports `a4` from the main bundle.
|
||||
- `a4` maps to `dX()`, which calls `GET /wallet/freight/balance`.
|
||||
- Original UI stores `body.toString()` and displays it under `my_coins`.
|
||||
|
||||
Usage in new H5:
|
||||
- Displays the current user's Coins card.
|
||||
- If the request fails, the page keeps showing `0` and the recharge flow still works.
|
||||
|
||||
Reusable fields:
|
||||
- `body` as number
|
||||
- `body.gold`
|
||||
- `body.goldBalance`
|
||||
- `body.coin`
|
||||
- `body.coins`
|
||||
- `body.balance`
|
||||
- `body.amount`
|
||||
|
||||
### Search target user
|
||||
|
||||
`GET /user/user-profile/open-search?account=<account>`
|
||||
@ -52,6 +90,55 @@ Reusable fields:
|
||||
- `isFreightAgent`
|
||||
- `isSuperFreightAgent`
|
||||
|
||||
### Recharge coins to target user
|
||||
|
||||
`POST /wallet/freight/ship`
|
||||
|
||||
Body:
|
||||
|
||||
```json
|
||||
{
|
||||
"acceptUserId": "<target user id>",
|
||||
"quantity": 1000
|
||||
}
|
||||
```
|
||||
|
||||
Original Vue reference:
|
||||
- The old coin seller page imports `a5` from the main bundle.
|
||||
- `a5` maps to `mX(payload)`, which calls `POST /wallet/freight/ship`.
|
||||
- Original submit logic sends `te({ acceptUserId: o, quantity: t })`.
|
||||
- If the response has `body`, Vue uses it as the updated current coin balance.
|
||||
|
||||
Usage in new H5:
|
||||
- After searching the target user, the page shows one coins input and a confirm recharge button.
|
||||
- It no longer shows country selection, payment methods, or recharge packages for this direct transfer flow.
|
||||
|
||||
Reusable fields:
|
||||
- `acceptUserId`: target user `id`
|
||||
- `quantity`: entered coins amount
|
||||
- response `body`: updated current user coin balance when returned
|
||||
|
||||
### Get transfer history
|
||||
|
||||
`GET /wallet/freight/balance/running/water/client/flowByUserId`
|
||||
|
||||
Query params:
|
||||
- `userId=<current user id>`
|
||||
- `type=0 | 1`
|
||||
- `searchId=<searched user id or empty>`
|
||||
- `lastId=<last record id for load more or empty>`
|
||||
|
||||
Original Vue reference:
|
||||
- The seller records page imports `ad` as `Z` from the main bundle.
|
||||
- `Z(params)` maps to `hX(params)`, which calls this endpoint.
|
||||
- Original page uses `type=0` for `income` and `type=1` for `expenditure`.
|
||||
- For each record, Vue displays `+quantity` when `record.type === 0`, otherwise `-quantity`.
|
||||
- For user display, Vue reads `record.userAccount` for income records and `record.acceptUserAccount` for expenditure records.
|
||||
|
||||
Usage in new H5:
|
||||
- The Coins card has a right-side History button.
|
||||
- History opens in a center modal with Income / Expenditure tabs, user ID search, and load more using `lastId`.
|
||||
|
||||
### Get payment application
|
||||
|
||||
`GET /order/web/pay/application/{applicationId}`
|
||||
@ -160,4 +247,5 @@ Reusable fields:
|
||||
- New page lives at `h5/hyapp/recharge-center`.
|
||||
- It keeps the existing hyapp center architecture: static `index.html`, `style.css`, `script.js`.
|
||||
- It uses URL `token` for Java API authorization and sends the same H5 request headers used by the existing hyapp center pages.
|
||||
- It merges the original `/recharge` and `/recharge-pay-way` flows into one page, so it does not depend on Vue router or Pinia `targetUser`.
|
||||
- It uses the old coin seller direct-transfer API for the current UI: search target user, enter coins amount, and confirm recharge.
|
||||
- The older `/recharge-pay-way` country / package / third-party payment flow is documented above for reference but is not rendered in the current H5 page.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -189,8 +189,7 @@ button {
|
||||
}
|
||||
|
||||
.search-card,
|
||||
.country-card,
|
||||
.payment-card {
|
||||
.coin-recharge-card {
|
||||
display: grid;
|
||||
gap: 14px;
|
||||
padding: 16px;
|
||||
@ -238,6 +237,11 @@ button {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.coin-recharge-form {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.search-form input {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
@ -257,7 +261,46 @@ button {
|
||||
box-shadow: 0 0 0 3px rgba(21, 189, 169, 0.12);
|
||||
}
|
||||
|
||||
.coin-input-shell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
min-height: 48px;
|
||||
padding: 0 12px;
|
||||
border: 1px solid #e4eeee;
|
||||
border-radius: 8px;
|
||||
background: #fbfdfd;
|
||||
}
|
||||
|
||||
.coin-input-shell:focus-within {
|
||||
border-color: rgba(21, 189, 169, 0.7);
|
||||
box-shadow: 0 0 0 3px rgba(21, 189, 169, 0.12);
|
||||
}
|
||||
|
||||
.input-coin {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
flex: 0 0 28px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.coin-input-shell input {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
height: 46px;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
background: transparent;
|
||||
color: #24282e;
|
||||
font-size: 16px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.search-form button,
|
||||
.coin-recharge-form button,
|
||||
.package-button,
|
||||
.mini-action {
|
||||
min-height: 44px;
|
||||
@ -274,7 +317,13 @@ button {
|
||||
padding: 0 14px;
|
||||
}
|
||||
|
||||
.coin-recharge-form button {
|
||||
width: 100%;
|
||||
padding: 0 14px;
|
||||
}
|
||||
|
||||
.search-form button:disabled,
|
||||
.coin-recharge-form button:disabled,
|
||||
.package-button:disabled,
|
||||
.mini-action:disabled {
|
||||
opacity: 0.55;
|
||||
@ -304,6 +353,121 @@ button {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.balance-card {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
padding: 16px;
|
||||
overflow: hidden;
|
||||
background:
|
||||
radial-gradient(circle at 88% 10%, rgba(75, 231, 216, 0.18), rgba(75, 231, 216, 0) 34%),
|
||||
linear-gradient(145deg, #ffffff 0%, #f8fffd 100%);
|
||||
}
|
||||
|
||||
.balance-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.balance-label {
|
||||
color: #24282e;
|
||||
font-size: 15px;
|
||||
font-weight: 950;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.balance-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
flex: 0 0 34px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.history-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
min-height: 34px;
|
||||
padding: 0 10px;
|
||||
border-radius: 999px;
|
||||
background: #e7fbf8;
|
||||
color: #0aa397;
|
||||
font-size: 12px;
|
||||
font-weight: 950;
|
||||
}
|
||||
|
||||
.history-button svg {
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
stroke-width: 2.2;
|
||||
}
|
||||
|
||||
.gold-coin-icon {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border: 2px solid #f0ad17;
|
||||
background:
|
||||
radial-gradient(circle at 34% 28%, rgba(255, 255, 255, 0.72) 0 9%, rgba(255, 255, 255, 0) 25%),
|
||||
linear-gradient(145deg, #ffe88a 0%, #ffc928 47%, #f4a800 100%);
|
||||
box-shadow:
|
||||
inset 0 -3px 0 rgba(174, 111, 0, 0.16),
|
||||
inset 0 2px 0 rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.gold-coin-icon::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 7px;
|
||||
border: 2px solid rgba(174, 111, 0, 0.24);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.gold-coin-shine {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 10px;
|
||||
width: 8px;
|
||||
height: 4px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.72);
|
||||
transform: rotate(-28deg);
|
||||
}
|
||||
|
||||
.balance-value {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 9px;
|
||||
min-width: 0;
|
||||
color: #181d24;
|
||||
}
|
||||
|
||||
.balance-coin {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
flex: 0 0 28px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.balance-value strong {
|
||||
min-width: 0;
|
||||
overflow-wrap: anywhere;
|
||||
font-size: 32px;
|
||||
font-weight: 950;
|
||||
line-height: 1.05;
|
||||
}
|
||||
|
||||
.avatar-shell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -358,6 +522,10 @@ button {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.self-profile-card .name {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.meta {
|
||||
margin-top: 6px;
|
||||
overflow: hidden;
|
||||
@ -369,6 +537,50 @@ button {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.whatsapp-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.whatsapp-meta span {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.whatsapp-icon,
|
||||
.whatsapp-input-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
flex: 0 0 22px;
|
||||
border-radius: 50%;
|
||||
background: #e7fbf8;
|
||||
color: #0aa397;
|
||||
}
|
||||
|
||||
.whatsapp-icon svg,
|
||||
.whatsapp-input-icon svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
stroke-width: 1.9;
|
||||
}
|
||||
|
||||
.whatsapp-add-button {
|
||||
color: #0aa397;
|
||||
font-size: 13px;
|
||||
font-weight: 950;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.mini-action {
|
||||
min-width: 78px;
|
||||
min-height: 36px;
|
||||
@ -377,6 +589,14 @@ button {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.mini-action-icon {
|
||||
width: 36px;
|
||||
min-width: 36px;
|
||||
padding: 0;
|
||||
font-size: 18px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.country-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(118px, 1fr));
|
||||
@ -513,9 +733,6 @@ button {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(145deg, #ffe694, #ffc93f);
|
||||
color: #8b5d00;
|
||||
font-weight: 950;
|
||||
}
|
||||
|
||||
.package-content,
|
||||
@ -548,7 +765,9 @@ button {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.help-modal {
|
||||
.help-modal,
|
||||
.history-modal,
|
||||
.whatsapp-modal {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 40;
|
||||
@ -629,6 +848,280 @@ button {
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.history-dialog {
|
||||
width: min(100%, 390px);
|
||||
}
|
||||
|
||||
.whatsapp-dialog {
|
||||
width: min(100%, 360px);
|
||||
}
|
||||
|
||||
.whatsapp-form {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
padding: 0 16px 18px;
|
||||
}
|
||||
|
||||
.whatsapp-input-shell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
min-height: 44px;
|
||||
border: 1px solid #e4eeee;
|
||||
border-radius: 8px;
|
||||
padding: 0 12px;
|
||||
background: #fbfdfd;
|
||||
}
|
||||
|
||||
.whatsapp-input-shell:focus-within {
|
||||
border-color: rgba(21, 189, 169, 0.7);
|
||||
box-shadow: 0 0 0 3px rgba(21, 189, 169, 0.12);
|
||||
}
|
||||
|
||||
.whatsapp-form input {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
height: 42px;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
color: #24282e;
|
||||
font-size: 14px;
|
||||
font-weight: 850;
|
||||
}
|
||||
|
||||
.whatsapp-form button {
|
||||
min-height: 44px;
|
||||
border-radius: 8px;
|
||||
background: linear-gradient(135deg, #30dfb4, #15bda9);
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
font-weight: 950;
|
||||
box-shadow: 0 8px 18px rgba(21, 189, 169, 0.24);
|
||||
}
|
||||
|
||||
.whatsapp-form button:disabled {
|
||||
opacity: 0.55;
|
||||
}
|
||||
|
||||
.history-body {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
overflow-y: auto;
|
||||
padding: 0 16px 18px;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.history-search-form {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto auto;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.history-search-form input {
|
||||
min-width: 0;
|
||||
height: 40px;
|
||||
border: 1px solid #e4eeee;
|
||||
border-radius: 8px;
|
||||
outline: 0;
|
||||
padding: 0 10px;
|
||||
background: #fbfdfd;
|
||||
color: #24282e;
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.history-search-form input:focus {
|
||||
border-color: rgba(21, 189, 169, 0.7);
|
||||
box-shadow: 0 0 0 3px rgba(21, 189, 169, 0.12);
|
||||
}
|
||||
|
||||
.history-search-form button {
|
||||
min-width: 56px;
|
||||
min-height: 40px;
|
||||
padding: 0 10px;
|
||||
border-radius: 8px;
|
||||
background: #e7fbf8;
|
||||
color: #0aa397;
|
||||
font-size: 12px;
|
||||
font-weight: 950;
|
||||
}
|
||||
|
||||
.history-search-form button[type="submit"] {
|
||||
background: linear-gradient(135deg, #30dfb4, #15bda9);
|
||||
color: #fff;
|
||||
box-shadow: 0 8px 18px rgba(21, 189, 169, 0.18);
|
||||
}
|
||||
|
||||
.history-tabs {
|
||||
position: relative;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 8px;
|
||||
padding: 4px;
|
||||
border-radius: 8px;
|
||||
background: #f3f7f7;
|
||||
}
|
||||
|
||||
.history-tab {
|
||||
min-height: 36px;
|
||||
border-radius: 7px;
|
||||
color: #7a7f87;
|
||||
font-size: 13px;
|
||||
font-weight: 950;
|
||||
}
|
||||
|
||||
.history-tab.is-active {
|
||||
background: #fff;
|
||||
color: #0aa397;
|
||||
box-shadow: 0 5px 14px rgba(22, 31, 42, 0.07);
|
||||
}
|
||||
|
||||
.history-status {
|
||||
padding: 10px 12px;
|
||||
border-radius: 8px;
|
||||
background: #f1fbf9;
|
||||
color: #0b958a;
|
||||
font-size: 12px;
|
||||
font-weight: 850;
|
||||
}
|
||||
|
||||
.history-status.is-error {
|
||||
background: #fff3f3;
|
||||
color: var(--danger);
|
||||
}
|
||||
|
||||
.history-list {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.history-record {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
min-width: 0;
|
||||
padding: 12px;
|
||||
border: 1px solid #eef0f2;
|
||||
border-radius: 8px;
|
||||
background: #fbfcfc;
|
||||
}
|
||||
|
||||
.history-record-user {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.history-avatar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
flex: 0 0 42px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(145deg, #d9fff5, #43e7d8);
|
||||
color: #0b5f56;
|
||||
font-size: 16px;
|
||||
font-weight: 950;
|
||||
}
|
||||
|
||||
.history-avatar img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.history-record-copy {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.history-record-name,
|
||||
.history-record-account {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.history-record-name {
|
||||
color: #25282e;
|
||||
font-size: 14px;
|
||||
font-weight: 950;
|
||||
}
|
||||
|
||||
.history-record-account {
|
||||
margin-top: 5px;
|
||||
color: var(--muted);
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.history-record-side {
|
||||
display: grid;
|
||||
justify-items: end;
|
||||
gap: 5px;
|
||||
min-width: 88px;
|
||||
}
|
||||
|
||||
.history-record-amount {
|
||||
color: #24282e;
|
||||
font-size: 13px;
|
||||
font-weight: 950;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.history-record-amount.is-income {
|
||||
color: #0aa397;
|
||||
}
|
||||
|
||||
.history-record-amount.is-expense {
|
||||
color: #e09a00;
|
||||
}
|
||||
|
||||
.history-record-time {
|
||||
color: var(--muted);
|
||||
direction: ltr;
|
||||
font-size: 11px;
|
||||
font-weight: 750;
|
||||
}
|
||||
|
||||
.history-empty {
|
||||
display: grid;
|
||||
justify-items: center;
|
||||
gap: 6px;
|
||||
padding: 32px 14px;
|
||||
border-radius: 8px;
|
||||
background: #f7fbfa;
|
||||
color: #8b8d92;
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.history-empty strong {
|
||||
color: #333840;
|
||||
font-size: 15px;
|
||||
font-weight: 950;
|
||||
}
|
||||
|
||||
.history-load-more {
|
||||
min-height: 40px;
|
||||
border-radius: 8px;
|
||||
background: #e7fbf8;
|
||||
color: #0aa397;
|
||||
font-size: 13px;
|
||||
font-weight: 950;
|
||||
}
|
||||
|
||||
.home-indicator {
|
||||
width: 134px;
|
||||
height: 5px;
|
||||
@ -772,6 +1265,14 @@ body.modal-open {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
[dir="rtl"] .history-record-side {
|
||||
justify-items: start;
|
||||
}
|
||||
|
||||
[dir="rtl"] .history-record-amount {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
@keyframes runner-bob {
|
||||
0%,
|
||||
100% {
|
||||
|
||||
@ -33,8 +33,10 @@ const deps = {
|
||||
const state = {
|
||||
applicationId: defaults.applicationId,
|
||||
productType: defaults.productType,
|
||||
application: null,
|
||||
userProfile: null,
|
||||
countries: [],
|
||||
regionId: "",
|
||||
selectedCountryId: "",
|
||||
commodityCard: null,
|
||||
selectedGoodsId: "",
|
||||
@ -112,6 +114,20 @@ function currentCountryId() {
|
||||
return state.selectedCountryId;
|
||||
}
|
||||
|
||||
function currentRegionId() {
|
||||
return state.regionId;
|
||||
}
|
||||
|
||||
function currentUserAccount() {
|
||||
return String(
|
||||
state.userProfile?.account ||
|
||||
state.userProfile?.actualAccount ||
|
||||
state.userProfile?.ownSpecialId?.account ||
|
||||
state.userProfile?.specialId?.account ||
|
||||
""
|
||||
).trim();
|
||||
}
|
||||
|
||||
function getCountryLabel(item) {
|
||||
return (
|
||||
item?.label ||
|
||||
@ -311,8 +327,36 @@ async function refreshMeta() {
|
||||
persistSettings();
|
||||
els.applicationId.value = state.applicationId;
|
||||
|
||||
const countriesResp = await deps.getApi("/order/web/pay/country");
|
||||
state.countries = Array.isArray(countriesResp?.body) ? countriesResp.body : [];
|
||||
const applicationResp = await deps.getApi(
|
||||
`/order/web/pay/application/${encodeURIComponent(state.applicationId)}`
|
||||
);
|
||||
state.application = applicationResp?.body || {};
|
||||
|
||||
const profileQuery = new URLSearchParams({
|
||||
sysOrigin: state.application?.appCode || state.userProfile?.originSys || "",
|
||||
type: state.productType,
|
||||
});
|
||||
const account = currentUserAccount();
|
||||
if (account) {
|
||||
profileQuery.set("account", account);
|
||||
}
|
||||
if (currentUserId()) {
|
||||
profileQuery.set("userId", currentUserId());
|
||||
}
|
||||
|
||||
const profileResp = await deps.getApi(
|
||||
`/order/web/pay/user-profile?${profileQuery.toString()}`
|
||||
);
|
||||
const payProfile = profileResp?.body || {};
|
||||
if (payProfile.userProfile) {
|
||||
state.userProfile = {
|
||||
...state.userProfile,
|
||||
...payProfile.userProfile,
|
||||
};
|
||||
}
|
||||
state.regionId = payProfile.regionId || "";
|
||||
state.countries = Array.isArray(payProfile.countryList) ? payProfile.countryList : [];
|
||||
|
||||
if (!state.countries.length) {
|
||||
state.selectedCountryId = "";
|
||||
state.commodityCard = null;
|
||||
@ -335,7 +379,7 @@ async function refreshMeta() {
|
||||
state.applicationId
|
||||
)}&payCountryId=${encodeURIComponent(currentCountryId())}&type=${encodeURIComponent(
|
||||
state.productType
|
||||
)}`
|
||||
)}®ionId=${encodeURIComponent(currentRegionId())}`
|
||||
);
|
||||
|
||||
state.commodityCard = commodityResp?.body || {};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user