showcase/wwwroot/showcase.js
yumoqing 1cce05a119 feat: showcase模块 - 产品展示平台(MVP)
- 4张数据表: posts/comments/likes/downloads
- 5种媒体类型: music/mtv/short_video/long_video/ktv
- 社交功能: 点赞(toggle)、评论(嵌套回复)
- KTV付费下载: 购买记录、下载计数
- 11个dspy API端点
- 3个CRUD管理界面(posts/comments/downloads)
- Feed流(类型筛选+分页)、作品详情(浏览计数+点赞状态)
- load_path.py RBAC权限注册
- 符合module/db-table/crud三规范
2026-06-11 14:46:02 +08:00

76 lines
2.7 KiB
JavaScript

// Showcase platform JavaScript
const MEDIA_LABELS = {
music: '🎵 音乐', mtv: '🎬 MTV', short_video: '📱 短视频',
long_video: '🎞️ 长视频', ktv: '🎤 KTV'
};
const MEDIA_ICONS = {
music: '🎵', mtv: '🎬', short_video: '📱', long_video: '🎞️', ktv: '🎤'
};
let currentFilter = '';
async function loadFeed(mediaType) {
currentFilter = mediaType || '';
const container = document.getElementById('showcase_feed_grid');
if (!container) return;
const url = `${MODULE_PREFIX}/api/showcase_feed.dspy?media_type=${currentFilter}&page=1&page_size=30`;
try {
const resp = await fetch(url);
const result = await resp.json();
if (result.status !== 'ok' || !result.data) {
container.innerHTML = '<div style="padding:40px;text-align:center;color:#999">暂无作品</div>';
return;
}
renderFeedCards(container, result.data);
} catch (e) {
container.innerHTML = '<div style="padding:40px;text-align:center;color:#c00">加载失败</div>';
}
}
function renderFeedCards(container, posts) {
if (!posts.length) {
container.innerHTML = '<div style="padding:40px;text-align:center;color:#999">暂无作品</div>';
return;
}
container.innerHTML = posts.map(p => `
<div class="showcase-card" onclick="openDetail('${p.id}')">
<div class="thumb">${p.thumbnail_url ? `<img src="${p.thumbnail_url}" style="width:100%;height:100%;object-fit:cover">` : MEDIA_ICONS[p.media_type] || '📄'}</div>
<div class="info">
<span class="badge badge-${p.media_type}">${MEDIA_LABELS[p.media_type] || p.media_type}</span>
<div class="title">${escHtml(p.title)}</div>
<div class="meta">
<span>❤ ${p.like_count || 0}</span>
<span>💬 ${p.comment_count || 0}</span>
<span>👁 ${p.view_count || 0}</span>
${parseFloat(p.price) > 0 ? `<span>💰 ¥${p.price}</span>` : ''}
</div>
</div>
</div>
`).join('');
}
function openDetail(postId) {
window.location.href = `${MODULE_PREFIX}/detail.ui?post_id=${postId}`;
}
function escHtml(s) {
if (!s) return '';
return s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
}
// Register filterByType function
if (typeof registerFunction !== 'undefined') {
registerFunction('filterByType', function(opts) {
loadFeed(opts.type);
});
}
// Auto-load on page ready
document.addEventListener('DOMContentLoaded', function() {
if (document.getElementById('showcase_feed_grid')) {
loadFeed('');
}
});