feat: update auto render

This commit is contained in:
2025-08-07 20:03:53 +08:00
parent fd67864247
commit d7e8ca38f8
39 changed files with 5684 additions and 130 deletions

View File

@@ -0,0 +1,162 @@
{{define "layout"}}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{.Title}} - 数据管理</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<style>
.tag {
@apply inline-block px-2 py-1 text-xs font-medium rounded-full;
}
.modal {
@apply fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden;
}
.modal-content {
@apply bg-white rounded-lg max-w-4xl w-full mx-4 max-h-[80vh] overflow-y-auto;
}
.loading {
@apply animate-pulse bg-gray-200 rounded;
}
</style>
</head>
<body class="bg-gray-50">
<div class="container mx-auto px-4 py-8">
<!-- 表选择器 -->
<div class="mb-6">
<select id="tableSelector" class="border rounded px-3 py-2" onchange="changeTable(this.value)">
<option value="">选择数据表...</option>
{{range .Tables}}
<option value="{{.Alias}}" {{if eq .Alias $.CurrentTable}}selected{{end}}>
{{.Alias}}
</option>
{{end}}
</select>
</div>
<!-- 主要内容区域 -->
<div id="mainContent">
{{template "content" .}}
</div>
</div>
<!-- 详情弹窗 -->
<div id="detailModal" class="modal">
<div class="modal-content">
<div class="p-6">
<h3 class="text-lg font-medium mb-4">详情信息</h3>
<div id="detailContent"></div>
<div class="mt-4 flex justify-end">
<button onclick="closeModal()" class="px-4 py-2 bg-gray-300 rounded">
关闭
</button>
</div>
</div>
</div>
</div>
<!-- 通用JavaScript -->
<script>
// 全局配置
const CONFIG = {
apiBase: '/api',
templates: {
builtin: '/templates/builtin',
custom: '/templates/custom'
}
};
// 模板系统核心
class TemplateSystem {
static async loadTemplate(path) {
const response = await fetch(path);
return response.text();
}
static async render(data, templateName, tableName) {
// 优先使用自定义模板,回退到默认模板
const customPath = `${CONFIG.templates.custom}/${tableName}/${templateName}.html`;
const defaultPath = `${CONFIG.templates.builtin}/${templateName}.html`;
try {
return await this.loadTemplate(customPath);
} catch {
return await this.loadTemplate(defaultPath);
}
}
static async renderField(value, type, column) {
const fieldMap = {
'raw': v => v,
'time': v => new Date(v).toLocaleString('zh-CN'),
'tag': (v, col) => {
const tag = col.values[v];
return tag ? `<span class="tag" style="background-color: ${tag.color}; color: white;">${tag.label}</span>` : v;
},
'markdown': v => marked.parse(v || ''),
'category': v => v
};
return fieldMap[type]?.(value, column) || value;
}
}
// 数据加载器
class DataLoader {
static async loadTableData(tableAlias, page = 1, perPage = 20, search = '', sort = '', order = 'desc') {
const params = new URLSearchParams({
page,
per_page: perPage,
search,
sort,
order
});
const response = await fetch(`${CONFIG.apiBase}/data/${tableAlias}?${params}`);
return response.json();
}
static async loadTableDetail(tableAlias, id) {
const response = await fetch(`${CONFIG.apiBase}/data/${tableAlias}/detail/${id}`);
return response.json();
}
}
// 通用函数
function changeTable(tableAlias) {
if (!tableAlias) return;
window.location.href = `/?table=${tableAlias}&page=1`;
}
function closeModal() {
document.getElementById('detailModal').classList.add('hidden');
}
function showLoading() {
document.getElementById('mainContent').innerHTML =
'<div class="text-center py-8"><div class="loading h-4 w-32 mx-auto"></div></div>';
}
// 初始化
document.addEventListener('DOMContentLoaded', function() {
// 绑定全局事件
window.closeModal = closeModal;
window.changeTable = changeTable;
window.TemplateSystem = TemplateSystem;
window.DataLoader = DataLoader;
});
</script>
<!-- 页面特定内容占位符 -->
{{template "scripts" .}}
<!-- 性能监控JS -->
<script src="/static/js/performance-monitor.js"></script>
<script src="/static/js/api-client.js"></script>
<script src="/static/js/template-engine.js"></script>
<script src="/static/js/ui-controller.js"></script>
</body>
</html>
{{end}}