feat(admin): R176-R180 公示表与新闻撤回 + 管理端多管理员权限(C 层)+ 交卷冻结
- R176 成绩公示表引擎(lib/publicitySheet.js + lib/assets/publicity-template.xlsx 官方模板基底) 与指导教师回填(lib/teacherBackfill.js);赛项名称/编号改为配置项 - R177 新闻「发布 ↔ 撤回」互斥:撤回只置 is_draft=1,不删除数据 - R178 C 层 RBAC:lib/adminPermissions.js(13 权限点 / 70 条路由规则,唯一 SoT) + middleware/auth.js 三段判定(默认拒绝 · is_super 单点 · token_version) + controller/service/adminUser.js + lib/auditLog.js + model/adminAuditLog.js - R178 B1 交卷冻结:service.exam.assertNotSubmitted(bizCode 4006 单一判据源) - R178 B④ 提交口径拆分:formalSubmitted / submitted / answeredCount 三字段 - R178 成绩总览补小组编号:resolveTeamLabels(与选手管理同源,含兜底与三态) - R181 生产迁移配套:admins +7 列、admin_audit_logs(scripts/migrate_r178_admin_rbac.py)
This commit is contained in:
118
app/controller/adminUser.js
Normal file
118
app/controller/adminUser.js
Normal file
@@ -0,0 +1,118 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* 管理员账号管理控制器(R178 · C 层)
|
||||
*
|
||||
* 统一错误约定(与项目其它控制器一致):
|
||||
* - 业务错误 = HTTP 200 + `code !== 0`(helper.error 不改 HTTP 状态)
|
||||
* - service 通过 `bizCode` 表达期望错误码,这里原样翻译
|
||||
* ⛔ 不要把业务错误包成 500(前端会当成系统故障,用户看到「服务器错误」)
|
||||
*/
|
||||
|
||||
const Controller = require('egg').Controller;
|
||||
const adminPermissions = require('../lib/adminPermissions');
|
||||
|
||||
class AdminUserController extends Controller {
|
||||
/** 把 service 抛出的 bizCode 翻译成业务响应;非业务异常交给上层 catch */
|
||||
_fail(err, fallbackMessage) {
|
||||
const { ctx } = this;
|
||||
if (err && err.bizCode) {
|
||||
ctx.body = ctx.helper.error(err.bizCode, err.bizMessage || err.message);
|
||||
return;
|
||||
}
|
||||
ctx.logger.error(`${fallbackMessage}:`, err);
|
||||
ctx.body = ctx.helper.error(500, fallbackMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前登录管理员的权限信息(自助,无需业务权限)
|
||||
* GET /api/admin/me
|
||||
*
|
||||
* 前端用途:① 渲染侧边菜单;② 权限被他人改动后,下次进页面能感知并提示。
|
||||
* 顺带返回权限点目录(catalog),避免前端硬编码一份权限清单(那是第二真相源)。
|
||||
*/
|
||||
async me() {
|
||||
const { ctx } = this;
|
||||
const admin = ctx.state.currentAdmin;
|
||||
if (!admin) {
|
||||
ctx.body = ctx.helper.error(401, '未登录或登录状态已失效');
|
||||
return;
|
||||
}
|
||||
ctx.body = ctx.helper.success({
|
||||
id: admin.id,
|
||||
username: admin.username,
|
||||
isSuper: Number(admin.is_super) === 1,
|
||||
permissions: admin.permissions || [],
|
||||
catalog: adminPermissions.PERMISSIONS,
|
||||
}, '获取当前管理员信息成功');
|
||||
}
|
||||
|
||||
/** GET /api/admin/admin-users */
|
||||
async list() {
|
||||
const { ctx, service } = this;
|
||||
try {
|
||||
const list = await service.adminUser.list();
|
||||
ctx.body = ctx.helper.success({ list, total: list.length }, '获取管理员列表成功');
|
||||
} catch (err) {
|
||||
this._fail(err, '获取管理员列表失败');
|
||||
}
|
||||
}
|
||||
|
||||
/** POST /api/admin/admin-users */
|
||||
async create() {
|
||||
const { ctx, service } = this;
|
||||
try {
|
||||
const result = await service.adminUser.create(ctx.request.body || {});
|
||||
ctx.body = ctx.helper.success(result, '管理员账号已创建');
|
||||
} catch (err) {
|
||||
this._fail(err, '创建管理员失败');
|
||||
}
|
||||
}
|
||||
|
||||
/** PUT /api/admin/admin-users/:id/permissions */
|
||||
async updatePermissions() {
|
||||
const { ctx, service } = this;
|
||||
try {
|
||||
const result = await service.adminUser.updatePermissions(ctx.params.id, ctx.request.body || {});
|
||||
ctx.body = ctx.helper.success(result, '权限已更新');
|
||||
} catch (err) {
|
||||
this._fail(err, '更新权限失败');
|
||||
}
|
||||
}
|
||||
|
||||
/** PUT /api/admin/admin-users/:id/password */
|
||||
async resetPassword() {
|
||||
const { ctx, service } = this;
|
||||
try {
|
||||
const result = await service.adminUser.resetPassword(ctx.params.id, ctx.request.body || {});
|
||||
ctx.body = ctx.helper.success(result, '口令已重置,该账号需重新登录');
|
||||
} catch (err) {
|
||||
this._fail(err, '重置口令失败');
|
||||
}
|
||||
}
|
||||
|
||||
/** PUT /api/admin/admin-users/:id/status */
|
||||
async setStatus() {
|
||||
const { ctx, service } = this;
|
||||
try {
|
||||
const result = await service.adminUser.setStatus(ctx.params.id, ctx.request.body || {});
|
||||
const msg = Number(result.status) === 1 ? '账号已启用' : '账号已禁用,其在线会话已失效';
|
||||
ctx.body = ctx.helper.success(result, msg);
|
||||
} catch (err) {
|
||||
this._fail(err, '修改账号状态失败');
|
||||
}
|
||||
}
|
||||
|
||||
/** DELETE /api/admin/admin-users/:id */
|
||||
async remove() {
|
||||
const { ctx, service } = this;
|
||||
try {
|
||||
const result = await service.adminUser.remove(ctx.params.id);
|
||||
ctx.body = ctx.helper.success(result, '管理员账号已删除');
|
||||
} catch (err) {
|
||||
this._fail(err, '删除管理员失败');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AdminUserController;
|
||||
Reference in New Issue
Block a user