Files
mce/templates/admin/static/js/energy.js
Victor_Jay 26e557de8a feat: 实现社区激励金(公户)系统,经济闭环
- 新增 CommunityFund / FundLog 模型(公户余额单行表 + 6种流水类型)
- 新增 FundRepo 仓储(GetBalance / IncrBalance / CreateLog / ListLogs / WithTx)
- 改造 EnergyService 五个方法:Energize 税收入公户、DeductOnRename/DeductOnDeletePost 入公户、RefundOnRenameReject 从公户支出、AdminAdjust 拆分为 admin_transfer/system_operation
- 新增 ErrInsufficientFund 错误哨兵
- 管理后台新增公户余额展示 + 公户流水页面 + 域能调整资金来源选择
- 新增 energy.css / energy.js 前端交互
- 侧边栏新增公户流水入口
2026-06-01 15:10:47 +08:00

208 lines
8.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 域能管理页面 JS
(function () {
const path = window.location.pathname;
if (path === '/admin/energy') {
initEnergyPage();
} else if (path === '/admin/energy/logs') {
initEnergyLogPage();
} else if (path === '/admin/energy/fund-logs') {
initFundLogPage();
}
// ----- 域能管理首页:公户余额 + 调整表单 -----
function initEnergyPage() {
var adjustForm = document.getElementById('adjust-form');
if (!adjustForm) return;
adjustForm.addEventListener('submit', function (e) {
e.preventDefault();
var form = e.target;
var submitBtn = form.querySelector('button[type="submit"]');
var msgEl = document.getElementById('adjust-message');
if (msgEl) msgEl.className = 'form-message';
var userIDsStr = form.querySelector('[name="user_ids"]').value.trim();
var amountStr = form.querySelector('[name="amount"]').value.trim();
var desc = form.querySelector('[name="description"]').value.trim();
var mode = form.querySelector('[name="mode"]').value;
if (!userIDsStr || !amountStr || !desc) {
showMsg(msgEl, '请填写完整信息', 'error');
return;
}
var userIDs = userIDsStr.split(',').map(function (s) { return parseInt(s.trim(), 10); }).filter(function (n) { return n > 0; });
var amount = parseInt(amountStr, 10);
if (userIDs.length === 0 || isNaN(amount) || amount === 0) {
showMsg(msgEl, '用户ID和金额格式不正确', 'error');
return;
}
if (submitBtn) submitBtn.disabled = true;
api.post('/api/admin/energy/adjust', {
user_ids: userIDs,
amount: amount,
description: desc,
mode: mode
}, function (res) {
if (submitBtn) submitBtn.disabled = false;
if (res.success) {
showMsg(msgEl, res.message || '调整成功', 'success');
// 刷新公户余额
setTimeout(function () {
api.get('/api/admin/energy/fund-balance', function (r) {
if (r.success && r.data) {
var balEl = document.getElementById('fund-balance');
if (balEl) {
balEl.textContent = r.data.balance_display.toFixed(1);
balEl.className = 'fund-balance' + (r.data.balance < 0 ? ' negative' : '');
}
}
});
}, 300);
} else {
showMsg(msgEl, res.message || '调整失败', 'error');
}
});
});
}
// ----- 域能日志页 -----
function initEnergyLogPage() {
var page = 1;
var typeFilter = document.getElementById('log-type-filter');
function loadLogs() {
var logType = typeFilter ? typeFilter.value : '';
api.get('/api/admin/energy/logs?page=' + page + '&page_size=20&type=' + encodeURIComponent(logType), function (res) {
if (!res.success) return;
renderLogTable('energy-log-tbody', res.data.items, function (item) {
return [
item.id,
formatTime(item.created_at),
item.user_id,
'<span class="' + (item.amount >= 0 ? 'amount-positive' : 'amount-negative') + '">' + item.energy_display.toFixed(1) + '</span>',
'<span class="type-badge">' + (item.type_name || item.type) + '</span>',
escapeHtml(item.description || '')
];
}, 6);
renderPagination('energy-log-pagination', page, res.data.total_pages, function (p) {
page = p;
loadLogs();
});
});
}
if (typeFilter) {
typeFilter.addEventListener('change', function () {
page = 1;
loadLogs();
});
}
loadLogs();
}
// ----- 公户流水页 -----
function initFundLogPage() {
var page = 1;
var typeFilter = document.getElementById('fund-log-type-filter');
function loadLogs() {
var logType = typeFilter ? typeFilter.value : '';
api.get('/api/admin/energy/fund-logs?page=' + page + '&page_size=20&type=' + encodeURIComponent(logType), function (res) {
if (!res.success) return;
renderLogTable('fund-log-tbody', res.data.items, function (item) {
return [
item.id,
formatTime(item.created_at),
'<span class="' + (item.amount >= 0 ? 'amount-positive' : 'amount-negative') + '">' + item.amount_display.toFixed(1) + '</span>',
'<span class="type-badge">' + (item.type_name || item.type) + '</span>',
escapeHtml(item.description || '')
];
}, 5);
renderPagination('fund-log-pagination', page, res.data.total_pages, function (p) {
page = p;
loadLogs();
});
});
}
if (typeFilter) {
typeFilter.addEventListener('change', function () {
page = 1;
loadLogs();
});
}
loadLogs();
}
// ----- 通用工具函数 -----
function renderLogTable(tbodyId, items, rowFn, colCount) {
var tbody = document.getElementById(tbodyId);
if (!tbody) return;
if (!items || items.length === 0) {
tbody.innerHTML = '<tr><td colspan="' + colCount + '" class="empty-state">暂无记录</td></tr>';
return;
}
var html = '';
for (var i = 0; i < items.length; i++) {
var cells = rowFn(items[i]);
html += '<tr>';
for (var j = 0; j < cells.length; j++) {
html += '<td>' + cells[j] + '</td>';
}
html += '</tr>';
}
tbody.innerHTML = html;
}
function renderPagination(paginationId, current, total, onChange) {
var container = document.getElementById(paginationId);
if (!container || total <= 1) { if (container) container.innerHTML = ''; return; }
var html = '';
html += '<button' + (current <= 1 ? ' disabled' : '') + ' data-page="' + (current - 1) + '"> 上一页</button>';
var start = Math.max(1, current - 2);
var end = Math.min(total, current + 2);
for (var p = start; p <= end; p++) {
html += '<button class="' + (p === current ? 'active' : '') + '" data-page="' + p + '">' + p + '</button>';
}
html += '<button' + (current >= total ? ' disabled' : '') + ' data-page="' + (current + 1) + '">下一页 </button>';
container.innerHTML = html;
var buttons = container.querySelectorAll('button');
for (var i = 0; i < buttons.length; i++) {
(function (btn) {
btn.addEventListener('click', function () {
var p = parseInt(this.getAttribute('data-page'), 10);
if (p > 0 && p <= total && p !== current) {
onChange(p);
}
});
})(buttons[i]);
}
}
function formatTime(isoStr) {
if (!isoStr) return '';
var d = new Date(isoStr);
var pad = function (n) { return n < 10 ? '0' + n : '' + n; };
return d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate()) + ' ' + pad(d.getHours()) + ':' + pad(d.getMinutes());
}
function escapeHtml(text) {
if (!text) return '';
return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}
function showMsg(msgEl, text, type) {
if (!msgEl) return;
msgEl.textContent = text;
msgEl.className = 'form-message ' + type;
setTimeout(function () { msgEl.className = 'form-message'; }, 4000);
}
})();