李寻欢 bd203141d8
All checks were successful
BuildImage / build-image (push) Successful in 1m55s
🎨 逻辑优化
2025-04-03 14:35:00 +08:00

322 lines
13 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

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

<div class="space-y-6">
<!-- 页面标题和操作栏 -->
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-4">
<h1 class="text-2xl font-semibold text-gray-800">机器人管理</h1>
<a href="/admin/robots/new" class="inline-flex items-center justify-center px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-gray-800 hover:bg-gray-700 transition-colors">
<i class="fas fa-plus mr-2"></i> 创建机器人
</a>
</div>
<!-- 搜索过滤栏 -->
<div class="clean-card p-4">
<div class="flex flex-col md:flex-row md:items-center gap-4">
<div class="flex-1">
<div class="relative rounded-md">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<i class="fas fa-search text-gray-400"></i>
</div>
<input id="robot-search" type="text" placeholder="搜索机器人..." class="block w-full pl-10 pr-3 py-2 border border-gray-200 rounded-md focus:ring-1 focus:ring-gray-200 focus:border-gray-300">
</div>
</div>
<div class="flex flex-wrap gap-2">
<button data-filter="all" class="filter-btn px-4 py-2 rounded-md text-sm border bg-gray-800 text-white">
全部
</button>
<button data-filter="online" class="filter-btn px-4 py-2 rounded-md text-sm border border-gray-200 bg-white text-gray-700 hover:bg-gray-50">
在线
</button>
<button data-filter="offline" class="filter-btn px-4 py-2 rounded-md text-sm border border-gray-200 bg-white text-gray-700 hover:bg-gray-50">
离线
</button>
<button data-filter="error" class="filter-btn px-4 py-2 rounded-md text-sm border border-gray-200 bg-white text-gray-700 hover:bg-gray-50">
错误
</button>
</div>
</div>
</div>
<!-- 统计信息 -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div class="clean-card px-6 py-4 flex items-center">
<div class="w-12 h-12 rounded-full bg-emerald-50 border border-emerald-100 flex items-center justify-center text-emerald-500 mr-4">
<i class="fas fa-check-circle text-xl"></i>
</div>
<div>
<p class="text-sm text-gray-600">在线机器人</p>
<p class="text-2xl font-semibold text-gray-800" id="online-count">{{.OnlineCount}}</p>
</div>
</div>
<div class="clean-card px-6 py-4 flex items-center">
<div class="w-12 h-12 rounded-full bg-blue-50 border border-blue-100 flex items-center justify-center text-blue-500 mr-4">
<i class="fas fa-robot text-xl"></i>
</div>
<div>
<p class="text-sm text-gray-600">总机器人</p>
<p class="text-2xl font-semibold text-gray-800" id="filtered-count">{{len .Robots}}</p>
</div>
</div>
<div class="clean-card px-6 py-4 flex items-center">
<div class="w-12 h-12 rounded-full bg-amber-50 border border-amber-100 flex items-center justify-center text-amber-500 mr-4">
<i class="fas fa-power-off text-xl"></i>
</div>
<div>
<p class="text-sm text-gray-600">离线机器人</p>
<p class="text-2xl font-semibold text-gray-800" id="offline-count">{{.OfflineCount}}</p>
</div>
</div>
</div>
<!-- 机器人卡片列表 -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{{if .Robots}}
{{range .Robots}}
<div class="robot-card bg-white rounded-lg shadow-sm overflow-hidden border border-gray-50 transition-all duration-300 hover:shadow-md">
<!-- 状态指示条 -->
<div class="h-1 {{if eq .Status "online"}}bg-green-500{{else}}bg-gray-300{{end}} w-full"></div>
<!-- 卡片内容 -->
<div class="p-6">
<div class="flex items-center">
<div class="w-10 h-10 rounded-full {{if eq .Status "online"}}bg-green-100 text-green-600{{else}}bg-gray-100 text-gray-500{{end}} flex items-center justify-center mr-4">
<i class="fas fa-robot text-lg"></i>
</div>
<div>
<h3 class="text-lg font-medium text-gray-800 robot-name">{{.Nickname}}</h3>
<div class="flex items-center mt-1">
<span class="inline-flex items-center px-2 py-0.5 text-xs font-medium rounded-full {{if eq .Status "online"}}bg-green-100 text-green-800{{else}}bg-gray-100 text-gray-700{{end}}">
{{if eq .Status "online"}}在线{{else}}离线{{end}}
</span>
{{if .WechatID}}
<span class="ml-2 text-xs text-gray-500">{{.WechatID}}</span>
{{end}}
</div>
</div>
</div>
<!-- 机器人信息 -->
<div class="mt-4 border-t border-gray-50 pt-4">
<div class="flex justify-between items-center text-sm text-gray-500 mb-2">
<span>容器ID</span>
<span class="font-mono text-xs truncate max-w-[120px]">{{.ContainerID}}</span>
</div>
<div class="flex justify-between items-center text-sm text-gray-500">
<span>创建时间</span>
<span>{{.CreatedAt.Format "01-02 15:04"}}</span>
</div>
</div>
</div>
<!-- 操作区域 -->
<div class="bg-gray-50 px-6 py-3 flex justify-between items-center">
<span class="text-xs text-gray-500">{{if eq .Status "online"}}运行中{{else}}已停止{{end}}</span>
<div class="flex space-x-2">
<a href="/admin/robots/{{.ID}}" class="p-1.5 rounded-md text-gray-600 hover:bg-gray-100 hover:text-gray-900" title="查看详情">
<i class="fas fa-eye"></i>
</a>
{{if eq .Status "offline"}}
<a href="/admin/robots/{{.ID}}/login" class="p-1.5 rounded-md text-blue-600 hover:bg-blue-50 hover:text-blue-700" title="登录微信">
<i class="fas fa-sign-in-alt"></i>
</a>
{{else}}
<form method="POST" action="/admin/robots/{{.ID}}/logout" class="inline">
<button type="submit" class="p-1.5 rounded-md text-yellow-600 hover:bg-yellow-50 hover:text-yellow-700" title="登出微信">
<i class="fas fa-sign-out-alt"></i>
</button>
</form>
{{end}}
<a href="#" class="p-1.5 rounded-md text-red-600 hover:bg-red-50 hover:text-red-700 delete-robot" data-id="{{.ID}}" data-robot-name="{{.Nickname}}" title="删除">
<i class="fas fa-trash"></i>
</a>
</div>
</div>
</div>
{{end}}
{{else}}
<div class="col-span-1 md:col-span-2 lg:col-span-3 bg-white rounded-lg shadow-sm p-12 text-center">
<div class="mx-auto w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center mb-4">
<i class="fas fa-robot text-3xl text-gray-400"></i>
</div>
<h3 class="text-lg font-medium text-gray-700 mb-2">还没有机器人</h3>
<p class="text-gray-500 mb-6">创建您的第一个微信机器人,开启自动化之旅</p>
<a href="/admin/robots/new" class="btn btn-primary">
<i class="fas fa-plus mr-2"></i> 新建机器人
</a>
</div>
{{end}}
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// 计算不同状态机器人数量
let onlineCount = 0;
let offlineCount = 0;
let errorCount = 0;
document.querySelectorAll('.robot-card').forEach(card => {
const status = card.dataset.status;
if (status === 'online') {
onlineCount++;
} else if (status === 'error') {
errorCount++;
} else {
offlineCount++;
}
});
// 更新统计数字
document.getElementById('online-count').textContent = onlineCount;
document.getElementById('offline-count').textContent = offlineCount;
document.getElementById('error-count').textContent = errorCount;
// 删除机器人确认
document.querySelectorAll('.delete-robot').forEach(btn => {
btn.addEventListener('click', async function(e) {
e.preventDefault();
const robotId = this.dataset.id;
const robotName = this.dataset.robotName || '此机器人';
if (window.confirm(`确定要删除 ${robotName} 吗?此操作不可恢复!`)) {
// 使用fetch API发送DELETE请求
fetch(`/admin/robots/${robotId}`, { method: 'DELETE' })
.then(response => {
if (response.ok) {
window.location.reload();
} else {
throw new Error('删除失败');
}
})
.catch(error => {
console.error('Error:', error);
alert('删除失败: ' + error.message);
});
}
});
});
});
</script>
<script>
document.addEventListener('DOMContentLoaded', function() {
// 删除机器人确认
document.querySelectorAll('.delete-robot').forEach(btn => {
btn.addEventListener('click', async function(e) {
e.preventDefault();
const robotId = this.dataset.id;
const robotName = this.dataset.robotName || '此机器人';
// 使用美观的确认对话框代替原生的window.confirm
if (typeof confirmDialog === 'function') {
// 使用confirmDialog函数
const confirmed = await confirmDialog(
`确定要删除 ${robotName} 吗?此操作不可恢复!`,
{ type: 'danger', title: '确认删除' }
);
if (confirmed) {
// 显示加载状态
this.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
this.disabled = true;
try {
// 使用fetch API发送DELETE请求
const response = await fetch(`/admin/robots/${robotId}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
});
if (response.ok) {
// 删除成功,刷新页面
window.location.reload();
} else {
// 读取错误信息
const errorData = await response.json();
throw new Error(errorData.message || '删除失败');
}
} catch (error) {
console.error('Error:', error);
alert('删除失败: ' + error.message);
// 恢复按钮状态
this.innerHTML = '<i class="fas fa-trash"></i>';
this.disabled = false;
}
}
} else {
// 降级方案使用原生confirm
if (window.confirm(`确定要删除 ${robotName} 吗?此操作不可恢复!`)) {
// 使用fetch API发送DELETE请求
fetch(`/admin/robots/${robotId}`, { method: 'DELETE' })
.then(response => {
if (response.ok) {
window.location.reload();
} else {
throw new Error('删除失败');
}
})
.catch(error => {
console.error('Error:', error);
alert('删除失败: ' + error.message);
});
}
}
});
});
});
</script>
<style>
.robot-card {
box-shadow: 0 2px 10px rgba(0,0,0,0.08); /* 保留基础阴影 */
position: relative;
margin: 3px 0;
border-radius: 8px;
overflow: hidden;
transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}
.robot-card:hover {
box-shadow: 0 8px 30px rgba(0,0,0,0.12); /* 保留悬停时的阴影效果 */
z-index: 10;
transform: translateY(-3px) scale(1.01); /* 保留上移和放大效果 */
/* 移除了原来的边框线outline: 1px solid rgba(99, 102, 241, 0.3); */
}
/* 移除左侧边框装饰线 */
.robot-card:before {
display: none; /* 完全移除左侧的灰色条 */
}
/* 移除悬停时的左侧边框装饰线 */
.robot-card:hover:before {
display: none;
}
/* 同样移除基于状态的左侧边框装饰线 */
.robot-card:has(.bg-green-100):hover:before,
.robot-card:has(.bg-gray-100):hover:before {
display: none;
}
/* 保留其他有用的样式 */
.robot-card a, .robot-card button {
transition: all 0.2s ease;
}
.robot-card:hover a, .robot-card:hover button {
transform: scale(1.15);
filter: drop-shadow(0 1px 2px rgba(0,0,0,0.2));
}
/* 移除每个卡片的间隔装饰线 */
.robot-card td:first-child:before {
display: none;
}
</style>