update admin
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
<#macro page title active adminName="admin">
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="_csrf" content="${_csrf.token}"/>
|
||||
<meta name="_csrf_header" content="${_csrf.headerName}"/>
|
||||
<title>${title}</title>
|
||||
<#include "admin-commjs.ftl"/>
|
||||
<style>
|
||||
body { background: #f6f7fb; }
|
||||
.admin-header { background: #1f2937; color: #fff; padding: 12px 18px; }
|
||||
.admin-grid { display: grid; grid-template-columns: 230px 1fr; gap: 16px; padding: 16px; }
|
||||
.admin-sidebar { background: #fff; border-radius: 8px; padding: 8px; box-shadow: 0 1px 3px rgba(0,0,0,.08); }
|
||||
.admin-main { background: #fff; border-radius: 8px; padding: 16px; box-shadow: 0 1px 3px rgba(0,0,0,.08); }
|
||||
.admin-sidebar a.item.active { background: #1d4ed8 !important; color: #fff !important; border-radius: 6px; }
|
||||
.metric-card { border: 1px solid #e5e7eb; border-radius: 8px; padding: 12px; }
|
||||
.small-muted { color: #6b7280; font-size: 12px; }
|
||||
@media (max-width: 900px) {
|
||||
.admin-grid { grid-template-columns: 1fr; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="admin-header">
|
||||
<div class="ui grid">
|
||||
<div class="ten wide column">Jiscuss 后台管理</div>
|
||||
<div class="six wide right aligned column">当前管理员: ${adminName} | <a style="color:#93c5fd" href="/swagger-ui.html" target="_blank">接口文档</a> | <a style="color:#93c5fd" href="/">前台首页</a></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-grid">
|
||||
<div class="admin-sidebar">
|
||||
<div class="ui vertical fluid menu">
|
||||
<a class="item <#if active=='home'>active</#if>" href="/admin/home">总览与运维</a>
|
||||
<a class="item <#if active=='users'>active</#if>" href="/admin/users">用户与角色</a>
|
||||
<a class="item <#if active=='discussions'>active</#if>" href="/admin/discussions">文章管理</a>
|
||||
<a class="item <#if active=='posts'>active</#if>" href="/admin/posts">评论管理</a>
|
||||
<a class="item <#if active=='upgradeLogs'>active</#if>" href="/admin/upgrade-logs">版本升级日志</a>
|
||||
<a class="item <#if active=='auditLogs'>active</#if>" href="/admin/audit-logs">操作审计日志</a>
|
||||
<div class="item small-muted">预留扩展</div>
|
||||
<a class="item <#if active=='plugins'>active</#if>" href="/admin/plugins">插件管理(预留)</a>
|
||||
<a class="item <#if active=='themes'>active</#if>" href="/admin/themes">主题管理(预留)</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-main">
|
||||
<#nested>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</#macro>
|
||||
@@ -0,0 +1,48 @@
|
||||
<#import "admin-shell.ftl" as shell>
|
||||
<@shell.page title="后台管理 - 操作审计日志" active=active adminName=adminName>
|
||||
<h2 class="ui header">操作审计日志</h2>
|
||||
<p class="small-muted">记录所有管理员的后台操作,包括角色管理、用户管理、内容管理等。</p>
|
||||
|
||||
<table class="ui striped celled table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>管理员</th>
|
||||
<th>操作类型</th>
|
||||
<th>目标类型</th>
|
||||
<th>目标ID</th>
|
||||
<th>描述</th>
|
||||
<th>状态</th>
|
||||
<th>操作时间</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<#list logs as l>
|
||||
<tr>
|
||||
<td>${l.id}</td>
|
||||
<td>${l.adminName!""}</td>
|
||||
<td><span class="ui label">${l.actionType!""}</span></td>
|
||||
<td>${l.targetType!""}</td>
|
||||
<td>${l.targetId!""}</td>
|
||||
<td>
|
||||
<div style="max-width:300px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;" title="${l.description!""}">
|
||||
${l.description!""}
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<#if l.status == "success">
|
||||
<span class="ui label green">成功</span>
|
||||
<#elseif l.status == "blocked">
|
||||
<span class="ui label orange">阻止</span>
|
||||
<#elseif l.status == "ignored">
|
||||
<span class="ui label yellow">忽略</span>
|
||||
<#else>
|
||||
<span class="ui label">${l.status!""}</span>
|
||||
</#if>
|
||||
</td>
|
||||
<td>${l.createTime?string('yyyy-MM-dd HH:mm:ss')!""}</td>
|
||||
</tr>
|
||||
</#list>
|
||||
</tbody>
|
||||
</table>
|
||||
</@shell.page>
|
||||
@@ -0,0 +1,32 @@
|
||||
<#import "admin-shell.ftl" as shell>
|
||||
<@shell.page title="后台管理 - 文章管理" active=active adminName=adminName>
|
||||
<h2 class="ui header">文章管理</h2>
|
||||
<table class="ui striped celled table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>标题</th>
|
||||
<th>创建人ID</th>
|
||||
<th>创建时间</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<#list discussions as d>
|
||||
<tr>
|
||||
<td>${d.id}</td>
|
||||
<td>${d.title!""}</td>
|
||||
<td>${d.createId!""}</td>
|
||||
<td>${d.createTime?string('yyyy-MM-dd HH:mm:ss')!""}</td>
|
||||
<td>
|
||||
<a class="ui tiny button" href="/getdiscussionsbyid?id=${d.id}" target="_blank">查看</a>
|
||||
<form style="display:inline" method="post" action="/admin/discussions/${d.id}/delete" onsubmit="return confirm('确认删除该文章及其评论吗?');">
|
||||
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
|
||||
<button class="ui tiny red button" type="submit">删除</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
</#list>
|
||||
</tbody>
|
||||
</table>
|
||||
</@shell.page>
|
||||
@@ -1,338 +1,50 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<title>后台管理首页</title>
|
||||
<head>
|
||||
<meta name="_csrf" content="${_csrf.token}"/>
|
||||
<meta name="_csrf_header" content="${_csrf.headerName}"/>
|
||||
<#import "admin-shell.ftl" as shell>
|
||||
<@shell.page title="后台管理 - 总览" active=active adminName=adminName>
|
||||
<h2 class="ui header">系统总览</h2>
|
||||
|
||||
<#--jquery-->
|
||||
<script crossorigin="anonymous" integrity="sha384-vk5WoKIaW/vJyUAd9n/wmopsmNhiy+L2Z+SBxGYnUkunIxVxAv/UtMOhba/xskxh"
|
||||
src="https://lib.baomitu.com/jquery/3.4.1/jquery.min.js"></script>
|
||||
|
||||
<#--semantic-ui-->
|
||||
<link rel="stylesheet" type="text/css" href="/static/semanticui/semantic.css">
|
||||
<script type="text/javascript" src="/static/semanticui/semantic.js"></script>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/static/semanticui/my.css">
|
||||
|
||||
<#--tinymce-->
|
||||
<script crossorigin="anonymous" integrity="sha384-CpsBIlOAWHuSRRN235sCBzEeKN6hLT6SpOGRkGadKpYj0gDP7+s3Q8pC38z8uGHH"
|
||||
src="https://lib.baomitu.com/tinymce/5.1.1/tinymce.min.js"></script>
|
||||
|
||||
|
||||
<#--layx-->
|
||||
<link href="/static/layx/layx.min.css?b14794a8a3baf3e8b58e" rel="stylesheet">
|
||||
|
||||
<script type="text/javascript" src="/static/layx/layx.min.js?b14794a8a3baf3e8b58e"></script>
|
||||
|
||||
<script type="text/javascript" charset="UTF-8" src="/static/js/comm/util.js"></script>
|
||||
|
||||
|
||||
<style type="text/css">
|
||||
body {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
#sidebar {
|
||||
position: fixed;
|
||||
height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
padding-top: 68px;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
#sidebar .ui.menu > a.item {
|
||||
padding: 10px 20px;
|
||||
line-height: 20px;
|
||||
color: #337ab7;
|
||||
border-radius: 0 !important;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#sidebar .ui.menu > a.item.active {
|
||||
background-color: #337ab7;
|
||||
color: white;
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
#sidebar .ui.menu > a.item:hover {
|
||||
background-color: #eee;
|
||||
color: #23527c;
|
||||
}
|
||||
|
||||
#content {
|
||||
padding-top: 56px;
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
#content h1 {
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
#content .ui.dividing.header {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ui.centered.small.circular.image {
|
||||
margin-top: 14px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.ui.borderless.menu {
|
||||
box-shadow: none;
|
||||
flex-wrap: wrap;
|
||||
border: none;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.ui.mobile.only.grid .ui.menu .ui.vertical.menu {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body id="root">
|
||||
<div class="ui tablet computer only padded grid">
|
||||
<div class="ui inverted borderless top fixed fluid menu">
|
||||
<a class="header item">Jiscuss后台管理</a>
|
||||
<div class="right menu">
|
||||
<div class="item">
|
||||
<div class="ui small input"><input placeholder="Search..." /></div>
|
||||
</div>
|
||||
<a class="item">常用管理</a> <a class="item">设置</a>
|
||||
<a class="item">用户</a> <a class="item">主题</a> <a class="item">注销</a>
|
||||
</div>
|
||||
<div class="ui four stackable cards">
|
||||
<div class="card"><div class="content"><div class="header">用户总数</div><div class="description">${userCount}</div></div></div>
|
||||
<div class="card"><div class="content"><div class="header">文章总数</div><div class="description">${discussionCount}</div></div></div>
|
||||
<div class="card"><div class="content"><div class="header">评论总数</div><div class="description">${postCount}</div></div></div>
|
||||
<div class="card"><div class="content"><div class="header">角色总数</div><div class="description">${roleCount}</div></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui mobile only padded grid">
|
||||
<div class="ui top fixed borderless fluid inverted menu">
|
||||
<a class="header item">Project Name</a>
|
||||
<div class="right menu">
|
||||
<div class="item">
|
||||
<button class="ui icon toggle basic inverted button">
|
||||
<i class="content icon"></i>
|
||||
</button>
|
||||
|
||||
<h3 class="ui dividing header">服务器与运行时</h3>
|
||||
<div class="ui two stackable cards">
|
||||
<div class="card">
|
||||
<div class="content">
|
||||
<div class="header">CPU / 内存</div>
|
||||
<div class="description">
|
||||
<p>CPU 负载: ${sys.cpuLoad}</p>
|
||||
<p>JVM 已用内存: ${sys.usedMb} MB / ${sys.totalMb} MB</p>
|
||||
<p>JVM 最大内存: ${sys.maxMb} MB</p>
|
||||
<p>Heap 已用: ${sys.heapUsedMb} MB</p>
|
||||
<p>应用运行时长: ${sys.uptimeMs} ms</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui vertical borderless inverted fluid menu">
|
||||
<a class="item">Dashboard</a> <a class="item">Settings</a>
|
||||
<a class="item">Profile</a> <a class="item">Help</a>
|
||||
<div class="ui fitted divider"></div>
|
||||
<div class="item">
|
||||
<div class="ui small input"><input placeholder="Search..." /></div>
|
||||
<div class="card">
|
||||
<div class="content">
|
||||
<div class="header">关键依赖版本</div>
|
||||
<div class="description">
|
||||
<p>Spring Boot: ${deps.springBoot}</p>
|
||||
<p>Java: ${deps.java}</p>
|
||||
<p>Spring: ${deps.spring}</p>
|
||||
<p>Hibernate: ${deps.hibernate}</p>
|
||||
<p>Flyway: ${deps.flyway}</p>
|
||||
<p>Druid: ${deps.druid}</p>
|
||||
<p>Ehcache: ${deps.ehcache}</p>
|
||||
<p>SpringDoc: ${deps.springdoc}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui padded grid">
|
||||
<div
|
||||
class="three wide tablet only three wide computer only column"
|
||||
id="sidebar"
|
||||
>
|
||||
<div class="ui vertical borderless fluid text menu">
|
||||
<a class="active item">常用管理</a> <a class="item">设置</a>
|
||||
<div class="ui hidden divider"></div>
|
||||
<a class="item">用户</a> <a class="item">主题</a>
|
||||
<div class="ui hidden divider"></div>
|
||||
<a class="item">Jiscuss文档</a>
|
||||
<a class="item" href="/">返回首页</a>
|
||||
</div>
|
||||
|
||||
<h3 class="ui dividing header">快捷入口</h3>
|
||||
<div class="ui buttons">
|
||||
<a class="ui primary button" href="/admin/users">用户与角色</a>
|
||||
<a class="ui button" href="/admin/discussions">文章管理</a>
|
||||
<a class="ui button" href="/admin/posts">评论管理</a>
|
||||
<a class="ui button" href="/swagger-ui.html" target="_blank">接口文档</a>
|
||||
</div>
|
||||
<div
|
||||
class="sixteen wide mobile thirteen wide tablet thirteen wide computer right floated column"
|
||||
id="content"
|
||||
>
|
||||
<div class="ui padded grid">
|
||||
<div class="row">
|
||||
<h1 class="ui huge dividing header">Dashboard</h1>
|
||||
</div>
|
||||
<div class="center aligned row">
|
||||
<div
|
||||
class="eight wide mobile four wide tablet four wide computer column"
|
||||
>
|
||||
<img
|
||||
class="ui centered small circular image"
|
||||
src="./static/images/wireframe/square-image.png"
|
||||
/>
|
||||
<div class="ui large basic label">Label</div>
|
||||
<p>Something else</p>
|
||||
</div>
|
||||
<div
|
||||
class="eight wide mobile four wide tablet four wide computer column"
|
||||
>
|
||||
<img
|
||||
class="ui centered small circular image"
|
||||
src="./static/images/wireframe/square-image.png"
|
||||
/>
|
||||
<div class="ui large basic label">Label</div>
|
||||
<p>Something else</p>
|
||||
</div>
|
||||
<div
|
||||
class="eight wide mobile four wide tablet four wide computer column"
|
||||
>
|
||||
<img
|
||||
class="ui centered small circular image"
|
||||
src="./static/images/wireframe/square-image.png"
|
||||
/>
|
||||
<div class="ui large basic label">Label</div>
|
||||
<p>Something else</p>
|
||||
</div>
|
||||
<div
|
||||
class="eight wide mobile four wide tablet four wide computer column"
|
||||
>
|
||||
<img
|
||||
class="ui centered small circular image"
|
||||
src="./static/images/wireframe/square-image.png"
|
||||
/>
|
||||
<div class="ui large basic label">Label</div>
|
||||
<p>Something else</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui hidden section divider"></div>
|
||||
<div class="row">
|
||||
<h1 class="ui huge dividing header">Section title</h1>
|
||||
</div>
|
||||
<div class="row">
|
||||
<table class="ui single line striped selectable unstackable table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Header</th>
|
||||
<th>Header</th>
|
||||
<th>Header</th>
|
||||
<th>Header</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1,001</td>
|
||||
<td>Lorem</td>
|
||||
<td>ipsum</td>
|
||||
<td>dolor</td>
|
||||
<td>sit</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,002</td>
|
||||
<td>amet</td>
|
||||
<td>consectetur</td>
|
||||
<td>adipiscing</td>
|
||||
<td>elit</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,003</td>
|
||||
<td>Integer</td>
|
||||
<td>nec</td>
|
||||
<td>odio</td>
|
||||
<td>Praesent</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,003</td>
|
||||
<td>libero</td>
|
||||
<td>Sed</td>
|
||||
<td>cursus</td>
|
||||
<td>ante</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,004</td>
|
||||
<td>dapibus</td>
|
||||
<td>diam</td>
|
||||
<td>Sed</td>
|
||||
<td>nisi</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,005</td>
|
||||
<td>Nulla</td>
|
||||
<td>quis</td>
|
||||
<td>sem</td>
|
||||
<td>at</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,006</td>
|
||||
<td>nibh</td>
|
||||
<td>elementum</td>
|
||||
<td>imperdiet</td>
|
||||
<td>Duis</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,007</td>
|
||||
<td>sagittis</td>
|
||||
<td>ipsum</td>
|
||||
<td>Praesent</td>
|
||||
<td>mauris</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,008</td>
|
||||
<td>Fusce</td>
|
||||
<td>nec</td>
|
||||
<td>tellus</td>
|
||||
<td>sed</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,009</td>
|
||||
<td>augue</td>
|
||||
<td>semper</td>
|
||||
<td>porta</td>
|
||||
<td>Mauris</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,010</td>
|
||||
<td>massa</td>
|
||||
<td>Vestibulum</td>
|
||||
<td>lacinia</td>
|
||||
<td>arcu</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,011</td>
|
||||
<td>eget</td>
|
||||
<td>nulla</td>
|
||||
<td>Class</td>
|
||||
<td>aptent</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,012</td>
|
||||
<td>taciti</td>
|
||||
<td>sociosqu</td>
|
||||
<td>ad</td>
|
||||
<td>litora</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,013</td>
|
||||
<td>torquent</td>
|
||||
<td>per</td>
|
||||
<td>conubia</td>
|
||||
<td>nostra</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,014</td>
|
||||
<td>per</td>
|
||||
<td>inceptos</td>
|
||||
<td>himenaeos</td>
|
||||
<td>Curabitur</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,015</td>
|
||||
<td>sodales</td>
|
||||
<td>ligula</td>
|
||||
<td>in</td>
|
||||
<td>libero</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$(".ui.toggle.button").click(function() {
|
||||
$(".mobile.only.grid .ui.vertical.menu").toggle(100);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</@shell.page>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<#import "admin-shell.ftl" as shell>
|
||||
<@shell.page title="后台管理 - 插件管理(预留)" active=active adminName=adminName>
|
||||
<h2 class="ui header">插件管理(预留)</h2>
|
||||
<div class="ui info message">
|
||||
<div class="header">预留扩展点</div>
|
||||
<p>后续可在此接入插件生命周期管理:安装、启停、配置、版本升级、依赖校验。</p>
|
||||
</div>
|
||||
</@shell.page>
|
||||
@@ -0,0 +1,33 @@
|
||||
<#import "admin-shell.ftl" as shell>
|
||||
<@shell.page title="后台管理 - 评论管理" active=active adminName=adminName>
|
||||
<h2 class="ui header">评论管理</h2>
|
||||
<table class="ui compact celled table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>文章</th>
|
||||
<th>作者</th>
|
||||
<th>内容</th>
|
||||
<th>创建时间</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<#list posts as p>
|
||||
<tr>
|
||||
<td>${p.id}</td>
|
||||
<td>${discussionNames[p.discussionId]!('#'+p.discussionId?c)}</td>
|
||||
<td>${userNames[p.createId]!('#'+p.createId?c)}</td>
|
||||
<td><div style="max-width:420px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">${p.content!""}</div></td>
|
||||
<td>${p.createTime?string('yyyy-MM-dd HH:mm:ss')!""}</td>
|
||||
<td>
|
||||
<form style="display:inline" method="post" action="/admin/posts/${p.id}/delete" onsubmit="return confirm('确认删除该评论吗?');">
|
||||
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
|
||||
<button class="ui tiny red button" type="submit">删除</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
</#list>
|
||||
</tbody>
|
||||
</table>
|
||||
</@shell.page>
|
||||
@@ -0,0 +1,8 @@
|
||||
<#import "admin-shell.ftl" as shell>
|
||||
<@shell.page title="后台管理 - 主题管理(预留)" active=active adminName=adminName>
|
||||
<h2 class="ui header">主题管理(预留)</h2>
|
||||
<div class="ui info message">
|
||||
<div class="header">预留扩展点</div>
|
||||
<p>后续可在此增加主题包管理、配色切换、模板覆盖与预览发布。</p>
|
||||
</div>
|
||||
</@shell.page>
|
||||
@@ -0,0 +1,65 @@
|
||||
<#import "admin-shell.ftl" as shell>
|
||||
<@shell.page title="后台管理 - 版本升级日志" active=active adminName=adminName>
|
||||
<h2 class="ui header">版本功能升级日志</h2>
|
||||
<p class="small-muted">记录每次升级新增与修复内容,便于发布追踪与回滚评估。</p>
|
||||
|
||||
<form class="ui form" method="post" action="/admin/upgrade-logs">
|
||||
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<label>版本号</label>
|
||||
<input name="version" placeholder="例如 v3.5.13" required>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>类型</label>
|
||||
<select class="ui dropdown" name="type">
|
||||
<option value="feature">feature</option>
|
||||
<option value="fix">fix</option>
|
||||
<option value="security">security</option>
|
||||
<option value="refactor">refactor</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>标题</label>
|
||||
<input name="title" placeholder="本次升级摘要" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>详细内容</label>
|
||||
<textarea name="content" rows="4" placeholder="描述新增、修复、兼容性说明等"></textarea>
|
||||
</div>
|
||||
<button class="ui primary button" type="submit">新增日志</button>
|
||||
</form>
|
||||
|
||||
<h3 class="ui dividing header">历史记录</h3>
|
||||
<table class="ui celled table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>版本</th>
|
||||
<th>类型</th>
|
||||
<th>标题</th>
|
||||
<th>内容</th>
|
||||
<th>创建人</th>
|
||||
<th>创建时间</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<#list logs as l>
|
||||
<tr>
|
||||
<td>${l.id}</td>
|
||||
<td>${l.version!""}</td>
|
||||
<td>${l.type!""}</td>
|
||||
<td>${l.title!""}</td>
|
||||
<td>${l.content!""}</td>
|
||||
<td>${l.createdBy!""}</td>
|
||||
<td>${l.createTime?string('yyyy-MM-dd HH:mm:ss')!""}</td>
|
||||
</tr>
|
||||
</#list>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<script>
|
||||
$('.ui.dropdown').dropdown();
|
||||
</script>
|
||||
</@shell.page>
|
||||
@@ -0,0 +1,82 @@
|
||||
<#import "admin-shell.ftl" as shell>
|
||||
<@shell.page title="后台管理 - 用户与角色" active=active adminName=adminName>
|
||||
<h2 class="ui header">用户与角色管理</h2>
|
||||
<p class="small-muted">简单 RBAC:用户可绑定多个角色,拥有 ADMIN 角色的用户可以进入后台管理。</p>
|
||||
|
||||
<h3 class="ui dividing header">角色管理</h3>
|
||||
<form class="ui form" method="post" action="/admin/roles">
|
||||
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
|
||||
<div class="three fields">
|
||||
<div class="field"><label>角色编码</label><input name="code" placeholder="如 ADMIN_AUDIT" required></div>
|
||||
<div class="field"><label>角色名称</label><input name="name" placeholder="如 审计管理员" required></div>
|
||||
<div class="field"><label>描述</label><input name="description" placeholder="角色用途说明"></div>
|
||||
</div>
|
||||
<button class="ui small primary button" type="submit">新增角色</button>
|
||||
</form>
|
||||
|
||||
<table class="ui celled compact table">
|
||||
<thead><tr><th>ID</th><th>编码</th><th>名称</th><th>状态</th><th>操作</th></tr></thead>
|
||||
<tbody>
|
||||
<#list roles as r>
|
||||
<tr>
|
||||
<td>${r.id}</td>
|
||||
<td>${r.code!""}</td>
|
||||
<td>${r.name!""}</td>
|
||||
<td><#if r.enabled?? && r.enabled==1>启用<#else>停用</#if></td>
|
||||
<td>
|
||||
<form style="display:inline" method="post" action="/admin/roles/${r.id}/toggle">
|
||||
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
|
||||
<button class="ui tiny button" type="submit">切换启停</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
</#list>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3 class="ui dividing header">用户角色绑定</h3>
|
||||
<table class="ui celled table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>用户名</th>
|
||||
<th>邮箱</th>
|
||||
<th>角色绑定</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<#list users as u>
|
||||
<tr>
|
||||
<td>${u.id}</td>
|
||||
<td>${u.username!""}</td>
|
||||
<td>${u.email!""}</td>
|
||||
<td>
|
||||
<form class="ui form" method="post" action="/admin/users/${u.id}/roles">
|
||||
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
|
||||
<div class="inline fields">
|
||||
<#list roles as r>
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" name="roleIds" value="${r.id}"
|
||||
<#if userRoleIds[u.id]?? && userRoleIds[u.id]?seq_contains(r.id)>checked</#if>>
|
||||
<label>${r.code}</label>
|
||||
</div>
|
||||
</div>
|
||||
</#list>
|
||||
</div>
|
||||
<button class="ui tiny primary button" type="submit">保存角色</button>
|
||||
</form>
|
||||
</td>
|
||||
<td>
|
||||
<a class="ui tiny button" href="/user?id=${u.id}" target="_blank">查看用户页</a>
|
||||
</td>
|
||||
</tr>
|
||||
</#list>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<script>
|
||||
$('.ui.checkbox').checkbox();
|
||||
</script>
|
||||
</@shell.page>
|
||||
Reference in New Issue
Block a user