HEL-342: 全站切换霜曜日间与黑金夜间主题
按定稿把运行时 token 换成霜曜/黑金双主题,登录与壳层接入官方 Logo 与主题记忆,不改业务接口与金额计算。 Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
co-authored by
Cursor
multica-agent
parent
2d0ae4d7d1
commit
b905cba52c
+66
-48
@@ -39,49 +39,20 @@ const motionQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
|
||||
|
||||
function animateView(view, { initial = false } = {}) {
|
||||
if (!view || motionQuery.matches || typeof view.animate !== "function") return;
|
||||
if (!initial) {
|
||||
view.getAnimations().forEach((animation) => animation.cancel());
|
||||
view.animate(
|
||||
[{ opacity: 0.84, transform: "translateY(5px)" }, { opacity: 1, transform: "translateY(0)" }],
|
||||
{ duration: 180, easing: "cubic-bezier(.22,1,.36,1)" },
|
||||
if (!initial) return;
|
||||
const rows = [...view.querySelectorAll(".ds-table tbody tr")].slice(0, 8);
|
||||
rows.forEach((row, index) => {
|
||||
row.getAnimations().forEach((animation) => animation.cancel());
|
||||
row.animate(
|
||||
[{ opacity: 0 }, { opacity: 1 }],
|
||||
{ duration: 300, delay: index * 45, easing: "cubic-bezier(0.23, 1, 0.32, 1)", fill: "both" },
|
||||
);
|
||||
return;
|
||||
}
|
||||
const selectors = [
|
||||
".page-head",
|
||||
".stat-card",
|
||||
".card",
|
||||
".notice",
|
||||
".list-row",
|
||||
".filters",
|
||||
];
|
||||
const elements = [...new Set(selectors.flatMap((selector) => [...view.querySelectorAll(selector)]))];
|
||||
|
||||
elements.forEach((element, index) => {
|
||||
element.getAnimations().forEach((animation) => animation.cancel());
|
||||
const keyframes = [
|
||||
{ opacity: 0, transform: `translateY(${initial ? 16 : 10}px)` },
|
||||
{ opacity: 1, transform: "translateY(0)" },
|
||||
];
|
||||
element.animate(keyframes, {
|
||||
duration: 440,
|
||||
delay: Math.min(index * 38, 260),
|
||||
easing: "cubic-bezier(.22,1,.36,1)",
|
||||
fill: "both",
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function initMotion() {
|
||||
if (motionQuery.matches) return;
|
||||
animateView($(".app-view.is-active"), { initial: true });
|
||||
|
||||
$$(".side-nav a", $("#sidebar") || document).forEach((item, index) => {
|
||||
item.animate(
|
||||
[{ opacity: 0, transform: "translateX(-8px)" }, { opacity: 1, transform: "translateX(0)" }],
|
||||
{ duration: 360, delay: 90 + index * 28, easing: "cubic-bezier(.22,1,.36,1)", fill: "both" },
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function recordStatus(status) {
|
||||
@@ -139,11 +110,23 @@ function showToast(title, detail = "", kind = "info") {
|
||||
}
|
||||
toast.append(dot, body);
|
||||
region.append(toast);
|
||||
window.setTimeout(() => {
|
||||
let remaining = 2600;
|
||||
let started = Date.now();
|
||||
let timer = window.setTimeout(dismiss, remaining);
|
||||
function dismiss() {
|
||||
toast.style.opacity = "0";
|
||||
toast.style.transition = "opacity 0.2s ease";
|
||||
window.setTimeout(() => toast.remove(), 200);
|
||||
}, 4200);
|
||||
toast.style.transition = "opacity 400ms cubic-bezier(0.32, 0.72, 0, 1), transform 400ms cubic-bezier(0.32, 0.72, 0, 1)";
|
||||
toast.style.transform = "translateX(12px)";
|
||||
window.setTimeout(() => toast.remove(), 400);
|
||||
}
|
||||
toast.addEventListener("mouseenter", () => {
|
||||
window.clearTimeout(timer);
|
||||
remaining -= Date.now() - started;
|
||||
});
|
||||
toast.addEventListener("mouseleave", () => {
|
||||
started = Date.now();
|
||||
timer = window.setTimeout(dismiss, Math.max(remaining, 0));
|
||||
});
|
||||
}
|
||||
|
||||
function toastIfLocked(result) {
|
||||
@@ -188,7 +171,9 @@ function showView(view) {
|
||||
closeNavigation({ restoreFocus: navigationWasOpen });
|
||||
const activeView = $(`.app-view[data-page="${view}"]`);
|
||||
requestAnimationFrame(() => animateView(activeView));
|
||||
window.scrollTo({ top: 0, behavior: motionQuery.matches ? "auto" : "smooth" });
|
||||
const shell = $(".main");
|
||||
if (shell) shell.scrollTop = 0;
|
||||
else window.scrollTo({ top: 0, behavior: motionQuery.matches ? "auto" : "smooth" });
|
||||
if (portal === "company" && view === "transfers") {
|
||||
if (state.transfersKeepDetail && state.transfersDetail?.company_id) {
|
||||
showTransfersDetailLayer();
|
||||
@@ -422,15 +407,19 @@ async function initAuthGuard() {
|
||||
|
||||
function applyCompanyIdentity(me) {
|
||||
if (!me) return;
|
||||
const row = $(".side-foot .user-row");
|
||||
if (row) {
|
||||
const foot = $(".side-foot") || $(".side-foot .user-row");
|
||||
if (foot) {
|
||||
const name = me.username || (portal === "company" ? (me.company_name || "公司用户") : "系统管理员");
|
||||
const avatar = $(".avatar", row);
|
||||
const avatar = $(".avatar", foot);
|
||||
if (avatar) avatar.textContent = name.slice(0, 1);
|
||||
const nameEl = $(".user-name", row);
|
||||
const nameEl = $(".user-name", foot);
|
||||
if (nameEl) nameEl.textContent = name;
|
||||
const metaEl = $(".user-meta", row);
|
||||
if (metaEl) metaEl.textContent = portal === "company" ? (me.company_name || "公司业务端") : "管理员";
|
||||
const metaEl = $(".user-meta", foot);
|
||||
if (metaEl) {
|
||||
metaEl.textContent = portal === "company"
|
||||
? `${me.company_name || "公司业务端"} · 仅本公司数据`
|
||||
: "管理员 · 集团全量数据";
|
||||
}
|
||||
}
|
||||
// The company portal always shows the session-bound company in page copy.
|
||||
if (portal === "company" && me.company_name) {
|
||||
@@ -1814,6 +1803,7 @@ async function loadAdminRemindersPending() {
|
||||
if (empty) empty.style.display = "";
|
||||
if (summary) summary.textContent = "0 家公司 · 0 项";
|
||||
if (sendAll) { sendAll.disabled = true; sendAll.textContent = "全部一键发送"; }
|
||||
syncPendingCheckAll();
|
||||
return;
|
||||
}
|
||||
if (empty) empty.style.display = "none";
|
||||
@@ -1831,7 +1821,7 @@ async function loadAdminRemindersPending() {
|
||||
row.dataset.companyId = String(item.company_id);
|
||||
const sentHint = item.send_count > 0 ? ` · 已提醒 ${item.send_count} 次` : "";
|
||||
row.innerHTML =
|
||||
'<label class="row" style="gap:6px;flex:none;"><input type="checkbox" class="pending-check" style="width:auto;" /></label>' +
|
||||
'<label class="row" style="gap:6px;flex:none;"><input type="checkbox" class="pending-check ds-check" /></label>' +
|
||||
`<span class="pill ${reminderTypePill(item.rule_key)}">${item.rule_label}</span>` +
|
||||
`<div class="lr-main"><div class="lr-title">${item.title}</div>` +
|
||||
`<div class="lr-sub"><span class="meta">${item.reason}${sentHint}</span></div></div>` +
|
||||
@@ -1839,6 +1829,16 @@ async function loadAdminRemindersPending() {
|
||||
`<div class="lr-side"><button type="button" class="btn btn-sm btn-primary pending-send-one">发送提醒</button></div>`;
|
||||
list.append(row);
|
||||
});
|
||||
syncPendingCheckAll();
|
||||
}
|
||||
|
||||
function syncPendingCheckAll() {
|
||||
const master = $("#pending-check-all");
|
||||
if (!master) return;
|
||||
const boxes = $$(".pending-check");
|
||||
const checked = boxes.filter((el) => el.checked).length;
|
||||
master.checked = boxes.length > 0 && checked === boxes.length;
|
||||
master.indeterminate = checked > 0 && checked < boxes.length;
|
||||
}
|
||||
|
||||
async function loadAdminRemindersHistory(sourceFilter) {
|
||||
@@ -1932,6 +1932,15 @@ function initAdminReminders() {
|
||||
loadAdminRemindersPending();
|
||||
loadAdminRemindersHistory("all");
|
||||
|
||||
$("#pending-check-all")?.addEventListener("change", (event) => {
|
||||
const on = event.target.checked;
|
||||
event.target.indeterminate = false;
|
||||
$$(".pending-check").forEach((box) => { box.checked = on; });
|
||||
});
|
||||
document.addEventListener("change", (event) => {
|
||||
if (event.target.classList?.contains("pending-check")) syncPendingCheckAll();
|
||||
});
|
||||
|
||||
$("#reminder-scan-btn")?.addEventListener("click", async () => {
|
||||
const response = await fetch("/api/admin/reminders/scan", { method: "POST" }).catch(() => null);
|
||||
if (response?.status === 401) { window.location.href = "index.html"; return; }
|
||||
@@ -4174,6 +4183,15 @@ function renderWorkspaceTransfersCard(summary) {
|
||||
? `${formatWanHtml(pending.amount_total)}<span class="unit"> · ${pCount} 笔</span>`
|
||||
: `0.00<span class="unit">万元 · 0 笔</span>`;
|
||||
}
|
||||
const confirmedSplit = $("#wsTfConfirmedSplit");
|
||||
const pendingSplit = $("#wsTfPendingSplit");
|
||||
if (confirmedSplit) confirmedSplit.innerHTML = formatWanHtml(confirmed.net_change, { signed: true });
|
||||
if (pendingSplit) {
|
||||
const pCount = Number(pending.count) || 0;
|
||||
pendingSplit.innerHTML = pCount
|
||||
? `${formatWanHtml(pending.amount_total)}<span class="unit"> · ${pCount} 笔</span>`
|
||||
: `0.00<span class="unit">万元 · 0 笔</span>`;
|
||||
}
|
||||
}
|
||||
|
||||
async function loadTransfersSummary({ asOf } = {}) {
|
||||
|
||||
Reference in New Issue
Block a user