| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- // 定价管理模块
- class PricingManager {
- constructor(options = {}) {
- this.apiBaseUrl = options.apiBaseUrl || 'http://localhost:3000';
- this.grid = options.grid || null;
-
- this.resources = [];
-
- this.init();
- }
- init() {
- this.bindEvents();
- // 默认进入页面时加载一次
- this.loadResources();
- }
- bindEvents() {
- // 刷新按钮
- const refreshBtn = document.getElementById('refreshPricingBtn');
- if (refreshBtn) {
- refreshBtn.addEventListener('click', () => {
- this.loadResources();
- });
- }
- }
- // 加载资源
- async loadResources() {
- if (!this.grid) return;
-
- this.grid.innerHTML = '<div class="loading-text">加载中...</div>';
- try {
- const response = await fetch(`${this.apiBaseUrl}/api/store/resources`);
- if (!response.ok) {
- throw new Error(`加载资源列表失败: ${response.status} ${response.statusText}`);
- }
- const result = await response.json();
-
- if (result.success && result.resources) {
- this.resources = result.resources;
- console.log('[PricingManager] 资源数:', this.resources.length, this.resources);
- this.renderResources();
- } else {
- this.grid.innerHTML = '<div class="loading-text">暂无资源数据</div>';
- }
- } catch (error) {
- console.error('[PricingManager] 加载资源失败:', error);
- const errorMessage = error.message || '未知错误';
- this.grid.innerHTML = `<div class="loading-text" style="color: #ef4444;">加载失败: ${errorMessage}</div>`;
- }
- }
- // 渲染资源
- renderResources() {
- if (!this.grid) return;
-
- // 使用 grid 布局,紧凑显示
- this.grid.style.display = 'grid';
- this.grid.style.gridTemplateColumns = 'repeat(auto-fill, minmax(240px, 1fr))';
- this.grid.style.gap = '16px';
- this.grid.style.padding = '20px';
- this.grid.style.background = '#f9fafb';
-
- if (this.resources.length === 0) {
- this.grid.innerHTML = '<div class="loading-text">暂无资源数据</div>';
- return;
- }
-
- console.log('[PricingManager] 渲染资源:', this.resources.length);
-
- this.grid.innerHTML = this.resources.map(resource => `
- <div class="pricing-item" style="
- border: 1px solid #e5e7eb;
- border-radius: 12px;
- padding: 12px;
- display: flex;
- flex-direction: column;
- gap: 10px;
- box-shadow: 0 2px 4px rgba(0,0,0,0.06);
- background: #fff;
- transition: transform 0.2s, box-shadow 0.2s;
- cursor: default;
- " onmouseover="this.style.transform='translateY(-2px)';this.style.boxShadow='0 4px 12px rgba(0,0,0,0.1)';" onmouseout="this.style.transform='';this.style.boxShadow='0 2px 4px rgba(0,0,0,0.06)';">
- <div class="pricing-preview" style="
- width: 100%;
- aspect-ratio: 1;
- display: flex;
- align-items: center;
- justify-content: center;
- background: linear-gradient(135deg, #f7f7f7 0%, #e9e9e9 100%);
- border-radius: 8px;
- overflow: hidden;
- position: relative;
- ">
- ${resource.previewUrl ?
- `<img src="${this.apiBaseUrl}${resource.previewUrl}" alt="${resource.name}" style="max-width:100%;max-height:100%;object-fit:contain;" onerror="this.parentElement.innerHTML='<div style=\\'color:#999;font-size:12px;\\'>无预览</div>'">` :
- '<div style="color:#999;font-size:12px;">无预览</div>'
- }
- <div style="position:absolute;bottom:4px;right:4px;background:rgba(0,0,0,0.6);color:#fff;font-size:10px;padding:2px 6px;border-radius:4px;">${resource.categoryDir || '-'}</div>
- </div>
- <div class="pricing-info" style="display:flex;flex-direction:column;gap:8px;">
- <div class="pricing-name" style="font-weight:600;font-size:14px;color:#111;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;" title="${resource.name}">${resource.name}</div>
- <div class="pricing-price-input" style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;">
- <div style="display:flex;align-items:center;gap:6px;">
- <label style="font-size:12px;color:#6b7280;flex-shrink:0;">价格</label>
- <input type="text" class="price-input" value="${resource.points || 0}"
- data-path="${resource.path}"
- data-original="${resource.points || 0}"
- style="width:60px;padding:6px 8px;border:1px solid #e5e7eb;border-radius:6px;outline:none;font-size:13px;transition:border-color 0.2s;text-align:center;"
- onfocus="this.style.borderColor='#667eea';"
- onblur="this.style.borderColor='#e5e7eb';"
- oninput="this.closest('.pricing-price-input').querySelector('.btn-confirm').style.display = this.value !== this.dataset.original ? 'inline-flex' : 'none';">
- <span style="font-size:12px;color:#6b7280;">Ani币</span>
- <button class="btn-confirm"
- onclick="window.pricingManagerInstance.confirmPrice('${resource.path}', this.closest('.pricing-price-input').querySelector('.price-input'))"
- style="display:none;width:24px;height:24px;background:#10b981;color:#fff;border:none;border-radius:50%;font-size:14px;font-weight:bold;cursor:pointer;transition:all 0.2s;align-items:center;justify-content:center;"
- onmouseover="this.style.background='#059669';this.style.transform='scale(1.1)';"
- onmouseout="this.style.background='#10b981';this.style.transform='';"
- title="确认修改">✓</button>
- </div>
- </div>
- </div>
- </div>
- `).join('');
- }
- // 确认价格修改
- async confirmPrice(resourcePath, inputEl) {
- const price = inputEl.value.trim();
- const priceNum = parseFloat(price);
-
- if (isNaN(priceNum) || priceNum < 0) {
- this.showError('价格必须是大于等于0的数字');
- return;
- }
- try {
- const response = await fetch(`${this.apiBaseUrl}/api/admin/store/update-price`, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify({
- resourcePath: resourcePath,
- price: priceNum
- })
- });
- const result = await response.json();
-
- if (result.success) {
- // 更新本地数据和原始值
- const resource = this.resources.find(r => r.path === resourcePath);
- if (resource) {
- resource.points = priceNum;
- }
- inputEl.dataset.original = priceNum;
- inputEl.value = priceNum;
-
- // 隐藏确认按钮
- const confirmBtn = inputEl.parentElement.querySelector('.btn-confirm');
- if (confirmBtn) {
- confirmBtn.style.display = 'none';
- }
-
- this.showSuccess('价格更新成功');
- } else {
- this.showError('价格更新失败: ' + (result.message || '未知错误'));
- }
- } catch (error) {
- console.error('[PricingManager] 更新价格失败:', error);
- this.showError('价格更新失败,请稍后重试');
- }
- }
- // 更新价格(保留兼容)
- async updatePrice(resourcePath, price) {
- // 现在由 confirmPrice 处理
- }
- // 显示错误/成功消息
- showError(message) {
- if (window.showCustomAlert) {
- window.showCustomAlert(message);
- } else {
- console.error('[PricingManager] 错误:', message);
- }
- }
- showSuccess(message) {
- if (window.showCustomAlert) {
- window.showCustomAlert(message, 'success');
- } else {
- console.log('[PricingManager] 成功:', message);
- }
- }
- }
- // 导出
- if (typeof module !== 'undefined' && module.exports) {
- module.exports = PricingManager;
- } else {
- window.PricingManager = PricingManager;
- }
|