This commit is contained in:
vipg
2025-11-12 16:44:02 +08:00
parent d030e07e51
commit 92da92f76f
24 changed files with 653 additions and 390 deletions

View File

@@ -1 +1,13 @@
# Frontend
假设你是一位经验丰富的前端开发人员精通jquery的使用的前端项目的架构设计搭建协助我完成资产管理的管理系统先完成以下需求
1、设计一个项目架构。
2、登录页面输入账号密码登录只有登录业务没有注册和找回密码。
3、主页分为侧边栏、顶部导航、右边内容区。
4、基于 localStorage 的令牌验证,未登录自动跳转到登录页。
5、常用组件
5.1、加载动画:全局加载状态提示。
5.2、消息提示:支持成功 / 错误 / 信息三种类型,自动消失。
5.3、菜单组件:支持多级菜单、折叠展开、激活状态。
5.4、页面管理:统一的页面加载机制,支持错误处理和重试功能。
6、扩展能力尽量多的配置操作。
7、样式需求该项目为金融性质项目页面风格样式需要偏向暗夜模式。

View File

@@ -0,0 +1,22 @@
# 依赖
node_modules/
.pnp/
.pnp.js
# 构建产物
dist/
# 日志
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# 编辑器配置
.idea/
.vscode/
*.swp
*.swo
# 操作系统文件
.DS_Store
Thumbs.db

View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>资产辅助系统</title>
<!-- 自动跳转到登录页 -->
<meta http-equiv="refresh" content="0;url=src/pages/login.html">
</head>
<body>
<p>正在跳转到登录页... 如果没有自动跳转,请<a href="src/pages/login.html">点击这里</a></p>
</body>
</html>

View File

@@ -0,0 +1,17 @@
{
"name": "asset-assistant-system",
"version": "1.0.0",
"description": "资产辅助管理系统",
"main": "index.html",
"scripts": {
"dev": "serve",
"build": "echo '构建脚本待实现'",
"test": "echo '测试脚本待实现'"
},
"keywords": ["asset", "management", "system"],
"author": "",
"license": "MIT",
"devDependencies": {
"serve": "^14.2.3"
}
}

View File

@@ -0,0 +1,14 @@
/* 通用样式 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Arial', sans-serif;
}
.container {
width: 100%;
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}

View File

@@ -0,0 +1,5 @@
/* 暗夜模式主题样式 */
body.dark-theme {
background-color: #1e1e1e;
color: #f5f5f5;
}

View File

@@ -0,0 +1,48 @@
/* 应用入口 */
import { renderHeader } from './components/header.js';
import { renderSidebar } from './components/sidebar.js';
import { Auth } from './core/auth.js';
import { Router } from './core/router.js';
import { themeConfig } from './config/theme.js';
// 初始化应用
function initApp() {
// 检查登录状态
if (!Auth.isLogin() && window.location.pathname.indexOf('login.html') === -1) {
Router.push('/login.html');
return;
}
// 初始化主题
initTheme();
// 渲染公共组件(非登录页)
if (window.location.pathname.indexOf('login.html') === -1) {
renderCommonComponents();
}
}
// 初始化主题
function initTheme() {
const savedTheme = localStorage.getItem(themeConfig.themeStorageKey) || themeConfig.defaultTheme;
if (savedTheme === 'dark') {
document.body.classList.add(themeConfig.darkThemeClass);
}
}
// 渲染公共组件(头部和侧边栏)
function renderCommonComponents() {
const header = renderHeader();
const sidebar = renderSidebar();
document.body.appendChild(header);
document.body.appendChild(sidebar);
// 创建主内容区域
const mainContent = document.createElement('div');
mainContent.className = 'main-content';
document.body.appendChild(mainContent);
}
// 页面加载完成后初始化
window.addEventListener('DOMContentLoaded', initApp);

View File

@@ -0,0 +1,31 @@
/* 顶部导航组件 */
import { systemConfig } from '../config/system.js';
import { Auth } from '../core/auth.js';
import { themeConfig } from '../config/theme.js';
export function renderHeader() {
const header = document.createElement('div');
header.className = 'header';
header.innerHTML = `
<div class="app-name">${systemConfig.appName}</div>
<div class="header-actions">
<button onclick="toggleTheme()">切换主题</button>
<button onclick="Auth.logout()">退出登录</button>
</div>
`;
return header;
}
// 主题切换函数
function toggleTheme() {
const body = document.body;
if (body.classList.contains(themeConfig.darkThemeClass)) {
body.classList.remove(themeConfig.darkThemeClass);
localStorage.setItem(themeConfig.themeStorageKey, 'light');
} else {
body.classList.add(themeConfig.darkThemeClass);
localStorage.setItem(themeConfig.themeStorageKey, 'dark');
}
}

View File

@@ -0,0 +1,10 @@
/* 加载动画组件 */
export function renderLoading() {
const loading = document.createElement('div');
loading.className = 'loading';
loading.innerHTML = `
<div class="spinner"></div>
<div class="loading-text">加载中...</div>
`;
return loading;
}

View File

@@ -0,0 +1,19 @@
/* 侧边栏组件 */
import { menuConfig } from '../config/menu.js';
import { Router } from '../core/router.js';
export function renderSidebar() {
const sidebar = document.createElement('div');
sidebar.className = 'sidebar';
// 渲染菜单
const menuHtml = menuConfig.map(item => `
<div class="menu-item" onclick="Router.push('${item.path}')">
<i class="icon-${item.icon}"></i>
<span>${item.name}</span>
</div>
`).join('');
sidebar.innerHTML = menuHtml;
return sidebar;
}

View File

