更新后端

This commit is contained in:
云泽网 2025-05-19 00:46:05 +08:00
parent 4c6f7277b0
commit 11fe0b4357
28 changed files with 4644 additions and 134 deletions

View File

@ -7,6 +7,7 @@ use app\admin\controller\Base;
use think\facade\Db;
use think\facade\View;
use think\facade\Request;
use app\common\service\LogService;
class Article extends Base
{
@ -411,4 +412,20 @@ class Article extends Base
}
return json(['code' => 0, 'msg' => '删除成功', 'data' => []]);
}
//统计文章数量
public function counts() {
$total = Db::table('yz_article')
->where('delete_time', null)
->where('status', '<>', 3)
->count();
return json([
'code' => 0,
'msg' => '获取成功',
'data' => [
'total' => $total
]
]);
}
}

View File

@ -61,10 +61,206 @@ class Index extends Base{
}
# 欢迎页面
public function welcome(){
View::assign([
'time' => date('Y-m-d',$_SERVER['REQUEST_TIME']),
// 获取今日统计数据
$today = date('Y-m-d');
$todayStats = Db::name('yz_daily_stats')
->where('date', $today)
->find();
// 获取最近7天的访问趋势
$last7Days = Db::name('yz_daily_stats')
->where('date', '>=', date('Y-m-d', strtotime('-7 days')))
->where('date', '<=', $today)
->order('date', 'asc')
->select()
->toArray();
// 获取用户增长趋势
$userGrowth = Db::name('yz_daily_stats')
->where('date', '>=', date('Y-m-d', strtotime('-30 days')))
->where('date', '<=', $today)
->field('date, new_users, total_users')
->order('date', 'asc')
->select()
->toArray();
// 获取资源下载统计
$resourceStats = Db::name('yz_daily_stats')
->where('date', '>=', date('Y-m-d', strtotime('-7 days')))
->where('date', '<=', $today)
->field('date, daily_resources, resource_downloads')
->order('date', 'asc')
->select()
->toArray();
// 获取文章访问统计
$articleStats = Db::name('yz_daily_stats')
->where('date', '>=', date('Y-m-d', strtotime('-7 days')))
->where('date', '<=', $today)
->field('date, daily_articles, article_views')
->order('date', 'asc')
->select()
->toArray();
// 获取最近的活动记录
$recentActivities = $this->getRecentActivities();
// 准备图表数据
$chartData = [
'visitTrend' => $this->formatVisitTrendData($last7Days),
'userGrowth' => $this->formatUserGrowthData($userGrowth),
'resourceStats' => $this->formatResourceStatsData($resourceStats),
'articleStats' => $this->formatArticleStatsData($articleStats)
];
// 准备统计数据
$stats = [
'total_users' => $todayStats['total_users'] ?? 0,
'daily_visits' => $todayStats['daily_visits'] ?? 0,
'total_articles' => $todayStats['total_articles'] ?? 0,
'total_resources' => $todayStats['total_resources'] ?? 0,
];
return View::fetch('', [
'stats' => $stats,
'chartData' => $chartData,
'recentActivities' => $recentActivities
]);
return View::fetch();
}
/**
* 获取最近的活动记录
*/
private function getRecentActivities()
{
$today = date('Y-m-d');
$activities = [];
// 获取今日新用户
$newUsers = Db::name('yz_daily_stats')
->where('date', $today)
->value('new_users');
if ($newUsers > 0) {
$activities[] = [
'icon' => '👥',
'title' => '新增用户 ' . $newUsers . ' 人',
'time' => '今日'
];
}
// 获取今日文章
$newArticles = Db::name('yz_daily_stats')
->where('date', $today)
->value('daily_articles');
if ($newArticles > 0) {
$activities[] = [
'icon' => '📝',
'title' => '发布文章 ' . $newArticles . ' 篇',
'time' => '今日'
];
}
// 获取今日资源
$newResources = Db::name('yz_daily_stats')
->where('date', $today)
->value('daily_resources');
if ($newResources > 0) {
$activities[] = [
'icon' => '📦',
'title' => '上传资源 ' . $newResources . ' 个',
'time' => '今日'
];
}
return $activities;
}
/**
* 格式化访问趋势数据
*/
private function formatVisitTrendData($data)
{
$dates = [];
$visits = [];
$uvs = [];
foreach ($data as $item) {
$dates[] = date('m-d', strtotime($item['date']));
$visits[] = $item['daily_visits'];
$uvs[] = $item['unique_visitors'];
}
return [
'dates' => $dates,
'visits' => $visits,
'uvs' => $uvs
];
}
/**
* 格式化用户增长数据
*/
private function formatUserGrowthData($data)
{
$dates = [];
$newUsers = [];
$totalUsers = [];
foreach ($data as $item) {
$dates[] = date('m-d', strtotime($item['date']));
$newUsers[] = $item['new_users'];
$totalUsers[] = $item['total_users'];
}
return [
'dates' => $dates,
'newUsers' => $newUsers,
'totalUsers' => $totalUsers
];
}
/**
* 格式化资源统计数据
*/
private function formatResourceStatsData($data)
{
$dates = [];
$resources = [];
$downloads = [];
foreach ($data as $item) {
$dates[] = date('m-d', strtotime($item['date']));
$resources[] = $item['daily_resources'];
$downloads[] = $item['resource_downloads'];
}
return [
'dates' => $dates,
'resources' => $resources,
'downloads' => $downloads
];
}
/**
* 格式化文章统计数据
*/
private function formatArticleStatsData($data)
{
$dates = [];
$articles = [];
$views = [];
foreach ($data as $item) {
$dates[] = date('m-d', strtotime($item['date']));
$articles[] = $item['daily_articles'];
$views[] = $item['article_views'];
}
return [
'dates' => $dates,
'articles' => $articles,
'views' => $views
];
}
/**
@ -243,4 +439,5 @@ class Index extends Base{
return json(['code'=>1, 'msg'=>$e->getMessage()])->send();
}
}
}

View File

@ -0,0 +1,208 @@
<?php
namespace app\admin\controller;
use app\admin\controller\Base;
use think\facade\Db;
use think\facade\Request;
use think\facade\View;
class Log extends Base
{
/**
* 登录日志列表
*/
public function login()
{
if (Request::isPost()) {
$page = input('post.page', 1);
$limit = input('post.limit', 10);
$username = input('post.username');
$ip = input('post.ip');
$status = input('post.status');
$startTime = input('post.start_time');
$endTime = input('post.end_time');
$query = Db::name('yz_logs_login');
// 搜索条件
if ($username) {
$query = $query->where('username', 'like', "%{$username}%");
}
if ($ip) {
$query = $query->where('ip_address', 'like', "%{$ip}%");
}
if ($status !== '') {
$query = $query->where('login_status', $status);
}
if ($startTime) {
$query = $query->where('login_time', '>=', $startTime);
}
if ($endTime) {
$query = $query->where('login_time', '<=', $endTime);
}
$count = $query->count();
$list = $query->order('id desc')
->page($page, $limit)
->select();
return json([
'code' => 0,
'msg' => '获取成功',
'count' => $count,
'data' => $list
]);
}
return View::fetch();
}
/**
* 操作日志列表
*/
public function operation()
{
if (Request::isPost()) {
$page = input('post.page', 1);
$limit = input('post.limit', 10);
$username = input('post.username');
$module = input('post.module');
$operation = input('post.operation');
$status = input('post.status');
$startTime = input('post.start_time');
$endTime = input('post.end_time');
$query = Db::name('yz_logs_operation');
// 搜索条件
if ($username) {
$query = $query->where('username', 'like', "%{$username}%");
}
if ($module) {
$query = $query->where('module', 'like', "%{$module}%");
}
if ($operation) {
$query = $query->where('operation', 'like', "%{$operation}%");
}
if ($status !== '') {
$query = $query->where('status', $status);
}
if ($startTime) {
$query = $query->where('operation_time', '>=', $startTime);
}
if ($endTime) {
$query = $query->where('operation_time', '<=', $endTime);
}
$count = $query->count();
$list = $query->order('id desc')
->page($page, $limit)
->select();
return json([
'code' => 0,
'msg' => '获取成功',
'count' => $count,
'data' => $list
]);
}
return View::fetch();
}
/**
* 记录操作日志
*/
protected function recordOperation($operation, $status = 1, $error_message = '')
{
$data = [
'username' => session('admin_username'),
'module' => '日志管理',
'operation' => $operation,
'request_method' => Request::method(),
'request_url' => Request::url(true),
'request_params' => json_encode(Request::param(), JSON_UNESCAPED_UNICODE),
'ip_address' => Request::ip(),
'status' => $status,
'error_message' => $error_message,
'operation_time' => date('Y-m-d H:i:s'),
'execution_time' => 0
];
Db::name('yz_logs_operation')->insert($data);
}
/**
* 删除登录日志
*/
public function deleteLogin()
{
$id = input('post.id');
try {
if (Db::name('yz_logs_login')->delete($id)) {
$this->recordOperation('删除登录日志');
return json(['code' => 0, 'msg' => '删除成功']);
}
$this->recordOperation('删除登录日志', 0, '删除失败');
return json(['code' => 1, 'msg' => '删除失败']);
} catch (\Exception $e) {
$this->recordOperation('删除登录日志', 0, $e->getMessage());
return json(['code' => 1, 'msg' => '删除失败:' . $e->getMessage()]);
}
}
/**
* 删除操作日志
*/
public function deleteOperation()
{
$id = input('post.id');
try {
if (Db::name('yz_logs_operation')->delete($id)) {
$this->recordOperation('删除操作日志');
return json(['code' => 0, 'msg' => '删除成功']);
}
$this->recordOperation('删除操作日志', 0, '删除失败');
return json(['code' => 1, 'msg' => '删除失败']);
} catch (\Exception $e) {
$this->recordOperation('删除操作日志', 0, $e->getMessage());
return json(['code' => 1, 'msg' => '删除失败:' . $e->getMessage()]);
}
}
/**
* 清空登录日志
*/
public function clearLogin()
{
try {
if (Db::name('yz_logs_login')->where('1=1')->delete()) {
$this->recordOperation('清空登录日志');
return json(['code' => 0, 'msg' => '清空成功']);
}
$this->recordOperation('清空登录日志', 0, '清空失败');
return json(['code' => 1, 'msg' => '清空失败']);
} catch (\Exception $e) {
$this->recordOperation('清空登录日志', 0, $e->getMessage());
return json(['code' => 1, 'msg' => '清空失败:' . $e->getMessage()]);
}
}
/**
* 清空操作日志
*/
public function clearOperation()
{
try {
if (Db::name('yz_logs_operation')->where('1=1')->delete()) {
$this->recordOperation('清空操作日志');
return json(['code' => 0, 'msg' => '清空成功']);
}
$this->recordOperation('清空操作日志', 0, '清空失败');
return json(['code' => 1, 'msg' => '清空失败']);
} catch (\Exception $e) {
$this->recordOperation('清空操作日志', 0, $e->getMessage());
return json(['code' => 1, 'msg' => '清空失败:' . $e->getMessage()]);
}
}
}

View File

@ -445,4 +445,20 @@ class Resources extends Base
return View::fetch();
}
//统计资源数量
public function counts() {
$total = Db::table('yz_resources')
->where('delete_time', null)
->where('status', '<>', 3)
->count();
return json([
'code' => 0,
'msg' => '获取成功',
'data' => [
'total' => $total
]
]);
}
}

View File

@ -109,7 +109,7 @@
<li class="layui-nav-item" data-name="index/welcome">
<a href="javascript:;" lay-tips="工作台" lay-direction="2"
onclick="menuFire('index/welcome',1)">
<i class="layui-icon layui-icon-home" style="margin-top: -30px;"></i>
<i class="layui-icon layui-icon-home" style="margin-top: -20px;"></i>
<cite>工作台</cite>
</a>
</li>

View File

