Spaces:
Running
Running
Upload 99 files
Browse files- 前端页面/core/侧边栏主程序.js +4 -3
- 前端页面/market/创作者卡片组件.js +7 -6
- 前端页面/social/私信聊天组件.js +5 -5
- 前端页面/social/通知中心组件.js +2 -2
前端页面/core/侧边栏主程序.js
CHANGED
|
@@ -10,7 +10,7 @@ import { createTopNav } from "../components/顶部导航组件.js";
|
|
| 10 |
import { loadSidebarContent, disposeSidebarContent } from "./侧边栏数据引擎.js";
|
| 11 |
import { showToast } from "../components/UI交互提示组件.js";
|
| 12 |
import { api, captureRequestSession } from "./网络请求API.js"; // 🔴 编辑模式需调用详情API获取完整数据
|
| 13 |
-
import { CACHE, UI, getBackgroundKey, IS_WEB_MODE } from "./全局配置.js";
|
| 14 |
import { debounce } from "../components/性能优化工具.js";
|
| 15 |
import { scrollCardIntoView } from "../components/动画音效引擎.js";
|
| 16 |
import { cleanupImageSandbox } from "../components/图片沙盒组件.js"; // 🔧 P3优化:导入清理函数
|
|
@@ -125,8 +125,9 @@ async function loadPublishFactory(kind) {
|
|
| 125 |
}
|
| 126 |
|
| 127 |
function _applySidebarBackground(container, value) {
|
| 128 |
-
const
|
| 129 |
-
|
|
|
|
| 130 |
container.style.backgroundColor = valid ? "transparent" : "var(--comfy-menu-bg)";
|
| 131 |
if (valid) {
|
| 132 |
container.style.backgroundSize = "cover";
|
|
|
|
| 10 |
import { loadSidebarContent, disposeSidebarContent } from "./侧边栏数据引擎.js";
|
| 11 |
import { showToast } from "../components/UI交互提示组件.js";
|
| 12 |
import { api, captureRequestSession } from "./网络请求API.js"; // 🔴 编辑模式需调用详情API获取完整数据
|
| 13 |
+
import { CACHE, UI, getBackgroundKey, IS_WEB_MODE, normalizeProfileImageUrl } from "./全局配置.js";
|
| 14 |
import { debounce } from "../components/性能优化工具.js";
|
| 15 |
import { scrollCardIntoView } from "../components/动画音效引擎.js";
|
| 16 |
import { cleanupImageSandbox } from "../components/图片沙盒组件.js"; // 🔧 P3优化:导入清理函数
|
|
|
|
| 125 |
}
|
| 126 |
|
| 127 |
function _applySidebarBackground(container, value) {
|
| 128 |
+
const source = normalizeProfileImageUrl(value);
|
| 129 |
+
const valid = !!source;
|
| 130 |
+
container.style.backgroundImage = valid ? `url(${JSON.stringify(source)})` : "none";
|
| 131 |
container.style.backgroundColor = valid ? "transparent" : "var(--comfy-menu-bg)";
|
| 132 |
if (valid) {
|
| 133 |
container.style.backgroundSize = "cover";
|
前端页面/market/创作者卡片组件.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
| 11 |
import { openOtherUserProfileModal } from "../profile/个人中心视图.js";
|
| 12 |
import { createCommentSection } from "../social/评论与互动组件.js";
|
| 13 |
import { renderTipLevelHTML, getTipLevelRuleShort } from "../components/打赏等级工具.js";
|
| 14 |
-
import { getBannerCacheKey, PLACEHOLDERS, getCachedProfile, getProfileWithSWR, escapeHtml, CACHE, API, getSettings } from "../core/全局配置.js";
|
| 15 |
import { api } from "../core/网络请求_业务API.js";
|
| 16 |
import { captureRequestSession, requestCancelManager } from "../core/网络请求_基础设施.js";
|
| 17 |
import { getUser, eventBus, EVENTS } from "../core/状态管理.js";
|
|
@@ -193,7 +193,7 @@ export function createTipBoardSection(tipBoard = [], title = t('creator.tip_boar
|
|
| 193 |
|
| 194 |
// 从缓存获取初始数据(0延迟渲染)
|
| 195 |
const cached = getCachedProfile(entry.account);
|
| 196 |
-
const avatarUrl = cached?.avatar || cached?.avatarDataUrl || PLACEHOLDERS.AVATAR_SMALL;
|
| 197 |
const userName = cached?.name || entry.account;
|
| 198 |
|
| 199 |
// 后台静默校对并更新 DOM
|
|
@@ -206,8 +206,9 @@ export function createTipBoardSection(tipBoard = [], title = t('creator.tip_boar
|
|
| 206 |
const avatarImg = itemContainer.querySelector('.tip-board-avatar');
|
| 207 |
const nameSpan = itemContainer.querySelector('.tip-board-name');
|
| 208 |
|
| 209 |
-
|
| 210 |
-
|
|
|
|
| 211 |
}
|
| 212 |
if (nameSpan && typeof profile.name === 'string' && profile.name) {
|
| 213 |
nameSpan.textContent = profile.name;
|
|
@@ -267,7 +268,7 @@ export function createCreatorCard(creatorData, currentUser = null) {
|
|
| 267 |
const summaryView = document.createElement("div");
|
| 268 |
summaryView.className = 'creator-card__summary';
|
| 269 |
|
| 270 |
-
const avatarSrc = creatorData.avatar || PLACEHOLDERS.AVATAR;
|
| 271 |
|
| 272 |
// ⚙️ 读取设置:是否显示创作者背景图
|
| 273 |
const settings = getSettings();
|
|
@@ -277,7 +278,7 @@ export function createCreatorCard(creatorData, currentUser = null) {
|
|
| 277 |
const cacheKey = getBannerCacheKey(creatorData.account);
|
| 278 |
let cachedBanner = null;
|
| 279 |
try { cachedBanner = localStorage.getItem(cacheKey); } catch (_) { /* 可选装饰缓存不可用时继续构建卡片。 */ }
|
| 280 |
-
const validBanner =
|
| 281 |
const bannerUrl = validBanner(cachedBanner) || validBanner(creatorData.bannerUrl);
|
| 282 |
const hasBanner = !!(showBanner && bannerUrl); // 有效本地缓存优先,受显示设置控制
|
| 283 |
|
|
|
|
| 11 |
import { openOtherUserProfileModal } from "../profile/个人中心视图.js";
|
| 12 |
import { createCommentSection } from "../social/评论与互动组件.js";
|
| 13 |
import { renderTipLevelHTML, getTipLevelRuleShort } from "../components/打赏等级工具.js";
|
| 14 |
+
import { getBannerCacheKey, PLACEHOLDERS, getCachedProfile, getProfileWithSWR, escapeHtml, CACHE, API, getSettings, normalizeProfileImageUrl } from "../core/全局配置.js";
|
| 15 |
import { api } from "../core/网络请求_业务API.js";
|
| 16 |
import { captureRequestSession, requestCancelManager } from "../core/网络请求_基础设施.js";
|
| 17 |
import { getUser, eventBus, EVENTS } from "../core/状态管理.js";
|
|
|
|
| 193 |
|
| 194 |
// 从缓存获取初始数据(0延迟渲染)
|
| 195 |
const cached = getCachedProfile(entry.account);
|
| 196 |
+
const avatarUrl = normalizeProfileImageUrl(cached?.avatar) || normalizeProfileImageUrl(cached?.avatarDataUrl) || PLACEHOLDERS.AVATAR_SMALL;
|
| 197 |
const userName = cached?.name || entry.account;
|
| 198 |
|
| 199 |
// 后台静默校对并更新 DOM
|
|
|
|
| 206 |
const avatarImg = itemContainer.querySelector('.tip-board-avatar');
|
| 207 |
const nameSpan = itemContainer.querySelector('.tip-board-name');
|
| 208 |
|
| 209 |
+
const avatarSource = normalizeProfileImageUrl(profile.avatar);
|
| 210 |
+
if (avatarImg && avatarSource) {
|
| 211 |
+
avatarImg.src = avatarSource;
|
| 212 |
}
|
| 213 |
if (nameSpan && typeof profile.name === 'string' && profile.name) {
|
| 214 |
nameSpan.textContent = profile.name;
|
|
|
|
| 268 |
const summaryView = document.createElement("div");
|
| 269 |
summaryView.className = 'creator-card__summary';
|
| 270 |
|
| 271 |
+
const avatarSrc = normalizeProfileImageUrl(creatorData.avatar) || PLACEHOLDERS.AVATAR;
|
| 272 |
|
| 273 |
// ⚙️ 读取设置:是否显示创作者背景图
|
| 274 |
const settings = getSettings();
|
|
|
|
| 278 |
const cacheKey = getBannerCacheKey(creatorData.account);
|
| 279 |
let cachedBanner = null;
|
| 280 |
try { cachedBanner = localStorage.getItem(cacheKey); } catch (_) { /* 可选装饰缓存不可用时继续构建卡片。 */ }
|
| 281 |
+
const validBanner = normalizeProfileImageUrl;
|
| 282 |
const bannerUrl = validBanner(cachedBanner) || validBanner(creatorData.bannerUrl);
|
| 283 |
const hasBanner = !!(showBanner && bannerUrl); // 有效本地缓存优先,受显示设置控制
|
| 284 |
|
前端页面/social/私信聊天组件.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
import { createUnreadBadgeUpdate, validUnreadCount } from "./未读角标工具.js";
|
| 2 |
import { api, captureRequestSession, requestCancelManager } from "../core/网络请求API.js";
|
| 3 |
import { showToast, showConfirm } from "../components/UI交互提示组件.js";
|
| 4 |
-
import { API, CACHE, UI, PAGINATION, PLACEHOLDERS } from "../core/全局配置.js";
|
| 5 |
import { openOtherUserProfileModal } from "../profile/个人中心视图.js";
|
| 6 |
import { t } from "../components/用户体验增强.js";
|
| 7 |
// 🔒 XSS防护:对用户可控字段进行 HTML 转义(🧹 P2归一:使用统一版)
|
|
@@ -187,7 +187,7 @@ export function openChatModal(currentUser, targetAccount = null) {
|
|
| 187 |
list.forEach(chat => {
|
| 188 |
const acc = chat.target_account || chat.account || chat.receiver || chat.sender;
|
| 189 |
const name = chat.target_name || chat.name || acc;
|
| 190 |
-
const avatar = chat.avatar || chat.target_avatar || PLACEHOLDERS.AVATAR_SMALL;
|
| 191 |
const lastMsg = chat.last_message || "";
|
| 192 |
const unread = validUnreadCount(chat.unread_count);
|
| 193 |
|
|
@@ -255,8 +255,8 @@ export function openChatModal(currentUser, targetAccount = null) {
|
|
| 255 |
const visibleMsgs = msgs.slice(startIdx);
|
| 256 |
|
| 257 |
messagesArea.innerHTML = "";
|
| 258 |
-
const myAvatar = currentUser.avatar || currentUser.avatarDataUrl || PLACEHOLDERS.AVATAR_SMALL;
|
| 259 |
-
const otherAvatar = targetAvatar || PLACEHOLDERS.AVATAR_SMALL;
|
| 260 |
|
| 261 |
// 🚀 P0-3:如果有更多历史消息,显示"加载更多"按钮
|
| 262 |
if (startIdx > 0) {
|
|
@@ -348,7 +348,7 @@ export function openChatModal(currentUser, targetAccount = null) {
|
|
| 348 |
requestCancelManager.cancelAll(`${componentId}-history`);
|
| 349 |
const current = () => scope.isCurrent() && currentChatTarget === targetAccount && generation === historyGeneration;
|
| 350 |
const displayName = targetName && targetName !== 'undefined' ? targetName : targetAccount;
|
| 351 |
-
const avatar = targetAvatar || PLACEHOLDERS.AVATAR_SMALL;
|
| 352 |
currentTargetInfo = { account: targetAccount, name: displayName, avatar };
|
| 353 |
try { localStorage.setItem(getLastChatKey(currentUser.account), JSON.stringify({ account: targetAccount })); } catch (_) {}
|
| 354 |
|
|
|
|
| 1 |
import { createUnreadBadgeUpdate, validUnreadCount } from "./未读角标工具.js";
|
| 2 |
import { api, captureRequestSession, requestCancelManager } from "../core/网络请求API.js";
|
| 3 |
import { showToast, showConfirm } from "../components/UI交互提示组件.js";
|
| 4 |
+
import { API, CACHE, UI, PAGINATION, PLACEHOLDERS, normalizeProfileImageUrl } from "../core/全局配置.js";
|
| 5 |
import { openOtherUserProfileModal } from "../profile/个人中心视图.js";
|
| 6 |
import { t } from "../components/用户体验增强.js";
|
| 7 |
// 🔒 XSS防护:对用户可控字段进行 HTML 转义(🧹 P2归一:使用统一版)
|
|
|
|
| 187 |
list.forEach(chat => {
|
| 188 |
const acc = chat.target_account || chat.account || chat.receiver || chat.sender;
|
| 189 |
const name = chat.target_name || chat.name || acc;
|
| 190 |
+
const avatar = normalizeProfileImageUrl(chat.avatar) || normalizeProfileImageUrl(chat.target_avatar) || PLACEHOLDERS.AVATAR_SMALL;
|
| 191 |
const lastMsg = chat.last_message || "";
|
| 192 |
const unread = validUnreadCount(chat.unread_count);
|
| 193 |
|
|
|
|
| 255 |
const visibleMsgs = msgs.slice(startIdx);
|
| 256 |
|
| 257 |
messagesArea.innerHTML = "";
|
| 258 |
+
const myAvatar = normalizeProfileImageUrl(currentUser.avatar) || normalizeProfileImageUrl(currentUser.avatarDataUrl) || PLACEHOLDERS.AVATAR_SMALL;
|
| 259 |
+
const otherAvatar = normalizeProfileImageUrl(targetAvatar) || PLACEHOLDERS.AVATAR_SMALL;
|
| 260 |
|
| 261 |
// 🚀 P0-3:如果有更多历史消息,显示"加载更多"按钮
|
| 262 |
if (startIdx > 0) {
|
|
|
|
| 348 |
requestCancelManager.cancelAll(`${componentId}-history`);
|
| 349 |
const current = () => scope.isCurrent() && currentChatTarget === targetAccount && generation === historyGeneration;
|
| 350 |
const displayName = targetName && targetName !== 'undefined' ? targetName : targetAccount;
|
| 351 |
+
const avatar = normalizeProfileImageUrl(targetAvatar) || PLACEHOLDERS.AVATAR_SMALL;
|
| 352 |
currentTargetInfo = { account: targetAccount, name: displayName, avatar };
|
| 353 |
try { localStorage.setItem(getLastChatKey(currentUser.account), JSON.stringify({ account: targetAccount })); } catch (_) {}
|
| 354 |
|
前端页面/social/通知中心组件.js
CHANGED
|
@@ -4,7 +4,7 @@ export { loadUnreadCount };
|
|
| 4 |
import { api, captureRequestSession, requestCancelManager } from "../core/网络请求API.js";
|
| 5 |
import { openOtherUserProfileModal } from "../profile/个人中心视图.js";
|
| 6 |
import { showToast, showConfirm } from "../components/UI交互提示组件.js";
|
| 7 |
-
import { API, CACHE, PLACEHOLDERS } from "../core/全局配置.js";
|
| 8 |
import { t } from "../components/用户体验增强.js";
|
| 9 |
import { escapeHtml } from "../components/互动工具函数.js"; // 🧹 P2归一:局部副本已移除
|
| 10 |
|
|
@@ -166,7 +166,7 @@ export async function openNotificationCenter(currentUser, bellBtn) {
|
|
| 166 |
|
| 167 |
html += `
|
| 168 |
<article class="notif-item${isSystem ? ' notif-item--system' : ''}${isUnread ? ' notif-item--unread' : ''}" data-account="${escapeHtml(msg.from_user)}" data-type="${escapeHtml(msg.type)}" data-item-id="${escapeHtml(msg.target_item_id || '')}">
|
| 169 |
-
<img class="notification-avatar" alt="" src="${escapeHtml(msg.from_avatar || PLACEHOLDERS.AVATAR)}">
|
| 170 |
<div class="notification-body">
|
| 171 |
<div class="notification-meta">${nameLabel}<time class="notification-time" datetime="${date.toISOString()}">${timeStr}</time></div>
|
| 172 |
<div class="notification-action">${actionText}</div>
|
|
|
|
| 4 |
import { api, captureRequestSession, requestCancelManager } from "../core/网络请求API.js";
|
| 5 |
import { openOtherUserProfileModal } from "../profile/个人中心视图.js";
|
| 6 |
import { showToast, showConfirm } from "../components/UI交互提示组件.js";
|
| 7 |
+
import { API, CACHE, PLACEHOLDERS, normalizeProfileImageUrl } from "../core/全局配置.js";
|
| 8 |
import { t } from "../components/用户体验增强.js";
|
| 9 |
import { escapeHtml } from "../components/互动工具函数.js"; // 🧹 P2归一:局部副本已移除
|
| 10 |
|
|
|
|
| 166 |
|
| 167 |
html += `
|
| 168 |
<article class="notif-item${isSystem ? ' notif-item--system' : ''}${isUnread ? ' notif-item--unread' : ''}" data-account="${escapeHtml(msg.from_user)}" data-type="${escapeHtml(msg.type)}" data-item-id="${escapeHtml(msg.target_item_id || '')}">
|
| 169 |
+
<img class="notification-avatar" alt="" src="${escapeHtml(normalizeProfileImageUrl(msg.from_avatar) || PLACEHOLDERS.AVATAR)}">
|
| 170 |
<div class="notification-body">
|
| 171 |
<div class="notification-meta">${nameLabel}<time class="notification-time" datetime="${date.toISOString()}">${timeStr}</time></div>
|
| 172 |
<div class="notification-action">${actionText}</div>
|