Files

100 lines
4.3 KiB
JavaScript
Raw Permalink Normal View History

2026-08-22 22:28:41 +08:00
/* =====================================================================
* 好友模块(friend.js
* 好友申请 / 状态展示 / 博主审批弹窗。
* ===================================================================== */
import { state } from "./state.js";
import { escapeHtml, formatDate, openModal, showToast } from "./utils.js";
import { api } from "./api.js";
import { openLoginModal } from "./auth.js";
import { renderAuthArea } from "./router.js";
export async function applyFriend() {
if (!state.user) { openLoginModal(); showToast("请先登录后再申请好友", "info"); return; }
try {
await api("/api/friend/apply", { method: "POST" });
state.friendStatus = "pending";
renderAuthArea();
showToast("好友申请已提交,等待博主审批", "success");
} catch (err) {
showToast(err.message, "error");
}
}
// 记录当前打开的审批弹窗引用,避免重复打开时弹窗叠加
let manageModal = null;
export function openFriendManageModal() {
// 先关闭上一次打开的审批弹窗
if (manageModal) { try { manageModal.close(); } catch (e) { /* 忽略 */ } }
const body = document.createElement("div");
body.innerHTML = '<p class="muted">加载中…</p>';
manageModal = openModal({ title: "好友申请管理", content: body });
renderApplications(body);
}
export async function openFriendListModal() {
const body = document.createElement("div");
body.innerHTML = '<p class="muted">加载中…</p>';
const modal = openModal({ title: "好友列表", content: body });
try {
const friends = await api("/api/friend/list");
if (!friends.length) { body.innerHTML = '<p class="empty">还没有好友</p>'; return; }
body.innerHTML = friends.map((f) => `
<div class="friend-row">
${f.avatar ? `<img class="friend-avatar" src="${escapeHtml(f.avatar)}" alt="">` : '<span class="friend-avatar friend-avatar-empty"></span>'}
<div class="friend-info">
<strong>${escapeHtml(f.username)}</strong>
<span class="muted">${escapeHtml(f.bio || `成为好友于 ${formatDate(f.friend_since)}`)}</span>
</div>
</div>`).join("");
} catch (err) {
body.innerHTML = "";
showToast(err.message, "error");
}
}
export async function renderApplications(body) {
try {
const records = await api("/api/friend/applications");
if (!records.length) { body.innerHTML = '<p class="empty">暂无申请记录</p>'; return; }
body.innerHTML = "";
const STATUS_TEXT = { pending: "待审批", accepted: "已通过", rejected: "已拒绝" };
for (const record of records) {
const row = document.createElement("div");
row.className = "app-row";
const statusText = STATUS_TEXT[record.status] || record.status;
row.innerHTML = `
<span class="app-user">${escapeHtml(record.username || "未知用户")}</span>
<span class="app-email muted">${escapeHtml(record.email || "")}</span>
<span class="app-time muted">${formatDate(record.created_time)}</span>
<span class="app-status">${statusText}</span>`;
if (record.status === "pending") {
const approveBtn = document.createElement("button");
approveBtn.className = "btn btn-primary btn-sm"; approveBtn.textContent = "通过";
approveBtn.addEventListener("click", async () => {
try {
await api(`/api/friend/${record.id}/approve`, { method: "POST" });
showToast("已通过好友申请", "success");
await renderApplications(body); // 原地刷新当前弹窗内容,不再叠加新弹窗
} catch (err) { showToast(err.message, "error"); }
});
const rejectBtn = document.createElement("button");
rejectBtn.className = "btn btn-outline btn-sm"; rejectBtn.textContent = "拒绝";
rejectBtn.addEventListener("click", async () => {
try {
await api(`/api/friend/${record.id}/reject`, { method: "POST" });
showToast("已拒绝好友申请");
await renderApplications(body); // 原地刷新当前弹窗内容,不再叠加新弹窗
} catch (err) { showToast(err.message, "error"); }
});
row.appendChild(approveBtn);
row.appendChild(rejectBtn);
}
body.appendChild(row);
}
} catch (err) {
body.innerHTML = "";
showToast(err.message, "error");
}
}