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

@@ -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>