@@ -0,0 +1,15 @@
/* 菜单配置 */
export const menuConfig = [
{
path: '/dashboard',
name: '数据概览',
icon: 'dashboard',
auth: true
},
{
path: '/asset-list',
name: '资产列表',
icon: 'assets',
auth: true
}
];

View File

@@ -0,0 +1,7 @@
/* 系统配置 */
export const systemConfig = {
appName: '资产辅助系统',
version: '1.0.0',
baseUrl: '/',
timeout: 5000
};

View File

@@ -0,0 +1,6 @@
/* 主题配置 */
export const themeConfig = {
defaultTheme: 'light',
darkThemeClass: 'dark-theme',
themeStorageKey: 'asset_system_theme'
};

View File

@@ -0,0 +1,18 @@
/* 权限验证 */
import { systemConfig } from '../config/system.js';
export const Auth = {
// 检查是否登录
isLogin() {
return localStorage.getItem('token') !== null;
},
// 登录
login(token) {
localStorage.setItem('token', token);
},
// 退出登录
logout() {
localStorage.removeItem('token');
window.location.href = `${systemConfig.baseUrl}login.html`;
}
};

View File

@@ -0,0 +1,25 @@
/* 加载器 */
export const Loader = {
show() {
const loader = document.createElement('div');
loader.id = 'app-loader';
loader.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(255,255,255,0.8);
display: flex;
align-items: center;
justify-content: center;
z-index: 9999;
`;
loader.innerHTML = '<div>加载中...</div>';
document.body.appendChild(loader);
},
hide() {
const loader = document.getElementById('app-loader');
if (loader) loader.remove();
}
};

View File

@@ -0,0 +1,26 @@
/* 消息提示 */
export const Message = {
success(content) {
this.showMessage(content, 'success');
},
error(content) {
this.showMessage(content, 'error');
},
showMessage(content, type) {
const message = document.createElement('div');
message.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
padding: 10px 20px;
border-radius: 4px;
color: white;
z-index: 9998;
transition: all 0.3s;
`;
message.style.backgroundColor = type === 'success' ? '#4CAF50' : '#f44336';
message.textContent = content;
document.body.appendChild(message);
setTimeout(() => message.remove(), 3000);
}
};

View File

@@ -0,0 +1,19 @@
/* 路由管理 */
import { Auth } from './auth.js';
import { systemConfig } from '../config/system.js';
export const Router = {
// 跳转页面
push(path) {
// 验证权限
if (path !== '/login' && !Auth.isLogin()) {
window.location.href = `${systemConfig.baseUrl}login.html`;
return;
}
window.location.href = `${systemConfig.baseUrl}${path.startsWith('/') ? path.slice(1) : path}`;
},
// 获取当前路径
getCurrentPath() {
return window.location.pathname.replace(systemConfig.baseUrl, '');
}
};

View File