@ -1,78 +1,205 @@
{include file="public/header" /}
<script src="__STATIC__/js/jquery.min.js"></script>
<style>
.dashboard-container {
padding: 20px;
font-family: 'Helvetica Neue', Arial, sans-serif;
padding: 24px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
/* background-color: #f5f7fa; */
/* min-height: calc(100vh - 60px); */
}
.welcome-header {
text-align: center;
margin-bottom: 30px;
background: linear-gradient(135deg, #3881fd 0%, #2c5fd9 100%);
border-radius: 12px;
padding: 30px;
color: white;
margin-bottom: 24px;
box-shadow: 0 4px 20px rgba(56, 129, 253, 0.15);
}
.welcome-header h1 {
color: #3881fd;
font-weight: 300;
font-size: 28px;
margin-bottom: 10px;
font-weight: 600;
margin-bottom: 8px;
}
.welcome-header p {
font-size: 15px;
opacity: 0.9;
margin: 0;
}
.stats-container {
display: flex;
flex-wrap: wrap;
gap: 20px;
justify-content: center;
margin-bottom: 30px;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 24px;
margin-bottom: 24px;
}
.stat-card {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
padding: 20px;
min-width: 200px;
flex: 1;
background: white;
border-radius: 12px;
padding: 24px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.stat-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 4px;
height: 100%;
background: #3881fd;
}
.stat-card:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
}
.stat-card .stat-value {
font-size: 24px;
font-weight: bold;
color: #3881fd;
margin: 10px 0;
font-size: 32px;
font-weight: 600;
color: #2c3e50;
margin: 12px 0;
display: flex;
align-items: baseline;
}
.stat-card .stat-title {
color: #7f8c8d;
color: #64748b;
font-size: 14px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.stat-card .stat-icon {
position: absolute;
right: 20px;
top: 50%;
transform: translateY(-50%);
font-size: 48px;
opacity: 0.1;
}
.quick-actions {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
padding: 20px;
margin-bottom: 20px;
background: white;
border-radius: 12px;
padding: 24px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
}
.quick-actions h2 {
color: #2c3e50;
color: #1e293b;
font-size: 18px;
margin-bottom: 15px;
font-weight: 500;
font-weight: 600;
margin-bottom: 20px;
display: flex;
align-items: center;
}
.quick-actions h2::before {
content: '';
display: inline-block;
width: 4px;
height: 18px;
background: #3881fd;
margin-right: 8px;
border-radius: 2px;
}
.action-buttons {
display: flex;
flex-wrap: wrap;
gap: 10px;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
gap: 16px;
}
.action-button {
background-color: #f8f9fa;
border: none;
border-radius: 4px;
padding: 10px 15px;
color: #3881fd;
background: #f8fafc;
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 12px 16px;
color: #1e293b;
font-weight: 500;
cursor: pointer;
transition: background-color 0.3s;
transition: all 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
text-decoration: none;
}
.action-button:hover {
background-color: #e9ecef;
background: #3881fd;
color: white;
border-color: #3881fd;
transform: translateY(-2px);
}
.action-button i {
margin-right: 8px;
}
.recent-activity {
margin-top: 24px;
background: white;
border-radius: 12px;
padding: 24px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
}
.activity-list {
margin-top: 16px;
}
.activity-item {
display: flex;
align-items: center;
padding: 12px 0;
border-bottom: 1px solid #f1f5f9;
}
.activity-item:last-child {
border-bottom: none;
}
.activity-icon {
width: 36px;
height: 36px;
border-radius: 8px;
background: #f1f5f9;
display: flex;
align-items: center;
justify-content: center;
margin-right: 12px;
}
.activity-content {
flex: 1;
}
.activity-title {
font-weight: 500;
color: #1e293b;
margin-bottom: 4px;
}
.activity-time {
font-size: 12px;
color: #64748b;
}
.charts-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
gap: 24px;
margin-top: 24px;
}
.chart-card {
background: white;
border-radius: 12px;
padding: 24px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
}
.chart-card h2 {
color: #1e293b;
font-size: 18px;
font-weight: 600;
margin-bottom: 20px;
display: flex;
align-items: center;
}
.chart-card h2::before {
content: '';
display: inline-block;
width: 4px;
height: 18px;
background: #3881fd;
margin-right: 8px;
border-radius: 2px;
}
.chart-container {
height: 300px;
width: 100%;
}
</style>
@ -85,34 +212,84 @@
<div class="stats-container">
<div class="stat-card">
<div class="stat-title">用户总数</div>
<div class="stat-value">1,234</div>
<div class="stat-value">{$stats.total_users|number_format}</div>
<div class="stat-icon">👥</div>
</div>
<div class="stat-card">
<div class="stat-title">今日访问</div>
<div class="stat-value">256</div>
<div class="stat-value">{$stats.daily_visits|number_format}</div>
<div class="stat-icon">📊</div>
</div>
<div class="stat-card">
<div class="stat-title">数据总量</div>
<div class="stat-value">8,642</div>
<div class="stat-title">文章总数</div>
<div class="stat-value">{$stats.total_articles|number_format}</div>
<div class="stat-icon">📝</div>
</div>
<div class="stat-card">
<div class="stat-title">系统消息</div>
<div class="stat-value">12</div>
<div class="stat-title">资源总数</div>
<div class="stat-value">{$stats.total_resources|number_format}</div>
<div class="stat-icon">📦</div>
</div>
</div>
<div class="quick-actions">
<h2>快捷操作</h2>
<div class="action-buttons">
<button class="action-button">用户管理</button>
<button class="action-button">内容发布</button>
<button class="action-button">数据统计</button>
<button class="action-button">系统设置</button>
<button class="action-button">清除缓存</button>
<a href="{:url('user/index')}" class="action-button">
<i class="fas fa-users"></i>用户管理
</a>
<a href="{:url('content/publish')}" class="action-button">
<i class="fas fa-edit"></i>内容发布
</a>
<a href="{:url('statistics/index')}" class="action-button">
<i class="fas fa-chart-bar"></i>数据统计
</a>
<a href="{:url('system/settings')}" class="action-button">
<i class="fas fa-cog"></i>系统设置
</a>
<a href="{:url('system/clear_cache')}" class="action-button">
<i class="fas fa-broom"></i>清除缓存
</a>
</div>
</div>
<div class="recent-activity">
<h2>最近动态</h2>
<div class="activity-list">
{volist name="recentActivities" id="activity"}
<div class="activity-item">
<div class="activity-icon">{$activity.icon}</div>
<div class="activity-content">
<div class="activity-title">{$activity.title}</div>
<div class="activity-time">{$activity.time}</div>
</div>
</div>
{/volist}
</div>
</div>
<div class="charts-container">
<div class="chart-card">
<h2>访问趋势</h2>
<div id="visitTrend" class="chart-container"></div>
</div>
<div class="chart-card">
<h2>用户增长</h2>
<div id="userGrowth" class="chart-container"></div>
</div>
<div class="chart-card">
<h2>资源统计</h2>
<div id="resourceStats" class="chart-container"></div>
</div>
<div class="chart-card">
<h2>文章统计</h2>
<div id="articleStats" class="chart-container"></div>
</div>
</div>
</div>
<script src="__JS__/echarts.min.js"></script>
<script>
function updateTime() {
var now = new Date();
@ -123,12 +300,10 @@ function updateTime() {
var minutes = now.getMinutes();
var seconds = now.getSeconds();
// 补零函数
var padZero = function(num) {
return num < 10 ? '0' + num : num;
};
// 格式化时间
var timeString = year + '年' +
padZero(month) + '月' +
padZero(date) + '日 ' +
@ -139,11 +314,296 @@ function updateTime() {
document.getElementById('current-time').innerHTML = timeString;
}
// 页面加载完立即执行一次
updateTime();
// 获取文章统计数据
function getArticleCounts() {
fetch('{:url("article/counts")}')
.then(response => response.json())
.then(res => {
console.log('文章统计接口返回数据:', res);
if (res.code === 0 && res.data) {
// 更新文章总数
document.querySelector('.stat-card:nth-child(3) .stat-value').textContent = res.data.total.toLocaleString();
} else {
console.warn('文章统计接口返回异常:', res);
}
})
.catch(error => {
console.error('获取文章统计失败:', error);
});
}
// 每秒更新一次时间
// 获取资源统计数据
function getResourcesCounts() {
fetch('{:url("resources/counts")}')
.then(response => response.json())
.then(res => {
console.log('资源统计接口返回数据:', res);
if (res.code === 0 && res.data) {
// 更新资源总数
document.querySelector('.stat-card:nth-child(4) .stat-value').textContent = res.data.total.toLocaleString();
} else {
console.warn('资源统计接口返回异常:', res);
}
})
.catch(error => {
console.error('获取资源统计失败:', error);
});
}
updateTime();
setInterval(updateTime, 1000);
// 页面加载完成后获取统计数据
document.addEventListener('DOMContentLoaded', function() {
getArticleCounts();
getResourcesCounts();
});
// 访问趋势图表
function initVisitTrend() {
var chart = echarts.init(document.getElementById('visitTrend'));
var option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
legend: {
data: ['访问量', '独立访客']
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
data: {$chartData.visitTrend.dates|json_encode},
axisLine: {
lineStyle: {
color: '#e2e8f0'
}
}
},
yAxis: {
type: 'value',
axisLine: {
lineStyle: {
color: '#e2e8f0'
}
},
splitLine: {
lineStyle: {
color: '#f1f5f9'
}
}
},
series: [{
name: '访问量',
data: {$chartData.visitTrend.visits|json_encode},
type: 'line',
smooth: true,
areaStyle: {
opacity: 0.1
},
itemStyle: {
color: '#3881fd'
},
lineStyle: {
width: 3
}
}, {
name: '独立访客',
data: {$chartData.visitTrend.uvs|json_encode},
type: 'line',
smooth: true,
itemStyle: {
color: '#10b981'
},
lineStyle: {
width: 3
}
}]
};
chart.setOption(option);
}
// 用户增长图表
function initUserGrowth() {
var chart = echarts.init(document.getElementById('userGrowth'));
var option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
}
},
legend: {
data: ['新增用户', '总用户数']
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: {$chartData.userGrowth.dates|json_encode}
},
yAxis: {
type: 'value'
},
series: [
{
name: '新增用户',
type: 'bar',
data: {$chartData.userGrowth.newUsers|json_encode},
itemStyle: {
color: '#3881fd'
}
},
{
name: '总用户数',
type: 'line',
smooth: true,
data: {$chartData.userGrowth.totalUsers|json_encode},
itemStyle: {
color: '#10b981'
}
}
]
};
chart.setOption(option);
}
// 资源统计图表
function initResourceStats() {
var chart = echarts.init(document.getElementById('resourceStats'));
var option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
}
},
legend: {
data: ['新增资源', '下载量']
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: {$chartData.resourceStats.dates|json_encode}
},
yAxis: {
type: 'value'
},
series: [
{
name: '新增资源',
type: 'bar',
data: {$chartData.resourceStats.resources|json_encode},
itemStyle: {
color: '#3881fd'
}
},
{
name: '下载量',
type: 'line',
smooth: true,
data: {$chartData.resourceStats.downloads|json_encode},
itemStyle: {
color: '#10b981'
}
}
]
};
chart.setOption(option);
}
// 文章统计图表
function initArticleStats() {
var chart = echarts.init(document.getElementById('articleStats'));
var option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
}
},
legend: {
data: ['新增文章', '访问量']
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: {$chartData.articleStats.dates|json_encode}
},
yAxis: {
type: 'value'
},
series: [
{
name: '新增文章',
type: 'bar',
data: {$chartData.articleStats.articles|json_encode},
itemStyle: {
color: '#3881fd'
}
},
{
name: '访问量',
type: 'line',
smooth: true,
data: {$chartData.articleStats.views|json_encode},
itemStyle: {
color: '#10b981'
}
}
]
};
chart.setOption(option);
}
// 初始化所有图表
document.addEventListener('DOMContentLoaded', function() {
initVisitTrend();
initUserGrowth();
initResourceStats();
initArticleStats();
// 监听窗口大小变化,重绘图表
window.addEventListener('resize', function() {
var charts = document.querySelectorAll('.chart-container');
charts.forEach(function(chart) {
echarts.getInstanceByDom(chart)?.resize();
});
});
});
</script>
{include file="public/tail" /}

View File

@ -0,0 +1,166 @@
{include file="public/header" /}
<div class="layui-card">
<div class="layui-card-header">
<span class="layui-badge layui-bg-blue">登录日志</span>
</div>
<div class="layui-card-body">
<form class="layui-form layui-form-pane" action="">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">用户名</label>
<div class="layui-input-inline">
<input type="text" name="username" placeholder="请输入用户名" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">IP地址</label>
<div class="layui-input-inline">
<input type="text" name="ip" placeholder="请输入IP地址" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">状态</label>
<div class="layui-input-inline">
<select name="status">
<option value="">全部</option>
<option value="1">成功</option>
<option value="0">失败</option>
</select>
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">时间范围</label>
<div class="layui-input-inline" style="width: 300px;">
<input type="text" name="time_range" class="layui-input" id="timeRange" placeholder="请选择时间范围">
</div>
</div>
<div class="layui-inline">
<button class="layui-btn" lay-submit lay-filter="searchForm">
<i class="layui-icon layui-icon-search"></i> 搜索
</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
<table id="loginLogTable" lay-filter="loginLogTable"></table>
</div>
</div>
<script type="text/html" id="tableToolbar">
<div class="layui-btn-container">
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="clearAll">
<i class="layui-icon layui-icon-delete"></i> 清空日志
</button>
</div>
</script>
<script type="text/html" id="tableBar">
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="del">删除</a>
</script>
<script src="/static/layui/layui.js"></script>
<script>
layui.use(['table', 'form', 'laydate'], function(){
var table = layui.table;
var form = layui.form;
var laydate = layui.laydate;
// 初始化时间范围选择器
laydate.render({
elem: '#timeRange',
type: 'datetime',
range: true
});
// 初始化表格
table.render({
elem: '#loginLogTable',
url: '{:url("log/login")}',
method: 'post',
toolbar: '#tableToolbar',
defaultToolbar: ['filter', 'exports', 'print'],
parseData: function(res) {
return {
"code": res.code === 0 ? 0 : 1,
"msg": res.msg,
"count": res.count,
"data": res.data
};
},
cols: [[
{field: 'id', title: 'ID', width: 80, sort: true},
{field: 'username', title: '用户名', width: 120},
{field: 'ip_address', title: 'IP地址', width: 130},
{field: 'location', title: '登录地点', width: 120},
{field: 'device_type', title: '设备类型', width: 100},
{field: 'user_agent', title: '浏览器', width: 200},
{field: 'login_status', title: '状态', width: 100, templet: function(d){
return d.login_status == 1 ?
'<span class="layui-badge layui-bg-green">成功</span>' :
'<span class="layui-badge layui-bg-red">失败</span>';
}},
{field: 'failure_reason', title: '失败原因', width: 150},
{field: 'login_time', title: '登录时间', width: 180, sort: true},
{title: '操作', toolbar: '#tableBar', width: 80, fixed: 'right'}
]],
page: true,
limit: 10,
limits: [10, 20, 50, 100]
});
// 监听搜索表单提交
form.on('submit(searchForm)', function(data){
var timeRange = data.field.time_range;
if(timeRange){
var times = timeRange.split(' - ');
data.field.start_time = times[0];
data.field.end_time = times[1];
}
delete data.field.time_range;
table.reload('loginLogTable', {
where: data.field,
page: {curr: 1}
});
return false;
});
// 监听工具条
table.on('tool(loginLogTable)', function(obj){
var data = obj.data;
if(obj.event === 'del'){
layer.confirm('确定删除这条日志吗?', function(index){
$.post('{:url("log/deleteLogin")}', {id: data.id}, function(res){
if(res.code === 0){
layer.msg(res.msg, {icon: 1});
obj.del();
}else{
layer.msg(res.msg, {icon: 2});
}
});
layer.close(index);
});
}
});
// 监听头工具栏事件
table.on('toolbar(loginLogTable)', function(obj){
if(obj.event === 'clearAll'){
layer.confirm('确定要清空所有登录日志吗?', function(index){
$.post('{:url("log/clearLogin")}', function(res){
if(res.code === 0){
layer.msg(res.msg, {icon: 1});
table.reload('loginLogTable');
}else{
layer.msg(res.msg, {icon: 2});
}
});
layer.close(index);
});
}
});
});
</script>
</body>
</html>

View File

@ -0,0 +1,175 @@
{include file="public/header" /}
<div class="layui-card">
<div class="layui-card-header">
<span class="layui-badge layui-bg-blue">操作日志</span>
</div>
<div class="layui-card-body">
<form class="layui-form layui-form-pane" action="">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">用户名</label>
<div class="layui-input-inline">
<input type="text" name="username" placeholder="请输入用户名" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">模块</label>
<div class="layui-input-inline">
<input type="text" name="module" placeholder="请输入模块" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">操作</label>
<div class="layui-input-inline">
<input type="text" name="operation" placeholder="请输入操作" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">状态</label>
<div class="layui-input-inline">
<select name="status">
<option value="">全部</option>
<option value="1">成功</option>
<option value="0">失败</option>
</select>
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">时间范围</label>
<div class="layui-input-inline" style="width: 300px;">
<input type="text" name="time_range" class="layui-input" id="timeRange" placeholder="请选择时间范围">
</div>
</div>
<div class="layui-inline">
<button class="layui-btn" lay-submit lay-filter="searchForm">
<i class="layui-icon layui-icon-search"></i> 搜索
</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
<table id="operationLogTable" lay-filter="operationLogTable"></table>
</div>
</div>
<script type="text/html" id="tableToolbar">
<div class="layui-btn-container">
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="clearAll">
<i class="layui-icon layui-icon-delete"></i> 清空日志
</button>
</div>
</script>
<script type="text/html" id="tableBar">
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="del">删除</a>
</script>
<script src="/static/layui/layui.js"></script>
<script>
layui.use(['table', 'form', 'laydate'], function(){
var table = layui.table;
var form = layui.form;
var laydate = layui.laydate;
// 初始化时间范围选择器
laydate.render({
elem: '#timeRange',
type: 'datetime',
range: true
});
// 初始化表格
table.render({
elem: '#operationLogTable',
url: '{:url("log/operation")}',
method: 'post',
toolbar: '#tableToolbar',
defaultToolbar: ['filter', 'exports', 'print'],
parseData: function(res) {
return {
"code": res.code === 0 ? 0 : 1,
"msg": res.msg,
"count": res.count,
"data": res.data
};
},
cols: [[
{field: 'id', title: 'ID', width: 80, sort: true},
{field: 'username', title: '用户名', width: 120},
{field: 'module', title: '模块', width: 120},
{field: 'operation', title: '操作', width: 120},
{field: 'request_method', title: '请求方法', width: 100},
{field: 'request_url', title: '请求URL', width: 200},
{field: 'request_params', title: '请求参数', width: 200},
{field: 'ip_address', title: 'IP地址', width: 130},
{field: 'status', title: '状态', width: 100, templet: function(d){
return d.status == 1 ?
'<span class="layui-badge layui-bg-green">成功</span>' :
'<span class="layui-badge layui-bg-red">失败</span>';
}},
{field: 'error_message', title: '错误信息', width: 150},
{field: 'operation_time', title: '操作时间', width: 180, sort: true},
{field: 'execution_time', title: '执行时间(ms)', width: 120, sort: true},
{title: '操作', toolbar: '#tableBar', width: 80, fixed: 'right'}
]],
page: true,
limit: 10,
limits: [10, 20, 50, 100]
});
// 监听搜索表单提交
form.on('submit(searchForm)', function(data){
var timeRange = data.field.time_range;
if(timeRange){
var times = timeRange.split(' - ');
data.field.start_time = times[0];
data.field.end_time = times[1];
}
delete data.field.time_range;
table.reload('operationLogTable', {
where: data.field,
page: {curr: 1}
});
return false;
});
// 监听工具条
table.on('tool(operationLogTable)', function(obj){
var data = obj.data;
if(obj.event === 'del'){
layer.confirm('确定删除这条日志吗?', function(index){
$.post('{:url("log/deleteOperation")}', {id: data.id}, function(res){
if(res.code === 0){
layer.msg(res.msg, {icon: 1});
obj.del();
}else{
layer.msg(res.msg, {icon: 2});
}
});
layer.close(index);
});
}
});
// 监听头工具栏事件
table.on('toolbar(operationLogTable)', function(obj){
if(obj.event === 'clearAll'){
layer.confirm('确定要清空所有操作日志吗?', function(index){
$.post('{:url("log/clearOperation")}', function(res){
if(res.code === 0){
layer.msg(res.msg, {icon: 1});
table.reload('operationLogTable');
}else{
layer.msg(res.msg, {icon: 2});
}
});
layer.close(index);
});
}
});
});
</script>
</body>
</html>

View File

@ -40,7 +40,7 @@
</div>
<div class="layui-col-xs5">
<div style="margin-left:10px;">
<img src="{:captcha_src()}" class="layadmin-user-login-codeimg" id="img"
<img src="{:captcha_src()}?t={:time()}" class="layadmin-user-login-codeimg" id="img"
onclick="reloadImg()">
</div>
</div>
@ -75,7 +75,8 @@
});
// 重新生成验证码
function reloadImg() {
$('#img').attr('src', '{:captcha_src()}?rand=' + Math.random());
var timestamp = new Date().getTime();
$('#img').attr('src', '{:captcha_src()}?t=' + timestamp);
}
// 登录处理函数

View File

@ -1,8 +1,13 @@
<?php
// 中间件配置
return [
// 别名或分组
'alias' => [],
'alias' => [
'auth' => \app\middleware\Auth::class,
],
// 优先级设置,此数组中的中间件会按照数组中的顺序优先执行
'priority' => [],
// 全局中间件
'global' => [
\app\middleware\Auth::class,
],
];

View File

