- 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三规范
76 lines
2.7 KiB
JavaScript
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,'&').replace(/</g,'<').replace(/>/g,'>');
|
|
}
|
|
|
|
// 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('');
|
|
}
|
|
});
|