@@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>资产辅助系统 - 主页</title>
<link rel="stylesheet" href="../assets/css/common.css">
<link rel="stylesheet" href="../assets/css/dark-theme.css">
<style>
.header { height: 60px; background: #2c3e50; color: white; display: flex; align-items: center; justify-content: space-between; padding: 0 20px; }
.sidebar { width: 200px; height: calc(100vh - 60px); background: #34495e; position: fixed; left: 0; top: 60px; }
.menu-item { color: white; padding: 15px 20px; cursor: pointer; transition: background 0.3s; }
.menu-item:hover { background: #2c3e50; }
.main-content { margin-left: 200px; padding: 20px; min-height: calc(100vh - 60px); }
</style>
</head>
<body>
<!-- 公共组件会通过 app.js 自动渲染 -->
<div class="main-content">
<h1>欢迎使用资产辅助系统</h1>
<p>请选择左侧菜单进行操作</p>
</div>
<script type="module" src="../assets/js/app.js"></script>
</body>
</html>

View File

@@ -0,0 +1,51 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>资产辅助系统 - 登录</title>
<link rel="stylesheet" href="../assets/css/common.css">
<link rel="stylesheet" href="../assets/css/dark-theme.css">
</head>
<body>
<div class="container">
<div class="login-form">
<h2>资产辅助系统</h2>
<div class="form-group">
<label>用户名</label>
<input type="text" id="username" placeholder="请输入用户名">
</div>
<div class="form-group">
<label>密码</label>
<input type="password" id="password" placeholder="请输入密码">
</div>
<button onclick="handleLogin()">登录</button>
</div>
</div>
<script type="module">
import { Auth } from '../assets/js/core/auth.js';
import { Router } from '../assets/js/core/router.js';
import { Message } from '../assets/js/core/message.js';
function handleLogin() {
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
if (!username || !password) {
Message.error('用户名和密码不能为空');
return;
}
// 模拟登录验证
if (username === 'admin' && password === '123456') {
Auth.login('mock-token-123456');
Message.success('登录成功');
setTimeout(() => Router.push('index.html'), 1000);
} else {
Message.error('用户名或密码错误');
}
}
</script>
</body>
</html>

View File

@@ -0,0 +1,81 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>资产详情 - 资产辅助系统</title>
<link rel="stylesheet" href="../../assets/css/common.css">
<link rel="stylesheet" href="../../assets/css/dark-theme.css">
<style>
.asset-detail { margin-top: 20px; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
.dark-theme .asset-detail { background: #2c3e50; }
.detail-item { margin-bottom: 15px; display: flex; }
.detail-label { width: 120px; font-weight: bold; }
.btn-back { margin-top: 20px; padding: 8px 16px; background: #3498db; color: white; border: none; border-radius: 4px; cursor: pointer; }
</style>
</head>
<body>
<div class="main-content">
<h2>资产详情</h2>
<div class="asset-detail">
<div class="detail-item">
<div class="detail-label">资产ID</div>
<div id="asset-id">--</div>
</div>
<div class="detail-item">
<div class="detail-label">资产名称:</div>
<div id="asset-name">--</div>
</div>
<div class="detail-item">
<div class="detail-label">资产类型:</div>
<div id="asset-type">--</div>
</div>
<div class="detail-item">
<div class="detail-label">购买日期:</div>
<div>2024-01-15</div>
</div>
<div class="detail-item">
<div class="detail-label">状态:</div>
<div style="color: #27ae60;">运行中</div>
</div>
</div>
<button class="btn-back" onclick="goBack()">返回列表</button>
</div>
<script type="module">
import { Router } from '../../assets/js/core/router.js';
// 获取资产ID参数
function getAssetId() {
const params = new URLSearchParams(window.location.search);
return params.get('id') || '';
}
// 初始化详情数据
function initDetail() {
const assetId = getAssetId();
if (!assetId) return;
document.getElementById('asset-id').textContent = assetId;
// 模拟根据ID获取资产名称和类型
const assetMap = {
'ASSET-001': { name: '服务器-Web01', type: '服务器' },
'ASSET-002': { name: '交换机-SW02', type: '网络设备' }
};
const asset = assetMap[assetId] || { name: '未知资产', type: '未知类型' };
document.getElementById('asset-name').textContent = asset.name;
document.getElementById('asset-type').textContent = asset.type;
}
function goBack() {
Router.push('asset-list.html');
}
// 初始化
initDetail();
</script>
<script type="module" src="../../assets/js/app.js"></script>
</body>
</html>

View File

@@ -0,0 +1,59 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>资产列表 - 资产辅助系统</title>
<link rel="stylesheet" href="../../assets/css/common.css">
<link rel="stylesheet" href="../../assets/css/dark-theme.css">
<style>
.asset-table { width: 100%; border-collapse: collapse; margin-top: 20px; }
.asset-table th, .asset-table td { padding: 12px; text-align: left; border-bottom: 1px solid #eee; }
.dark-theme .asset-table th, .dark-theme .asset-table td { border-bottom-color: #34495e; }
.asset-table th { background: #f5f5f5; }
.dark-theme .asset-table th { background: #34495e; }
.btn { padding: 6px 12px; border: none; border-radius: 4px; cursor: pointer; }
.btn-detail { background: #3498db; color: white; }
</style>
</head>
<body>
<div class="main-content">
<h2>资产列表</h2>
<table class="asset-table">
<thead>
<tr>
<th>资产ID</th>
<th>资产名称</th>
<th>资产类型</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>ASSET-001</td>
<td>服务器-Web01</td>
<td>服务器</td>
<td>运行中</td>
<td><button class="btn btn-detail" onclick="goToDetail('ASSET-001')">查看详情</button></td>
</tr>
<tr>
<td>ASSET-002</td>
<td>交换机-SW02</td>
<td>网络设备</td>
<td>运行中</td>
<td><button class="btn btn-detail" onclick="goToDetail('ASSET-002')">查看详情</button></td>
</tr>
</tbody>
</table>
</div>
<script type="module">
import { Router } from '../../assets/js/core/router.js';
window.goToDetail = function(assetId) {
Router.push(`asset-detail.html?id=${assetId}`);
}
</script>
<script type="module" src="../../assets/js/app.js"></script>
</body>
</html>

View File

@@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数据概览 - 资产辅助系统</title>
<link rel="stylesheet" href="../../assets/css/common.css">
<link rel="stylesheet" href="../../assets/css/dark-theme.css">
<style>
.dashboard-cards { display: flex; gap: 20px; margin-top: 20px; }
.card { flex: 1; padding: 20px; background: white; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
.dark-theme .card { background: #2c3e50; color: white; }
</style>
</head>
<body>
<div class="main-content">
<h2>数据概览</h2>
<div class="dashboard-cards">
<div class="card">
<h3>总资产数</h3>
<p>1,286</p>
</div>
<div class="card">
<h3>在线设备</h3>
<p>952</p>
</div>
<div class="card">
<h3>待处理工单</h3>
<p>36</p>
</div>
</div>
</div>
<script type="module" src="../../assets/js/app.js"></script>
</body>
</html>

93
frontend/create.py Normal file
View File

@@ -0,0 +1,93 @@
import os
from pathlib import Path
# 定义项目根目录(脚本所在目录下的 asset-assistant-system
PROJECT_ROOT = Path(__file__).parent / "asset-assistant-system"
# 定义需要创建的目录列表
DIRECTORIES = [
"dist",
"src/assets/css",
"src/assets/css/components",
"src/assets/js/config",
"src/assets/js/core",
"src/assets/js/components",
"src/assets/icons",
"src/pages/modules",
"src/template"
]
# 定义需要创建的文件列表(路径: 文件初始内容)
FILES = {
# CSS 文件
"src/assets/css/dark-theme.css": "/* 暗夜模式主题样式 */\nbody.dark-theme {\n background-color: #1e1e1e;\n color: #f5f5f5;\n}\n",
"src/assets/css/common.css": "/* 通用样式 */\n* {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n font-family: 'Arial', sans-serif;\n}\n\n.container {\n width: 100%;\n max-width: 1200px;\n margin: 0 auto;\n padding: 0 20px;\n}\n",
# JS 配置文件
"src/assets/js/config/menu.js": "/* 菜单配置 */\nexport const menuConfig = [\n {\n path: '/dashboard',\n name: '数据概览',\n icon: 'dashboard',\n auth: true\n },\n {\n path: '/asset-list',\n name: '资产列表',\n icon: 'assets',\n auth: true\n }\n];\n",
"src/assets/js/config/theme.js": "/* 主题配置 */\nexport const themeConfig = {\n defaultTheme: 'light',\n darkThemeClass: 'dark-theme',\n themeStorageKey: 'asset_system_theme'\n};\n",
"src/assets/js/config/system.js": "/* 系统配置 */\nexport const systemConfig = {\n appName: '资产辅助系统',\n version: '1.0.0',\n baseUrl: '/',\n timeout: 5000\n};\n",
# JS 核心功能
"src/assets/js/core/auth.js": "/* 权限验证 */\nimport { systemConfig } from '../config/system.js';\n\nexport const Auth = {\n // 检查是否登录\n isLogin() {\n return localStorage.getItem('token') !== null;\n },\n // 登录\n login(token) {\n localStorage.setItem('token', token);\n },\n // 退出登录\n logout() {\n localStorage.removeItem('token');\n window.location.href = `${systemConfig.baseUrl}login.html`;\n }\n};\n",
"src/assets/js/core/loader.js": "/* 加载器 */\nexport const Loader = {\n show() {\n const loader = document.createElement('div');\n loader.id = 'app-loader';\n loader.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(255,255,255,0.8);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 9999;\n `;\n loader.innerHTML = '<div>加载中...</div>';\n document.body.appendChild(loader);\n },\n hide() {\n const loader = document.getElementById('app-loader');\n if (loader) loader.remove();\n }\n};\n",
"src/assets/js/core/message.js": "/* 消息提示 */\nexport const Message = {\n success(content) {\n this.showMessage(content, 'success');\n },\n error(content) {\n this.showMessage(content, 'error');\n },\n showMessage(content, type) {\n const message = document.createElement('div');\n message.style.cssText = `\n position: fixed;\n top: 20px;\n right: 20px;\n padding: 10px 20px;\n border-radius: 4px;\n color: white;\n z-index: 9998;\n transition: all 0.3s;\n `;\n message.style.backgroundColor = type === 'success' ? '#4CAF50' : '#f44336';\n message.textContent = content;\n document.body.appendChild(message);\n setTimeout(() => message.remove(), 3000);\n }\n};\n",
"src/assets/js/core/router.js": "/* 路由管理 */\nimport { Auth } from './auth.js';\nimport { systemConfig } from '../config/system.js';\n\nexport const Router = {\n // 跳转页面\n push(path) {\n // 验证权限\n if (path !== '/login' && !Auth.isLogin()) {\n window.location.href = `${systemConfig.baseUrl}login.html`;\n return;\n }\n window.location.href = `${systemConfig.baseUrl}${path.startsWith('/') ? path.slice(1) : path}`;\n },\n // 获取当前路径\n getCurrentPath() {\n return window.location.pathname.replace(systemConfig.baseUrl, '');\n }\n};\n",
# JS 组件
"src/assets/js/components/sidebar.js": "/* 侧边栏组件 */\nimport { menuConfig } from '../config/menu.js';\nimport { Router } from '../core/router.js';\n\nexport function renderSidebar() {\n const sidebar = document.createElement('div');\n sidebar.className = 'sidebar';\n \n // 渲染菜单\n const menuHtml = menuConfig.map(item => `\n <div class=\"menu-item\" onclick=\"Router.push('${item.path}')\">\n <i class=\"icon-${item.icon}\"></i>\n <span>${item.name}</span>\n </div>\n `).join('');\n \n sidebar.innerHTML = menuHtml;\n return sidebar;\n}\n",
"src/assets/js/components/header.js": "/* 顶部导航组件 */\nimport { systemConfig } from '../config/system.js';\nimport { Auth } from '../core/auth.js';\nimport { themeConfig } from '../config/theme.js';\n\nexport function renderHeader() {\n const header = document.createElement('div');\n header.className = 'header';\n \n header.innerHTML = `\n <div class=\"app-name\">${systemConfig.appName}</div>\n <div class=\"header-actions\">\n <button onclick=\"toggleTheme()\">切换主题</button>\n <button onclick=\"Auth.logout()\">退出登录</button>\n </div>\n `;\n \n return header;\n}\n\n// 主题切换函数\nfunction toggleTheme() {\n const body = document.body;\n if (body.classList.contains(themeConfig.darkThemeClass)) {\n body.classList.remove(themeConfig.darkThemeClass);\n localStorage.setItem(themeConfig.themeStorageKey, 'light');\n } else {\n body.classList.add(themeConfig.darkThemeClass);\n localStorage.setItem(themeConfig.themeStorageKey, 'dark');\n }\n}\n",
"src/assets/js/components/loading.js": "/* 加载动画组件 */\nexport function renderLoading() {\n const loading = document.createElement('div');\n loading.className = 'loading';\n loading.innerHTML = `\n <div class=\"spinner\"></div>\n <div class=\"loading-text\">加载中...</div>\n `;\n return loading;\n}\n",
# 应用入口
"src/assets/js/app.js": "/* 应用入口 */\nimport { renderHeader } from './components/header.js';\nimport { renderSidebar } from './components/sidebar.js';\nimport { Auth } from './core/auth.js';\nimport { Router } from './core/router.js';\nimport { themeConfig } from './config/theme.js';\n\n// 初始化应用\nfunction initApp() {\n // 检查登录状态\n if (!Auth.isLogin() && window.location.pathname.indexOf('login.html') === -1) {\n Router.push('/login.html');\n return;\n }\n \n // 初始化主题\n initTheme();\n \n // 渲染公共组件(非登录页)\n if (window.location.pathname.indexOf('login.html') === -1) {\n renderCommonComponents();\n }\n}\n\n// 初始化主题\nfunction initTheme() {\n const savedTheme = localStorage.getItem(themeConfig.themeStorageKey) || themeConfig.defaultTheme;\n if (savedTheme === 'dark') {\n document.body.classList.add(themeConfig.darkThemeClass);\n }\n}\n\n// 渲染公共组件(头部和侧边栏)\nfunction renderCommonComponents() {\n const header = renderHeader();\n const sidebar = renderSidebar();\n \n document.body.appendChild(header);\n document.body.appendChild(sidebar);\n \n // 创建主内容区域\n const mainContent = document.createElement('div');\n mainContent.className = 'main-content';\n document.body.appendChild(mainContent);\n}\n\n// 页面加载完成后初始化\nwindow.addEventListener('DOMContentLoaded', initApp);\n",
# HTML 页面
"src/pages/login.html": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>资产辅助系统 - 登录</title>\n <link rel=\"stylesheet\" href=\"../assets/css/common.css\">\n <link rel=\"stylesheet\" href=\"../assets/css/dark-theme.css\">\n</head>\n<body>\n <div class=\"container\">\n <div class=\"login-form\">\n <h2>资产辅助系统</h2>\n <div class=\"form-group\">\n <label>用户名</label>\n <input type=\"text\" id=\"username\" placeholder=\"请输入用户名\">\n </div>\n <div class=\"form-group\">\n <label>密码</label>\n <input type=\"password\" id=\"password\" placeholder=\"请输入密码\">\n </div>\n <button onclick=\"handleLogin()\">登录</button>\n </div>\n </div>\n\n <script type=\"module\">\n import { Auth } from '../assets/js/core/auth.js';\n import { Router } from '../assets/js/core/router.js';\n import { Message } from '../assets/js/core/message.js';\n\n function handleLogin() {\n const username = document.getElementById('username').value;\n const password = document.getElementById('password').value;\n\n if (!username || !password) {\n Message.error('用户名和密码不能为空');\n return;\n }\n\n // 模拟登录验证\n if (username === 'admin' && password === '123456') {\n Auth.login('mock-token-123456');\n Message.success('登录成功');\n setTimeout(() => Router.push('index.html'), 1000);\n } else {\n Message.error('用户名或密码错误');\n }\n }\n </script>\n</body>\n</html>",
"src/pages/index.html": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>资产辅助系统 - 主页</title>\n <link rel=\"stylesheet\" href=\"../assets/css/common.css\">\n <link rel=\"stylesheet\" href=\"../assets/css/dark-theme.css\">\n <style>\n .header { height: 60px; background: #2c3e50; color: white; display: flex; align-items: center; justify-content: space-between; padding: 0 20px; }\n .sidebar { width: 200px; height: calc(100vh - 60px); background: #34495e; position: fixed; left: 0; top: 60px; }\n .menu-item { color: white; padding: 15px 20px; cursor: pointer; transition: background 0.3s; }\n .menu-item:hover { background: #2c3e50; }\n .main-content { margin-left: 200px; padding: 20px; min-height: calc(100vh - 60px); }\n </style>\n</head>\n<body>\n <!-- 公共组件会通过 app.js 自动渲染 -->\n <div class=\"main-content\">\n <h1>欢迎使用资产辅助系统</h1>\n <p>请选择左侧菜单进行操作</p>\n </div>\n\n <script type=\"module\" src=\"../assets/js/app.js\"></script>\n</body>\n</html>",
"src/pages/modules/dashboard.html": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>数据概览 - 资产辅助系统</title>\n <link rel=\"stylesheet\" href=\"../../assets/css/common.css\">\n <link rel=\"stylesheet\" href=\"../../assets/css/dark-theme.css\">\n <style>\n .dashboard-cards { display: flex; gap: 20px; margin-top: 20px; }\n .card { flex: 1; padding: 20px; background: white; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }\n .dark-theme .card { background: #2c3e50; color: white; }\n </style>\n</head>\n<body>\n <div class=\"main-content\">\n <h2>数据概览</h2>\n <div class=\"dashboard-cards\">\n <div class=\"card\">\n <h3>总资产数</h3>\n <p>1,286</p>\n </div>\n <div class=\"card\">\n <h3>在线设备</h3>\n <p>952</p>\n </div>\n <div class=\"card\">\n <h3>待处理工单</h3>\n <p>36</p>\n </div>\n </div>\n </div>\n\n <script type=\"module\" src=\"../../assets/js/app.js\"></script>\n</body>\n</html>",
"src/pages/modules/asset-list.html": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>资产列表 - 资产辅助系统</title>\n <link rel=\"stylesheet\" href=\"../../assets/css/common.css\">\n <link rel=\"stylesheet\" href=\"../../assets/css/dark-theme.css\">\n <style>\n .asset-table { width: 100%; border-collapse: collapse; margin-top: 20px; }\n .asset-table th, .asset-table td { padding: 12px; text-align: left; border-bottom: 1px solid #eee; }\n .dark-theme .asset-table th, .dark-theme .asset-table td { border-bottom-color: #34495e; }\n .asset-table th { background: #f5f5f5; }\n .dark-theme .asset-table th { background: #34495e; }\n .btn { padding: 6px 12px; border: none; border-radius: 4px; cursor: pointer; }\n .btn-detail { background: #3498db; color: white; }\n </style>\n</head>\n<body>\n <div class=\"main-content\">\n <h2>资产列表</h2>\n <table class=\"asset-table\">\n <thead>\n <tr>\n <th>资产ID</th>\n <th>资产名称</th>\n <th>资产类型</th>\n <th>状态</th>\n <th>操作</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <td>ASSET-001</td>\n <td>服务器-Web01</td>\n <td>服务器</td>\n <td>运行中</td>\n <td><button class=\"btn btn-detail\" onclick=\"goToDetail('ASSET-001')\">查看详情</button></td>\n </tr>\n <tr>\n <td>ASSET-002</td>\n <td>交换机-SW02</td>\n <td>网络设备</td>\n <td>运行中</td>\n <td><button class=\"btn btn-detail\" onclick=\"goToDetail('ASSET-002')\">查看详情</button></td>\n </tr>\n </tbody>\n </table>\n </div>\n\n <script type=\"module\">\n import { Router } from '../../assets/js/core/router.js';\n window.goToDetail = function(assetId) {\n Router.push(`asset-detail.html?id=${assetId}`);\n }\n </script>\n <script type=\"module\" src=\"../../assets/js/app.js\"></script>\n</body>\n</html>",
"src/pages/modules/asset-detail.html": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>资产详情 - 资产辅助系统</title>\n <link rel=\"stylesheet\" href=\"../../assets/css/common.css\">\n <link rel=\"stylesheet\" href=\"../../assets/css/dark-theme.css\">\n <style>\n .asset-detail { margin-top: 20px; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }\n .dark-theme .asset-detail { background: #2c3e50; }\n .detail-item { margin-bottom: 15px; display: flex; }\n .detail-label { width: 120px; font-weight: bold; }\n .btn-back { margin-top: 20px; padding: 8px 16px; background: #3498db; color: white; border: none; border-radius: 4px; cursor: pointer; }\n </style>\n</head>\n<body>\n <div class=\"main-content\">\n <h2>资产详情</h2>\n <div class=\"asset-detail\">\n <div class=\"detail-item\">\n <div class=\"detail-label\">资产ID</div>\n <div id=\"asset-id\">--</div>\n </div>\n <div class=\"detail-item\">\n <div class=\"detail-label\">资产名称:</div>\n <div id=\"asset-name\">--</div>\n </div>\n <div class=\"detail-item\">\n <div class=\"detail-label\">资产类型:</div>\n <div id=\"asset-type\">--</div>\n </div>\n <div class=\"detail-item\">\n <div class=\"detail-label\">购买日期:</div>\n <div>2024-01-15</div>\n </div>\n <div class=\"detail-item\">\n <div class=\"detail-label\">状态:</div>\n <div style=\"color: #27ae60;\">运行中</div>\n </div>\n </div>\n <button class=\"btn-back\" onclick=\"goBack()\">返回列表</button>\n </div>\n\n <script type=\"module\">\n import { Router } from '../../assets/js/core/router.js';\n\n // 获取资产ID参数\n function getAssetId() {\n const params = new URLSearchParams(window.location.search);\n return params.get('id') || '';\n }\n\n // 初始化详情数据\n function initDetail() {\n const assetId = getAssetId();\n if (!assetId) return;\n\n document.getElementById('asset-id').textContent = assetId;\n \n // 模拟根据ID获取资产名称和类型\n const assetMap = {\n 'ASSET-001': { name: '服务器-Web01', type: '服务器' },\n 'ASSET-002': { name: '交换机-SW02', type: '网络设备' }\n };\n\n const asset = assetMap[assetId] || { name: '未知资产', type: '未知类型' };\n document.getElementById('asset-name').textContent = asset.name;\n document.getElementById('asset-type').textContent = asset.type;\n }\n\n function goBack() {\n Router.push('asset-list.html');\n }\n\n // 初始化\n initDetail();\n </script>\n <script type=\"module\" src=\"../../assets/js/app.js\"></script>\n</body>\n</html>",
# 根目录文件
".gitignore": "# 依赖\nnode_modules/\n.pnp/\n.pnp.js\n\n# 构建产物\ndist/\n\n# 环境变量\n.env\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\n# 日志\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# 编辑器配置\n.idea/\n.vscode/\n*.swp\n*.swo\n\n# 操作系统文件\n.DS_Store\nThumbs.db",
"index.html": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>资产辅助系统</title>\n <!-- 自动跳转到登录页 -->\n <meta http-equiv=\"refresh\" content=\"0;url=src/pages/login.html\">\n</head>\n<body>\n <p>正在跳转到登录页... 如果没有自动跳转,请<a href=\"src/pages/login.html\">点击这里</a></p>\n</body>\n</html>",
"package.json": "{\n \"name\": \"asset-assistant-system\",\n \"version\": \"1.0.0\",\n \"description\": \"资产辅助管理系统\",\n \"main\": \"index.html\",\n \"scripts\": {\n \"dev\": \"serve\",\n \"build\": \"echo '构建脚本待实现'\",\n \"test\": \"echo '测试脚本待实现'\"\n },\n \"keywords\": [\"asset\", \"management\", \"system\"],\n \"author\": \"\",\n \"license\": \"MIT\",\n \"devDependencies\": {\n \"serve\": \"^14.2.3\"\n }\n}"
}
def create_project_structure():
"""创建项目目录结构和文件"""
try:
# 1. 创建根目录
PROJECT_ROOT.mkdir(exist_ok=True)
print(f"✅ 创建项目根目录: {PROJECT_ROOT}")
# 2. 创建所有子目录
for dir_path in DIRECTORIES:
full_dir_path = PROJECT_ROOT / dir_path
full_dir_path.mkdir(parents=True, exist_ok=True)
print(f"✅ 创建目录: {full_dir_path}")
# 3. 创建所有文件并写入初始内容
for file_path, content in FILES.items():
full_file_path = PROJECT_ROOT / file_path
# 确保文件所在目录存在(防止遗漏)
full_file_path.parent.mkdir(parents=True, exist_ok=True)
# 写入文件内容
with open(full_file_path, 'w', encoding='utf-8') as f:
f.write(content)
print(f"✅ 创建文件: {full_file_path}")
print("\n🎉 项目结构创建完成!")
print(f"📁 项目路径: {PROJECT_ROOT}")
print("\n💡 后续操作建议:")
print(" 1. 进入项目目录: cd asset-assistant-system")
print(" 2. 安装依赖: npm install")
print(" 3. 启动开发服务器: npm run dev")
print(" 4. 访问: http://localhost:3000")
except Exception as e:
print(f"\n❌ 创建项目结构时出错: {e}")
if __name__ == "__main__":
create_project_structure()

View File

@@ -1,390 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>EasyUI 后台管理系统</title>
<!-- 引入必要资源 -->
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/jquery-easyui/1.10.14/themes/default/easyui.css">
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/jquery-easyui/1.10.14/themes/icon.css">
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery-easyui/1.10.14/jquery.easyui.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery-easyui/1.10.14/locale/easyui-lang-zh_CN.js"></script>
<style>
/* 全局样式调整 */
body {
margin: 0;
padding: 0;
font-family: "Microsoft YaHei", sans-serif;
}
/* 顶部导航样式 */
.top-nav {
height: 60px;
background: #2d3748;
color: #fff;
line-height: 60px;
padding: 0 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
font-size: 20px;
font-weight: bold;
}
.user-info {
display: flex;
align-items: center;
gap: 15px;
}
.user-avatar {
width: 36px;
height: 36px;
border-radius: 50%;
background: #4299e1;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
}
/* 主容器布局 */
.main-container {
display: flex;
height: calc(100vh - 60px);
}
/* 左侧菜单样式 */
.left-menu {
width: 220px;
background: #374151;
color: #fff;
}
.easyui-tree {
background: transparent;
}
.easyui-tree li a {
color: #e5e7eb !important;
height: 40px !important;
line-height: 40px !important;
}
.easyui-tree li a:hover, .easyui-tree li.selected a {
background: #4b5563 !important;
color: #fff !important;
}
/* 内容区域样式 */
.content-area {
flex: 1;
padding: 20px;
overflow-y: auto;
background: #f3f4f6;
}
.panel-header {
background: #4299e1 !important;
color: #fff !important;
}
/* 表单样式调整 */
.form-group {
margin-bottom: 15px;
}
.form-label {
display: inline-block;
width: 80px;
text-align: right;
margin-right: 10px;
}
/* 响应式调整 */
@media (max-width: 768px) {
.left-menu {
width: 60px;
}
.logo span {
display: none;
}
}
</style>
</head>
<body class="easyui-layout">
<!-- 顶部导航 -->
<div class="top-nav">
<div class="logo">
<i class="icon-menu"></i>
<span>EasyUI 管理系统</span>
</div>
<div class="user-info">
<span>欢迎回来,管理员</span>
<div class="user-avatar"></div>
<a href="javascript:;" class="easyui-linkbutton" plain="true" iconCls="icon-exit" onclick="logout()">退出登录</a>
</div>
</div>
<!-- 主容器 -->
<div class="main-container">
<!-- 左侧菜单 -->
<div class="left-menu" id="menuTree"></div>
<!-- 右侧内容区域 -->
<div class="content-area">
<div class="easyui-panel" title="数据管理" style="padding: 20px;">
<!-- 工具栏 -->
<div style="margin-bottom: 15px;">
<a href="javascript:;" class="easyui-linkbutton" iconCls="icon-add" onclick="addData()">新增</a>
<a href="javascript:;" class="easyui-linkbutton" iconCls="icon-edit" onclick="editData()">编辑</a>
<a href="javascript:;" class="easyui-linkbutton" iconCls="icon-remove" onclick="deleteData()">删除</a>
<input class="easyui-searchbox" style="width: 300px; float: right;"
prompt="请输入关键词搜索" onsearch="searchData()">
</div>
<!-- 数据表格 -->
<table id="dataGrid" class="easyui-datagrid"
style="width:100%;height:calc(100vh - 220px);"
data-options="
singleSelect:true,
fitColumns:true,
pagination:true,
rownumbers:true,
pageSize:10,
pageList:[10,20,30],
url:'#',
method:'get'">
<thead>
<tr>
<th data-options="field:'id',width:50,align:'center'">ID</th>
<th data-options="field:'name',width:100">名称</th>
<th data-options="field:'category',width:80,align:'center'">分类</th>
<th data-options="field:'status',width:80,align:'center',formatter:statusFormatter">状态</th>
<th data-options="field:'createTime',width:150,align:'center'">创建时间</th>
<th data-options="field:'operate',width:120,align:'center',formatter:operateFormatter">操作</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
<!-- 新增/编辑弹窗 -->
<div id="dataDialog" class="easyui-dialog" title="数据操作"
style="width:500px;height:350px;"
data-options="closed:true,modal:true,buttons:[
{text:'保存',iconCls:'icon-save',handler:saveData},
{text:'取消',iconCls:'icon-cancel',handler:function(){$('#dataDialog').dialog('close');}}
]">
<form id="dataForm" method="post">
<div class="form-group">
<label class="form-label">名称:</label>
<input class="easyui-textbox" name="name" style="width:350px;" required="true">
</div>
<div class="form-group">
<label class="form-label">分类:</label>
<select class="easyui-combobox" name="category" style="width:350px;" required="true">
<option value="分类1">分类1</option>
<option value="分类2">分类2</option>
<option value="分类3">分类3</option>
</select>
</div>
<div class="form-group">
<label class="form-label">状态:</label>
<select class="easyui-combobox" name="status" style="width:350px;" required="true">
<option value="1">启用</option>
<option value="0">禁用</option>
</select>
</div>
<div class="form-group">
<label class="form-label">备注:</label>
<textarea class="easyui-textbox" name="remark" style="width:350px;height:100px;" multiline="true"></textarea>
</div>
<input type="hidden" name="id">
</form>
</div>
<script>
// 页面加载完成后初始化
$(function() {
// 初始化左侧菜单树
initMenuTree();
// 加载表格数据
loadGridData();
});
// 初始化左侧菜单树
function initMenuTree() {
$('#menuTree').tree({
data: [
{
text: '系统管理',
iconCls: 'icon-sys',
children: [
{text: '用户管理', iconCls: 'icon-user', url: 'user.html'},
{text: '角色管理', iconCls: 'icon-role', url: 'role.html'},
{text: '权限管理', iconCls: 'icon-perm', url: 'perm.html'}
]
},
{
text: '数据管理',
iconCls: 'icon-data',
children: [
{text: '基础数据', iconCls: 'icon-base', url: 'base.html', selected: true},
{text: '日志管理', iconCls: 'icon-log', url: 'log.html'},
{text: '统计分析', iconCls: 'icon-stat', url: 'stat.html'}
]
},
{
text: '系统设置',
iconCls: 'icon-set',
children: [
{text: '基本设置', iconCls: 'icon-basic', url: 'setting.html'},
{text: '安全设置', iconCls: 'icon-safe', url: 'safe.html'}
]
}
],
lines: true,
onClick: function(node) {
// 菜单点击事件(实际项目中可用于加载对应页面)
console.log('点击菜单:', node.text, ',对应页面:', node.url);
// 这里可以通过AJAX加载页面内容到content-area
}
});
}
// 加载表格数据(模拟数据)
function loadGridData() {
// 模拟后端返回数据
var mockData = {
total: 30,
rows: [
{id: 1, name: '测试数据1', category: '分类1', status: 1, createTime: '2025-11-01 10:20:30'},
{id: 2, name: '测试数据2', category: '分类2', status: 1, createTime: '2025-11-02 14:30:15'},
{id: 3, name: '测试数据3', category: '分类3', status: 0, createTime: '2025-11-03 09:15:22'},
{id: 4, name: '测试数据4', category: '分类1', status: 1, createTime: '2025-11-04 16:40:55'},
{id: 5, name: '测试数据5', category: '分类2', status: 0, createTime: '2025-11-05 11:25:33'}
]
};
$('#dataGrid').datagrid('loadData', mockData);
}
// 状态格式化函数
function statusFormatter(value) {
return value === 1 ? '<span style="color:green;">启用</span>' : '<span style="color:red;">禁用</span>';
}
// 操作列格式化函数
function operateFormatter(value, row) {
return `
<a href="javascript:;" class="easyui-linkbutton" plain="true" iconCls="icon-edit" onclick="editData(${row.id})">编辑</a>
<a href="javascript:;" class="easyui-linkbutton" plain="true" iconCls="icon-remove" onclick="deleteData(${row.id})">删除</a>
`;
}
// 新增数据
function addData() {
$('#dataForm').form('clear');
$('#dataDialog').dialog('setTitle', '新增数据').dialog('open');
}
// 编辑数据
function editData(id) {
// 如果传入id直接根据id获取数据否则获取选中行
var row = id
? $('#dataGrid').datagrid('findRow', id)
: $('#dataGrid').datagrid('getSelected');
if (!row) {
$.messager.alert('提示', '请选择要编辑的数据!', 'info');
return;
}
// 填充表单数据
$('#dataForm').form('load', row);
$('#dataDialog').dialog('setTitle', '编辑数据').dialog('open');
}
// 删除数据
function deleteData(id) {
var row = id
? $('#dataGrid').datagrid('findRow', id)
: $('#dataGrid').datagrid('getSelected');
if (!row) {
$.messager.alert('提示', '请选择要删除的数据!', 'info');
return;
}
$.messager.confirm('确认', '确定要删除【' + row.name + '】吗?', function(r) {
if (r) {
// 模拟删除操作
$('#dataGrid').datagrid('deleteRow', $('#dataGrid').datagrid('getRowIndex', row));
$.messager.show({title: '成功', msg: '数据删除成功!'});
}
});
}
// 保存数据
function saveData() {
$('#dataForm').form('submit', {
url: '#', // 实际项目中替换为后端接口
onSubmit: function() {
return $(this).form('validate'); // 表单验证
},
success: function() {
var id = $('input[name="id"]').val();
var data = $('#dataForm').form('getData');
if (id) {
// 编辑操作:更新表格数据
var rowIndex = $('#dataGrid').datagrid('getRowIndex', $('#dataGrid').datagrid('findRow', id));
$('#dataGrid').datagrid('updateRow', {
index: rowIndex,
row: data
});
} else {
// 新增操作:添加到表格
data.id = Math.floor(Math.random() * 1000); // 模拟生成ID
data.createTime = new Date().format('yyyy-MM-dd hh:mm:ss');
$('#dataGrid').datagrid('insertRow', {
index: 0,
row: data
});
}
$('#dataDialog').dialog('close');
$.messager.show({title: '成功', msg: '数据保存成功!'});
}
});
}
// 搜索数据
function searchData(value) {
$('#dataGrid').datagrid('load', {
keyword: value // 实际项目中传递关键词到后端查询
});
}
// 退出登录
function logout() {
$.messager.confirm('确认', '确定要退出登录吗?', function(r) {
if (r) {
window.location.href = 'login.html'; // 跳转到登录页
}
});
}
// 日期格式化扩展
Date.prototype.format = function(fmt) {
var o = {
"M+": this.getMonth() + 1,
"d+": this.getDate(),
"h+": this.getHours(),
"m+": this.getMinutes(),
"s+": this.getSeconds(),
"q+": Math.floor((this.getMonth() + 3) / 3),
"S": this.getMilliseconds()
};
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
return fmt;
};
</script>
</body>
</html>