100 lines
4.3 KiB
JavaScript
100 lines
4.3 KiB
JavaScript
/* =====================================================================
|
||||
|
|
* 好友模块(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");
|
|||
|
|
}
|
|||
|
|
}
|