Files
ESP32_GDEY042T81_server/templates/admin/content_detail.html
jeremygan2021 a2682dc040 first commit
2025-11-16 17:21:25 +08:00

295 lines
12 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.
{% extends "admin/base.html" %}
{% block title %}内容详情 - {{ content.title }} - 墨水屏管理系统{% endblock %}
{% block content %}
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
<h1 class="h2"><i class="fas fa-file-alt me-2"></i>内容详情 - {{ content.title }}</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<a href="/admin/contents" class="btn btn-secondary me-2">
<i class="fas fa-arrow-left me-1"></i> 返回内容列表
</a>
<a href="/admin/devices/{{ device.device_id }}" class="btn btn-primary">
<i class="fas fa-tv me-1"></i> 查看设备
</a>
</div>
</div>
<div class="row">
<!-- 内容信息 -->
<div class="col-lg-6 mb-4">
<div class="card shadow-sm">
<div class="card-header bg-white py-3">
<h6 class="m-0 font-weight-bold text-primary"><i class="fas fa-info-circle me-2"></i>内容信息</h6>
</div>
<div class="card-body">
<table class="table table-borderless table-hover">
<tr>
<th width="30%"><i class="fas fa-tv me-2"></i>设备</th>
<td><a href="/admin/devices/{{ device.device_id }}">{{ device.name }} ({{ device.device_id }})</a></td>
</tr>
<tr>
<th><i class="fas fa-heading me-2"></i>标题</th>
<td>{{ content.title }}</td>
</tr>
<tr>
<th><i class="fas fa-code-branch me-2"></i>版本</th>
<td><span class="badge bg-info">v{{ content.version }}</span></td>
</tr>
<tr>
<th><i class="fas fa-align-left me-2"></i>描述</th>
<td>{{ content.description or '无' }}</td>
</tr>
<tr>
<th><i class="fas fa-toggle-on me-2"></i>状态</th>
<td>
{% if content.is_active %}
<span class="badge bg-success"><i class="fas fa-check-circle me-1"></i>活跃</span>
{% else %}
<span class="badge bg-secondary"><i class="fas fa-pause-circle me-1"></i>禁用</span>
{% endif %}
</td>
</tr>
<tr>
<th><i class="fas fa-globe me-2"></i>时区</th>
<td>{{ content.timezone }}</td>
</tr>
<tr>
<th><i class="fas fa-clock me-2"></i>时间格式</th>
<td><code>{{ content.time_format }}</code></td>
</tr>
<tr>
<th><i class="fas fa-calendar-plus me-2"></i>创建时间</th>
<td>{{ content.created_at.strftime('%Y-%m-%d %H:%M:%S') }}</td>
</tr>
</table>
</div>
</div>
</div>
<!-- 内容操作 -->
<div class="col-lg-6 mb-4">
<div class="card shadow-sm">
<div class="card-header bg-white py-3">
<h6 class="m-0 font-weight-bold text-info"><i class="fas fa-cogs me-2"></i>内容操作</h6>
</div>
<div class="card-body">
<div class="d-grid gap-2">
<button class="btn btn-success" onclick="pushContent('{{ device.device_id }}', {{ content.version }})">
<i class="fas fa-paper-plane me-2"></i> 推送到设备
</button>
<button class="btn btn-warning" onclick="toggleContentStatus('{{ device.device_id }}', {{ content.version }})">
{% if content.is_active %}
<i class="fas fa-pause me-2"></i> 禁用内容
{% else %}
<i class="fas fa-play me-2"></i> 启用内容
{% endif %}
</button>
<a href="/admin/upload?device_id={{ device.device_id }}&version={{ content.version }}" class="btn btn-info">
<i class="fas fa-image me-2"></i> 上传图片
</a>
<button class="btn btn-danger" onclick="deleteContent('{{ device.device_id }}', {{ content.version }})">
<i class="fas fa-trash me-2"></i> 删除内容
</button>
</div>
<div class="mt-4">
<h6 class="mb-3"><i class="fas fa-chart-line me-2"></i>推送历史</h6>
<div class="list-group list-group-flush">
<div class="list-group-item px-0 d-flex justify-content-between align-items-center">
<span><i class="fas fa-history me-2"></i>最后推送时间</span>
<span class="badge bg-primary rounded-pill">{{ content.last_pushed_at.strftime('%Y-%m-%d %H:%M') if content.last_pushed_at else '从未' }}</span>
</div>
<div class="list-group-item px-0 d-flex justify-content-between align-items-center">
<span><i class="fas fa-sync-alt me-2"></i>推送次数</span>
<span class="badge bg-info rounded-pill">{{ content.push_count or 0 }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 图片预览 -->
{% if content.image_path %}
<div class="card shadow-sm mb-4">
<div class="card-header bg-white py-3">
<h6 class="m-0 font-weight-bold text-primary"><i class="fas fa-image me-2"></i>图片预览</h6>
</div>
<div class="card-body text-center">
<div class="position-relative d-inline-block">
<img src="{{ content.image_path }}" alt="内容图片" class="img-fluid rounded shadow-sm" style="max-height: 400px;">
<div class="position-absolute top-0 end-0 p-2">
<a href="{{ content.image_path }}" target="_blank" class="btn btn-sm btn-light bg-white rounded-circle">
<i class="fas fa-expand"></i>
</a>
</div>
</div>
<div class="mt-3">
<button class="btn btn-sm btn-outline-secondary" onclick="downloadImage('{{ content.image_path }}')">
<i class="fas fa-download me-1"></i> 下载图片
</button>
</div>
</div>
</div>
{% endif %}
<!-- 布局配置 -->
{% if layout_config %}
<div class="card shadow-sm mb-4">
<div class="card-header bg-white py-3">
<h6 class="m-0 font-weight-bold text-primary"><i class="fas fa-th-large me-2"></i>布局配置</h6>
</div>
<div class="card-body">
<div class="bg-light p-3 rounded">
<pre class="mb-0">{{ layout_config | tojson(indent=2) }}</pre>
</div>
<div class="mt-3">
<button class="btn btn-sm btn-outline-primary" onclick="copyLayoutConfig()">
<i class="fas fa-copy me-1"></i> 复制配置
</button>
</div>
</div>
</div>
{% endif %}
<!-- 设备信息 -->
<div class="card shadow-sm">
<div class="card-header bg-white py-3">
<h6 class="m-0 font-weight-bold text-primary"><i class="fas fa-tv me-2"></i>设备信息</h6>
</div>
<div class="card-body">
<table class="table table-borderless table-hover">
<tr>
<th width="30%"><i class="fas fa-barcode me-2"></i>设备ID</th>
<td><code>{{ device.device_id }}</code></td>
</tr>
<tr>
<th><i class="fas fa-tag me-2"></i>设备名称</th>
<td>{{ device.name }}</td>
</tr>
<tr>
<th><i class="fas fa-map-marker-alt me-2"></i>应用场景</th>
<td>{{ device.scene }}</td>
</tr>
<tr>
<th><i class="fas fa-toggle-on me-2"></i>状态</th>
<td>
{% if device.is_active %}
{% if device.is_online %}
<span class="badge bg-success"><i class="fas fa-wifi me-1"></i>在线</span>
{% else %}
<span class="badge bg-warning"><i class="fas fa-wifi-slash me-1"></i>离线</span>
{% endif %}
{% else %}
<span class="badge bg-secondary"><i class="fas fa-ban me-1"></i>禁用</span>
{% endif %}
</td>
</tr>
<tr>
<th><i class="fas fa-clock me-2"></i>最后上线</th>
<td>{{ device.last_online.strftime('%Y-%m-%d %H:%M:%S') if device.last_online else '从未' }}</td>
</tr>
</table>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
function pushContent(deviceId, version) {
if (confirm('确定要推送此内容到设备吗?')) {
fetch(`/api/devices/${deviceId}/update`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
version: version
})
})
.then(response => response.json())
.then(data => {
showToast('内容推送成功', 'success');
})
.catch(error => {
console.error('Error:', error);
showToast('内容推送失败', 'error');
});
}
}
function toggleContentStatus(deviceId, version) {
const action = event.target.textContent.includes('启用') ? '启用' : '禁用';
if (confirm(`确定要${action}此内容吗?`)) {
fetch(`/api/contents/${deviceId}/${version}/toggle`, {
method: 'POST'
})
.then(response => response.json())
.then(data => {
showToast(`内容${action}成功`, 'success');
location.reload();
})
.catch(error => {
console.error('Error:', error);
showToast(`内容${action}失败`, 'error');
});
}
}
function deleteContent(deviceId, version) {
if (confirm('确定要删除此内容吗?此操作不可恢复!')) {
fetch(`/api/contents/${deviceId}/${version}`, {
method: 'DELETE'
})
.then(response => response.json())
.then(data => {
showToast('内容删除成功', 'success');
window.location.href = `/admin/devices/${deviceId}`;
})
.catch(error => {
console.error('Error:', error);
showToast('内容删除失败', 'error');
});
}
}
function downloadImage(imagePath) {
const link = document.createElement('a');
link.href = imagePath;
link.download = imagePath.split('/').pop();
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
function copyLayoutConfig() {
const configText = document.querySelector('pre').textContent;
navigator.clipboard.writeText(configText).then(() => {
showToast('布局配置已复制到剪贴板', 'success');
}).catch(err => {
console.error('复制失败:', err);
showToast('复制失败', 'error');
});
}
function showToast(message, type) {
// 创建一个简单的toast通知而不是使用alert
const toast = document.createElement('div');
toast.className = `alert alert-${type === 'success' ? 'success' : 'danger'} position-fixed top-0 end-0 m-3`;
toast.style.zIndex = '1050';
toast.innerHTML = `<i class="fas fa-${type === 'success' ? 'check-circle' : 'exclamation-circle'} me-2"></i>${message}`;
document.body.appendChild(toast);
// 3秒后自动移除
setTimeout(() => {
toast.style.opacity = '0';
toast.style.transition = 'opacity 0.5s';
setTimeout(() => {
document.body.removeChild(toast);
}, 500);
}, 3000);
}
</script>
{% endblock %}