bugfix260122.1

全站通知:

Widget:代号梗投稿

来自代号鸢WIKI_BWIKI_哔哩哔哩
跳到导航 跳到搜索

这个Widget用于《代号梗》页面的投稿和瀑布流展示功能。

使用方式:在页面底部添加

{{#Widget:代号梗投稿}}


<script> RLQ.push(['jquery', () => { $(document).ready(function () {

   // ========== 全局变量 ==========
   var api = new mw.Api();
   var user = mw.config.values.wgUserName;
   var allGengData = {};
   var cachedImageUrls = {};
   // ========== 获取用户头像(多来源兜底)==========
   function getUserAvatar() {
       if (window.thisUser && window.thisUser.icon) {
           return window.thisUser.icon;
       }
       if (window.Bikit && window.Bikit.userId) {
           return 'https://i0.hdslb.com/bfs/face/' + window.Bikit.userId + '.jpg';
       }
       var match = document.cookie.match(/DedeUserID=([^;]+)/);
       if (match) {
           return 'https://i0.hdslb.com/bfs/face/' + match[1] + '.jpg';
       }
       return ;
   }
   // ========== 初始化 ==========
   $(".rocom_screen_box").appendTo("body");
   var screenBox = document.querySelector('.rocom_screen_box');
   if (screenBox) {
       var observer = new MutationObserver(function (mutations) {
           mutations.forEach(function (mutation) {
               if ($(mutation.target).is(':visible')) {
                   $('body').css('overflow', 'hidden');
               } else {
                   $('body').css('overflow', );
               }
           });
       });
       observer.observe(screenBox, { attributes: true, attributeFilter: ['style'] });
   }
   function extractFileName(imageCode) {
       if (!imageCode) return null;
       var match = imageCode.match(/\[\[file:(.*?)(?:\||\])/i);
       if (match && match[1]) {
           return match[1].trim();
       }
       return null;
   }
   // 通过API获取文件真实URL
   async function getRealImageUrl(fileName) {
       if (!fileName) return ;
       if (cachedImageUrls[fileName]) return cachedImageUrls[fileName];
       
       try {
           let data = await api.get({
               action: 'query',
               titles: 'File:' + fileName,
               prop: 'imageinfo',
               iiprop: 'url',
               format: 'json'
           });
           let pages = data.query.pages;
           for (let id in pages) {
               if (pages[id].imageinfo && pages[id].imageinfo[0]) {
                   cachedImageUrls[fileName] = pages[id].imageinfo[0].url;
                   return cachedImageUrls[fileName];
               }
           }
       } catch(e) {
           console.error('获取图片URL失败:', e);
       }
       return ;
   }
   // 构建图片HTML - 卡片用
   async function buildImageHtml(imageCode, size) {
       var fileName = extractFileName(imageCode);
       if (!fileName) return ;
       var url = await getRealImageUrl(fileName);
       if (!url) return ;
       var imgSize = size || '80px';
       return '<img src="' + url + '" onerror="this.src=\'https://patchwiki.biligame.com/images/rocom/6/6c/luimkdv9n7jernb6gukhpyyc6hlnnev.png\'" style="width:' + imgSize + '; height:' + imgSize + '; object-fit:cover; border-radius:8px;">';
   }
   // 构建弹窗图片HTML - 完整显示
   async function buildModalImageHtml(imageCode) {
       var fileName = extractFileName(imageCode);
       if (!fileName) return ;
       var url = await getRealImageUrl(fileName);
       if (!url) return ;
       // 提取图片名称(不含扩展名)
       var imageName = fileName.replace(/\.[^/.]+$/, "");

return '

' +
              '<img src="' + url + '" onerror="this.src=\'https://patchwiki.biligame.com/images/rocom/6/6c/luimkdv9n7jernb6gukhpyyc6hlnnev.png\'" style="width:100%; height:auto; border-radius:10px; display:block;">' +
'
' + imageName + '
' + '

';

   }
   // ========== 加载所有梗数据 ==========
   function loadAllGengData() {
       return new Promise((resolve, reject) => {
           api.get({
               action: 'query',
               list: 'categorymembers',
               cmtitle: '分类:梗投稿',
               cmtype: 'page',
               cmlimit: '500',
               format: 'json'
           }).done(function(data) {
               var pages = data.query.categorymembers;
               if (!pages || pages.length === 0) {
                   resolve({});
                   return;
               }
               var pageTitles = pages.map(p => p.title);
               api.get({
                   action: 'query',
                   titles: pageTitles,
                   prop: 'revisions',
                   rvprop: 'content|timestamp',
                   format: 'json'
               }).done(function(pageData) {
                   var result = {};
                   for (var id in pageData.query.pages) {
                       var page = pageData.query.pages[id];
                       var title = page.title;
                       var content = page.revisions ? page.revisions[0]['*'] : ;
                       var match = content.match(/\{\{梗数据\n([\s\S]*?)\}\}/);
                       if (match) {
                           var params = match[1];
                           var geng = {};
                           
                           // 改进的解析方法,支持多行内容
                           var paramsStr = match[1];
                           var paramsObj = {};
                           var lines = paramsStr.split('\n');
                           var currentKey = null;
                           var currentValue = [];
                           
                           lines.forEach(function(line) {
                               line = line.trim();
                               if (line) {
                                   if (line.startsWith('|')) {
                                       // 保存上一个键值对
                                       if (currentKey) {
                                           paramsObj[currentKey] = currentValue.join('\n').trim();
                                       }
                                       // 开始新的键值对
                                       var parts = line.split('=');
                                       if (parts.length >= 2) {
                                           currentKey = parts[0].replace(/^\|/, ).trim();
                                           currentValue = [parts.slice(1).join('=').trim()];
                                       } else {
                                           currentKey = null;
                                           currentValue = [];
                                       }
                                   } else if (currentKey) {
                                       // 继续上一个值的内容(多行)
                                       currentValue.push(line);
                                   }
                               }
                           });
                           
                           // 保存最后一个键值对
                           if (currentKey) {
                               paramsObj[currentKey] = currentValue.join('\n').trim();
                           }
                           
                           geng.title = paramsObj['标题'] || ;
                           geng.chuchu = paramsObj['出处'] || ;
                           geng.image = paramsObj['图片'] || ;
                           geng.source = paramsObj['梗来源'] || ;
                           geng.detail = paramsObj['详情'] || ;
                           geng.contributor = paramsObj['贡献者'] || ;
                           geng.avatar = paramsObj['头像'] || ;
                           geng.activityType = paramsObj['活动类型'] || ;
                           geng.contentType = paramsObj['投稿类型'] || ;
                           geng.propName = paramsObj['道具名'] || ;
                           geng.speaker = paramsObj['说话人'] || ;
                           geng.dialogContent = paramsObj['对话内容'] || ;
                           geng.pageTitle = title;
                           // 优先使用页面修改时间,其次用模板里的提交时间
                           var revTimestamp = page.revisions && page.revisions[0].timestamp ? page.revisions[0].timestamp : ;
                           if (revTimestamp) {
                               var d = new Date(revTimestamp);
                               geng.time = d.getFullYear() + '-' + 
                                               String(d.getMonth() + 1).padStart(2, '0') + '-' + 
                                               String(d.getDate()).padStart(2, '0');
                           } else {
                               geng.time = paramsObj['提交时间'] || '未知时间';
                           }
                           
                           if (geng.title) {
                               result[geng.title] = geng;
                           }
                       }
                   }
                   allGengData = result;
                   resolve(allGengData);
               }).fail(reject);
           }).fail(reject);
       });
   }
   // ========== 删除梗页面(只有上传者可删除)==========
   function deleteGengPage(pageTitle, gengTitle, contributor) {
       if (user !== contributor) {
           showCustomAlert('您只能删除自己上传的梗!');
           return;
       }
       if (!confirm('确定要删除【' + gengTitle + '】吗?删除后无法恢复!')) {
           return;
       }
       
       api.post({
           action: 'delete',
           title: pageTitle,
           token: mw.user.tokens.get('csrfToken'),
           reason: '通过梗投稿工具删除'
       }).done(function() {
           showCustomAlert('删除成功!正在刷新列表...');
           allGengData = {};
           cachedImageUrls = {};
           loadAllGengData().then(function() {
               renderWaterfall();
           });
       }).fail(function(error) {
           showCustomAlert('删除失败:' + (error.error && error.error.info ? error.error.info : '您没有权限删除'));
       });
   }
   // ========== 修改梗页面(只有上传者可修改)==========
   function editGengPage(title) {
       var geng = allGengData[title];
       if (!geng) return;
       
       if (user !== geng.contributor) {
           showCustomAlert('您只能修改自己上传的梗!');
           return;
       }
       
       $('.rocom_modal_container').remove();
       $('body').css('overflow', );
       
       // 调用Widget_代号梗投稿弹窗.html中的方法显示修改表单
       if (window.showGengUploadFormForEdit) {
           window.showGengUploadFormForEdit(geng);
       } else {
           showCustomAlert('修改功能未加载');
       }
   }
   
   function updateGeng(pageTitle, newTitle, chuchu, image, source, detail, contributor) {
       var pageContent = '{{梗数据\n';
       pageContent += '|标题=' + newTitle + '\n';
       pageContent += '|出处=' + chuchu + '\n';
       pageContent += '|图片=' + image + '\n';
       pageContent += '|梗来源=' + source + '\n';
       pageContent += '|详情=' + detail + '\n';
       pageContent += '|贡献者=' + contributor + '\n';
       pageContent += '|头像=' + getUserAvatar() + '\n';
       pageContent += '}}\n';
       pageContent += ;
       
       var newPageTitle = '梗/' + newTitle;
       if (newPageTitle !== pageTitle) {
           api.post({
               action: 'move',
               from: pageTitle,
               to: newPageTitle,
               token: mw.user.tokens.get('csrfToken'),
               reason: '修改梗标题'
           }).done(function() {
               api.edit(newPageTitle, function() {
                   return { text: pageContent, summary: '通过梗投稿工具修改' };
               }).done(function() {
                   refreshAfterEdit();
               });
           }).fail(function() {
               api.edit(pageTitle, function() {
                   return { text: pageContent, summary: '通过梗投稿工具修改' };
               }).done(function() {
                   refreshAfterEdit();
               });
           });
       } else {
           api.edit(pageTitle, function() {
               return { text: pageContent, summary: '通过梗投稿工具修改' };
           }).done(function() {
               refreshAfterEdit();
           }).fail(function(error) {
               showCustomAlert('修改失败,请稍后重试');
           });
       }
   }
   
   function refreshAfterEdit() {
       showCustomAlert('修改成功!正在刷新列表...');
       allGengData = {};
       cachedImageUrls = {};
       loadAllGengData().then(function() {
           renderWaterfall();
       });
   }
   function bindCardEvents() {
       $('.rocom_geng_card').off('click').on('click', function(e) {
           if ($(e.target).hasClass('rocom_geng_card_delete')) return;
           var title = decodeURIComponent($(this).data('title'));
           showDetailModal(title);
       });
       
       $('.rocom_geng_card_delete').off('click').on('click', function(e) {
           e.stopPropagation();
           var pageTitle = decodeURIComponent($(this).data('page'));
           var gengTitle = decodeURIComponent($(this).data('title'));
           var contributor = decodeURIComponent($(this).data('contributor'));
           deleteGengPage(pageTitle, gengTitle, contributor);
       });
   }
   // ========== 渲染瀑布流卡片(带筛选和排序)==========
   async function renderWaterfall() {
       var $container = $('.rocom_geng_waterfall');
       if ($container.length === 0) {

$('.rocom_lineup_line_pet_deteils').after('

');

           $container = $('.rocom_geng_waterfall');
       }
       $container.empty();
       
       // 获取筛选和排序参数
       var searchKeyword = $('#gengSearch').val().trim().toLowerCase();
       var sortType = $('#gengSortType').val();
       var sortOrder = $('#gengSortOrder').val();
       var myOnly = $('#gengMyOnly').prop('checked');
       
       // 筛选数据
       var filteredData = {};
       for (var title in allGengData) {
           var geng = allGengData[title];
           
           // 仅查看自己投稿
           if (myOnly && user && geng.contributor !== user) {
               continue;
           }
           
           // 搜索关键词
           if (searchKeyword) {
               var match = false;
               if (geng.title.toLowerCase().includes(searchKeyword) ||
                   geng.chuchu.toLowerCase().includes(searchKeyword) ||
                   geng.source.toLowerCase().includes(searchKeyword) ||
                   geng.detail.toLowerCase().includes(searchKeyword) ||
                   geng.contributor.toLowerCase().includes(searchKeyword)) {
                   match = true;
               }
               if (!match) continue;
           }
           
           filteredData[title] = geng;
       }
       
       // 排序
       var titles = Object.keys(filteredData);
       titles.sort(function(a, b) {
           var gengA = filteredData[a];
           var gengB = filteredData[b];
           
           if (sortType === 'time') {
               var timeA = gengA.time || '1970-01-01';
               var timeB = gengB.time || '1970-01-01';
               if (sortOrder === 'desc') {
                   return timeB.localeCompare(timeA);
               } else if (sortOrder === 'asc') {
                   return timeA.localeCompare(timeB);
               }
           } else if (sortType === 'activity') {
               var activityA = gengA['活动类型'] || ;
               var activityB = gengB['活动类型'] || ;
               return activityA.localeCompare(activityB);
           }
           return 0;
       });
       
       if (titles.length === 0) {

$container.html('

✨ 暂无符合条件的梗投稿

');

           return;
       }
       
       for (var i = 0; i < titles.length; i++) {
           var geng = filteredData[titles[i]];
           var hasImage = extractFileName(geng.image) !== null;
           var imageHtml = hasImage ? await buildImageHtml(geng.image, '80px') : ;
           var canDelete = (user && user === geng.contributor);
           

var cardHtml = '

' + (hasImage ? '
' + imageHtml + '
' : ) + '
' + escapeHtml(geng.title) + '
' + '
' + escapeHtml(geng.chuchu) + '
' + '' + (canDelete ? '
🗑️
' : ) + '

';

           $container.append(cardHtml);
       }
       
       bindCardEvents();
   }
   
   // ========== 弹窗详情 ==========
   async function showDetailModal(title) {
       var geng = allGengData[title];
       if (!geng) return;
       
       var hasImage = extractFileName(geng.image) !== null;
       var imageHtml = hasImage ? await buildModalImageHtml(geng.image) : ;
       var canEdit = (user && user === geng.contributor);
       var displayTime = geng.time !== '未知时间' ? geng.time : ;
       var contributorName = geng.contributor || '匿名';
       var avatarUrl = geng.avatar || 'https://i0.hdslb.com/bfs/face/member/noface.jpg';
       

var modalHtml = '

' + '
' + '
' + '
' + '
' + '
' + '
' + escapeHtml(geng.title) + '
' + '
' + escapeHtml(geng.chuchu) + '
' + '
' + '
梗来源
' + '
' + escapeHtml(geng.source) + '
' + '
详情
' + '
' + '
' + escapeHtml(geng.detail).replace(/\n/g, '
') + '
' + '
' + '
' + (hasImage ? '
' + '
' + imageHtml + '
' + '
' : ) + '
' + '
' + '' +
           (canEdit ? '<button class="rocom_modal_edit_btn" data-title="' + encodeURIComponent(geng.title) + '">修改</button>' : ) +
'
' + '
' + '
' + '

';

       $('.rocom_modal_container').remove();
       $('body').append(modalHtml);
       $('body').css('overflow', 'hidden');
       
       $('.rocom_modal_overlay').on('click', function() {
           $('.rocom_modal_container').remove();
           $('body').css('overflow', );
       });
       
       $('.rocom_modal_edit_btn').off('click').on('click', function(e) {
           e.stopPropagation();
           var editTitle = decodeURIComponent($(this).data('title'));
           editGengPage(editTitle);
       });
   }
   // ========== 提交梗 ==========    
   function submitGeng(title, chuchu, image, source, detail, contributor, activityType, activity, contentType, speaker, dialogContent) {
       var pageContent = '{{梗数据\n';
       pageContent += '|标题=' + title + '\n';
       pageContent += '|出处=' + chuchu + '\n';
       pageContent += '|梗来源=' + source + '\n';
       pageContent += '|详情=' + detail + '\n';
       pageContent += '|贡献者=' + contributor + '\n';
       pageContent += '|头像=' + getUserAvatar() + '\n';
       
       if (activityType) pageContent += '|活动类型=' + activityType + '\n';
       if (activity) pageContent += '|具体活动=' + activity + '\n';
       if (contentType) pageContent += '|投稿类型=' + contentType + '\n';
       
       if (contentType === '道具描述' && speaker) {
           pageContent += '|道具名=' + speaker + '\n';
       } else if (contentType === '对话台词') {
           if (speaker) pageContent += '|说话人=' + speaker + '\n';
           if (dialogContent) pageContent += '|对话内容=' + dialogContent + '\n';
       }
       
       pageContent += '}}\n';
       
       // 为对话台词添加特殊模板
       if (contentType === '对话台词' && speaker && dialogContent) {

pageContent += '\n

\n'; pageContent += '
' + speaker + '
' + dialogContent + '
\n'; pageContent += '

\n';

       }
       
       pageContent += ;
       
       var pageTitle = '梗/' + title;
       
       api.get({
           action: 'query',
           titles: pageTitle,
           format: 'json'
       }).done(function(data) {
           var pages = data.query.pages;
           var exists = false;
           for (var id in pages) {
               if (id !== '-1') {
                   exists = true;
                   break;
               }
           }
           
           if (exists) {
               showCustomAlert('这个梗标题已经存在啦!请换个标题~');
               return;
           }
           
           api.create(pageTitle, { summary: '通过梗投稿工具创建' }, pageContent)
               .done(function() {
                   showCustomAlert('投稿成功!正在刷新列表...');
                   allGengData = {};
                   cachedImageUrls = {};
                   loadAllGengData().then(function() {
                       renderWaterfall();
                   });
               })
               .fail(function(error) {
                   showCustomAlert('投稿失败,请稍后重试');
               });
       });
   }
   function showCustomAlert(message) {
       $('.rocom_alert').remove();

var $modal = $('

').html( '

' + message + '

'

       );
       $('body').append($modal);
       setTimeout(function() {
           $modal.fadeOut(300, function() { $(this).remove(); });
       }, 2000);
   }
   
   function escapeHtml(str) {
       if (!str) return ;
       return str.replace(/[&<>]/g, function(m) {
           if (m === '&') return '&';
           if (m === '<') return '<';
           if (m === '>') return '>';
           return m;
       });
   }
   // ========== 初始化页面结构 ==========
   function initPage() {
       $('.rocom_lineup_upload_box').remove();
       $('.rocom_geng_waterfall').remove();
       $('.rocom_screen_box').remove();
       // 主容器

var containerHtml = '

' +
           // 主内容区域
'
' +
           // 投稿按钮和筛选区域
'
' + '
' +
           '<input type="text" id="gengSearch" placeholder="搜索关键词..." style="padding:8px 12px; border:1px solid #e2d5c0; border-radius:20px; font-size:14px; width:200px;">' +
           '<select id="gengSortType" style="padding:8px 12px; border:1px solid #e2d5c0; border-radius:20px; font-size:14px;">' +
           '<option value="activity">活动类型</option>' +
           '<option value="time" selected>上传时间</option>' +
           '</select>' +
           '<select id="gengSortOrder" style="padding:8px 12px; border:1px solid #e2d5c0; border-radius:20px; font-size:14px;">' +
           '<option value="desc" selected>降序</option>' +
           '<option value="asc">升序</option>' +
           '</select>' +
           '<label style="display:flex; align-items:center; gap:4px; font-size:14px; color:#5a3e2b;">' +
           '<input type="checkbox" id="gengMyOnly"> 仅查看自己投稿' +
           '</label>' +
'
' +
           '<button class="rocom_lineup_upload_btn" style="background:#c49a6c; color:white; border:none; padding:10px 28px; border-radius:40px; font-size:16px; cursor:pointer;">投稿新梗</button>' +
'
' +
           // 瀑布流容器
'
' + '
' + '

';

       // 添加到容器
       $('.rocom_lineup_line_pet_deteils').append(containerHtml);
       // 投稿按钮点击事件
       $('.rocom_lineup_upload_btn').off('click').on('click', function() {
           if (window.showGengUploadForm) {
               window.showGengUploadForm();
           } else {
               showCustomAlert('投稿功能未加载');
           }
       });
       // 筛选和排序事件监听器
       $('#gengSearch').off('input').on('input', function() {
           renderWaterfall();
       });
       $('#gengSortType').off('change').on('change', function() {
           var sortType = $(this).val();
           var $orderSelect = $('#gengSortOrder');
           
           if (sortType === 'time') {
               $orderSelect.html('<option value="desc">降序</option><option value="asc">升序</option>');
           } else if (sortType === 'activity') {
               $orderSelect.html('<option value="">请选择排序方式</option>');
           }
           
           renderWaterfall();
       });
       $('#gengSortOrder').off('change').on('change', function() {
           renderWaterfall();
       });
       $('#gengMyOnly').off('change').on('change', function() {
           renderWaterfall();
       });
       // 加载数据
       loadAllGengData().then(function() {
           renderWaterfall();
       });
   }
   function waitForContainer() {
       var checkInterval = setInterval(function() {
           if ($('.rocom_lineup_line_pet_deteils').length > 0) {
               clearInterval(checkInterval);
               $('.rocom_lineup_line_pet_deteils').empty();
               initPage();
           }
       }, 100);
   }
   
   // 暴露刷新函数供弹窗调用
   window.refreshGengList = function() {
       loadAllGengData().then(function() {
           renderWaterfall();
       });
   };
   
   waitForContainer();

}); }]); </script>

<style> /* ========== 瀑布流样式 ========== */ .rocom_geng_waterfall {

   column-count: 4;
   column-gap: 16px;
   padding: 16px;

} @media (max-width: 1200px) { .rocom_geng_waterfall { column-count: 3; } } @media (max-width: 800px) { .rocom_geng_waterfall { column-count: 2; } } @media (max-width: 500px) { .rocom_geng_waterfall { column-count: 1; } }

.rocom_geng_card {

   break-inside: avoid;
   background: #fffef7;
   border-radius: 16px;
   box-shadow: 0 2px 8px rgba(0,0,0,0.08);
   margin-bottom: 16px;
   overflow: hidden;
   cursor: pointer;
   transition: 0.2s;
   position: relative;
   padding: 16px;

} .rocom_geng_card:hover {

   transform: translateY(-2px);
   box-shadow: 0 6px 16px rgba(0,0,0,0.12);

}

.rocom_geng_card_title {

   font-size: 16px;
   font-weight: bold;
   color: #5a3e2b;
   margin-bottom: 4px;
   text-align: center;

} .rocom_geng_card_chuchu {

   font-size: 12px;
   color: #888;
   margin-bottom: 8px;
   text-align: center;

}

.rocom_geng_card_no_img .rocom_geng_card_title {

   text-align: center;

}

.rocom_geng_card_img_wrap {

   text-align: center;
   margin-bottom: 10px;

} .rocom_geng_card_img_wrap img {

   display: inline-block;
   width: 80px;
   height: 80px;
   object-fit: cover;
   border-radius: 8px;

}

.rocom_geng_card_footer {

   display: flex;
   justify-content: space-between;
   align-items: center;
   font-size: 11px;
   margin-top: 8px;
   padding-top: 8px;
   border-top: 1px solid #f0ebe0;

} .rocom_geng_card_contributor {

   color: #999;
   flex-shrink: 0;

} .rocom_geng_card_time {

   color: #bbb;
   flex-shrink: 0;
   text-align: right;

}

.rocom_geng_card_delete {

   position: absolute;
   top: 6px;
   right: 10px;
   background: rgba(0,0,0,0.5);
   color: white;
   padding: 2px 6px;
   border-radius: 20px;
   font-size: 12px;
   cursor: pointer;
   opacity: 0;
   transition: 0.2s;

} .rocom_geng_card:hover .rocom_geng_card_delete {

   opacity: 1;

}

/* ========== 弹窗样式 ========== */ .rocom_modal_container {

   position: fixed;
   top: 0;
   left: 0;
   width: 100%;
   height: 100%;
   z-index: 20000;
   display: flex;
   align-items: center;
   justify-content: center;

} .rocom_modal_overlay {

   position: absolute;
   top: 0;
   left: 0;
   width: 100%;
   height: 100%;
   background: rgba(0, 0, 0, 0.6);

} .rocom_modal_content {

   position: relative;
   background: white;
   border-radius: 16px;
   box-shadow: 0 20px 40px rgba(0,0,0,0.3);
   max-height: 85vh;
   overflow-y: auto;
   width: 90%;
   max-width: 680px;

} .rocom_modal_body {

   padding: 24px;

}

.rocom_modal_layout {

   display: flex;
   gap: 24px;
   align-items: flex-start;

}

.rocom_modal_layout.rocom_modal_no_image .rocom_modal_right {

   max-width: 100%;

}

.rocom_modal_left {

   flex-shrink: 0;
   width: 180px;
   display: flex;
   align-items: center;
   justify-content: center;
   margin-top: 45px;

} .rocom_modal_image_wrap {

   width: 70%;
   display: flex;
   align-items: center;
   justify-content: center;

} .rocom_modal_image_wrap img {

   width: 100%;
   height: auto;
   display: block;
   border-radius: 10px;
   object-fit: contain;

}

.rocom_modal_right {

   flex: 1;
   min-width: 0;

} .rocom_modal_title {

   font-size: 22px;
   font-weight: bold;
   color: #5a3e2b;
   margin-bottom: 6px;
   text-align: center;

} .rocom_modal_source {

   font-size: 14px;
   color: #c49a6c;
   margin-bottom: 4px;
   text-align: center;

}

.rocom_modal_divider {

   height: 1px;
   background: #eee;
   margin: 16px 0;

} .rocom_modal_label {

   font-size: 14px;
   font-weight: bold;
   color: #5a3e2b;
   margin: 12px 0 6px;

} .rocom_modal_text {

   font-size: 14px;
   line-height: 1.6;
   color: #444;
   word-break: break-all;

}

.rocom_modal_detail_wrap {

   max-height: calc(1.6em * 3);
   overflow-y: auto;
   overflow-x: hidden;
   margin-bottom: 16px;

} .rocom_modal_detail_text {

   margin: 0;
   word-wrap: break-word;
   white-space: normal;

}

/* 底部区域 - 水平布局 */ .rocom_modal_bottom {

   display: flex;
   justify-content: space-between;
   align-items: center;
   margin-top: 12px;
   padding-top: 12px;
   border-top: 1px solid #eee;
   gap: 16px;
   margin-bottom: -10px;

} .rocom_modal_user_info {

   display: flex;
   justify-content: space-between;
   align-items: center;
   flex: 1;

} .rocom_modal_user_name {

   font-size: 13px;
   color: #666;
   flex-shrink: 0;

} .rocom_modal_user_time {

   font-size: 13px;
   color: #666;
   flex-shrink: 0;
   text-align: right;

}

.rocom_modal_edit_btn {

   padding: 6px 18px;
   background: #c49a6c;
   color: white;
   border: none;
   border-radius: 20px;
   cursor: pointer;
   font-size: 13px;
   transition: 0.2s;
   white-space: nowrap;
   flex-shrink: 0;

} .rocom_modal_edit_btn:hover {

   background: #a87d4f;

}

/* 手机端响应式 */ @media (max-width: 500px) {

   .rocom_modal_layout {
       flex-direction: column;
   }
   .rocom_modal_left {
       width: 120px;
       margin: 0 auto 16px auto;
   }
   .rocom_modal_bottom {
       margin-top: 16px;
       padding-top: 10px;
   }
   .rocom_modal_detail_wrap {
       max-height: calc(1.6em * 4);
   }
   .rocom_modal_user_info {
       gap: 12px;
       flex-wrap: wrap;
   }

}

/* 上传人头像手机端适配 */ @media (max-width: 500px) {

   .rocom_modal_user_avatar {
       width: 32px !important;
       height: 32px !important;
   }

} </style>