fix: update bd leader salary history entry

This commit is contained in:
170-carry 2026-04-28 23:53:04 +08:00
parent 126079cc6a
commit f146dfdcab
3 changed files with 240 additions and 121 deletions

View File

@ -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>BD Leader Center</title>
<link rel="stylesheet" href="./style.css?v=20260428-2225" />
<link rel="stylesheet" href="./style.css?v=20260429-0010" />
</head>
<body>
<div class="bd-leader-center" aria-label="BD Leader Center" data-i18n-aria="page_label" data-loading="true">
@ -53,7 +53,7 @@
<section class="card salary-card">
<div class="salary-head">
<div>
<div class="salary-label" data-i18n="my_available_salary">salary</div>
<div class="salary-label" data-i18n="my_available_salary">Salary</div>
<div class="salary-period" id="billTitle">-</div>
</div>
<button class="text-link" type="button" data-route="/hyapp/withdraw-exchange/index.html?identity=BD_LEADER&salaryType=BD_LEADER_SALARY" data-i18n="details">Withdraw/Exchange</button>
@ -64,55 +64,13 @@
</div>
</section>
<section class="card metrics-card">
<div class="metric">
<div class="label" data-i18n="bd_number">BD number</div>
<div class="value" id="bdNumber">0</div>
</div>
<div class="vertical-line" aria-hidden="true"></div>
<div class="metric">
<div class="label" data-i18n="team_salary">Team salary</div>
<div class="value metric-money">
<span aria-hidden="true">$</span>
<span id="teamSalary">0.00</span>
</div>
</div>
</section>
<section class="card menu-card">
<button class="menu-row" type="button" data-route="/policy?from=BDLead">
<span class="menu-left">
<span class="menu-icon policy-icon" aria-hidden="true">
<svg viewBox="0 0 28 28"><path d="M8 5h10l3 3v15H8Z" /><path d="M18 5v5h4M11 14h7M11 18h6" /></svg>
</span>
<span data-i18n="bd_policy_link">BD policy</span>
</span>
<span class="chevron">&rsaquo;</span>
</button>
<button class="menu-row" type="button" data-action="history">
<span class="menu-left">
<span class="menu-icon history-icon" aria-hidden="true">
<svg viewBox="0 0 28 28"><path d="M14 5a9 9 0 1 1-8.1 5.1" /><path d="M6 5v5h5M14 10v5l4 2" /></svg>
</span>
<span data-i18n="bd_leader_history">BD Leader history</span>
</span>
<span class="chevron">&rsaquo;</span>
</button>
<button class="menu-row" type="button" data-route="/agency-list">
<span class="menu-left">
<span class="menu-icon list-icon" aria-hidden="true">
<svg viewBox="0 0 28 28"><path d="M8 8h12M8 14h12M8 20h12" /><path d="M4 8h.1M4 14h.1M4 20h.1" /></svg>
</span>
<span data-i18n="agency_list_link">Agency list</span>
</span>
<span class="chevron">&rsaquo;</span>
</button>
<button class="menu-row" type="button" data-route="/bd-list">
<span class="menu-left">
<span class="menu-icon bd-icon" aria-hidden="true">
<svg viewBox="0 0 28 28"><path d="M10 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8ZM20 12a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM3 24c1-6 4-9 7-9s6 3 7 9ZM16 22c.6-3.8 2.2-5.8 4-5.8 2.2 0 4 2.3 5 5.8" /></svg>
</span>
<span data-i18n="bd_list_link">BD List</span>
<span data-i18n="bd_leader_history">Salary History</span>
</span>
<span class="chevron">&rsaquo;</span>
</button>
@ -136,15 +94,13 @@
</button>
</section>
<section class="card member-card">
<div class="section-head">
<div>
<div class="section-title" data-i18n="bd_list_preview">BD List</div>
<div class="section-subtitle" data-i18n="bd_list_preview_subtitle">Current settlement period</div>
</div>
<button class="text-link" type="button" data-route="/bd-list" data-i18n="more">More</button>
<section class="card team-list-card">
<div class="team-list-tabs" role="tablist" aria-label="Team lists">
<button class="team-list-tab is-active" type="button" role="tab" aria-selected="true" data-list-tab="bd" data-i18n="bd_list_link">BD List</button>
<button class="team-list-tab" type="button" role="tab" aria-selected="false" data-list-tab="agency" data-i18n="agency_list_link">Agency list</button>
</div>
<div class="member-list" id="bdMemberList">
<div class="team-list-summary" id="teamListSummary"></div>
<div class="team-list-content" id="teamListContent">
<div class="empty-state" data-i18n="loading_data">Loading...</div>
</div>
</section>
@ -154,7 +110,7 @@
<div class="history-backdrop" data-close-history></div>
<section class="history-dialog" role="dialog" aria-modal="true" aria-labelledby="historyTitle">
<div class="history-head">
<h2 id="historyTitle" data-i18n="bd_leader_history">BD Leader history</h2>
<h2 id="historyTitle" data-i18n="bd_leader_history">Salary History</h2>
<button class="history-close" type="button" aria-label="Close" data-i18n-aria="close" data-close-history>&times;</button>
</div>
<div class="history-summary">
@ -223,6 +179,6 @@
<div class="toast" id="toast" role="status" aria-live="polite" hidden></div>
</div>
<script src="./script.js?v=20260428-2215" defer></script>
<script src="./script.js?v=20260429-0020" defer></script>
</body>
</html>