@ -86,12 +86,12 @@ html{
/* 侧边菜单 */
.layui-side-menu .layui-side-scroll{width: 240px;}
.layui-side-menu .layui-nav{width: 220px; margin-top: 70px; background: none;}
.layui-side-menu .layui-nav .layui-nav-item a{height: 60px; line-height: 60px; padding-left: 45px; padding-right: 30px;}
.layui-side-menu .layui-nav .layui-nav-item a{height: 40px; line-height: 40px; padding-left: 45px; padding-right: 30px;}
.layui-side-menu .layui-nav .layui-nav-item > a{padding-top: 8px; padding-bottom: 8px;}
.layui-side-menu .layui-nav .layui-nav-item a:hover{background: none;}
.layui-side-menu .layui-nav .layui-nav-itemed > .layui-nav-child{padding: 5px 0;}
.layui-side-menu .layui-nav .layui-nav-item .layui-icon{position: absolute; top: 50%; left: 20px; margin-top: -35px;}
.layui-side-menu .layui-nav .layui-nav-item .layui-icons{margin-top: -29px;}
.layui-side-menu .layui-nav .layui-nav-item .layui-icon{position: absolute; top: 50%; left: 20px; margin-top: -25px;}
.layui-side-menu .layui-nav .layui-nav-item .layui-icons{margin-top: -20px;}
.layui-side-menu .layui-nav .layui-nav-child .layui-nav-child{background: none!important;}
.layui-side-menu .layui-nav .layui-nav-child .layui-nav-child a{padding-left: 60px}
.layui-side-menu .layui-nav .layui-nav-more{right: 15px;}

45
public/static/js/echarts.min.js vendored Normal file

File diff suppressed because one or more lines are too long

2
public/static/js/jquery.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
<?php /*a:1:{s:49:"E:\Demo\PHP\yunzer\app\admin\view\login\index.php";i:1747321871;}*/ ?>
<?php /*a:1:{s:49:"E:\Demo\PHP\yunzer\app\admin\view\login\index.php";i:1747586453;}*/ ?>
<!DOCTYPE html>
<html lang="zh-CN">
@ -41,7 +41,7 @@
</div>
<div class="layui-col-xs5">
<div style="margin-left:10px;">
<img src="<?php echo captcha_src(); ?>" class="layadmin-user-login-codeimg" id="img"
<img src="<?php echo captcha_src(); ?>?t=<?php echo time(); ?>" class="layadmin-user-login-codeimg" id="img"
onclick="reloadImg()">
</div>
</div>
@ -76,7 +76,8 @@
});
// 重新生成验证码
function reloadImg() {
$('#img').attr('src', '<?php echo captcha_src(); ?>?rand=' + Math.random());
var timestamp = new Date().getTime();
$('#img').attr('src', '<?php echo captcha_src(); ?>?t=' + timestamp);
}
// 登录处理函数

View File

