Files
24kycj 88c6ce8ccc 重构 monorepo 并完善网页端订阅与首页体验
- 迁移为 frontend-web、frontend-electron、backend-web 与 docker 部署结构
- 网页端:订阅门禁二次弹窗、套餐/支付组件化、顶栏分组对齐
- 首页:最近文件与模板库布局优化,缩略图对齐,下载与删除操作
- 新增管理后台、支付与云端文件 API,更新 README 与项目规范

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-08 18:17:39 +08:00

145 lines
5.6 KiB
JavaScript

(function () {
'use strict';
var Api = function () { return window.AdminApi; };
var Ui = function () { return window.AdminUi; };
var I = function () { return window.AdminI18n; };
var State = function () { return window.AdminState; };
var Filter = function () { return window.AdminFilter; };
var Router = function () { return window.AdminRouter; };
var ACTION_OPTS = [
{ v: '', l: '全部操作' },
{ v: 'users.setStatus', l: '变更用户状态' },
{ v: 'users.create', l: '创建用户' },
{ v: 'users.update', l: '编辑用户' },
{ v: 'users.delete', l: '删除用户' },
{ v: 'users.setPassword', l: '重置密码' },
{ v: 'users.setSubscription', l: '设置会员' },
{ v: 'users.detail', l: '查看用户详情' },
{ v: 'orders.detail', l: '查看订单详情' },
{ v: 'orders.cancel', l: '取消订单' },
{ v: 'orders.refundApprove', l: '通过退款' },
{ v: 'orders.refundReject', l: '拒绝退款' },
{ v: 'plans.upsert', l: '编辑套餐' },
{ v: 'settings.set', l: '修改系统设置' },
{ v: 'settings.set_batch', l: '批量修改设置' },
{ v: 'payment.key.upload', l: '上传支付密钥' },
];
function buildQuery() {
var st = State().audits;
var q = 'audits?page=' + st.page + '&size=' + st.size;
if (st.q) q += '&q=' + encodeURIComponent(st.q);
if (st.from) q += '&from=' + encodeURIComponent(st.from);
if (st.to) q += '&to=' + encodeURIComponent(st.to);
if (st.action) q += '&action=' + encodeURIComponent(st.action);
return q;
}
function actionOptions(selected) {
return ACTION_OPTS.map(function (o) {
return '<option value="' + o.v + '"' + (selected === o.v ? ' selected' : '') + '>' + o.l + '</option>';
}).join('');
}
function formatContext(ctx) {
if (!ctx) return '';
var body;
try {
body = '<pre class="soon-admin-code">' + I().esc(JSON.stringify(JSON.parse(ctx), null, 2)) + '</pre>';
} catch (e) {
body = '<div class="soon-audit-item__context">' + I().esc(ctx) + '</div>';
}
return '<details class="soon-audit-item__details"><summary>查看上下文</summary>' + body + '</details>';
}
function renderFilterBar(st) {
return Filter().bar(
Filter().field('关键词', Filter().searchInput('auditQ', st.q, '操作、目标或管理员')) +
Filter().field('操作类型', Filter().select('auditAction', actionOptions(st.action))) +
Ui().filterDateField('auditFrom', '从', st.from) +
Ui().filterDateField('auditTo', '至', st.to),
'<button type="button" class="soon-btn soon-btn--sm" id="auditSearchBtn">查询</button>' +
'<button type="button" class="soon-btn soon-btn--sm soon-btn--ghost" id="auditResetBtn">重置</button>'
);
}
function bindFilters(st) {
var searchBtn = Ui().el('auditSearchBtn');
var resetBtn = Ui().el('auditResetBtn');
var qInput = Ui().el('auditQ');
if (searchBtn) {
searchBtn.onclick = function () {
st.q = qInput ? qInput.value.trim() : '';
st.action = Ui().el('auditAction').value;
st.from = Ui().el('auditFrom').value;
st.to = Ui().el('auditTo').value;
if (st.from && st.to && st.from > st.to) {
soonToast('开始日期不能晚于结束日期', 'warn');
return;
}
st.page = 1;
Router().syncQuery();
render();
};
}
if (qInput) {
qInput.onkeydown = function (e) {
if (e.key === 'Enter' && searchBtn) searchBtn.click();
};
}
if (resetBtn) {
resetBtn.onclick = function () {
State().audits = { page: 1, size: 50, q: '', from: '', to: '', action: '' };
Router().syncQuery();
render();
};
}
}
function renderTimeline(items) {
if (!items.length) {
return Ui().emptyBlock('暂无审计记录', '调整筛选条件或等待管理员操作产生日志', '');
}
return items.map(function (a) {
return '<div class="soon-audit-item"><div class="soon-audit-item__title">' +
I().esc(I().tAction(a.action)) + ' · ' + I().esc(a.target) + '</div>' +
'<div class="soon-audit-item__meta">' + I().esc(a.admin_email || '') + ' · ' +
I().formatDateTime(a.created_at) + '</div>' + formatContext(a.context) + '</div>';
}).join('');
}
function render() {
var panel = Ui().el('panel-audits');
if (!panel) return;
var st = State().audits;
var header = Ui().pageHeader('审计日志', '管理员操作记录,支持按操作类型与时间筛选');
panel.innerHTML = '<div class="soon-admin-page">' + header + renderFilterBar(st) + Ui().skeletonTable() + '</div>';
Api().get(buildQuery()).then(function (j) {
if (!j) {
panel.innerHTML = '<div class="soon-admin-page">' + header + renderFilterBar(st) +
Ui().listError('审计日志加载失败', 'auditsListRetry') + '</div>';
bindFilters(st);
Ui().el('auditsListRetry').onclick = render;
return;
}
var items = j.data.items || [];
panel.innerHTML = '<div class="soon-admin-page">' + header + renderFilterBar(st) +
'<div class="soon-admin-card"><div class="soon-audit-timeline">' + renderTimeline(items) + '</div></div>' +
Ui().pagerHtml(j.data.page, j.data.size, j.data.total) + '</div>';
bindFilters(st);
Ui().bindPager(panel, j.data.page, j.data.size, j.data.total, function (p, newSize) {
st.page = p;
if (newSize) st.size = newSize;
Router().syncQuery();
render();
});
});
}
window.AdminViews = window.AdminViews || {};
window.AdminViews.audits = { render: render };
})();