View File

@ -17,12 +17,11 @@
language_button_aria: "Change language",
role: "BD Leader",
uid_prefix: "UID:",
my_available_salary: "salary",
my_available_salary: "Salary",
details: "Withdraw/Exchange",
bd_number: "BD number",
team_salary: "Team salary",
bd_policy_link: "BD policy",
bd_leader_history: "BD Leader history",
bd_leader_history: "Salary History",
agency_list_link: "Agency list",
bd_list_link: "BD List",
invite_become_agent: "Invite Agent",
@ -43,6 +42,10 @@
previous_period_income: "Previous period income",
salary: "Salary",
agencies: "Agencies",
agency_number: "Agency number",
team_recharge: "Team recharge",
recharge: "Recharge",
host: "Host",
loading_data: "Loading...",
no_data: "No data",
in_progress: "In Progress",
@ -71,8 +74,7 @@
details: "سحب/تبديل",
bd_number: "عدد BD",
team_salary: "راتب الفريق",
bd_policy_link: "سياسة BD",
bd_leader_history: "سجل قائد BD",
bd_leader_history: "سجل الراتب",
agency_list_link: "قائمة الوكالات",
bd_list_link: "قائمة BD",
invite_become_agent: "دعوة وكيل",
@ -121,8 +123,7 @@
details: "Withdraw/Exchange",
bd_number: "BD sayısı",
team_salary: "Takım maaşı",
bd_policy_link: "BD politikası",
bd_leader_history: "BD Leader geçmişi",
bd_leader_history: "Maaş Geçmişi",
agency_list_link: "Ajans listesi",
bd_list_link: "BD Listesi",
invite_become_agent: "Ajans Davet Et",
@ -171,8 +172,7 @@
details: "Withdraw/Exchange",
bd_number: "Jumlah BD",
team_salary: "Gaji tim",
bd_policy_link: "Kebijakan BD",
bd_leader_history: "Riwayat BD Leader",
bd_leader_history: "Riwayat Gaji",
agency_list_link: "Daftar agensi",
bd_list_link: "Daftar BD",
invite_become_agent: "Invite Agent",
@ -220,8 +220,14 @@
teamEntry: null,
balanceTotal: {},
bill: {},
agencyBill: null,
history: null,
historyMore: null,
teamList: {
type: "bd",
loading: false,
error: ""
},
invite: {
mode: "agent",
invited: [],
@ -475,7 +481,8 @@
return span;
}
function createMemberRow(item) {
function createMemberRow(item, options = {}) {
const type = options.type || "bd";
const name = item?.agentName || item?.bdUserName || "-";
const account = item?.agentAccount || item?.account || "-";
const row = document.createElement("article");
@ -508,11 +515,21 @@
const side = document.createElement("div");
side.className = "member-side";
const salary = document.createElement("div");
salary.textContent = `${message("team_salary")}: $${formatMoney(item?.teamSalaryAmount || 0)}`;
const agencies = document.createElement("div");
agencies.textContent = `${message("agencies")}: ${formatCount(item?.teamMemberCount || item?.agencyCount || 0)}`;
side.append(salary, agencies);
const sideLines = type === "agency"
? [
`${message("team_salary")}: $${formatMoney(item?.teamSalaryAmount || 0)}`,
`${message("recharge")}: $${formatMoney(item?.teamRechargeAmount || 0)}`,
`${message("host")}: ${formatCount(item?.teamMemberCount || 0)}`
]
: [
`${message("team_salary")}: $${formatMoney(item?.teamSalaryAmount || 0)}`,
`${message("agencies")}: ${formatCount(item?.teamMemberCount || item?.agencyCount || 0)}`
];
sideLines.forEach((line) => {
const itemNode = document.createElement("div");
itemNode.textContent = line;
side.appendChild(itemNode);
});
row.append(avatar, main, side);
return row;
@ -537,6 +554,77 @@
replaceChildren(list, preview.map(createMemberRow));
}
function normalizeTeamListType(type) {
return type === "agency" ? "agency" : "bd";
}
function teamListBill(type = state.teamList.type) {
return normalizeTeamListType(type) === "agency" ? state.agencyBill : state.bill;
}
function hasTeamListData(data) {
return Boolean(data && (Array.isArray(data.memberBillList) || data.billTitle || data.memberCount !== undefined));
}
function createSummaryCell(label, value) {
const cell = document.createElement("div");
const labelNode = document.createElement("span");
labelNode.textContent = label;
const valueNode = document.createElement("strong");
valueNode.textContent = value;
cell.append(labelNode, valueNode);
return cell;
}
function renderTeamListCard() {
const type = normalizeTeamListType(state.teamList.type);
const data = teamListBill(type) || {};
const members = Array.isArray(data.memberBillList) ? data.memberBillList : [];
const summary = document.querySelector("#teamListSummary");
const content = document.querySelector("#teamListContent");
document.querySelectorAll("[data-list-tab]").forEach((button) => {
const active = normalizeTeamListType(button.dataset.listTab) === type;
button.classList.toggle("is-active", active);
button.setAttribute("aria-selected", String(active));
});
if (summary) {
const cells = type === "agency"
? [
createSummaryCell(message("agency_number"), formatCount(data.memberCount ?? members.length)),
createSummaryCell(message("team_salary"), `$${formatMoney(data.totalSalary || 0)}`),
createSummaryCell(message("team_recharge"), `$${formatMoney(data.totalRecharge || 0)}`)
]
: [
createSummaryCell(message("bd_number"), formatCount(data.memberCount ?? members.length)),
createSummaryCell(message("team_salary"), `$${formatMoney(data.totalSalary || 0)}`)
];
replaceChildren(summary, cells);
}
if (!content) return;
if (state.teamList.loading) {
const loading = document.createElement("div");
loading.className = "empty-state";
loading.textContent = message("loading_data");
replaceChildren(content, [loading]);
return;
}
if (state.teamList.error) {
const error = document.createElement("div");
error.className = "empty-state";
error.textContent = state.teamList.error;
replaceChildren(content, [error]);
return;
}
if (!members.length) {
const empty = document.createElement("div");
empty.className = "empty-state";
empty.textContent = message("no_data");
replaceChildren(content, [empty]);
return;
}
replaceChildren(content, members.map((item) => createMemberRow(item, { type })));
}
function normalizeStatus(status) {
if (status === "UNPAID" || status === "In Progress" || status === message("in_progress")) return message("in_progress");
if (status === "Pending" || status === message("pending")) return message("pending");
@ -833,11 +921,12 @@
const list = document.querySelector("#inviteList");
const empty = document.querySelector("#inviteEmpty");
const rows = state.invite.showSearch ? state.invite.searched : state.invite.invited;
const hasQuery = Boolean(String(state.invite.query || "").trim());
if (title) title.textContent = message(config.titleKey);
if (input && document.activeElement !== input) input.value = state.invite.query;
if (searchButton) {
searchButton.disabled = state.invite.locked;
searchButton.disabled = state.invite.locked || !hasQuery;
searchButton.textContent = state.invite.searching ? message("searching") : message("search");
}
setInviteStatus(state.invite.statusText, state.invite.statusType);
@ -861,6 +950,17 @@
}
}
function handleInviteInput(event) {
const query = String(event?.target?.value || "");
state.invite.query = query;
if (!query.trim()) {
state.invite.showSearch = false;
state.invite.searched = [];
setInviteStatus("");
}
renderInviteModal();
}
async function searchInviteProfile(query) {
let profile = null;
let firstError = null;
@ -1048,6 +1148,40 @@
async function fetchBDLeaderBill() {
state.bill = await requestJSON("/team/bd/member-bill/list?type=BDLEADER") || {};
renderBill();
if (normalizeTeamListType(state.teamList.type) === "bd") renderTeamListCard();
}
async function fetchAgencyBill() {
state.agencyBill = await requestJSON("/team/bd/member-bill/list?type=BD") || {};
if (normalizeTeamListType(state.teamList.type) === "agency") renderTeamListCard();
}
async function ensureTeamListData(type) {
const normalizedType = normalizeTeamListType(type);
if (hasTeamListData(teamListBill(normalizedType))) return;
if (normalizedType === "agency") {
await fetchAgencyBill();
return;
}
await fetchBDLeaderBill();
}
async function switchTeamList(type) {
state.teamList.type = normalizeTeamListType(type);
state.teamList.error = "";
state.teamList.loading = !hasTeamListData(teamListBill(state.teamList.type));
renderTeamListCard();
if (!state.teamList.loading) return;
try {
await ensureTeamListData(state.teamList.type);
} catch (error) {
console.error("Failed to load team list:", error);
state.teamList.error = error.response?.errorMsg || error.message || message("failed_to_load");
} finally {
state.teamList.loading = false;
renderTeamListCard();
}
}
async function fetchHistory() {
@ -1155,6 +1289,7 @@
renderBill();
renderHistory();
renderDetails();
renderTeamListCard();
renderInviteModal();
}
@ -1194,8 +1329,12 @@
node.addEventListener("click", () => navigateTo(node.dataset.route));
});
document.querySelector("[data-action='history']")?.addEventListener("click", showHistoryModal);
document.querySelectorAll("[data-list-tab]").forEach((button) => {
button.addEventListener("click", () => switchTeamList(button.dataset.listTab));
});
document.querySelector("[data-action='invite-agent']")?.addEventListener("click", () => showInviteModal("agent"));
document.querySelector("[data-action='invite-bd']")?.addEventListener("click", () => showInviteModal("bd"));
document.querySelector("#inviteSearchInput")?.addEventListener("input", handleInviteInput);
document.querySelector("#inviteSearchForm")?.addEventListener("submit", searchInviteUser);
document.querySelectorAll("[data-close-history]").forEach((node) => {
node.addEventListener("click", () => setModalOpen("#historyModal", false));

View File

@ -397,56 +397,6 @@ button {
line-height: 1.08;
}
.metrics-card {
display: grid;
grid-template-columns: minmax(0, 1fr) 1px minmax(0, 1fr);
min-height: 110px;
padding: 18px 16px;
}
.metric {
display: flex;
min-width: 0;
flex-direction: column;
justify-content: center;
}
.metric:first-child {
padding-right: 16px;
}
.metric:last-child {
padding-left: 16px;
}
.label {
color: var(--muted);
font-size: 13px;
font-weight: 800;
line-height: 1.2;
}
.value {
margin-top: 8px;
overflow-wrap: anywhere;
color: #24282e;
font-size: 27px;
font-weight: 950;
line-height: 1.05;
}
.metric-money {
display: flex;
align-items: baseline;
gap: 4px;
font-size: 24px;
}
.vertical-line {
width: 1px;
background: var(--line);
}
.menu-card {
overflow: hidden;
}
@ -512,6 +462,80 @@ button {
line-height: 1;
}
.team-list-card {
display: grid;
gap: 12px;
padding: 14px;
}
.team-list-tabs {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 8px;
padding: 4px;
border-radius: 8px;
background: #f2f6f6;
}
.team-list-tab {
min-width: 0;
min-height: 38px;
padding: 0 10px;
border-radius: 7px;
color: #697078;
font-size: 13px;
font-weight: 950;
line-height: 1.1;
}
.team-list-tab.is-active {
background: linear-gradient(135deg, #30dfb4, #15bda9);
color: #fff;
box-shadow: 0 8px 18px rgba(21, 189, 169, 0.24);
}
.team-list-summary {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
gap: 8px;
}
.team-list-summary > div {
min-width: 0;
padding: 10px;
border-radius: 8px;
background: #f7fbfa;
}
.team-list-summary span {
display: block;
overflow: hidden;
color: #8b8d92;
font-size: 11px;
font-weight: 850;
line-height: 1.2;
text-overflow: ellipsis;
white-space: nowrap;
}
.team-list-summary strong {
display: block;
margin-top: 4px;
overflow-wrap: anywhere;
color: #24282e;
font-size: 15px;
font-weight: 950;
line-height: 1.15;
}
.team-list-content {
display: grid;
gap: 10px;
max-height: 360px;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
.member-card {
padding: 16px;
}