@ -0,0 +1,311 @@
<?php /*a:3:{s:56:"E:\Demo\PHP\yunzer\app\admin\view\yunzer\configvalue.php";i:1747402501;s:51:"E:\Demo\PHP\yunzer\app\admin\view\public\header.php";i:1746890051;s:49:"E:\Demo\PHP\yunzer\app\admin\view\public\tail.php";i:1745855804;}*/ ?>
<!DOCTYPE html>
<html>
<head>
<title><?php echo htmlentities((string) $config['admin_name']); ?></title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="stylesheet" type="text/css" href="/static/layui/css/layui.css" media="all"/>
<link rel="stylesheet" type="text/css" href="/static/css/moban.css" media="all"/>
<link rel="stylesheet" type="text/css" href="/static/css/wangeditor.css" media="all"/>
<style type="text/css">
.header span{background:#009688;margin-left:30px;padding:10px;color:#ffffff;}
.header div{border-bottom:solid 2px #009688;margin-top: 8px;}
.header button{float:right;margin-top:-5px;}
.pagination {
display: inline-block;
padding-left: 0;
margin: 20px 0;
border-radius: 4px;
}
.pagination > li {
display: inline;
}
.pagination > li > a,
.pagination > li > span {
position: relative;
float: left;
padding: 6px 12px;
margin-left: -1px;
line-height: 1.42857143;
color: #337ab7;
text-decoration: none;
background-color: #fff;
border: 1px solid #ddd;
}
.pagination > li:first-child > a,
.pagination > li:first-child > span {
margin-left: 0;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
.pagination > li:last-child > a,
.pagination > li:last-child > span {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.pagination > li > a:hover,
.pagination > li > span:hover,
.pagination > li > a:focus,
.pagination > li > span:focus {
z-index: 2;
color: #23527c;
background-color: #eee;
border-color: #ddd;
}
.pagination > .active > a,
.pagination > .active > span,
.pagination > .active > a:hover,
.pagination > .active > span:hover,
.pagination > .active > a:focus,
.pagination > .active > span:focus {
z-index: 3;
color: #fff;
cursor: default;
background-color: #337ab7;
border-color: #337ab7;
}
.pagination > .disabled > span,
.pagination > .disabled > span:hover,
.pagination > .disabled > span:focus,
.pagination > .disabled > a,
.pagination > .disabled > a:hover,
.pagination > .disabled > a:focus {
color: #777;
cursor: not-allowed;
background-color: #fff;
border-color: #ddd;
}
.close-img { background: url(/static/images/close_img.png); background-size: 20px 20px; width:20px; height: 20px; position: absolute; right: 5px; top: 5px; z-index: 2;}
</style>
<script type="text/javascript" src="/static/layui/layui.js"></script>
<script type="text/javascript">
layui.use(['layer','form','table','laydate','element','upload'],function(){
layer = layui.layer; // layui 弹框
form = layui.form; // layui form表单
table = layui.table; // layui 表格
laydate = layui.laydate; // layui 时间框
element = layui.element; // layui element
upload = layui.upload; // layui 上传
$ = layui.jquery; // layui jquery
})
</script>
</head>
<body style="padding:10px; box-sizing: border-box;">
<style>
.config-container {
padding: 20px;
background-color: #fff;
border-radius: 8px;
/* box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08); */
}
.config-header {
display: flex;
align-items: center;
margin-bottom: 30px;
padding-bottom: 15px;
border-bottom: 1px solid #eee;
}
.config-header span {
font-size: 18px;
color: #2c3e50;
font-weight: 500;
margin-right: 20px;
}
.config-header a {
text-decoration: none;
}
.config-header a span {
padding: 6px 15px;
background: #f8f9fa;
border-radius: 4px;
color: #606266;
font-size: 14px;
transition: all 0.3s;
}
.config-header a span:hover {
background: #e9ecef;
color: #409EFF;
}
.layui-form-item {
margin-bottom: 25px;
}
.layui-form-label {
color: #606266;
font-weight: 500;
}
.layui-input {
border-radius: 4px;
}
.layui-input:focus {
border-color: #409EFF;
}
.layui-textarea {
border-radius: 4px;
min-height: 100px;
}
.layui-word-aux {
color: #909399;
}
.layui-btn {
border-radius: 4px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
transition: all 0.3s;
}
.layui-btn:hover {
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
}
.upload-preview {
margin-top: 10px;
}
.upload-preview img {
border-radius: 4px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
transition: all 0.3s;
}
.upload-preview img:hover {
transform: scale(1.02);
}
.save-button-container {
text-align: center;
margin-top: 40px;
padding-top: 20px;
border-top: 1px solid #eee;
}
.save-button-container .layui-btn {
padding: 0 50px;
height: 40px;
line-height: 40px;
font-size: 15px;
}
</style>
<div class="config-container">
<div class="config-header">
<span>站点配置</span>
<!-- <a href="<?php echo htmlentities((string) $config['admin_route']); ?>Yunzer/configlist">
<span>站点管理</span>
</a> -->
</div>
<form class="layui-form">
<?php foreach($lists as $lists_v): if(($lists_v['config_type'] == 1)): ?>
<div class="layui-form-item">
<label class="layui-form-label"><?php echo htmlentities((string) $lists_v['config_info']); ?></label>
<div class="layui-input-inline" style="width: 350px;">
<input type="text" class="layui-input" id="<?php echo htmlentities((string) $lists_v['config_name']); ?>" name="<?php echo htmlentities((string) $lists_v['config_name']); ?>" placeholder="<?php echo htmlentities((string) $lists_v['config_desc']); ?>" value="<?php echo htmlentities((string) $lists_v['config_value']); ?>">
</div>
<div class="layui-form-mid layui-word-aux"><?php echo htmlentities((string) $lists_v['config_desc']); ?></div>
</div>
<?php elseif(($lists_v['config_type'] == 2)): ?>
<div class="layui-form-item">
<label class="layui-form-label"><?php echo htmlentities((string) $lists_v['config_info']); ?></label>
<div class="layui-input-inline">
<button type="button" class="layui-btn layui-btn-normal" id="<?php echo htmlentities((string) $lists_v['config_name']); ?>">
<i class="layui-icon layui-icon-upload"></i> 上传图片
</button>
</div>
<div class="layui-form-mid layui-word-aux"><?php echo htmlentities((string) $lists_v['config_desc']); ?></div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"><?php echo htmlentities((string) $lists_v['config_info']); ?>预览</label>
<div class="layui-input-block">
<div class="layui-upload-list upload-preview" id="yulan_<?php echo htmlentities((string) $lists_v['config_name']); ?>" style="width:90%;">
<?php if(!empty($lists_v['config_value'])): ?>
<div class="upload_pic_li" style="position:relative;width:120px;margin:0 10px 10px 0">
<img style="background-color: #efefef;height:120px;object-fit:cover;" src="<?php echo htmlentities((string) $lists_v['config_value']); ?>" class="layui-upload-img" onmouseover="show_img(this)" onmouseleave="hide_img()">
<input type="hidden" name="<?php echo htmlentities((string) $lists_v['config_name']); ?>" value="<?php echo htmlentities((string) $lists_v['config_value']); ?>"/>
</div>
<?php endif; ?>
</div>
</div>
</div>
<script type="text/javascript">
layui.use(['layer','upload'],function(){
layer = layui.layer;
upload = layui.upload;
$ = layui.jquery;
upload.render({
elem: "#<?php echo htmlentities((string) $lists_v['config_name']); ?>",
url: "<?php echo htmlentities((string) $config['admin_route']); ?>index/upload_img",
multiple: true,
done: function(res,title){
if(res.code > 0){
return layer.msg("上传失败,"+res.msg, {icon: 2});
}else{
$("#yulan_<?php echo htmlentities((string) $lists_v['config_name']); ?>").html('<div class="upload_pic_li" style="position:relative;width:120px;margin:0 10px 10px 0"><img style="width:120px;height:120px;object-fit:cover;" src="'+ res.url +'" class="layui-upload-img" onmouseover="show_img(this)" onmouseleave="hide_img()"><input type="hidden" name="<?php echo htmlentities((string) $lists_v['config_name']); ?>" value="'+res.data+'"/></div>');
layer.msg("上传成功", {icon: 1});
}
}
});
})
</script>
<?php elseif(($lists_v['config_type'] == 3)): ?>
<div class="layui-form-item">
<label class="layui-form-label"><?php echo htmlentities((string) $lists_v['config_info']); ?></label>
<div class="layui-input-block">
<textarea class="layui-textarea" id="<?php echo htmlentities((string) $lists_v['config_name']); ?>" name="<?php echo htmlentities((string) $lists_v['config_name']); ?>" placeholder="<?php echo htmlentities((string) $lists_v['config_desc']); ?>"><?php echo htmlentities((string) $lists_v['config_value']); ?></textarea>
</div>
</div>
<?php endif; ?>
<?php endforeach; ?>
</form>
<div class="save-button-container">
<button type="button" class="layui-btn layui-btn-normal" onclick="save()">
<i class="layui-icon layui-icon-ok"></i> 保存配置
</button>
</div>
</div>
<script type="text/javascript">
function save(){
var loadIndex = layer.load(1, {
shade: [0.1,'#fff']
});
$.post('<?php echo htmlentities((string) $config["admin_route"]); ?>yunzer/configvalue',$('form').serialize(),function(res){
layer.close(loadIndex);
if(res.code>0){
layer.msg(res.msg,{'icon':2});
}else{
layer.msg(res.msg,{'icon':1});
setTimeout(function(){
history.go(0);
}, 1000);
}
},'json');
}
</script>
</body>
</html>
<script type="text/javascript">
// 显示图片
function show_img(obj){
var imgurl = $(obj).attr('src');
var res = getMousePos();
var html = '<div style="background:#fff;position:absolute;width:200px;border:solid 1px #cdcdcd;border-radius:6px;padding:2px;left:'+res.x+'px;top:'+res.y+'px;z-index:1000" id="preview">\
<img style="width:100%;border-radius:6px;" src="'+imgurl+'">\
</div>';
$('body').append(html);
}
// 隐藏图片
function hide_img(){
$('#preview').remove();
}
// 图片位置计算
function getMousePos(event) {
var e = event || window.event;
var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
var x = e.pageX || e.clientX + scrollX;
var y = e.pageY || e.clientY + scrollY;
return { 'x': x, 'y': y };
}
// 删除图片
function deleteImage(path,obj){
$(obj).closest('.upload_pic_li').remove();
}
</script>

View File

@ -0,0 +1,277 @@
<?php /*a:3:{s:55:"E:\Demo\PHP\yunzer\app\admin\view\yunzer\buttoninfo.php";i:1745855804;s:51:"E:\Demo\PHP\yunzer\app\admin\view\public\header.php";i:1746890051;s:49:"E:\Demo\PHP\yunzer\app\admin\view\public\tail.php";i:1745855804;}*/ ?>
<!DOCTYPE html>
<html>
<head>
<title><?php echo htmlentities((string) $config['admin_name']); ?></title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="stylesheet" type="text/css" href="/static/layui/css/layui.css" media="all"/>
<link rel="stylesheet" type="text/css" href="/static/css/moban.css" media="all"/>
<link rel="stylesheet" type="text/css" href="/static/css/wangeditor.css" media="all"/>
<style type="text/css">
.header span{background:#009688;margin-left:30px;padding:10px;color:#ffffff;}
.header div{border-bottom:solid 2px #009688;margin-top: 8px;}
.header button{float:right;margin-top:-5px;}
.pagination {
display: inline-block;
padding-left: 0;
margin: 20px 0;
border-radius: 4px;
}
.pagination > li {
display: inline;
}
.pagination > li > a,
.pagination > li > span {
position: relative;
float: left;
padding: 6px 12px;
margin-left: -1px;
line-height: 1.42857143;
color: #337ab7;
text-decoration: none;
background-color: #fff;
border: 1px solid #ddd;
}
.pagination > li:first-child > a,
.pagination > li:first-child > span {
margin-left: 0;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
.pagination > li:last-child > a,
.pagination > li:last-child > span {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.pagination > li > a:hover,
.pagination > li > span:hover,
.pagination > li > a:focus,
.pagination > li > span:focus {
z-index: 2;
color: #23527c;
background-color: #eee;
border-color: #ddd;
}
.pagination > .active > a,
.pagination > .active > span,
.pagination > .active > a:hover,
.pagination > .active > span:hover,
.pagination > .active > a:focus,
.pagination > .active > span:focus {
z-index: 3;
color: #fff;
cursor: default;
background-color: #337ab7;
border-color: #337ab7;
}
.pagination > .disabled > span,
.pagination > .disabled > span:hover,
.pagination > .disabled > span:focus,
.pagination > .disabled > a,
.pagination > .disabled > a:hover,
.pagination > .disabled > a:focus {
color: #777;
cursor: not-allowed;
background-color: #fff;
border-color: #ddd;
}
.close-img { background: url(/static/images/close_img.png); background-size: 20px 20px; width:20px; height: 20px; position: absolute; right: 5px; top: 5px; z-index: 2;}
</style>
<script type="text/javascript" src="/static/layui/layui.js"></script>
<script type="text/javascript">
layui.use(['layer','form','table','laydate','element','upload'],function(){
layer = layui.layer; // layui 弹框
form = layui.form; // layui form表单
table = layui.table; // layui 表格
laydate = layui.laydate; // layui 时间框
element = layui.element; // layui element
upload = layui.upload; // layui 上传
$ = layui.jquery; // layui jquery
})
</script>
</head>
<body style="padding:10px; box-sizing: border-box;">
<div class="layui-card">
<div class="layui-card-header">
<div class="layui-row">
<div class="layui-col-md6">
<div class="layui-breadcrumb">
<a href="<?php echo htmlentities((string) $config['admin_route']); ?>Yunzer/menuInfo"><i class="layui-icon layui-icon-menu-fill"></i> 上级菜单</a>
<a><cite>本级菜单</cite></a>
</div>
</div>
<div class="layui-col-md6" style="text-align: right;">
<button type="button" class="layui-btn layui-btn-normal layui-btn-sm" onclick="add(<?php echo htmlentities((string) $smid); ?>)">
<i class="layui-icon layui-icon-add-1"></i> 添加按钮
</button>
</div>
</div>
</div>
<div class="layui-card-body">
<div class="layui-row layui-col-space15">
<div class="layui-col-md3">
<div class="layui-card">
<div class="layui-card-header"><i class="layui-icon layui-icon-tree"></i> 菜单结构</div>
<div class="layui-card-body" id="menuTree">
<!-- 树形结构将在这里渲染 -->
</div>
</div>
</div>
<div class="layui-col-md9">
<table class="layui-table" lay-skin="line">
<thead>
<tr>
<th>排序</th>
<th>类型</th>
<th>按钮名</th>
<th>图标</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<?php if(is_array($lists) || $lists instanceof \think\Collection || $lists instanceof \think\Paginator): $i = 0; $__LIST__ = $lists;if( count($__LIST__)==0 ) : echo "" ;else: foreach($__LIST__ as $key=>$vo): $mod = ($i % 2 );++$i;?>
<tr>
<td><span class="layui-badge layui-bg-gray"><?php echo htmlentities((string) $vo['sort']); ?></span></td>
<td>
<?php if(($vo['type']==1)): ?>
<span class="layui-badge layui-bg-blue">功能模块</span> <?php echo htmlentities((string) $vo['src']); elseif(($vo['type']==2)): ?>
<span class="layui-badge layui-bg-green">超链接</span> <?php echo htmlentities((string) $vo['src']); ?>
<?php endif; ?>
</td>
<td><b><?php echo htmlentities((string) $vo['label']); ?></b></td>
<td><i class="layui-icon <?php echo htmlentities((string) $vo['icon_class']); ?>"></i> <?php echo htmlentities((string) $vo['icon_class']); ?></td>
<td>
<?php if(($vo['status']==1)): ?>
<span class="layui-badge layui-bg-green">开启</span>
<?php else: ?>
<span class="layui-badge layui-bg-red">禁用</span>
<?php endif; ?>
</td>
<td>
<div class="layui-btn-group">
<button type="button" class="layui-btn layui-btn-xs" onclick="edit(<?php echo htmlentities((string) $vo['smid']); ?>)">
<i class="layui-icon layui-icon-edit"></i> 编辑
</button>
<button type="button" class="layui-btn layui-btn-xs layui-btn-danger" onclick="del(<?php echo htmlentities((string) $vo['smid']); ?>)">
<i class="layui-icon layui-icon-delete"></i> 删除
</button>
</div>
</td>
</tr>
<?php endforeach; endif; else: echo "" ;endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<script type="text/javascript">
layui.use(['layer', 'tree'], function(){
layer = layui.layer;
$ = layui.jquery;
var tree = layui.tree;
// 构建树形结构数据
var treeData = [{
title: '当前菜单',
id: <?php echo htmlentities((string) $smid); ?>,
spread: true,
children: []
}];
// 将按钮数据添加到树中
<?php if(is_array($lists) || $lists instanceof \think\Collection || $lists instanceof \think\Paginator): $i = 0; $__LIST__ = $lists;if( count($__LIST__)==0 ) : echo "" ;else: foreach($__LIST__ as $key=>$vo): $mod = ($i % 2 );++$i;?>
treeData[0].children.push({
title: '<?php echo htmlentities((string) $vo['label']); ?>',
id: <?php echo htmlentities((string) $vo['smid']); ?>,
icon: 'layui-icon <?php echo htmlentities((string) $vo['icon_class']); ?>'
});
<?php endforeach; endif; else: echo "" ;endif; ?>
// 渲染树形结构
tree.render({
elem: '#menuTree',
data: treeData,
showLine: true,
click: function(obj){
var data = obj.data;
if(data.id != <?php echo htmlentities((string) $smid); ?>) {
edit(data.id);
}
}
});
});
// 添加
function add(smid){
layer.open({
type: 2,
title: '添加按钮',
shade: 0.3,
area: ['550px','550px'],
content: '<?php echo htmlentities((string) $config["admin_route"]); ?>yunzer/buttonadd?smid='+smid
});
}
// 编辑
function edit(smid){
layer.open({
type: 2,
title: '编辑按钮',
shade: 0.3,
area: ['550px','550px'],
content: '<?php echo htmlentities((string) $config["admin_route"]); ?>yunzer/buttonedit?smid='+smid
});
}
// 删除
function del(smid){
layer.confirm('确定要删除吗?', {
icon: 3,
btn: ['确定','取消']
}, function(){
$.post('<?php echo htmlentities((string) $config["admin_route"]); ?>yunzer/buttondel',{'smid':smid},function(res){
if(res.code>0){
layer.alert(res.msg,{icon:2});
}else{
layer.msg(res.msg,{icon:1});
setTimeout(function(){window.location.reload();},1000);
}
},'json');
});
}
</script>
</body>
</html>
<script type="text/javascript">
// 显示图片
function show_img(obj){
var imgurl = $(obj).attr('src');
var res = getMousePos();
var html = '<div style="background:#fff;position:absolute;width:200px;border:solid 1px #cdcdcd;border-radius:6px;padding:2px;left:'+res.x+'px;top:'+res.y+'px;z-index:1000" id="preview">\
<img style="width:100%;border-radius:6px;" src="'+imgurl+'">\
</div>';
$('body').append(html);
}
// 隐藏图片
function hide_img(){
$('#preview').remove();
}
// 图片位置计算
function getMousePos(event) {
var e = event || window.event;
var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
var x = e.pageX || e.clientX + scrollX;
var y = e.pageY || e.clientY + scrollY;
return { 'x': x, 'y': y };
}
// 删除图片
function deleteImage(path,obj){
$(obj).closest('.upload_pic_li').remove();
}
</script>

View File

@ -0,0 +1,269 @@
<?php /*a:2:{s:51:"E:\Demo\PHP\yunzer\app\admin\view\log\operation.php";i:1747584845;s:51:"E:\Demo\PHP\yunzer\app\admin\view\public\header.php";i:1746890051;}*/ ?>
<!DOCTYPE html>
<html>
<head>
<title><?php echo htmlentities((string) $config['admin_name']); ?></title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="stylesheet" type="text/css" href="/static/layui/css/layui.css" media="all"/>
<link rel="stylesheet" type="text/css" href="/static/css/moban.css" media="all"/>
<link rel="stylesheet" type="text/css" href="/static/css/wangeditor.css" media="all"/>
<style type="text/css">
.header span{background:#009688;margin-left:30px;padding:10px;color:#ffffff;}
.header div{border-bottom:solid 2px #009688;margin-top: 8px;}
.header button{float:right;margin-top:-5px;}
.pagination {
display: inline-block;
padding-left: 0;
margin: 20px 0;
border-radius: 4px;
}
.pagination > li {
display: inline;
}
.pagination > li > a,
.pagination > li > span {
position: relative;
float: left;
padding: 6px 12px;
margin-left: -1px;
line-height: 1.42857143;
color: #337ab7;
text-decoration: none;
background-color: #fff;
border: 1px solid #ddd;
}
.pagination > li:first-child > a,
.pagination > li:first-child > span {
margin-left: 0;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
.pagination > li:last-child > a,
.pagination > li:last-child > span {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.pagination > li > a:hover,
.pagination > li > span:hover,
.pagination > li > a:focus,
.pagination > li > span:focus {
z-index: 2;
color: #23527c;
background-color: #eee;
border-color: #ddd;
}
.pagination > .active > a,
.pagination > .active > span,
.pagination > .active > a:hover,
.pagination > .active > span:hover,
.pagination > .active > a:focus,
.pagination > .active > span:focus {
z-index: 3;
color: #fff;
cursor: default;
background-color: #337ab7;
border-color: #337ab7;
}
.pagination > .disabled > span,
.pagination > .disabled > span:hover,
.pagination > .disabled > span:focus,
.pagination > .disabled > a,
.pagination > .disabled > a:hover,
.pagination > .disabled > a:focus {
color: #777;
cursor: not-allowed;
background-color: #fff;
border-color: #ddd;
}
.close-img { background: url(/static/images/close_img.png); background-size: 20px 20px; width:20px; height: 20px; position: absolute; right: 5px; top: 5px; z-index: 2;}
</style>
<script type="text/javascript" src="/static/layui/layui.js"></script>
<script type="text/javascript">
layui.use(['layer','form','table','laydate','element','upload'],function(){
layer = layui.layer; // layui 弹框
form = layui.form; // layui form表单
table = layui.table; // layui 表格
laydate = layui.laydate; // layui 时间框
element = layui.element; // layui element
upload = layui.upload; // layui 上传
$ = layui.jquery; // layui jquery
})
</script>
</head>
<body style="padding:10px; box-sizing: border-box;">
<div class="layui-card">
<div class="layui-card-header">
<span class="layui-badge layui-bg-blue">操作日志</span>
</div>
<div class="layui-card-body">
<form class="layui-form layui-form-pane" action="">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">用户名</label>
<div class="layui-input-inline">
<input type="text" name="username" placeholder="请输入用户名" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">模块</label>
<div class="layui-input-inline">
<input type="text" name="module" placeholder="请输入模块" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">操作</label>
<div class="layui-input-inline">
<input type="text" name="operation" placeholder="请输入操作" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">状态</label>
<div class="layui-input-inline">
<select name="status">
<option value="">全部</option>
<option value="1">成功</option>
<option value="0">失败</option>
</select>
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">时间范围</label>
<div class="layui-input-inline" style="width: 300px;">
<input type="text" name="time_range" class="layui-input" id="timeRange" placeholder="请选择时间范围">
</div>
</div>
<div class="layui-inline">
<button class="layui-btn" lay-submit lay-filter="searchForm">
<i class="layui-icon layui-icon-search"></i> 搜索
</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
<table id="operationLogTable" lay-filter="operationLogTable"></table>
</div>
</div>
<script type="text/html" id="tableToolbar">
<div class="layui-btn-container">
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="clearAll">
<i class="layui-icon layui-icon-delete"></i> 清空日志
</button>
</div>
</script>
<script type="text/html" id="tableBar">
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="del">删除</a>
</script>
<script src="/static/layui/layui.js"></script>
<script>
layui.use(['table', 'form', 'laydate'], function(){
var table = layui.table;
var form = layui.form;
var laydate = layui.laydate;
// 初始化时间范围选择器
laydate.render({
elem: '#timeRange',
type: 'datetime',
range: true
});
// 初始化表格
table.render({
elem: '#operationLogTable',
url: '<?php echo url("log/operation"); ?>',
method: 'post',
toolbar: '#tableToolbar',
defaultToolbar: ['filter', 'exports', 'print'],
parseData: function(res) {
return {
"code": res.code === 0 ? 0 : 1,
"msg": res.msg,
"count": res.count,
"data": res.data
};
},
cols: [[
{field: 'id', title: 'ID', width: 80, sort: true},
{field: 'username', title: '用户名', width: 120},
{field: 'module', title: '模块', width: 120},
{field: 'operation', title: '操作', width: 120},
{field: 'request_method', title: '请求方法', width: 100},
{field: 'request_url', title: '请求URL', width: 200},
{field: 'request_params', title: '请求参数', width: 200},
{field: 'ip_address', title: 'IP地址', width: 130},
{field: 'status', title: '状态', width: 100, templet: function(d){
return d.status == 1 ?
'<span class="layui-badge layui-bg-green">成功</span>' :
'<span class="layui-badge layui-bg-red">失败</span>';
}},
{field: 'error_message', title: '错误信息', width: 150},
{field: 'operation_time', title: '操作时间', width: 180, sort: true},
{field: 'execution_time', title: '执行时间(ms)', width: 120, sort: true},
{title: '操作', toolbar: '#tableBar', width: 80, fixed: 'right'}
]],
page: true,
limit: 10,
limits: [10, 20, 50, 100]
});
// 监听搜索表单提交
form.on('submit(searchForm)', function(data){
var timeRange = data.field.time_range;
if(timeRange){
var times = timeRange.split(' - ');
data.field.start_time = times[0];
data.field.end_time = times[1];
}
delete data.field.time_range;
table.reload('operationLogTable', {
where: data.field,
page: {curr: 1}
});
return false;
});
// 监听工具条
table.on('tool(operationLogTable)', function(obj){
var data = obj.data;
if(obj.event === 'del'){
layer.confirm('确定删除这条日志吗?', function(index){
$.post('<?php echo url("log/deleteOperation"); ?>', {id: data.id}, function(res){
if(res.code === 0){
layer.msg(res.msg, {icon: 1});
obj.del();
}else{
layer.msg(res.msg, {icon: 2});
}
});
layer.close(index);
});
}
});
// 监听头工具栏事件
table.on('toolbar(operationLogTable)', function(obj){
if(obj.event === 'clearAll'){
layer.confirm('确定要清空所有操作日志吗?', function(index){
$.post('<?php echo url("log/clearOperation"); ?>', function(res){
if(res.code === 0){
layer.msg(res.msg, {icon: 1});
table.reload('operationLogTable');
}else{
layer.msg(res.msg, {icon: 2});
}
});
layer.close(index);
});
}
});
});
</script>
</body>
</html>

View File

@ -0,0 +1,177 @@
<?php /*a:3:{s:59:"E:\Demo\PHP\yunzer\app\admin\view\yunzeradmin\groupedit.php";i:1745855804;s:51:"E:\Demo\PHP\yunzer\app\admin\view\public\header.php";i:1746890051;s:49:"E:\Demo\PHP\yunzer\app\admin\view\public\tail.php";i:1745855804;}*/ ?>
<!DOCTYPE html>
<html>
<head>
<title><?php echo htmlentities((string) $config['admin_name']); ?></title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="stylesheet" type="text/css" href="/static/layui/css/layui.css" media="all"/>
<link rel="stylesheet" type="text/css" href="/static/css/moban.css" media="all"/>
<link rel="stylesheet" type="text/css" href="/static/css/wangeditor.css" media="all"/>
<style type="text/css">
.header span{background:#009688;margin-left:30px;padding:10px;color:#ffffff;}
.header div{border-bottom:solid 2px #009688;margin-top: 8px;}
.header button{float:right;margin-top:-5px;}
.pagination {
display: inline-block;
padding-left: 0;
margin: 20px 0;
border-radius: 4px;
}
.pagination > li {
display: inline;
}
.pagination > li > a,
.pagination > li > span {
position: relative;
float: left;
padding: 6px 12px;
margin-left: -1px;
line-height: 1.42857143;
color: #337ab7;
text-decoration: none;
background-color: #fff;
border: 1px solid #ddd;
}
.pagination > li:first-child > a,
.pagination > li:first-child > span {
margin-left: 0;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
.pagination > li:last-child > a,
.pagination > li:last-child > span {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.pagination > li > a:hover,
.pagination > li > span:hover,
.pagination > li > a:focus,
.pagination > li > span:focus {
z-index: 2;
color: #23527c;
background-color: #eee;
border-color: #ddd;
}
.pagination > .active > a,
.pagination > .active > span,
.pagination > .active > a:hover,
.pagination > .active > span:hover,
.pagination > .active > a:focus,
.pagination > .active > span:focus {
z-index: 3;
color: #fff;
cursor: default;
background-color: #337ab7;
border-color: #337ab7;
}
.pagination > .disabled > span,
.pagination > .disabled > span:hover,
.pagination > .disabled > span:focus,
.pagination > .disabled > a,
.pagination > .disabled > a:hover,
.pagination > .disabled > a:focus {
color: #777;
cursor: not-allowed;
background-color: #fff;
border-color: #ddd;
}
.close-img { background: url(/static/images/close_img.png); background-size: 20px 20px; width:20px; height: 20px; position: absolute; right: 5px; top: 5px; z-index: 2;}
</style>
<script type="text/javascript" src="/static/layui/layui.js"></script>
<script type="text/javascript">
layui.use(['layer','form','table','laydate','element','upload'],function(){
layer = layui.layer; // layui 弹框
form = layui.form; // layui form表单
table = layui.table; // layui 表格
laydate = layui.laydate; // layui 时间框
element = layui.element; // layui element
upload = layui.upload; // layui 上传
$ = layui.jquery; // layui jquery
})
</script>
</head>
<body style="padding:10px; box-sizing: border-box;">
<form class="layui-form">
<input type="hidden" name="group_id" value="<?php echo htmlentities((string) $group['group_id']); ?>">
<div class="layui-form-item">
<label class="layui-form-label">角色名称</label>
<div class="layui-input-block">
<input type="text" class="layui-input" name="group_name" placeholder="请输入角色名称" value="<?php echo htmlentities((string) $group['group_name']); ?>">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">状态</label>
<div class="layui-input-block">
<input type="radio" name="status" value="1" title="开启" <?php echo $group['status']==1 ? 'checked' : ''; ?>>
<input type="radio" name="status" value="0" title="禁用" <?php echo $group['status']==0 ? 'checked' : ''; ?>>
</div>
</div>
<div class="layui-form-itme">
<label class="layui-form-label">权限菜单</label>
<?php if(is_array($menus) || $menus instanceof \think\Collection || $menus instanceof \think\Paginator): $i = 0; $__LIST__ = $menus;if( count($__LIST__)==0 ) : echo "" ;else: foreach($__LIST__ as $key=>$vo): $mod = ($i % 2 );++$i;?>
<hr>
<div class="layui-input-block">
<input type="checkbox" name="menu[<?php echo htmlentities((string) $vo['smid']); ?>]" lay-skin="primary" title="<?php echo htmlentities((string) $vo['label']); ?>" <?php echo isset($group['rights']) && $group['rights'] && in_array($vo['smid'],$group['rights'])?'checked':''; ?>>
<hr>
<?php if(is_array($vo['children']) || $vo['children'] instanceof \think\Collection || $vo['children'] instanceof \think\Paginator): $i = 0; $__LIST__ = $vo['children'];if( count($__LIST__)==0 ) : echo "" ;else: foreach($__LIST__ as $key=>$cvo): $mod = ($i % 2 );++$i;?>
<input type="checkbox" name="menu[<?php echo htmlentities((string) $cvo['smid']); ?>]" lay-skin="primary" title="<?php echo htmlentities((string) $cvo['label']); ?>" <?php echo isset($group['rights']) && $group['rights'] && in_array($cvo['smid'],$group['rights'])?'checked':''; ?>>
<?php endforeach; endif; else: echo "" ;endif; ?>
</div>
<?php endforeach; endif; else: echo "" ;endif; ?>
</div>
</form>
<div class="layui-form-item" style="margin-top:10px;">
<div class="layui-input-block">
<button type="button" class="layui-btn" onclick="save()">保存</button>
</div>
</div>
<script type="text/javascript">
layui.use(['layer','form'],function(){
var form = layui.form;
layer = layui.layer;
$ = layui.jquery;
});
function save(){
$.post("<?php echo htmlentities((string) $config['admin_route']); ?>yunzeradmin/groupedit",$('form').serialize(),function(res){
if(res.code>0){
layer.msg(res.msg,{'icon':2});
}else{
layer.msg(res.msg,{'icon':1});
setTimeout(function(){parent.window.location.reload();},1000);
}
},'json');
}
</script>
</body>
</html>
<script type="text/javascript">
// 显示图片
function show_img(obj){
var imgurl = $(obj).attr('src');
var res = getMousePos();
var html = '<div style="background:#fff;position:absolute;width:200px;border:solid 1px #cdcdcd;border-radius:6px;padding:2px;left:'+res.x+'px;top:'+res.y+'px;z-index:1000" id="preview">\
<img style="width:100%;border-radius:6px;" src="'+imgurl+'">\
</div>';
$('body').append(html);
}
// 隐藏图片
function hide_img(){
$('#preview').remove();
}
// 图片位置计算
function getMousePos(event) {
var e = event || window.event;
var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
var x = e.pageX || e.clientX + scrollX;
var y = e.pageY || e.clientY + scrollY;
return { 'x': x, 'y': y };
}
// 删除图片
function deleteImage(path,obj){
$(obj).closest('.upload_pic_li').remove();
}
</script>

View File

@ -0,0 +1,223 @@
<?php /*a:3:{s:59:"E:\Demo\PHP\yunzer\app\admin\view\yunzeradmin\groupinfo.php";i:1747402501;s:51:"E:\Demo\PHP\yunzer\app\admin\view\public\header.php";i:1746890051;s:49:"E:\Demo\PHP\yunzer\app\admin\view\public\tail.php";i:1745855804;}*/ ?>
<!DOCTYPE html>
<html>
<head>
<title><?php echo htmlentities((string) $config['admin_name']); ?></title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="stylesheet" type="text/css" href="/static/layui/css/layui.css" media="all"/>
<link rel="stylesheet" type="text/css" href="/static/css/moban.css" media="all"/>
<link rel="stylesheet" type="text/css" href="/static/css/wangeditor.css" media="all"/>
<style type="text/css">
.header span{background:#009688;margin-left:30px;padding:10px;color:#ffffff;}
.header div{border-bottom:solid 2px #009688;margin-top: 8px;}
.header button{float:right;margin-top:-5px;}
.pagination {
display: inline-block;
padding-left: 0;
margin: 20px 0;
border-radius: 4px;
}
.pagination > li {
display: inline;
}
.pagination > li > a,
.pagination > li > span {
position: relative;
float: left;
padding: 6px 12px;
margin-left: -1px;
line-height: 1.42857143;
color: #337ab7;
text-decoration: none;
background-color: #fff;
border: 1px solid #ddd;
}
.pagination > li:first-child > a,
.pagination > li:first-child > span {
margin-left: 0;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
.pagination > li:last-child > a,
.pagination > li:last-child > span {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.pagination > li > a:hover,
.pagination > li > span:hover,
.pagination > li > a:focus,
.pagination > li > span:focus {
z-index: 2;
color: #23527c;
background-color: #eee;
border-color: #ddd;
}
.pagination > .active > a,
.pagination > .active > span,
.pagination > .active > a:hover,
.pagination > .active > span:hover,
.pagination > .active > a:focus,
.pagination > .active > span:focus {
z-index: 3;
color: #fff;
cursor: default;
background-color: #337ab7;
border-color: #337ab7;
}
.pagination > .disabled > span,
.pagination > .disabled > span:hover,
.pagination > .disabled > span:focus,
.pagination > .disabled > a,
.pagination > .disabled > a:hover,
.pagination > .disabled > a:focus {
color: #777;
cursor: not-allowed;
background-color: #fff;
border-color: #ddd;
}
.close-img { background: url(/static/images/close_img.png); background-size: 20px 20px; width:20px; height: 20px; position: absolute; right: 5px; top: 5px; z-index: 2;}
</style>
<script type="text/javascript" src="/static/layui/layui.js"></script>
<script type="text/javascript">
layui.use(['layer','form','table','laydate','element','upload'],function(){
layer = layui.layer; // layui 弹框
form = layui.form; // layui form表单
table = layui.table; // layui 表格
laydate = layui.laydate; // layui 时间框
element = layui.element; // layui element
upload = layui.upload; // layui 上传
$ = layui.jquery; // layui jquery
})
</script>
</head>
<body style="padding:10px; box-sizing: border-box;">
<div class="config-container">
<!-- 页面头部样式 -->
<div class="config-header" style="display: flex;flex-direction: column;flex-wrap: wrap;align-items: flex-start;">
<div class="maintitle">
<i class="layui-icon layui-icon-group"></i>
<span>角色列表</span>
</div>
<div style="display: flex;align-items: flex-start;flex-direction: column;gap: 15px;margin-bottom: 10px;">
<div>
<button class="layui-btn layui-bg-blue" onclick="add()">
<i class="layui-icon layui-icon-add-1"></i>添加
</button>
<button type="button" class="layui-btn layui-btn-primary layui-border-blue" onclick="refresh()">
<i class="layui-icon layui-icon-refresh"></i>刷新
</button>
</div>
</div>
</div>
<table class="layui-table">
<thead>
<tr>
<th>角色名</th>
<th>状态</th>
<th>添加时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<?php if(is_array($group) || $group instanceof \think\Collection || $group instanceof \think\Paginator): $i = 0; $__LIST__ = $group;if( count($__LIST__)==0 ) : echo "" ;else: foreach($__LIST__ as $key=>$vo): $mod = ($i % 2 );++$i;?>
<tr>
<td><?php echo htmlentities((string) $vo['group_name']); ?></td>
<td><?php echo $vo['status']==1 ? '开启' : '<span style="color:red;">禁用</span>'; ?></td>
<td><?php echo date('Y-m-d H:i:s',$vo['create_time']); ?></td>
<td>
<button type="button" class="layui-btn layui-btn-primary layui-btn-xs"
onclick="edit(<?php echo htmlentities((string) $vo['group_id']); ?>)">
<i class="layui-icon layui-icon-edit"></i>编辑
</button>
<button type="button" class="layui-btn layui-btn-primary layui-btn-xs"
onclick="del(<?php echo htmlentities((string) $vo['group_id']); ?>)">
<i class="layui-icon layui-icon-delete"></i>删除
</button>
</td>
</tr>
<?php endforeach; endif; else: echo "" ;endif; ?>
</tbody>
</table>
</div>
<script type="text/javascript">
layui.use(['layer'], function () {
layer = layui.layer;
$ = layui.jquery;
});
// 添加
function add() {
layer.open({
type: 2,
title: '添加角色',
shade: 0.3,
area: ['450px', '550px'],
content: "<?php echo htmlentities((string) $config['admin_route']); ?>yunzeradmin/groupadd"
});
}
// 编辑
function edit(group_id) {
layer.open({
type: 2,
title: '编辑角色',
shade: 0.3,
area: ['450px', '550px'],
content: "<?php echo htmlentities((string) $config['admin_route']); ?>yunzeradmin/groupedit?group_id=" + group_id
});
}
// 删除
function del(group_id) {
layer.confirm('确定要删除吗?', {
icon: 3,
btn: ['确定', '取消']
}, function () {
$.post("<?php echo htmlentities((string) $config['admin_route']); ?>yunzeradmin/groupdel", { 'group_id': group_id }, function (res) {
if (res.code > 0) {
layer.alert(res.msg, { icon: 2 });
} else {
layer.msg(res.msg, { icon: 1 });
setTimeout(function () { window.location.reload(); }, 1000);
}
}, 'json');
});
}
//刷新列表
function refresh() {
window.location.reload();
}
</script>
</body>
</html>
<script type="text/javascript">
// 显示图片
function show_img(obj){
var imgurl = $(obj).attr('src');
var res = getMousePos();
var html = '<div style="background:#fff;position:absolute;width:200px;border:solid 1px #cdcdcd;border-radius:6px;padding:2px;left:'+res.x+'px;top:'+res.y+'px;z-index:1000" id="preview">\
<img style="width:100%;border-radius:6px;" src="'+imgurl+'">\
</div>';
$('body').append(html);
}
// 隐藏图片
function hide_img(){
$('#preview').remove();
}
// 图片位置计算
function getMousePos(event) {
var e = event || window.event;
var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
var x = e.pageX || e.clientX + scrollX;
var y = e.pageY || e.clientY + scrollY;
return { 'x': x, 'y': y };
}
// 删除图片
function deleteImage(path,obj){
$(obj).closest('.upload_pic_li').remove();
}
</script>

View File

@ -1,4 +1,4 @@
<?php /*a:3:{s:51:"E:\Demo\PHP\yunzer\app\admin\view\index\welcome.php";i:1745855804;s:51:"E:\Demo\PHP\yunzer\app\admin\view\public\header.php";i:1746890051;s:49:"E:\Demo\PHP\yunzer\app\admin\view\public\tail.php";i:1745855804;}*/ ?>
<?php /*a:3:{s:51:"E:\Demo\PHP\yunzer\app\admin\view\index\welcome.php";i:1747583088;s:51:"E:\Demo\PHP\yunzer\app\admin\view\public\header.php";i:1746890051;s:49:"E:\Demo\PHP\yunzer\app\admin\view\public\tail.php";i:1745855804;}*/ ?>
<!DOCTYPE html>
<html>
<head>
@ -93,80 +93,207 @@
</script>
</head>
<body style="padding:10px; box-sizing: border-box;">
<script src="/static/js/jquery.min.js"></script>
<style>
.dashboard-container {
padding: 20px;
font-family: 'Helvetica Neue', Arial, sans-serif;
padding: 24px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
/* background-color: #f5f7fa; */
/* min-height: calc(100vh - 60px); */
}
.welcome-header {
text-align: center;
margin-bottom: 30px;
background: linear-gradient(135deg, #3881fd 0%, #2c5fd9 100%);
border-radius: 12px;
padding: 30px;
color: white;
margin-bottom: 24px;
box-shadow: 0 4px 20px rgba(56, 129, 253, 0.15);
}
.welcome-header h1 {
color: #3881fd;
font-weight: 300;
font-size: 28px;
margin-bottom: 10px;
font-weight: 600;
margin-bottom: 8px;
}
.welcome-header p {
font-size: 15px;
opacity: 0.9;
margin: 0;
}
.stats-container {
display: flex;
flex-wrap: wrap;
gap: 20px;
justify-content: center;
margin-bottom: 30px;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 24px;
margin-bottom: 24px;
}
.stat-card {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
padding: 20px;
min-width: 200px;
flex: 1;
background: white;
border-radius: 12px;
padding: 24px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.stat-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 4px;
height: 100%;
background: #3881fd;
}
.stat-card:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
}
.stat-card .stat-value {
font-size: 24px;
font-weight: bold;
color: #3881fd;
margin: 10px 0;
font-size: 32px;
font-weight: 600;
color: #2c3e50;
margin: 12px 0;
display: flex;
align-items: baseline;
}
.stat-card .stat-title {
color: #7f8c8d;
color: #64748b;
font-size: 14px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.stat-card .stat-icon {
position: absolute;
right: 20px;
top: 50%;
transform: translateY(-50%);
font-size: 48px;
opacity: 0.1;
}
.quick-actions {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
padding: 20px;
margin-bottom: 20px;
background: white;
border-radius: 12px;
padding: 24px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
}
.quick-actions h2 {
color: #2c3e50;
color: #1e293b;
font-size: 18px;
margin-bottom: 15px;
font-weight: 500;
font-weight: 600;
margin-bottom: 20px;
display: flex;
align-items: center;
}
.quick-actions h2::before {
content: '';
display: inline-block;
width: 4px;
height: 18px;
background: #3881fd;
margin-right: 8px;
border-radius: 2px;
}
.action-buttons {
display: flex;
flex-wrap: wrap;
gap: 10px;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
gap: 16px;
}
.action-button {
background-color: #f8f9fa;
border: none;
border-radius: 4px;
padding: 10px 15px;
color: #3881fd;
background: #f8fafc;
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 12px 16px;
color: #1e293b;
font-weight: 500;
cursor: pointer;
transition: background-color 0.3s;
transition: all 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
text-decoration: none;
}
.action-button:hover {
background-color: #e9ecef;
background: #3881fd;
color: white;
border-color: #3881fd;
transform: translateY(-2px);
}
.action-button i {
margin-right: 8px;
}
.recent-activity {
margin-top: 24px;
background: white;
border-radius: 12px;
padding: 24px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
}
.activity-list {
margin-top: 16px;
}
.activity-item {
display: flex;
align-items: center;
padding: 12px 0;
border-bottom: 1px solid #f1f5f9;
}
.activity-item:last-child {
border-bottom: none;
}
.activity-icon {
width: 36px;
height: 36px;
border-radius: 8px;
background: #f1f5f9;
display: flex;
align-items: center;
justify-content: center;
margin-right: 12px;
}
.activity-content {
flex: 1;
}
.activity-title {
font-weight: 500;
color: #1e293b;
margin-bottom: 4px;
}
.activity-time {
font-size: 12px;
color: #64748b;
}
.charts-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
gap: 24px;
margin-top: 24px;
}
.chart-card {
background: white;
border-radius: 12px;
padding: 24px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
}
.chart-card h2 {
color: #1e293b;
font-size: 18px;
font-weight: 600;
margin-bottom: 20px;
display: flex;
align-items: center;
}
.chart-card h2::before {
content: '';
display: inline-block;
width: 4px;
height: 18px;
background: #3881fd;
margin-right: 8px;
border-radius: 2px;
}
.chart-container {
height: 300px;
width: 100%;
}
</style>
@ -179,34 +306,84 @@
<div class="stats-container">
<div class="stat-card">
<div class="stat-title">用户总数</div>
<div class="stat-value">1,234</div>
<div class="stat-value"><?php echo htmlentities((string) number_format($stats['total_users'])); ?></div>
<div class="stat-icon">👥</div>
</div>
<div class="stat-card">
<div class="stat-title">今日访问</div>
<div class="stat-value">256</div>
<div class="stat-value"><?php echo htmlentities((string) number_format($stats['daily_visits'])); ?></div>
<div class="stat-icon">📊</div>
</div>
<div class="stat-card">
<div class="stat-title">数据总量</div>
<div class="stat-value">8,642</div>
<div class="stat-title">文章总数</div>
<div class="stat-value"><?php echo htmlentities((string) number_format($stats['total_articles'])); ?></div>
<div class="stat-icon">📝</div>
</div>
<div class="stat-card">
<div class="stat-title">系统消息</div>
<div class="stat-value">12</div>
<div class="stat-title">资源总数</div>
<div class="stat-value"><?php echo htmlentities((string) number_format($stats['total_resources'])); ?></div>
<div class="stat-icon">📦</div>
</div>
</div>
<div class="quick-actions">
<h2>快捷操作</h2>
<div class="action-buttons">
<button class="action-button">用户管理</button>
<button class="action-button">内容发布</button>
<button class="action-button">数据统计</button>
<button class="action-button">系统设置</button>
<button class="action-button">清除缓存</button>
<a href="<?php echo url('user/index'); ?>" class="action-button">
<i class="fas fa-users"></i>用户管理
</a>
<a href="<?php echo url('content/publish'); ?>" class="action-button">
<i class="fas fa-edit"></i>内容发布
</a>
<a href="<?php echo url('statistics/index'); ?>" class="action-button">
<i class="fas fa-chart-bar"></i>数据统计
</a>
<a href="<?php echo url('system/settings'); ?>" class="action-button">
<i class="fas fa-cog"></i>系统设置
</a>
<a href="<?php echo url('system/clear_cache'); ?>" class="action-button">
<i class="fas fa-broom"></i>清除缓存
</a>
</div>
</div>
<div class="recent-activity">
<h2>最近动态</h2>
<div class="activity-list">
<?php if(is_array($recentActivities) || $recentActivities instanceof \think\Collection || $recentActivities instanceof \think\Paginator): $i = 0; $__LIST__ = $recentActivities;if( count($__LIST__)==0 ) : echo "" ;else: foreach($__LIST__ as $key=>$activity): $mod = ($i % 2 );++$i;?>
<div class="activity-item">
<div class="activity-icon"><?php echo htmlentities((string) $activity['icon']); ?></div>
<div class="activity-content">
<div class="activity-title"><?php echo htmlentities((string) $activity['title']); ?></div>
<div class="activity-time"><?php echo htmlentities((string) $activity['time']); ?></div>
</div>
</div>
<?php endforeach; endif; else: echo "" ;endif; ?>
</div>
</div>
<div class="charts-container">
<div class="chart-card">
<h2>访问趋势</h2>
<div id="visitTrend" class="chart-container"></div>
</div>
<div class="chart-card">
<h2>用户增长</h2>
<div id="userGrowth" class="chart-container"></div>
</div>
<div class="chart-card">
<h2>资源统计</h2>
<div id="resourceStats" class="chart-container"></div>
</div>
<div class="chart-card">
<h2>文章统计</h2>
<div id="articleStats" class="chart-container"></div>
</div>
</div>
</div>
<script src="/static/js/echarts.min.js"></script>
<script>
function updateTime() {
var now = new Date();
@ -217,12 +394,10 @@ function updateTime() {
var minutes = now.getMinutes();
var seconds = now.getSeconds();
// 补零函数
var padZero = function(num) {
return num < 10 ? '0' + num : num;
};
// 格式化时间
var timeString = year + '年' +
padZero(month) + '月' +
padZero(date) + '日 ' +
@ -233,11 +408,296 @@ function updateTime() {
document.getElementById('current-time').innerHTML = timeString;
}
// 页面加载完立即执行一次
updateTime();
// 获取文章统计数据
function getArticleCounts() {
fetch('<?php echo url("article/counts"); ?>')
.then(response => response.json())
.then(res => {
console.log('文章统计接口返回数据:', res);
if (res.code === 0 && res.data) {
// 更新文章总数
document.querySelector('.stat-card:nth-child(3) .stat-value').textContent = res.data.total.toLocaleString();
} else {
console.warn('文章统计接口返回异常:', res);
}
})
.catch(error => {
console.error('获取文章统计失败:', error);
});
}
// 每秒更新一次时间
// 获取资源统计数据
function getResourcesCounts() {
fetch('<?php echo url("resources/counts"); ?>')
.then(response => response.json())
.then(res => {
console.log('资源统计接口返回数据:', res);
if (res.code === 0 && res.data) {
// 更新资源总数
document.querySelector('.stat-card:nth-child(4) .stat-value').textContent = res.data.total.toLocaleString();
} else {
console.warn('资源统计接口返回异常:', res);
}
})
.catch(error => {
console.error('获取资源统计失败:', error);
});
}
updateTime();
setInterval(updateTime, 1000);
// 页面加载完成后获取统计数据
document.addEventListener('DOMContentLoaded', function() {
getArticleCounts();
getResourcesCounts();
});
// 访问趋势图表
function initVisitTrend() {
var chart = echarts.init(document.getElementById('visitTrend'));
var option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
legend: {
data: ['访问量', '独立访客']
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
data: <?php echo htmlentities((string) json_encode($chartData['visitTrend']['dates'])); ?>,
axisLine: {
lineStyle: {
color: '#e2e8f0'
}
}
},
yAxis: {
type: 'value',
axisLine: {
lineStyle: {
color: '#e2e8f0'
}
},
splitLine: {
lineStyle: {
color: '#f1f5f9'
}
}
},
series: [{
name: '访问量',
data: <?php echo htmlentities((string) json_encode($chartData['visitTrend']['visits'])); ?>,
type: 'line',
smooth: true,
areaStyle: {
opacity: 0.1
},
itemStyle: {
color: '#3881fd'
},
lineStyle: {
width: 3
}
}, {
name: '独立访客',
data: <?php echo htmlentities((string) json_encode($chartData['visitTrend']['uvs'])); ?>,
type: 'line',
smooth: true,
itemStyle: {
color: '#10b981'
},
lineStyle: {
width: 3
}
}]
};
chart.setOption(option);
}
// 用户增长图表
function initUserGrowth() {
var chart = echarts.init(document.getElementById('userGrowth'));
var option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
}
},
legend: {
data: ['新增用户', '总用户数']
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: <?php echo htmlentities((string) json_encode($chartData['userGrowth']['dates'])); ?>
},
yAxis: {
type: 'value'
},
series: [
{
name: '新增用户',
type: 'bar',
data: <?php echo htmlentities((string) json_encode($chartData['userGrowth']['newUsers'])); ?>,
itemStyle: {
color: '#3881fd'
}
},
{
name: '总用户数',
type: 'line',
smooth: true,
data: <?php echo htmlentities((string) json_encode($chartData['userGrowth']['totalUsers'])); ?>,
itemStyle: {
color: '#10b981'
}
}
]
};
chart.setOption(option);
}
// 资源统计图表
function initResourceStats() {
var chart = echarts.init(document.getElementById('resourceStats'));
var option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
}
},
legend: {
data: ['新增资源', '下载量']
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: <?php echo htmlentities((string) json_encode($chartData['resourceStats']['dates'])); ?>
},
yAxis: {
type: 'value'
},
series: [
{
name: '新增资源',
type: 'bar',
data: <?php echo htmlentities((string) json_encode($chartData['resourceStats']['resources'])); ?>,
itemStyle: {
color: '#3881fd'
}
},
{
name: '下载量',
type: 'line',
smooth: true,
data: <?php echo htmlentities((string) json_encode($chartData['resourceStats']['downloads'])); ?>,
itemStyle: {
color: '#10b981'
}
}
]
};
chart.setOption(option);
}
// 文章统计图表
function initArticleStats() {
var chart = echarts.init(document.getElementById('articleStats'));
var option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
}
},
legend: {
data: ['新增文章', '访问量']
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: <?php echo htmlentities((string) json_encode($chartData['articleStats']['dates'])); ?>
},
yAxis: {
type: 'value'
},
series: [
{
name: '新增文章',
type: 'bar',
data: <?php echo htmlentities((string) json_encode($chartData['articleStats']['articles'])); ?>,
itemStyle: {
color: '#3881fd'
}
},
{
name: '访问量',
type: 'line',
smooth: true,
data: <?php echo htmlentities((string) json_encode($chartData['articleStats']['views'])); ?>,
itemStyle: {
color: '#10b981'
}
}
]
};
chart.setOption(option);
}
// 初始化所有图表
document.addEventListener('DOMContentLoaded', function() {
initVisitTrend();
initUserGrowth();
initResourceStats();
initArticleStats();
// 监听窗口大小变化,重绘图表
window.addEventListener('resize', function() {
var charts = document.querySelectorAll('.chart-container');
charts.forEach(function(chart) {
echarts.getInstanceByDom(chart)?.resize();
});
});
});
</script>
</body>

View File

@ -0,0 +1,260 @@
<?php /*a:2:{s:47:"E:\Demo\PHP\yunzer\app\admin\view\log\login.php";i:1747584845;s:51:"E:\Demo\PHP\yunzer\app\admin\view\public\header.php";i:1746890051;}*/ ?>
<!DOCTYPE html>
<html>
<head>
<title><?php echo htmlentities((string) $config['admin_name']); ?></title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="stylesheet" type="text/css" href="/static/layui/css/layui.css" media="all"/>
<link rel="stylesheet" type="text/css" href="/static/css/moban.css" media="all"/>
<link rel="stylesheet" type="text/css" href="/static/css/wangeditor.css" media="all"/>
<style type="text/css">
.header span{background:#009688;margin-left:30px;padding:10px;color:#ffffff;}
.header div{border-bottom:solid 2px #009688;margin-top: 8px;}
.header button{float:right;margin-top:-5px;}
.pagination {
display: inline-block;
padding-left: 0;
margin: 20px 0;
border-radius: 4px;
}
.pagination > li {
display: inline;
}
.pagination > li > a,
.pagination > li > span {
position: relative;
float: left;
padding: 6px 12px;
margin-left: -1px;
line-height: 1.42857143;
color: #337ab7;
text-decoration: none;
background-color: #fff;
border: 1px solid #ddd;
}
.pagination > li:first-child > a,
.pagination > li:first-child > span {
margin-left: 0;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
.pagination > li:last-child > a,
.pagination > li:last-child > span {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.pagination > li > a:hover,
.pagination > li > span:hover,
.pagination > li > a:focus,
.pagination > li > span:focus {
z-index: 2;
color: #23527c;
background-color: #eee;
border-color: #ddd;
}
.pagination > .active > a,
.pagination > .active > span,
.pagination > .active > a:hover,
.pagination > .active > span:hover,
.pagination > .active > a:focus,
.pagination > .active > span:focus {
z-index: 3;
color: #fff;
cursor: default;
background-color: #337ab7;
border-color: #337ab7;
}
.pagination > .disabled > span,
.pagination > .disabled > span:hover,
.pagination > .disabled > span:focus,
.pagination > .disabled > a,
.pagination > .disabled > a:hover,
.pagination > .disabled > a:focus {
color: #777;
cursor: not-allowed;
background-color: #fff;
border-color: #ddd;
}
.close-img { background: url(/static/images/close_img.png); background-size: 20px 20px; width:20px; height: 20px; position: absolute; right: 5px; top: 5px; z-index: 2;}
</style>
<script type="text/javascript" src="/static/layui/layui.js"></script>
<script type="text/javascript">
layui.use(['layer','form','table','laydate','element','upload'],function(){
layer = layui.layer; // layui 弹框
form = layui.form; // layui form表单
table = layui.table; // layui 表格
laydate = layui.laydate; // layui 时间框
element = layui.element; // layui element
upload = layui.upload; // layui 上传
$ = layui.jquery; // layui jquery
})
</script>
</head>
<body style="padding:10px; box-sizing: border-box;">
<div class="layui-card">
<div class="layui-card-header">
<span class="layui-badge layui-bg-blue">登录日志</span>
</div>
<div class="layui-card-body">
<form class="layui-form layui-form-pane" action="">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">用户名</label>
<div class="layui-input-inline">
<input type="text" name="username" placeholder="请输入用户名" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">IP地址</label>
<div class="layui-input-inline">
<input type="text" name="ip" placeholder="请输入IP地址" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">状态</label>
<div class="layui-input-inline">
<select name="status">
<option value="">全部</option>
<option value="1">成功</option>
<option value="0">失败</option>
</select>
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">时间范围</label>
<div class="layui-input-inline" style="width: 300px;">
<input type="text" name="time_range" class="layui-input" id="timeRange" placeholder="请选择时间范围">
</div>
</div>
<div class="layui-inline">
<button class="layui-btn" lay-submit lay-filter="searchForm">
<i class="layui-icon layui-icon-search"></i> 搜索
</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
<table id="loginLogTable" lay-filter="loginLogTable"></table>
</div>
</div>
<script type="text/html" id="tableToolbar">
<div class="layui-btn-container">
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="clearAll">
<i class="layui-icon layui-icon-delete"></i> 清空日志
</button>
</div>
</script>
<script type="text/html" id="tableBar">
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="del">删除</a>
</script>
<script src="/static/layui/layui.js"></script>
<script>
layui.use(['table', 'form', 'laydate'], function(){
var table = layui.table;
var form = layui.form;
var laydate = layui.laydate;
// 初始化时间范围选择器
laydate.render({
elem: '#timeRange',
type: 'datetime',
range: true
});
// 初始化表格
table.render({
elem: '#loginLogTable',
url: '<?php echo url("log/login"); ?>',
method: 'post',
toolbar: '#tableToolbar',
defaultToolbar: ['filter', 'exports', 'print'],
parseData: function(res) {
return {
"code": res.code === 0 ? 0 : 1,
"msg": res.msg,
"count": res.count,
"data": res.data
};
},
cols: [[
{field: 'id', title: 'ID', width: 80, sort: true},
{field: 'username', title: '用户名', width: 120},
{field: 'ip_address', title: 'IP地址', width: 130},
{field: 'location', title: '登录地点', width: 120},
{field: 'device_type', title: '设备类型', width: 100},
{field: 'user_agent', title: '浏览器', width: 200},
{field: 'login_status', title: '状态', width: 100, templet: function(d){
return d.login_status == 1 ?
'<span class="layui-badge layui-bg-green">成功</span>' :
'<span class="layui-badge layui-bg-red">失败</span>';
}},
{field: 'failure_reason', title: '失败原因', width: 150},
{field: 'login_time', title: '登录时间', width: 180, sort: true},
{title: '操作', toolbar: '#tableBar', width: 80, fixed: 'right'}
]],
page: true,
limit: 10,
limits: [10, 20, 50, 100]
});
// 监听搜索表单提交
form.on('submit(searchForm)', function(data){
var timeRange = data.field.time_range;
if(timeRange){
var times = timeRange.split(' - ');
data.field.start_time = times[0];
data.field.end_time = times[1];
}
delete data.field.time_range;
table.reload('loginLogTable', {
where: data.field,
page: {curr: 1}
});
return false;
});
// 监听工具条
table.on('tool(loginLogTable)', function(obj){
var data = obj.data;
if(obj.event === 'del'){
layer.confirm('确定删除这条日志吗?', function(index){
$.post('<?php echo url("log/deleteLogin"); ?>', {id: data.id}, function(res){
if(res.code === 0){
layer.msg(res.msg, {icon: 1});
obj.del();
}else{
layer.msg(res.msg, {icon: 2});
}
});
layer.close(index);
});
}
});
// 监听头工具栏事件
table.on('toolbar(loginLogTable)', function(obj){
if(obj.event === 'clearAll'){
layer.confirm('确定要清空所有登录日志吗?', function(index){
$.post('<?php echo url("log/clearLogin"); ?>', function(res){
if(res.code === 0){
layer.msg(res.msg, {icon: 1});
table.reload('loginLogTable');
}else{
layer.msg(res.msg, {icon: 2});
}
});
layer.close(index);
});
}
});
});
</script>
</body>
</html>

View File

@ -0,0 +1,218 @@
<?php /*a:3:{s:52:"E:\Demo\PHP\yunzer\app\admin\view\yunzer\menuadd.php";i:1745855804;s:51:"E:\Demo\PHP\yunzer\app\admin\view\public\header.php";i:1746890051;s:49:"E:\Demo\PHP\yunzer\app\admin\view\public\tail.php";i:1745855804;}*/ ?>
<!DOCTYPE html>
<html>
<head>
<title><?php echo htmlentities((string) $config['admin_name']); ?></title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="stylesheet" type="text/css" href="/static/layui/css/layui.css" media="all"/>
<link rel="stylesheet" type="text/css" href="/static/css/moban.css" media="all"/>
<link rel="stylesheet" type="text/css" href="/static/css/wangeditor.css" media="all"/>
<style type="text/css">
.header span{background:#009688;margin-left:30px;padding:10px;color:#ffffff;}
.header div{border-bottom:solid 2px #009688;margin-top: 8px;}
.header button{float:right;margin-top:-5px;}
.pagination {
display: inline-block;
padding-left: 0;
margin: 20px 0;
border-radius: 4px;
}
.pagination > li {
display: inline;
}
.pagination > li > a,
.pagination > li > span {
position: relative;
float: left;
padding: 6px 12px;
margin-left: -1px;
line-height: 1.42857143;
color: #337ab7;
text-decoration: none;
background-color: #fff;
border: 1px solid #ddd;
}
.pagination > li:first-child > a,
.pagination > li:first-child > span {
margin-left: 0;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
.pagination > li:last-child > a,
.pagination > li:last-child > span {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.pagination > li > a:hover,
.pagination > li > span:hover,
.pagination > li > a:focus,
.pagination > li > span:focus {
z-index: 2;
color: #23527c;
background-color: #eee;
border-color: #ddd;
}
.pagination > .active > a,
.pagination > .active > span,
.pagination > .active > a:hover,
.pagination > .active > span:hover,
.pagination > .active > a:focus,
.pagination > .active > span:focus {
z-index: 3;
color: #fff;
cursor: default;
background-color: #337ab7;
border-color: #337ab7;
}
.pagination > .disabled > span,
.pagination > .disabled > span:hover,
.pagination > .disabled > span:focus,
.pagination > .disabled > a,
.pagination > .disabled > a:hover,
.pagination > .disabled > a:focus {
color: #777;
cursor: not-allowed;
background-color: #fff;
border-color: #ddd;
}
.close-img { background: url(/static/images/close_img.png); background-size: 20px 20px; width:20px; height: 20px; position: absolute; right: 5px; top: 5px; z-index: 2;}
</style>
<script type="text/javascript" src="/static/layui/layui.js"></script>
<script type="text/javascript">
layui.use(['layer','form','table','laydate','element','upload'],function(){
layer = layui.layer; // layui 弹框
form = layui.form; // layui form表单
table = layui.table; // layui 表格
laydate = layui.laydate; // layui 时间框
element = layui.element; // layui element
upload = layui.upload; // layui 上传
$ = layui.jquery; // layui jquery
})
</script>
</head>
<body style="padding:10px; box-sizing: border-box;">
<form class="layui-form">
<div class="layui-form-item">
<label class="layui-form-label">菜单名</label>
<div class="layui-input-block">
<input type="text" class="layui-input" name="label" placeholder="请输入菜单名">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">图标</label>
<div class="layui-input-block">
<select name="icon_class" lay-verify="required" lay-search="">
<option value="">请输入layui图标</option>
<?php foreach($iconfont as $icon_v): ?>
<option value="<?php echo htmlentities((string) $icon_v['icon_css']); ?>"><?php echo htmlentities((string) $icon_v['icon_css']); ?> <?php echo htmlentities((string) $icon_v['icon_name']); ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">类型</label>
<div class="layui-input-inline">
<select name="type" lay-filter="type">
<option value='0' selected>顶级菜单</option>
<option value='1'>内部代码</option>
<option value='2'>超链接</option>
</select>
</div>
</div>
<div class="layui-form-item" style="display:none;" id="src1">
<label class="layui-form-label">内部代码</label>
<div class="layui-input-block">
<input type="text" class="layui-input" name="src1" placeholder="请输入:模块/方法">
</div>
</div>
<div class="layui-form-item" style="display:none;" id="src2">
<label class="layui-form-label">链接地址</label>
<div class="layui-input-block">
<input type="text" class="layui-input" name="src2" placeholder="请输入http网址">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">排序</label>
<div class="layui-input-block">
<input type="number" class="layui-input" name="sort" placeholder="值越大越靠前">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">状态</label>
<div class="layui-input-block">
<input type="radio" name="status" value="1" title="开启" checked>
<input type="radio" name="status" value="0" title="禁用">
</div>
</div>
</form>
<div class="layui-form-item" style="margin-top:10px;">
<div class="layui-input-block">
<button type="button" class="layui-btn" onclick="save()">保存</button>
</div>
</div>
<script type="text/javascript">
layui.use(['layer','form'],function(){
var form = layui.form;
layer = layui.layer;
$ = layui.jquery;
form.on('select(type)', function(data){
if(data.value == 1){
$("#src1").show();
$("#src2").hide();
$("#src3").hide();
}else if(data.value == 2){
$("#src1").hide();
$("#src2").show();
$("#src3").hide();
}else{
$("#src1").hide();
$("#src2").hide();
$("#src3").hide();
}
});
});
function save(){
$.post('<?php echo htmlentities((string) $config["admin_route"]); ?>yunzer/menuadd',$('form').serialize(),function(res){
if(res.code>0){
layer.msg(res.msg,{'icon':2});
}else{
layer.msg(res.msg,{'icon':1});
setTimeout(function(){parent.window.location.reload();},1000);
}
},'json');
}
</script>
</body>
</html>
<script type="text/javascript">
// 显示图片
function show_img(obj){
var imgurl = $(obj).attr('src');
var res = getMousePos();
var html = '<div style="background:#fff;position:absolute;width:200px;border:solid 1px #cdcdcd;border-radius:6px;padding:2px;left:'+res.x+'px;top:'+res.y+'px;z-index:1000" id="preview">\
<img style="width:100%;border-radius:6px;" src="'+imgurl+'">\
</div>';
$('body').append(html);
}
// 隐藏图片
function hide_img(){
$('#preview').remove();
}
// 图片位置计算
function getMousePos(event) {
var e = event || window.event;
var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
var x = e.pageX || e.clientX + scrollX;
var y = e.pageY || e.clientY + scrollY;
return { 'x': x, 'y': y };
}
// 删除图片
function deleteImage(path,obj){
$(obj).closest('.upload_pic_li').remove();
}
</script>

View File

@ -1,4 +1,4 @@
<?php /*a:1:{s:49:"E:\Demo\PHP\yunzer\app\admin\view\index\index.php";i:1747402501;}*/ ?>
<?php /*a:1:{s:49:"E:\Demo\PHP\yunzer\app\admin\view\index\index.php";i:1747582419;}*/ ?>
<!DOCTYPE html>
<html>
@ -110,7 +110,7 @@
<li class="layui-nav-item" data-name="index/welcome">
<a href="javascript:;" lay-tips="工作台" lay-direction="2"
onclick="menuFire('index/welcome',1)">
<i class="layui-icon layui-icon-home" style="margin-top: -30px;"></i>
<i class="layui-icon layui-icon-home" style="margin-top: -20px;"></i>
<cite>工作台</cite>
</a>
</li>

View File

@ -0,0 +1,241 @@
<?php /*a:3:{s:53:"E:\Demo\PHP\yunzer\app\admin\view\yunzer\menuinfo.php";i:1747402501;s:51:"E:\Demo\PHP\yunzer\app\admin\view\public\header.php";i:1746890051;s:49:"E:\Demo\PHP\yunzer\app\admin\view\public\tail.php";i:1745855804;}*/ ?>
<!DOCTYPE html>
<html>
<head>
<title><?php echo htmlentities((string) $config['admin_name']); ?></title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="stylesheet" type="text/css" href="/static/layui/css/layui.css" media="all"/>
<link rel="stylesheet" type="text/css" href="/static/css/moban.css" media="all"/>
<link rel="stylesheet" type="text/css" href="/static/css/wangeditor.css" media="all"/>
<style type="text/css">
.header span{background:#009688;margin-left:30px;padding:10px;color:#ffffff;}
.header div{border-bottom:solid 2px #009688;margin-top: 8px;}
.header button{float:right;margin-top:-5px;}
.pagination {
display: inline-block;
padding-left: 0;
margin: 20px 0;
border-radius: 4px;
}
.pagination > li {
display: inline;
}
.pagination > li > a,
.pagination > li > span {
position: relative;
float: left;
padding: 6px 12px;
margin-left: -1px;
line-height: 1.42857143;
color: #337ab7;
text-decoration: none;
background-color: #fff;
border: 1px solid #ddd;
}
.pagination > li:first-child > a,
.pagination > li:first-child > span {
margin-left: 0;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
.pagination > li:last-child > a,
.pagination > li:last-child > span {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.pagination > li > a:hover,
.pagination > li > span:hover,
.pagination > li > a:focus,
.pagination > li > span:focus {
z-index: 2;
color: #23527c;
background-color: #eee;
border-color: #ddd;
}
.pagination > .active > a,
.pagination > .active > span,
.pagination > .active > a:hover,
.pagination > .active > span:hover,
.pagination > .active > a:focus,
.pagination > .active > span:focus {
z-index: 3;
color: #fff;
cursor: default;
background-color: #337ab7;
border-color: #337ab7;
}
.pagination > .disabled > span,
.pagination > .disabled > span:hover,
.pagination > .disabled > span:focus,
.pagination > .disabled > a,
.pagination > .disabled > a:hover,
.pagination > .disabled > a:focus {
color: #777;
cursor: not-allowed;
background-color: #fff;
border-color: #ddd;
}
.close-img { background: url(/static/images/close_img.png); background-size: 20px 20px; width:20px; height: 20px; position: absolute; right: 5px; top: 5px; z-index: 2;}
</style>
<script type="text/javascript" src="/static/layui/layui.js"></script>
<script type="text/javascript">
layui.use(['layer','form','table','laydate','element','upload'],function(){
layer = layui.layer; // layui 弹框
form = layui.form; // layui form表单
table = layui.table; // layui 表格
laydate = layui.laydate; // layui 时间框
element = layui.element; // layui element
upload = layui.upload; // layui 上传
$ = layui.jquery; // layui jquery
})
</script>
</head>
<body style="padding:10px; box-sizing: border-box;">
<div class="config-container">
<!-- 页面头部样式 -->
<div class="config-header" style="display: flex;flex-direction: column;flex-wrap: wrap;align-items: flex-start;">
<div class="maintitle">
<i class="layui-icon layui-icon-picture"></i>
<span>菜单管理</span>
</div>
<div style="display: flex;align-items: flex-start;flex-direction: column;gap: 15px;margin-bottom: 10px;">
<div>
<button class="layui-btn layui-bg-blue" onclick="add()">
<i class="layui-icon layui-icon-add-1"></i>添加菜单
</button>
<button type="button" class="layui-btn layui-btn-primary layui-border-blue" onclick="refresh()">
<i class="layui-icon layui-icon-refresh"></i>刷新
</button>
</div>
</div>
</div>
<div id="test7" class="demo-tree"></div>
<table class="layui-table">
<thead>
<tr>
<th style="text-align:center">类型</th>
<th style="text-align:center">菜单名</th>
<th style="text-align:center">图标</th>
<th style="text-align:center">排序</th>
<th style="text-align:center">状态</th>
<th style="text-align:center">操作</th>
</tr>
</thead>
<tbody>
<?php if(is_array($lists) || $lists instanceof \think\Collection || $lists instanceof \think\Paginator): $i = 0; $__LIST__ = $lists;if( count($__LIST__)==0 ) : echo "" ;else: foreach($__LIST__ as $key=>$vo): $mod = ($i % 2 );++$i;?>
<tr>
<td align="center">
<?php if(($vo['type']==1)): ?>
功能模块:<?php echo htmlentities((string) $vo['src']); elseif(($vo['type']==2)): ?>
超链接:<?php echo htmlentities((string) $vo['src']); else: ?>
顶级
<?php endif; ?>
</td>
<td align="center"><?php echo htmlentities((string) $vo['label']); ?></td>
<td align="center"><i class="layui-icon <?php echo htmlentities((string) $vo['icon_class']); ?>"></i> <?php echo htmlentities((string) $vo['icon_class']); ?></td>
<td align="center"><?php echo htmlentities((string) $vo['sort']); ?></td>
<td align="center"><?php echo $vo['status']==1 ? '开启' : '<span style="color:red;">禁用</span>'; ?></td>
<td align="center">
<?php if(($vo['type'] == 0)): ?>
<button type="button" class="layui-btn layui-btn-xs layui-btn-normal"
onclick="buttonInfo(<?php echo htmlentities((string) $vo['smid']); ?>)">下级菜单</button>
<?php endif; ?>
<button type="button" class="layui-btn layui-btn-xs layui-btn-primary" onclick="edit(<?php echo htmlentities((string) $vo['smid']); ?>)">
<i class="layui-icon layui-icon-edit"></i>编辑
</button>
<button type="button" class="layui-btn layui-btn-xs layui-btn-primary" onclick="del(<?php echo htmlentities((string) $vo['smid']); ?>)">
<i class="layui-icon layui-icon-delete"></i>删除
</button>
</td>
</tr>
<?php endforeach; endif; else: echo "" ;endif; ?>
</tbody>
</table>
</div>
<script type="text/javascript">
layui.use(['layer'], function () {
layer = layui.layer;
$ = layui.jquery;
});
// 添加
function add() {
layer.open({
type: 2,
title: '添加菜单',
shade: 0.3,
area: ['550px', '550px'],
content: '<?php echo htmlentities((string) $config["admin_route"]); ?>yunzer/menuadd'
});
}
// 编辑
function edit(smid) {
layer.open({
type: 2,
title: '编辑菜单',
shade: 0.3,
area: ['550px', '550px'],
content: '<?php echo htmlentities((string) $config["admin_route"]); ?>yunzer/menuedit?smid=' + smid
});
}
// 删除
function del(smid) {
layer.confirm('确定要删除吗?', {
icon: 3,
btn: ['确定', '取消']
}, function () {
$.post('<?php echo htmlentities((string) $config["admin_route"]); ?>yunzer/menudel', { 'smid': smid }, function (res) {
if (res.code > 0) {
layer.alert(res.msg, { icon: 2 });
} else {
layer.msg(res.msg, { icon: 1 });
setTimeout(function () { window.location.reload(); }, 1000);
}
}, 'json');
});
}
// 按钮列表
function buttonInfo(smid) {
window.location.href = "<?php echo htmlentities((string) $config['admin_route']); ?>yunzer/buttoninfo?smid=" + smid;
}
//刷新列表
function refresh() {
window.location.reload();
}
</script>
</body>
</html>
<script type="text/javascript">
// 显示图片
function show_img(obj){
var imgurl = $(obj).attr('src');
var res = getMousePos();
var html = '<div style="background:#fff;position:absolute;width:200px;border:solid 1px #cdcdcd;border-radius:6px;padding:2px;left:'+res.x+'px;top:'+res.y+'px;z-index:1000" id="preview">\
<img style="width:100%;border-radius:6px;" src="'+imgurl+'">\
</div>';
$('body').append(html);
}
// 隐藏图片
function hide_img(){
$('#preview').remove();
}
// 图片位置计算
function getMousePos(event) {
var e = event || window.event;
var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
var x = e.pageX || e.clientX + scrollX;
var y = e.pageY || e.clientY + scrollY;
return { 'x': x, 'y': y };
}
// 删除图片
function deleteImage(path,obj){
$(obj).closest('.upload_pic_li').remove();
}
</script>

View File

@ -0,0 +1,221 @@
<?php /*a:3:{s:55:"E:\Demo\PHP\yunzer\app\admin\view\yunzer\buttonedit.php";i:1745855804;s:51:"E:\Demo\PHP\yunzer\app\admin\view\public\header.php";i:1746890051;s:49:"E:\Demo\PHP\yunzer\app\admin\view\public\tail.php";i:1745855804;}*/ ?>
<!DOCTYPE html>
<html>
<head>
<title><?php echo htmlentities((string) $config['admin_name']); ?></title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="stylesheet" type="text/css" href="/static/layui/css/layui.css" media="all"/>
<link rel="stylesheet" type="text/css" href="/static/css/moban.css" media="all"/>
<link rel="stylesheet" type="text/css" href="/static/css/wangeditor.css" media="all"/>
<style type="text/css">
.header span{background:#009688;margin-left:30px;padding:10px;color:#ffffff;}
.header div{border-bottom:solid 2px #009688;margin-top: 8px;}
.header button{float:right;margin-top:-5px;}
.pagination {
display: inline-block;
padding-left: 0;
margin: 20px 0;
border-radius: 4px;
}
.pagination > li {
display: inline;
}
.pagination > li > a,
.pagination > li > span {
position: relative;
float: left;
padding: 6px 12px;
margin-left: -1px;
line-height: 1.42857143;
color: #337ab7;
text-decoration: none;
background-color: #fff;
border: 1px solid #ddd;
}
.pagination > li:first-child > a,
.pagination > li:first-child > span {
margin-left: 0;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
.pagination > li:last-child > a,
.pagination > li:last-child > span {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.pagination > li > a:hover,
.pagination > li > span:hover,
.pagination > li > a:focus,
.pagination > li > span:focus {
z-index: 2;
color: #23527c;
background-color: #eee;
border-color: #ddd;
}
.pagination > .active > a,
.pagination > .active > span,
.pagination > .active > a:hover,
.pagination > .active > span:hover,
.pagination > .active > a:focus,
.pagination > .active > span:focus {
z-index: 3;
color: #fff;
cursor: default;
background-color: #337ab7;
border-color: #337ab7;
}
.pagination > .disabled > span,
.pagination > .disabled > span:hover,
.pagination > .disabled > span:focus,
.pagination > .disabled > a,
.pagination > .disabled > a:hover,
.pagination > .disabled > a:focus {
color: #777;
cursor: not-allowed;
background-color: #fff;
border-color: #ddd;
}
.close-img { background: url(/static/images/close_img.png); background-size: 20px 20px; width:20px; height: 20px; position: absolute; right: 5px; top: 5px; z-index: 2;}
</style>
<script type="text/javascript" src="/static/layui/layui.js"></script>
<script type="text/javascript">
layui.use(['layer','form','table','laydate','element','upload'],function(){
layer = layui.layer; // layui 弹框
form = layui.form; // layui form表单
table = layui.table; // layui 表格
laydate = layui.laydate; // layui 时间框
element = layui.element; // layui element
upload = layui.upload; // layui 上传
$ = layui.jquery; // layui jquery
})
</script>
</head>
<body style="padding:10px; box-sizing: border-box;">
<form class="layui-form">
<input type="hidden" name="smid" value="<?php echo htmlentities((string) $lists['smid']); ?>">
<div class="layui-form-item">
<label class="layui-form-label">按钮名</label>
<div class="layui-input-block">
<input type="text" class="layui-input" name="label" placeholder="请输入按钮名" value="<?php echo htmlentities((string) $lists['label']); ?>">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">图标</label>
<div class="layui-input-block">
<select name="icon_class" lay-verify="required" lay-search="">
<option value="">请输入layui图标</option>
<?php foreach($iconfont as $icon_v): ?>
<option value="<?php echo htmlentities((string) $icon_v['icon_css']); ?>" <?php if(($icon_v['icon_css'] == $lists['icon_class'])): ?>selected<?php endif; ?>><?php echo htmlentities((string) $icon_v['icon_css']); ?> <?php echo htmlentities((string) $icon_v['icon_name']); ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">类型</label>
<div class="layui-input-inline">
<select name="type" lay-filter="type">
<option value='1' <?php echo $lists['type']==1 ? 'selected' : ''; ?>>内部代码</option>
<option value='2' <?php echo $lists['type']==2 ? 'selected' : ''; ?>>超链接</option>
</select>
</div>
</div>
<div class="layui-form-item" <?php echo $lists['type']==1 ? 'style="display : none;"':''; ?> id="src1">
<label class="layui-form-label">内部代码</label>
<div class="layui-input-block">
<input type="text" class="layui-input" name="src1" placeholder="请输入:/项目/模块/方法" <?php if($lists['type']==1): ?>value="<?php echo htmlentities((string) $lists['src']); ?>"<?php endif; ?>>
</div>
</div>
<div class="layui-form-item" <?php echo $lists['type']==2 ? 'style="display : none;"':''; ?> id="src2">
<label class="layui-form-label">链接地址</label>
<div class="layui-input-block">
<input type="text" class="layui-input" name="src2" placeholder="请输入http网址" <?php if($lists['type']==2): ?>value="<?php echo htmlentities((string) $lists['src']); ?>"<?php endif; ?>>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">排序</label>
<div class="layui-input-block">
<input type="number" class="layui-input" name="sort" placeholder="值越大越靠前" value="<?php echo htmlentities((string) $lists['sort']); ?>">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">状态</label>
<div class="layui-input-block">
<input type="radio" name="status" value="1" title="开启" <?php echo $lists['status']==1 ? 'checked' : ''; ?>>
<input type="radio" name="status" value="0" title="禁用" <?php echo $lists['status']==0 ? 'checked' : ''; ?>>
</div>
</div>
</form>
<div class="layui-form-item" style="margin-top:10px;">
<div class="layui-input-block">
<button type="button" class="layui-btn" onclick="save()">保存</button>
</div>
</div>
<script type="text/javascript">
layui.use(['layer','form'],function(){
form = layui.form;
layer = layui.layer;
$ = layui.jquery;
type(<?php echo htmlentities((string) $lists['type']); ?>);
form.on('select(type)', function(data){
type(data.value);
});
});
function type(value){
if(value == 1){
$("#src1").show();
$("#src2").hide();
$("#src3").hide();
}else if(value == 2){
$("#src1").hide();
$("#src2").show();
$("#src3").hide();
}else{
$("#src1").show();
$("#src2").hide();
$("#src3").hide();
}
}
function save(){
$.post('<?php echo htmlentities((string) $config["admin_route"]); ?>yunzer/buttonedit',$('form').serialize(),function(res){
if(res.code>0){
layer.msg(res.msg,{'icon':2});
}else{
layer.msg(res.msg,{'icon':1});
setTimeout(function(){parent.window.location.reload();},1000);
}
},'json');
}
</script>
</body>
</html>
<script type="text/javascript">
// 显示图片
function show_img(obj){
var imgurl = $(obj).attr('src');
var res = getMousePos();
var html = '<div style="background:#fff;position:absolute;width:200px;border:solid 1px #cdcdcd;border-radius:6px;padding:2px;left:'+res.x+'px;top:'+res.y+'px;z-index:1000" id="preview">\
<img style="width:100%;border-radius:6px;" src="'+imgurl+'">\
</div>';
$('body').append(html);
}
// 隐藏图片
function hide_img(){
$('#preview').remove();
}
// 图片位置计算
function getMousePos(event) {
var e = event || window.event;
var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
var x = e.pageX || e.clientX + scrollX;
var y = e.pageY || e.clientY + scrollY;
return { 'x': x, 'y': y };
}
// 删除图片
function deleteImage(path,obj){
$(obj).closest('.upload_pic_li').remove();
}
</script>

View File

@ -0,0 +1,217 @@
<?php /*a:3:{s:54:"E:\Demo\PHP\yunzer\app\admin\view\yunzer\buttonadd.php";i:1745855804;s:51:"E:\Demo\PHP\yunzer\app\admin\view\public\header.php";i:1746890051;s:49:"E:\Demo\PHP\yunzer\app\admin\view\public\tail.php";i:1745855804;}*/ ?>
<!DOCTYPE html>
<html>
<head>
<title><?php echo htmlentities((string) $config['admin_name']); ?></title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="stylesheet" type="text/css" href="/static/layui/css/layui.css" media="all"/>
<link rel="stylesheet" type="text/css" href="/static/css/moban.css" media="all"/>
<link rel="stylesheet" type="text/css" href="/static/css/wangeditor.css" media="all"/>
<style type="text/css">
.header span{background:#009688;margin-left:30px;padding:10px;color:#ffffff;}
.header div{border-bottom:solid 2px #009688;margin-top: 8px;}
.header button{float:right;margin-top:-5px;}
.pagination {
display: inline-block;
padding-left: 0;
margin: 20px 0;
border-radius: 4px;
}
.pagination > li {
display: inline;
}
.pagination > li > a,
.pagination > li > span {
position: relative;
float: left;
padding: 6px 12px;
margin-left: -1px;
line-height: 1.42857143;
color: #337ab7;
text-decoration: none;
background-color: #fff;
border: 1px solid #ddd;
}
.pagination > li:first-child > a,
.pagination > li:first-child > span {
margin-left: 0;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
.pagination > li:last-child > a,
.pagination > li:last-child > span {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.pagination > li > a:hover,
.pagination > li > span:hover,
.pagination > li > a:focus,
.pagination > li > span:focus {
z-index: 2;
color: #23527c;
background-color: #eee;
border-color: #ddd;
}
.pagination > .active > a,
.pagination > .active > span,
.pagination > .active > a:hover,
.pagination > .active > span:hover,
.pagination > .active > a:focus,
.pagination > .active > span:focus {
z-index: 3;
color: #fff;
cursor: default;
background-color: #337ab7;
border-color: #337ab7;
}
.pagination > .disabled > span,
.pagination > .disabled > span:hover,
.pagination > .disabled > span:focus,
.pagination > .disabled > a,
.pagination > .disabled > a:hover,
.pagination > .disabled > a:focus {
color: #777;
cursor: not-allowed;
background-color: #fff;
border-color: #ddd;
}
.close-img { background: url(/static/images/close_img.png); background-size: 20px 20px; width:20px; height: 20px; position: absolute; right: 5px; top: 5px; z-index: 2;}
</style>
<script type="text/javascript" src="/static/layui/layui.js"></script>
<script type="text/javascript">
layui.use(['layer','form','table','laydate','element','upload'],function(){
layer = layui.layer; // layui 弹框
form = layui.form; // layui form表单
table = layui.table; // layui 表格
laydate = layui.laydate; // layui 时间框
element = layui.element; // layui element
upload = layui.upload; // layui 上传
$ = layui.jquery; // layui jquery
})
</script>
</head>
<body style="padding:10px; box-sizing: border-box;">
<form class="layui-form">
<input type="hidden" name="smid" value="<?php echo htmlentities((string) $smid); ?>">
<div class="layui-form-item">
<label class="layui-form-label">按钮名</label>
<div class="layui-input-block">
<input type="text" class="layui-input" name="label" placeholder="请输入按钮名">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">图标</label>
<div class="layui-input-block">
<select name="icon_class" lay-verify="required" lay-search="">
<option value="">请输入layui图标</option>
<?php foreach($iconfont as $icon_v): ?>
<option value="<?php echo htmlentities((string) $icon_v['icon_css']); ?>"><?php echo htmlentities((string) $icon_v['icon_css']); ?> <?php echo htmlentities((string) $icon_v['icon_name']); ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">类型</label>
<div class="layui-input-inline">
<select name="type" lay-filter="type">
<option value='1' selected>内部代码</option>
<option value='2'>超链接</option>
</select>
</div>
</div>
<div class="layui-form-item" id="src1">
<label class="layui-form-label">内部代码</label>
<div class="layui-input-block">
<input type="text" class="layui-input" name="src1" placeholder="请输入:模块/方法">
</div>
</div>
<div class="layui-form-item" style="display:none;" id="src2">
<label class="layui-form-label">链接地址</label>
<div class="layui-input-block">
<input type="text" class="layui-input" name="src2" placeholder="请输入http网址">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">排序</label>
<div class="layui-input-block">
<input type="number" class="layui-input" name="sort" placeholder="值越大越靠前">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">状态</label>
<div class="layui-input-block">
<input type="radio" name="status" value="1" title="开启" checked>
<input type="radio" name="status" value="0" title="禁用">
</div>
</div>
</form>
<div class="layui-form-item" style="margin-top:10px;">
<div class="layui-input-block">
<button type="button" class="layui-btn" onclick="save()">保存</button>
</div>
</div>
<script type="text/javascript">
layui.use(['layer','form'],function(){
var form = layui.form;
layer = layui.layer;
$ = layui.jquery;
form.on('select(type)', function(data){
if(data.value == 1){
$("#src1").show();
$("#src2").hide();
$("#src3").hide();
}else if(data.value == 2){
$("#src1").hide();
$("#src2").show();
$("#src3").hide();
}else{
$("#src1").show();
$("#src2").hide();
$("#src3").hide();
}
});
});
function save(){
$.post('<?php echo htmlentities((string) $config["admin_route"]); ?>yunzer/buttonadd',$('form').serialize(),function(res){
if(res.code>0){
layer.msg(res.msg,{'icon':2});
}else{
layer.msg(res.msg,{'icon':1});
setTimeout(function(){parent.window.location.reload();},1000);
}
},'json');
}
</script>
</body>
</html>
<script type="text/javascript">
// 显示图片
function show_img(obj){
var imgurl = $(obj).attr('src');
var res = getMousePos();
var html = '<div style="background:#fff;position:absolute;width:200px;border:solid 1px #cdcdcd;border-radius:6px;padding:2px;left:'+res.x+'px;top:'+res.y+'px;z-index:1000" id="preview">\
<img style="width:100%;border-radius:6px;" src="'+imgurl+'">\
</div>';
$('body').append(html);
}
// 隐藏图片
function hide_img(){
$('#preview').remove();
}
// 图片位置计算
function getMousePos(event) {
var e = event || window.event;
var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
var x = e.pageX || e.clientX + scrollX;
var y = e.pageY || e.clientY + scrollY;
return { 'x': x, 'y': y };
}
// 删除图片
function deleteImage(path,obj){
$(obj).closest('.upload_pic_li').remove();
}
</script>

View File

@ -0,0 +1,343 @@
<?php /*a:2:{s:56:"E:\Demo\PHP\yunzer\app\admin\view\yunzeradmin\banner.php";i:1747402501;s:51:"E:\Demo\PHP\yunzer\app\admin\view\public\header.php";i:1746890051;}*/ ?>
<!DOCTYPE html>
<html>
<head>
<title><?php echo htmlentities((string) $config['admin_name']); ?></title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="stylesheet" type="text/css" href="/static/layui/css/layui.css" media="all"/>
<link rel="stylesheet" type="text/css" href="/static/css/moban.css" media="all"/>
<link rel="stylesheet" type="text/css" href="/static/css/wangeditor.css" media="all"/>
<style type="text/css">
.header span{background:#009688;margin-left:30px;padding:10px;color:#ffffff;}
.header div{border-bottom:solid 2px #009688;margin-top: 8px;}
.header button{float:right;margin-top:-5px;}
.pagination {
display: inline-block;
padding-left: 0;
margin: 20px 0;
border-radius: 4px;
}
.pagination > li {
display: inline;
}
.pagination > li > a,
.pagination > li > span {
position: relative;
float: left;
padding: 6px 12px;
margin-left: -1px;
line-height: 1.42857143;
color: #337ab7;
text-decoration: none;
background-color: #fff;
border: 1px solid #ddd;
}
.pagination > li:first-child > a,
.pagination > li:first-child > span {
margin-left: 0;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
.pagination > li:last-child > a,
.pagination > li:last-child > span {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.pagination > li > a:hover,
.pagination > li > span:hover,
.pagination > li > a:focus,
.pagination > li > span:focus {
z-index: 2;
color: #23527c;
background-color: #eee;
border-color: #ddd;
}
.pagination > .active > a,
.pagination > .active > span,
.pagination > .active > a:hover,
.pagination > .active > span:hover,
.pagination > .active > a:focus,
.pagination > .active > span:focus {
z-index: 3;
color: #fff;
cursor: default;
background-color: #337ab7;
border-color: #337ab7;
}
.pagination > .disabled > span,
.pagination > .disabled > span:hover,
.pagination > .disabled > span:focus,
.pagination > .disabled > a,
.pagination > .disabled > a:hover,
.pagination > .disabled > a:focus {
color: #777;
cursor: not-allowed;
background-color: #fff;
border-color: #ddd;
}
.close-img { background: url(/static/images/close_img.png); background-size: 20px 20px; width:20px; height: 20px; position: absolute; right: 5px; top: 5px; z-index: 2;}
</style>
<script type="text/javascript" src="/static/layui/layui.js"></script>
<script type="text/javascript">
layui.use(['layer','form','table','laydate','element','upload'],function(){
layer = layui.layer; // layui 弹框
form = layui.form; // layui form表单
table = layui.table; // layui 表格
laydate = layui.laydate; // layui 时间框
element = layui.element; // layui element
upload = layui.upload; // layui 上传
$ = layui.jquery; // layui jquery
})
</script>
</head>
<body style="padding:10px; box-sizing: border-box;">
<!-- 主体内容 -->
<div class="config-container">
<!-- 页面头部样式 -->
<div class="config-header" style="display: flex;flex-direction: column;flex-wrap: wrap;align-items: flex-start;">
<div class="maintitle">
<i class="layui-icon layui-icon-picture"></i>
<span>Banner管理</span>
</div>
<div style="display: flex;align-items: flex-start;flex-direction: column;gap: 15px;margin-bottom: 10px;">
<div>
<button class="layui-btn layui-bg-blue" id="addBanner">
<i class="layui-icon layui-icon-add-1"></i>添加Banner
</button>
<button type="button" class="layui-btn layui-btn-primary layui-border-blue" onclick="refresh()">
<i class="layui-icon layui-icon-refresh"></i>刷新
</button>
</div>
</div>
</div>
<div class="layui-fluid">
<div class="layui-card">
<div class="layui-card-body">
<table id="bannerTable" lay-filter="bannerTable"></table>
</div>
</div>
</div>
<!-- Banner表单 -->
<div id="bannerForm" style="display: none;">
<form class="layui-form banner-form">
<input type="hidden" name="id">
<div class="layui-form-item">
<label class="layui-form-label">标题</label>
<div class="layui-input-block">
<input type="text" name="title" required lay-verify="required" placeholder="请输入标题"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">图片</label>
<div class="layui-input-block">
<div class="layui-upload-drag" id="uploadImage">
<i class="layui-icon layui-icon-upload"></i>
<p>点击上传或拖拽图片至此处</p>
<div id="uploadPreview" style="display: none;">
<img src="" alt="Banner图片" class="banner-upload-preview">
</div>
</div>
<input type="hidden" name="image" id="imageInput">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">链接</label>
<div class="layui-input-block">
<input type="text" name="url" placeholder="请输入链接地址" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">排序</label>
<div class="layui-input-block">
<input type="number" name="sort" value="0" class="layui-input" placeholder="数字越大越靠前">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">状态</label>
<div class="layui-input-block">
<input type="radio" name="status" value="1" title="启用" checked>
<input type="radio" name="status" value="0" title="禁用">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="saveBanner">保存</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
</div>
</div>
<script>
layui.use(['table', 'form', 'upload', 'layer'], function () {
var table = layui.table,
form = layui.form,
upload = layui.upload,
layer = layui.layer;
// 表格列配置
var tableColumns = [[
{ field: 'id', title: 'ID', width: 80, align: 'center' },
{ field: 'title', title: '标题', align: 'center' },
{
field: 'image', title: '图片', width: 180, align: 'center', templet: function (d) {
return '<img src="' + d.image + '" class="banner-preview-img" onclick="previewImage(\'' + d.image + '\')">';
}
},
{ field: 'url', title: '链接', align: 'center', width: 300 },
{ field: 'sort', title: '排序', align: 'center', width: 100, sort: true },
{ field: 'create_time', title: '创建时间', align: 'center', width: 180, sort: true },
{
title: '操作', align: 'center', width: 240, templet: function (d) {
return '<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>' +
'<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>';
}
}
]];
// 初始化表格
table.render({
elem: '#bannerTable',
url: '/admin/yunzeradmin/bannerlist',
method: 'get',
page: true,
cols: tableColumns,
limit: 10,
limits: [10, 20, 30, 50],
text: { none: '暂无相关数据' }
});
// 上传组件配置
var uploadConfig = {
elem: '#uploadImage',
url: '/admin/upload/image',
accept: 'images',
acceptMime: 'image/*',
done: function (res) {
if (res.code === 0) {
$('#uploadPreview').show().find('img').attr('src', res.data.url);
$('#imageInput').val(res.data.url);
layer.msg('上传成功');
} else {
layer.msg('上传失败');
}
}
};
// 初始化上传组件
upload.render(uploadConfig);
// 监听表格工具条事件
table.on('tool(bannerTable)', function (obj) {
var data = obj.data;
if (obj.event === 'edit') {
showBannerForm(data);
} else if (obj.event === 'del') {
layer.confirm('确定删除此Banner', function (index) {
deleteBanner(data.id, obj);
layer.close(index);
});
}
});
// 添加Banner按钮点击事件
$('#addBanner').on('click', function () {
showBannerForm();
});
// 监听表单提交
form.on('submit(saveBanner)', function (data) {
var url = data.field.id ? '/admin/yunzeradmin/banneredit' : '/admin/yunzeradmin/banneradd';
$.post(url, data.field, function (res) {
if (res.code === 0) {
layer.closeAll('page');
table.reload('bannerTable');
layer.msg('保存成功');
} else {
layer.msg(res.msg);
}
});
return false;
});
// 显示Banner表单
function showBannerForm(data) {
layer.open({
type: 1,
title: data ? '编辑Banner' : '添加Banner',
content: $('#bannerForm'),
area: ['800px', '600px'],
success: function (layero) {
form.render();
if (data) {
form.val('bannerForm', data);
if (data.image) {
$('#uploadPreview').show().find('img').attr('src', data.image);
$('#imageInput').val(data.image);
}
}
}
});
}
// 删除Banner
function deleteBanner(id, obj) {
$.post('/admin/yunzeradmin/bannerdel', { id: id }, function (res) {
if (res.code === 0) {
obj.del();
layer.msg('删除成功');
} else {
layer.msg(res.msg);
}
});
}
});
// 预览图片
function previewImage(url) {
layer.photos({
photos: {
"data": [{
"src": url
}]
}
});
}
</script>
<!-- 页面样式 -->
<style>
.layui-table-cell {
height: 40px;
line-height: 40px;
}
.layui-table-cell img {
height: 36px;
width: auto;
max-width: 80px;
}
.banner-preview-img {
max-width: 80px;
cursor: pointer;
}
.banner-form {
padding: 20px;
}
.banner-upload-preview {
max-width: 100%;
margin-top: 10px;
}
</style>

View File

@ -1,4 +1,4 @@
<?php /*a:5:{s:52:"E:\Demo\PHP\yunzer\app\index\view\program\detail.php";i:1747417030;s:52:"E:\Demo\PHP\yunzer\app\index\view\component\head.php";i:1746890051;s:61:"E:\Demo\PHP\yunzer\app\index\view\component\header-simple.php";i:1747415782;s:54:"E:\Demo\PHP\yunzer\app\index\view\component\footer.php";i:1747402501;s:52:"E:\Demo\PHP\yunzer\app\index\view\component\foot.php";i:1746808046;}*/ ?>
<?php /*a:5:{s:52:"E:\Demo\PHP\yunzer\app\index\view\program\detail.php";i:1747417109;s:52:"E:\Demo\PHP\yunzer\app\index\view\component\head.php";i:1746890051;s:61:"E:\Demo\PHP\yunzer\app\index\view\component\header-simple.php";i:1747415782;s:54:"E:\Demo\PHP\yunzer\app\index\view\component\footer.php";i:1747402501;s:52:"E:\Demo\PHP\yunzer\app\index\view\component\foot.php";i:1746808046;}*/ ?>
<!DOCTYPE html>
<html>