一、项目结构
├── index.html # 主游戏界面
├── officials.html # 官员管理系统
├── economy.html # 经济系统界面
├── harem.html # 后宫系统界面
├── main.js # 主要游戏逻辑
├── resources/ # 资源文件夹
│ ├── emperor_portrait.png
│ ├── senior_official.png
│ ├── imperial_concubine.png
│ ├── throne_room.png
│ └── court_scene.png
├── interaction.md # 交互设计文档
├── design.md # 视觉设计文档
└── outline.md # 项目概述文档
二、核心功能模块
1. 主游戏界面 (index.html)
功能概述:
- 时间系统显示和控制
- 皇帝属性面板
- 资源状态监控
- 奏折处理系统
- 事件通知区域
核心组件:
- 顶部状态栏:时间、国库、威望、精力
- 左侧导航栏:快速切换功能
- 中央决策区:奏折处理和事件响应
- 右侧信息面板:属性图表和待办事项
- 底部消息区:滚动显示最新消息
2. 官员管理系统 (officials.html)
功能概述:
- 官员列表展示
- 任命和罢免功能
- 派系平衡监控
- 忠诚度管理
核心组件:
- 官员卡片网格:显示所有官员信息
- 任命界面:选择职位和候选人
- 派系图表:可视化派系势力分布
- 官员详情弹窗:详细信息和管理选项
3. 经济系统界面 (economy.html)
功能概述:
- 资源管理
- 税收政策调整
- 建设项目规划
- 经济数据分析
核心组件:
- 资源仪表盘:银两、粮草、人力、威望
- 税收控制面板:税率滑块和影响预览
- 建设项目列表:可选择和规划的项目
- 经济图表:历史数据和趋势分析
4. 后宫系统界面 (harem.html)
功能概述:
- 妃子管理
- 子嗣教育
- 继承规划
- 宫廷事件处理
核心组件:
- 妃子画廊:展示所有妃子信息
- 子嗣列表:皇子公主的详细信息
- 教育界面:为子嗣选择老师和培养方案
- 继承顺序:可视化继承权排序
三、游戏机制实现
时间系统
- 游戏时间:1回合=1旬(10天)
- 现实时间:正常模式15秒/回合,加速模式3秒/回合
- 时间控制:暂停、播放、加速功能
属性系统
- 皇帝六维: 威仪、智略、仁德、健体、魅力、心计
- 成长机制: 通过决策和事件动态调整属性
- 衰减机制: 长期不处理相关事务导致属性下降
事件系统
-事件生成: 基于概率和条件的随机事件生成
-事件分类: 政务、军事、经济、宫廷、外交等
-事件链: 重大事件触发后续连锁反应
决策系统
-多选决策: 每个事件提供2-4个处理选项
-后果计算: 基于属性和条件的动态后果计算
-反馈机制: 即时的视觉和文字反馈
四、代码部分
1、index.html
<!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 href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;700&family=Noto+Sans+SC:wght@300;400;500;700&family=Ma+Shan+Zheng&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet">
<!-- 核心库引入 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.4.3/echarts.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/7.3.2/pixi.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/typed.js/2.0.12/typed.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@splidejs/splide@4.1.4/dist/js/splide.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@splidejs/splide@4.1.4/dist/css/splide.min.css">
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<style>
:root {
--imperial-gold: #D4AF37;
--deep-red: #8B0000;
--dark-bg: #1A1A1A;
--text-light: #F5F5DC;
--success-green: #228B22;
--warning-orange: #FF8C00;
--error-red: #DC143C;
--neutral-gray: #696969;
}
body {
font-family: 'Noto Sans SC', sans-serif;
background: var(--dark-bg);
color: var(--text-light);
overflow-x: hidden;
}
.title-font {
font-family: 'Noto Serif SC', serif;
}
.decorative-font {
font-family: 'Ma Shan Zheng', cursive;
}
.mono-font {
font-family: 'JetBrains Mono', monospace;
}
.imperial-gold {
color: var(--imperial-gold);
}
.imperial-bg {
background: linear-gradient(135deg, var(--imperial-gold) 0%, #B8860B 100%);
}
.glass-effect {
background: rgba(26, 26, 26, 0.8);
backdrop-filter: blur(10px);
border: 1px solid rgba(212, 175, 55, 0.2);
}
.glow-effect {
box-shadow: 0 0 20px rgba(212, 175, 55, 0.3);
}
.dragon-border {
border: 2px solid var(--imperial-gold);
border-image: linear-gradient(45deg, var(--imperial-gold), #B8860B, var(--imperial-gold)) 1;
}
.attribute-bar {
background: linear-gradient(90deg, var(--imperial-gold) 0%, #B8860B 100%);
height: 8px;
border-radius: 4px;
transition: width 0.3s ease;
}
.scroll-container {
background: rgba(139, 0, 0, 0.1);
border-left: 3px solid var(--deep-red);
}
.memorial-scroll {
background: linear-gradient(135deg, #FFF8DC 0%, #F5DEB3 100%);
color: #2F4F4F;
border: 1px solid #D4AF37;
box-shadow: 0 2px 10px rgba(0,0,0,0.3);
cursor: pointer;
transition: all 0.3s ease;
}
.memorial-scroll:hover {
transform: translateY(-2px);
box-shadow: 0 4px 20px rgba(212, 175, 55, 0.4);
}
.floating-particles {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 1;
}
.notification-popup {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(26, 26, 26, 0.95);
border: 2px solid var(--imperial-gold);
border-radius: 10px;
padding: 20px;
z-index: 1000;
max-width: 500px;
display: none;
}
.decision-button {
background: linear-gradient(135deg, var(--imperial-gold) 0%, #B8860B 100%);
color: var(--dark-bg);
border: none;
padding: 10px 20px;
border-radius: 5px;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
margin: 5px;
}
.decision-button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 15px rgba(212, 175, 55, 0.5);
}
.resource-icon {
width: 24px;
height: 24px;
background: var(--imperial-gold);
border-radius: 50%;
display: inline-flex;
align-items: center;
justify-content: center;
margin-right: 8px;
}
#p5-background {
position: fixed;
top: 0;
left: 0;
z-index: -1;
}
.typing-effect {
border-right: 2px solid var(--imperial-gold);
animation: blink 1s infinite;
}
@keyframes blink {
0%, 50% { border-color: var(--imperial-gold); }
51%, 100% { border-color: transparent; }
}
.dragon-decoration {
position: absolute;
width: 60px;
height: 60px;
background: url(https://blog.csdn.net/'data:image/svg+xml,<svg%20xmlns="http://www.w3.org/2000/svg"%20viewBox="0%200%20100%20100"><path%20d="M20,50%20Q30,30%2050,35%20Q70,30%2080,50%20Q70,70%2050,65%20Q30,70%2020,50"%20fill="%23D4AF37"%20opacity="0.6"/></svg>') no-repeat center;
background-size: contain;
}
.dragon-top-left { top: 10px; left: 10px; }
.dragon-top-right { top: 10px; right: 10px; }
.dragon-bottom-left { bottom: 10px; left: 10px; }
.dragon-bottom-right { bottom: 10px; right: 10px; }
</style>
</head>
<body class="min-h-screen">
<!-- P5.js 背景画布 -->
<div id="p5-background"></div>
<!-- 浮动粒子效果 -->
<div class="floating-particles" id="particles"></div>
<!-- 龙纹装饰 -->
<div class="dragon-decoration dragon-top-left"></div>
<div class="dragon-decoration dragon-top-right"></div>
<div class="dragon-decoration dragon-bottom-left"></div>
<div class="dragon-decoration dragon-bottom-right"></div>
<!-- 顶部状态栏 -->
<header class="glass-effect fixed top-0 left-0 right-0 z-50 p-4">
<div class="flex justify-between items-center">
<!-- 游戏标题 -->
<div class="flex items-center">
<h1 class="title-font text-2xl font-bold imperial-gold mr-6">天子纪元</h1>
<div class="decorative-font text-lg">大胤王朝</div>
</div>
<!-- 时间控制 -->
<div class="flex items-center space-x-4">
<div class="glass-effect px-4 py-2 rounded">
<span class="mono-font text-sm">景耀元年</span>
<span class="mono-font text-sm ml-2" id="game-time">正月初一</span>
</div>
<div class="flex space-x-2">
<button class="decision-button text-sm px-3 py-1" id="pause-btn">⏸️</button>
<button class="decision-button text-sm px-3 py-1" id="play-btn">▶️</button>
<button class="decision-button text-sm px-3 py-1" id="fast-btn">⚡</button>
</div>
</div>
<!-- 资源状态 -->
<div class="flex items-center space-x-6">
<div class="flex items-center">
<div class="resource-icon">💰</div>
<span class="mono-font" id="money">100,000</span>
</div>
<div class="flex items-center">
<div class="resource-icon">🌾</div>
<span class="mono-font" id="food">50,000</span>
</div>
<div class="flex items-center">
<div class="resource-icon">👥</div>
<span class="mono-font" id="population">1,000,000</span>
</div>
<div class="flex items-center">
<div class="resource-icon">👑</div>
<span class="mono-font" id="prestige">75</span>
</div>
<div class="flex items-center">
<div class="resource-icon">⚡</div>
<span class="mono-font" id="energy">100</span>
</div>
</div>
</div>
</header>
<!-- 左侧导航栏 -->
<nav class="glass-effect fixed left-0 top-20 bottom-0 w-20 z-40 flex flex-col items-center py-6 space-y-4">
<button class="nav-btn w-12 h-12 rounded-full imperial-bg text-dark-bg font-bold" data-page="main">🏛️</button>
<button class="nav-btn w-12 h-12 rounded-full glass-effect" data-page="officials">👔</button>
<button class="nav-btn w-12 h-12 rounded-full glass-effect" data-page="economy">💹</button>
<button class="nav-btn w-12 h-12 rounded-full glass-effect" data-page="harem">👸</button>
<button class="nav-btn w-12 h-12 rounded-full glass-effect" data-page="military">⚔️</button>
<button class="nav-btn w-12 h-12 rounded-full glass-effect" data-page="diplomacy">🌍</button>
<div class="flex-1"></div>
<button class="nav-btn w-12 h-12 rounded-full glass-effect" id="save-btn">💾</button>
<button class="nav-btn w-12 h-12 rounded-full glass-effect" id="settings-btn">⚙️</button>
</nav>
<!-- 主内容区域 -->
<main class="ml-20 mt-20 p-6 min-h-screen">
<!-- 皇帝属性面板 -->
<section class="glass-effect rounded-lg p-6 mb-6">
<h2 class="title-font text-xl font-bold imperial-gold mb-4">皇帝属性</h2>
<div class="grid grid-cols-6 gap-4">
<div class="attribute-item text-center">
<div class="text-2xl mb-2">👑</div>
<div class="text-sm text-gray-300">威仪</div>
<div class="w-full bg-gray-700 rounded-full h-2 mt-2">
<div class="attribute-bar" style="width: 65%" data-value="65"></div>
</div>
<div class="mono-font text-sm mt-1">65</div>
</div>
<div class="attribute-item text-center">
<div class="text-2xl mb-2">🧠</div>
<div class="text-sm text-gray-300">智略</div>
<div class="w-full bg-gray-700 rounded-full h-2 mt-2">
<div class="attribute-bar" style="width: 72%" data-value="72"></div>
</div>
<div class="mono-font text-sm mt-1">72</div>
</div>
<div class="attribute-item text-center">
<div class="text-2xl mb-2">💝</div>
<div class="text-sm text-gray-300">仁德</div>
<div class="w-full bg-gray-700 rounded-full h-2 mt-2">
<div class="attribute-bar" style="width: 58%" data-value="58"></div>
</div>
<div class="mono-font text-sm mt-1">58</div>
</div>
<div class="attribute-item text-center">
<div class="text-2xl mb-2">💪</div>
<div class="text-sm text-gray-300">健体</div>
<div class="w-full bg-gray-700 rounded-full h-2 mt-2">
<div class="attribute-bar" style="width: 80%" data-value="80"></div>
</div>
<div class="mono-font text-sm mt-1">80</div>
</div>
<div class="attribute-item text-center">
<div class="text-2xl mb-2">✨</div>
<div class="text-sm text-gray-300">魅力</div>
<div class="w-full bg-gray-700 rounded-full h-2 mt-2">
<div class="attribute-bar" style="width: 70%" data-value="70"></div>
</div>
<div class="mono-font text-sm mt-1">70</div>
</div>
<div class="attribute-item text-center">
<div class="text-2xl mb-2">🕵️</div>
<div class="text-sm text-gray-300">心计</div>
<div class="w-full bg-gray-700 rounded-full h-2 mt-2">
<div class="attribute-bar" style="width: 45%" data-value="45"></div>
</div>
<div class="mono-font text-sm mt-1">45</div>
</div>
</div>
</section>
<!-- 中央决策区域 -->
<div class="grid grid-cols-3 gap-6">
<!-- 奏折处理区 -->
<section class="col-span-2 glass-effect rounded-lg p-6">
<div class="flex justify-between items-center mb-4">
<h2 class="title-font text-xl font-bold imperial-gold">待批奏折</h2>
<div class="text-sm text-gray-300">
今日已处理: <span class="mono-font" id="processed-count">3</span> / <span class="mono-font" id="total-count">8</span>
</div>
</div>
<!-- 奏折堆叠区域 -->
<div class="memorial-scrolls-area min-h-96 relative">
<div class="scroll-container p-4 rounded-lg min-h-96">
<div id="memorial-list" class="space-y-3">
<!-- 奏折将通过JavaScript动态生成 -->
</div>
</div>
</div>
<!-- 处理选项 -->
<div class="mt-6 flex justify-center space-x-4">
<button class="decision-button" id="personal-review">🖋️ 朱批</button>
<button class="decision-button" id="hold-back">⏳ 留中</button>
<button class="decision-button" id="cabinet-review">🏛️ 内阁</button>
<button class="decision-button" id="summon-official">👤 召对</button>
</div>
</section>
<!-- 右侧面板 -->
<section class="space-y-6">
<!-- 待办事项 -->
<div class="glass-effect rounded-lg p-4">
<h3 class="title-font text-lg font-bold imperial-gold mb-3">待办事项</h3>
<div class="space-y-2" id="todo-list">
<div class="flex items-center text-sm">
<div class="w-2 h-2 bg-red-500 rounded-full mr-2"></div>
<span>处理边疆军报</span>
</div>
<div class="flex items-center text-sm">
<div class="w-2 h-2 bg-orange-500 rounded-full mr-2"></div>
<span>审阅科举名单</span>
</div>
<div class="flex items-center text-sm">
<div class="w-2 h-2 bg-yellow-500 rounded-full mr-2"></div>
<span>后宫选秀</span>
</div>
</div>
</div>
<!-- 势力图表 -->
<div class="glass-effect rounded-lg p-4">
<h3 class="title-font text-lg font-bold imperial-gold mb-3">朝中势力</h3>
<div id="faction-chart" style="height: 200px;"></div>
</div>
<!-- 快速操作 -->
<div class="glass-effect rounded-lg p-4">
<h3 class="title-font text-lg font-bold imperial-gold mb-3">快速操作</h3>
<div class="space-y-2">
<button class="w-full decision-button text-sm py-2">🏮 举办宴会</button>
<button class="w-full decision-button text-sm py-2">🎯 微服私访</button>
<button class="w-full decision-button text-sm py-2">📚 读书学习</button>
<button class="w-full decision-button text-sm py-2">🏹 狩猎锻炼</button>
</div>
</div>
</section>
</div>
<!-- 消息滚动条 -->
<div class="fixed bottom-0 left-20 right-0 glass-effect p-3 z-30">
<div class="flex items-center">
<span class="imperial-gold font-bold mr-3">📜 朝政消息:</span>
<div class="flex-1 overflow-hidden">
<div class="scrolling-text whitespace-nowrap" id="news-ticker">
边疆传来捷报,大将军成功击退匈奴入侵,保卫了边境安宁。朝中清流派对您的决策表示赞赏,威望提升。
</div>
</div>
</div>
</div>
</main>
<!-- 事件弹窗 -->
<div class="notification-popup" id="event-popup">
<div class="text-center mb-4">
<div class="text-4xl mb-2" id="event-icon">🏮</div>
<h3 class="title-font text-xl font-bold imperial-gold" id="event-title">事件标题</h3>
</div>
<div class="mb-6" id="event-description">
事件描述内容...
</div>
<div class="flex justify-center space-x-4" id="event-choices">
<!-- 决策选项将通过JavaScript动态生成 -->
</div>
<button class="absolute top-2 right-2 text-gray-400 hover:text-white" onclick="closeEventPopup()">✕</button>
</div>
<!-- 遮罩层 -->
<div class="fixed inset-0 bg-black bg-opacity-50 z-999 hidden" id="overlay"></div>
<script src="main.js"></script>
</body>
</html>
2、harem.html
<!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 href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;700&family=Noto+Sans+SC:wght@300;400;500;700&family=Ma+Shan+Zheng&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet">
<!-- 核心库引入 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@splidejs/splide@4.1.4/dist/js/splide.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@splidejs/splide@4.1.4/dist/css/splide.min.css">
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<style>
:root {
--imperial-gold: #D4AF37;
--deep-red: #8B0000;
--dark-bg: #1A1A1A;
--text-light: #F5F5DC;
--success-green: #228B22;
--warning-orange: #FF8C00;
--error-red: #DC143C;
--neutral-gray: #696969;
}
body {
font-family: 'Noto Sans SC', sans-serif;
background: var(--dark-bg);
color: var(--text-light);
overflow-x: hidden;
}
.title-font {
font-family: 'Noto Serif SC', serif;
}
.decorative-font {
font-family: 'Ma Shan Zheng', cursive;
}
.mono-font {
font-family: 'JetBrains Mono', monospace;
}
.imperial-gold {
color: var(--imperial-gold);
}
.glass-effect {
background: rgba(26, 26, 26, 0.8);
backdrop-filter: blur(10px);
border: 1px solid rgba(212, 175, 55, 0.2);
}
.concubine-card {
background: linear-gradient(135deg, rgba(212, 175, 55, 0.1) 0%, rgba(139, 0, 0, 0.1) 100%);
border: 1px solid rgba(212, 175, 55, 0.3);
border-radius: 12px;
padding: 20px;
transition: all 0.3s ease;
cursor: pointer;
position: relative;
overflow: hidden;
}
.concubine-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 25px rgba(212, 175, 55, 0.3);
border-color: var(--imperial-gold);
}
.concubine-card.favorited {
border-color: var(--imperial-gold);
box-shadow: 0 0 20px rgba(212, 175, 55, 0.4);
}
.rank-badge {
position: absolute;
top: 10px;
right: 10px;
padding: 4px 8px;
border-radius: 12px;
font-size: 0.75rem;
font-weight: bold;
z-index: 10;
}
.rank-empress { background: #D4AF37; color: black; }
.rank-imperial-concubine { background: #8B0000; color: white; }
.rank-imperial-noble-consort { background: #4169E1; color: white; }
.rank-imperial-consort { background: #228B22; color: white; }
.rank-imperial-lady { background: #FF8C00; color: black; }
.rank-ordinary-lady { background: #696969; color: white; }
.affection-heart {
color: #DC143C;
font-size: 1.2rem;
margin-right: 2px;
}
.prince-card {
background: rgba(26, 26, 26, 0.9);
border: 1px solid rgba(212, 175, 55, 0.3);
border-radius: 8px;
padding: 15px;
margin-bottom: 10px;
transition: all 0.3s ease;
}
.prince-card:hover {
border-color: var(--imperial-gold);
box-shadow: 0 4px 15px rgba(212, 175, 55, 0.2);
}
.prince-card.crown-prince {
border-color: var(--imperial-gold);
background: rgba(212, 175, 55, 0.1);
}
.modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.8);
display: none;
z-index: 1000;
}
.modal-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: var(--dark-bg);
border: 2px solid var(--imperial-gold);
border-radius: 10px;
padding: 20px;
max-width: 600px;
width: 90%;
max-height: 80vh;
overflow-y: auto;
}
.splide__slide {
display: flex;
align-items: center;
justify-content: center;
}
.selection-ceremony {
background: linear-gradient(135deg, rgba(212, 175, 55, 0.2) 0%, rgba(139, 0, 0, 0.2) 100%);
border-radius: 15px;
padding: 30px;
text-align: center;
position: relative;
overflow: hidden;
}
.selection-ceremony::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: radial-gradient(circle, rgba(212, 175, 55, 0.1) 0%, transparent 70%);
animation: rotate 20s linear infinite;
}
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.concubine-portrait {
width: 120px;
height: 150px;
background: rgba(212, 175, 55, 0.1);
border: 2px solid var(--imperial-gold);
border-radius: 8px;
margin: 0 auto 15px;
display: flex;
align-items: center;
justify-content: center;
font-size: 3rem;
position: relative;
}
.attribute-bar {
height: 6px;
border-radius: 3px;
background: #333;
overflow: hidden;
margin-top: 4px;
}
.attribute-fill {
height: 100%;
transition: width 0.5s ease;
}
.fill-beauty { background: linear-gradient(90deg, #FF69B4, #FFB6C1); }
.fill-talent { background: linear-gradient(90deg, #4169E1, #87CEEB); }
.fill-scheming { background: linear-gradient(90deg, #8B0000, #DC143C); }
.fill-health { background: linear-gradient(90deg, #228B22, #32CD32); }
</style>
</head>
<body class="min-h-screen">
<!-- 顶部导航 -->
<header class="glass-effect fixed top-0 left-0 right-0 z-50 p-4">
<div class="flex justify-between items-center">
<div class="flex items-center">
<button onclick="window.location.href='index.html'" class="mr-4 text-2xl">🏛️</button>
<h1 class="title-font text-2xl font-bold imperial-gold">后宫管理</h1>
</div>
<div class="flex space-x-4">
<button class="px-4 py-2 bg-pink-600 text-white rounded hover:bg-pink-700" onclick="showSelectionCeremony()">
🌸 选秀
</button>
<button class="px-4 py-2 bg-purple-600 text-white rounded hover:bg-purple-700" onclick="showSuccessionPlanning()">
👑 立储
</button>
<button class="px-4 py-2 bg-yellow-600 text-white rounded hover:bg-yellow-700" onclick="showPalaceEvents()">
🎭 宫廷事件
</button>
</div>
</div>
</header>
<!-- 主内容区域 -->
<main class="pt-20 p-6">
<!-- 后宫概况 -->
<section class="glass-effect rounded-lg p-6 mb-6">
<h2 class="title-font text-xl font-bold imperial-gold mb-4">后宫概况</h2>
<div class="grid grid-cols-2 md:grid-cols-4 gap-6">
<div class="text-center">
<div class="text-3xl font-bold imperial-gold" id="total-concubines">12</div>
<div class="text-sm text-gray-300">后宫妃嫔</div>
</div>
<div class="text-center">
<div class="text-3xl font-bold text-blue-400" id="total-princes">8</div>
<div class="text-sm text-gray-300">皇子</div>
</div>
<div class="text-center">
<div class="text-3xl font-bold text-pink-400" id="total-princesses">6</div>
<div class="text-sm text-gray-300">公主</div>
</div>
<div class="text-center">
<div class="text-3xl font-bold text-yellow-400" id="imperial-favor">85</div>
<div class="text-sm text-gray-300">总体宠爱</div>
</div>
</div>
</section>
<!-- 妃嫔列表 -->
<section class="glass-effect rounded-lg p-6 mb-6">
<div class="flex justify-between items-center mb-6">
<h2 class="title-font text-xl font-bold imperial-gold">后宫妃嫔</h2>
<div class="flex space-x-4">
<select class="bg-gray-700 text-white px-3 py-1 rounded" id="rank-filter">
<option value="all">所有品级</option>
<option value="empress">皇后</option>
<option value="imperial-concubine">皇贵妃</option>
<option value="imperial-noble-consort">贵妃</option>
<option value="imperial-consort">妃</option>
<option value="imperial-lady">嫔</option>
<option value="ordinary-lady">贵人</option>
</select>
<select class="bg-gray-700 text-white px-3 py-1 rounded" id="favor-filter">
<option value="all">宠爱程度</option>
<option value="high">盛宠</option>
<option value="medium">得宠</option>
<option value="low">失宠</option>
</select>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6" id="concubines-grid">
<!-- 妃嫔卡片将通过JavaScript动态生成 -->
</div>
</section>
<!-- 子嗣列表 -->
<section class="glass-effect rounded-lg p-6 mb-6">
<div class="flex justify-between items-center mb-6">
<h2 class="title-font text-xl font-bold imperial-gold">皇子公主</h2>
<div class="flex space-x-4">
<button class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700" onclick="showEducationSystem()">
📚 教育管理
</button>
<button class="px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700" onclick="showMarriagePlanning()">
💒 婚配安排
</button>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<h3 class="font-bold mb-4 text-blue-400">皇子</h3>
<div id="princes-list">
<!-- 皇子列表将通过JavaScript生成 -->
</div>
</div>
<div>
<h3 class="font-bold mb-4 text-pink-400">公主</h3>
<div id="princesses-list">
<!-- 公主列表将通过JavaScript生成 -->
</div>
</div>
</div>
</section>
<!-- 继承顺序 -->
<section class="glass-effect rounded-lg p-6">
<h2 class="title-font text-xl font-bold imperial-gold mb-4">继承顺序</h2>
<div class="space-y-3" id="succession-list">
<!-- 继承顺序将通过JavaScript生成 -->
</div>
</section>
</main>
<!-- 妃嫔详情模态框 -->
<div class="modal" id="concubine-detail-modal">
<div class="modal-content">
<div class="flex justify-between items-center mb-6">
<h3 class="title-font text-xl font-bold imperial-gold" id="concubine-name">妃嫔详情</h3>
<button onclick="closeConcubineDetailModal()" class="text-gray-400 hover:text-white text-2xl">×</button>
</div>
<div id="concubine-detail-content">
<!-- 妃嫔详情内容将通过JavaScript生成 -->
</div>
<div class="flex justify-end space-x-4 mt-6">
<button onclick="summonConcubine()" class="px-4 py-2 bg-pink-600 text-white rounded hover:bg-pink-700">
🌙 召幸
</button>
<button onclick="giftConcubine()" class="px-4 py-2 bg-yellow-600 text-white rounded hover:bg-yellow-700">
💎 赏赐
</button>
<button onclick="punishConcubine()" class="px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700">
⚖️ 惩罚
</button>
</div>
</div>
</div>
<!-- 选秀仪式模态框 -->
<div class="modal" id="selection-ceremony-modal">
<div class="modal-content">
<div class="flex justify-between items-center mb-6">
<h3 class="title-font text-xl font-bold imperial-gold">选秀大典</h3>
<button onclick="closeSelectionCeremony()" class="text-gray-400 hover:text-white text-2xl">×</button>
</div>
<div class="selection-ceremony">
<div class="mb-6">
<h4 class="decorative-font text-2xl imperial-gold mb-4">选秀仪式</h4>
<p class="text-sm text-gray-300 mb-6">
三年一度的选秀大典即将开始,各地佳丽云集京师。陛下可从中挑选心仪的妃嫔充实后宫。
</p>
</div>
<div class="splide" id="selection-carousel">
<div class="splide__track">
<ul class="splide__list" id="selection-candidates">
<!-- 候选人将通过JavaScript生成 -->
</ul>
</div>
</div>
<div class="mt-6">
<button onclick="selectCandidate()" class="px-6 py-3 bg-yellow-600 text-white rounded hover:bg-yellow-700 font-bold">
选中此女
</button>
</div>
</div>
</div>
</div>
<!-- 立储模态框 -->
<div class="modal" id="succession-modal">
<div class="modal-content">
<div class="flex justify-between items-center mb-6">
<h3 class="title-font text-xl font-bold imperial-gold">立储大典</h3>
<button onclick="closeSuccessionModal()" class="text-gray-400 hover:text-white text-2xl">×</button>
</div>
<div id="succession-content">
<!-- 立储内容将通过JavaScript生成 -->
</div>
<div class="flex justify-end space-x-4 mt-6">
<button onclick="closeSuccessionModal()" class="px-4 py-2 bg-gray-600 text-white rounded hover:bg-gray-700">
取消
</button>
<button onclick="confirmCrownPrince()" class="px-4 py-2 bg-yellow-600 text-white rounded hover:bg-yellow-700">
立为太子
</button>
</div>
</div>
</div>
<script>
// 后宫管理系统
class HaremManager {
constructor() {
this.concubines = [];
this.princes = [];
this.princesses = [];
this.selectedConcubine = null;
this.selectedCandidate = null;
this.currentCarouselIndex = 0;
this.init();
}
init() {
this.generateConcubines();
this.generateChildren();
this.setupEventListeners();
this.renderConcubines();
this.renderChildren();
this.renderSuccessionList();
this.updateStatistics();
}
generateConcubines() {
const surnames = ['王', '李', '张', '刘', '陈', '杨', '赵', '黄', '周', '吴'];
const names = ['昭君', '玉环', '飞燕', '西施', '貂蝉', '昭君', '丽华', '惠儿', '淑华', '雅琴'];
const ranks = [
{ name: '皇后', level: 1, key: 'empress' },
{ name: '皇贵妃', level: 2, key: 'imperial-concubine' },
{ name: '贵妃', level: 3, key: 'imperial-noble-consort' },
{ name: '妃', level: 4, key: 'imperial-consort' },
{ name: '嫔', level: 5, key: 'imperial-lady' },
{ name: '贵人', level: 6, key: 'ordinary-lady' }
];
// 生成皇后
this.concubines.push({
id: 1,
name: '王皇后',
rank: ranks[0],
age: 28,
beauty: 85,
talent: 90,
scheming: 70,
health: 95,
affection: 95,
personality: '贤德端庄',
background: '名门望族',
children: [1],
status: 'healthy'
});
// 生成其他妃嫔
for (let i = 1; i < 12; i++) {
const surname = surnames[Math.floor(Math.random() * surnames.length)];
const name = names[Math.floor(Math.random() * names.length)];
const rank = ranks[Math.floor(Math.random() * (ranks.length - 1)) + 1]; // 排除皇后
this.concubines.push({
id: i + 1,
name: surname + name,
rank: rank,
age: Math.floor(Math.random() * 15) + 18,
beauty: Math.floor(Math.random() * 30) + 70,
talent: Math.floor(Math.random() * 40) + 60,
scheming: Math.floor(Math.random() * 60) + 20,
health: Math.floor(Math.random() * 30) + 70,
affection: Math.floor(Math.random() * 80) + 20,
personality: this.getRandomPersonality(),
background: this.getRandomBackground(),
children: [],
status: 'healthy'
});
}
}
generateChildren() {
const princeNames = ['胤礽', '胤禛', '胤禩', '胤禟', '胤祥', '胤祯', '胤禵', '胤禑'];
const princessNames = ['和敬', '和静', '和婉', '和嘉', '和宜', '和淑'];
// 生成皇子
for (let i = 0; i < 8; i++) {
const mother = this.concubines[Math.floor(Math.random() * this.concubines.length)];
mother.children.push(i + 1);
this.princes.push({
id: i + 1,
name: princeNames[i],
age: Math.floor(Math.random() * 20) + 5,
mother: mother.name,
intelligence: Math.floor(Math.random() * 40) + 60,
martial: Math.floor(Math.random() * 40) + 60,
virtue: Math.floor(Math.random() * 40) + 60,
ambition: Math.floor(Math.random() * 60) + 20,
health: Math.floor(Math.random() * 30) + 70,
status: 'unmarried',
successionOrder: i + 1
});
}
// 生成公主
for (let i = 0; i < 6; i++) {
const mother = this.concubines[Math.floor(Math.random() * this.concubines.length)];
if (!mother.children.includes(i + 101)) {
mother.children.push(i + 101);
}
this.princesses.push({
id: i + 101,
name: princessNames[i],
age: Math.floor(Math.random() * 18) + 3,
mother: mother.name,
beauty: Math.floor(Math.random() * 40) + 60,
talent: Math.floor(Math.random() * 40) + 60,
virtue: Math.floor(Math.random() * 40) + 60,
health: Math.floor(Math.random() * 30) + 70,
status: 'unmarried'
});
}
}
getRandomPersonality() {
const personalities = ['温婉贤淑', '活泼开朗', '端庄稳重', '聪慧机敏', '娇俏可人', '清冷高雅'];
return personalities[Math.floor(Math.random() * personalities.length)];
}
getRandomBackground() {
const backgrounds = ['官宦世家', '书香门第', '商贾之家', '平民百姓', '将门之后', '名门望族'];
return backgrounds[Math.floor(Math.random() * backgrounds.length)];
}
setupEventListeners() {
document.getElementById('rank-filter').addEventListener('change', () => this.filterConcubines());
document.getElementById('favor-filter').addEventListener('change', () => this.filterConcubines());
}
renderConcubines() {
const container = document.getElementById('concubines-grid');
container.innerHTML = '';
this.concubines.forEach((concubine, index) => {
const card = this.createConcubineCard(concubine);
container.appendChild(card);
// 添加进入动画
anime({
targets: card,
scale: [0.8, 1],
opacity: [0, 1],
duration: 600,
delay: index * 100,
easing: 'easeOutCubic'
});
});
}
createConcubineCard(concubine) {
const card = document.createElement('div');
card.className = `concubine-card ${concubine.affection >= 80 ? 'favorited' : ''}`;
card.dataset.concubineId = concubine.id;
const hearts = '♥'.repeat(Math.ceil(concubine.affection / 20));
const rankClass = `rank-${concubine.rank.key}`;
card.innerHTML = `
<div class="rank-badge ${rankClass}">${concubine.rank.name}</div>
<div class="concubine-portrait">
👸
</div>
<div class="text-center mb-4">
<h3 class="font-bold text-lg">${concubine.name}</h3>
<p class="text-sm text-gray-300">${concubine.age}岁 · ${concubine.personality}</p>
</div>
<div class="space-y-3 text-sm">
<div>
<div class="flex justify-between mb-1">
<span>宠爱度</span>
<span class="mono-font">${concubine.affection}</span>
</div>
<div class="attribute-bar">
<div class="attribute-fill fill-beauty" style="width: ${concubine.affection}%"></div>
</div>
</div>
<div>
<div class="flex justify-between mb-1">
<span>美貌</span>
<span class="mono-font">${concubine.beauty}</span>
</div>
<div class="attribute-bar">
<div class="attribute-fill fill-beauty" style="width: ${concubine.beauty}%"></div>
</div>
</div>
<div>
<div class="flex justify-between mb-1">
<span>才情</span>
<span class="mono-font">${concubine.talent}</span>
</div>
<div class="attribute-bar">
<div class="attribute-fill fill-talent" style="width: ${concubine.talent}%"></div>
</div>
</div>
<div class="flex justify-between text-xs text-gray-400">
<span>出身: ${concubine.background}</span>
<span>子嗣: ${concubine.children.length}人</span>
</div>
</div>
<div class="mt-4 flex space-x-2">
<button onclick="showConcubineDetail(${concubine.id})" class="flex-1 px-3 py-2 bg-purple-600 text-white rounded text-sm hover:bg-purple-700">
详情
</button>
<button onclick="summonConcubine(${concubine.id})" class="flex-1 px-3 py-2 bg-pink-600 text-white rounded text-sm hover:bg-pink-700">
召幸
</button>
</div>
`;
return card;
}
renderChildren() {
// 渲染皇子
const princesContainer = document.getElementById('princes-list');
princesContainer.innerHTML = '';
this.princes.forEach(prince => {
const card = this.createPrinceCard(prince);
princesContainer.appendChild(card);
});
// 渲染公主
const princessesContainer = document.getElementById('princesses-list');
princessesContainer.innerHTML = '';
this.princesses.forEach(princess => {
const card = this.createPrincessCard(princess);
princessesContainer.appendChild(card);
});
}
createPrinceCard(prince) {
const card = document.createElement('div');
card.className = `prince-card ${prince.successionOrder === 1 ? 'crown-prince' : ''}`;
card.innerHTML = `
<div class="flex justify-between items-start mb-3">
<div>
<h4 class="font-bold">${prince.name}</h4>
<p class="text-sm text-gray-300">${prince.age}岁 · ${prince.mother}</p>
</div>
${prince.successionOrder === 1 ? '<span class="px-2 py-1 bg-yellow-600 text-white rounded text-xs">太子</span>' : ''}
</div>
<div class="grid grid-cols-2 gap-2 text-sm">
<div>智谋: <span class="mono-font">${prince.intelligence}</span></div>
<div>武艺: <span class="mono-font">${prince.martial}</span></div>
<div>德行: <span class="mono-font">${prince.virtue}</span></div>
<div>野心: <span class="mono-font">${prince.ambition}</span></div>
</div>
<div class="mt-3 flex space-x-2">
<button onclick="showPrinceDetail(${prince.id})" class="flex-1 px-2 py-1 bg-blue-600 text-white rounded text-xs hover:bg-blue-700">
详情
</button>
<button onclick="educatePrince(${prince.id})" class="flex-1 px-2 py-1 bg-green-600 text-white rounded text-xs hover:bg-green-700">
教育
</button>
</div>
`;
return card;
}
createPrincessCard(princess) {
const card = document.createElement('div');
card.className = 'prince-card';
card.innerHTML = `
<div class="flex justify-between items-start mb-3">
<div>
<h4 class="font-bold">${princess.name}</h4>
<p class="text-sm text-gray-300">${princess.age}岁 · ${princess.mother}</p>
</div>
<span class="px-2 py-1 bg-pink-600 text-white rounded text-xs">公主</span>
</div>
<div class="grid grid-cols-2 gap-2 text-sm">
<div>美貌: <span class="mono-font">${princess.beauty}</span></div>
<div>才艺: <span class="mono-font">${princess.talent}</span></div>
<div>品德: <span class="mono-font">${princess.virtue}</span></div>
<div>健康: <span class="mono-font">${princess.health}</span></div>
</div>
<div class="mt-3 flex space-x-2">
<button onclick="showPrincessDetail(${princess.id})" class="flex-1 px-2 py-1 bg-purple-600 text-white rounded text-xs hover:bg-purple-700">
详情
</button>
<button onclick="arrangeMarriage(${princess.id})" class="flex-1 px-2 py-1 bg-red-600 text-white rounded text-xs hover:bg-red-700">
婚配
</button>
</div>
`;
return card;
}
renderSuccessionList() {
const container = document.getElementById('succession-list');
container.innerHTML = '';
// 按继承顺序排序
const sortedPrinces = [...this.princes].sort((a, b) => a.successionOrder - b.successionOrder);
sortedPrinces.forEach((prince, index) => {
const item = document.createElement('div');
item.className = 'flex items-center justify-between p-4 bg-gray-800 rounded-lg';
item.innerHTML = `
<div class="flex items-center">
<div class="w-8 h-8 rounded-full bg-yellow-600 flex items-center justify-center text-sm font-bold mr-4">
${index + 1}
</div>
<div>
<h4 class="font-bold">${prince.name}</h4>
<p class="text-sm text-gray-300">${prince.age}岁 · ${prince.mother}</p>
</div>
</div>
<div class="flex items-center space-x-4">
<div class="text-sm">
智: <span class="mono-font">${prince.intelligence}</span>
武: <span class="mono-font">${prince.martial}</span>
德: <span class="mono-font">${prince.virtue}</span>
</div>
${index === 0 ?
'<span class="px-3 py-1 bg-yellow-600 text-white rounded text-sm">太子</span>' :
'<button onclick="designateCrownPrince(' + prince.id + ')" class="px-3 py-1 bg-blue-600 text-white rounded text-sm hover:bg-blue-700">立为太子</button>'
}
</div>
`;
container.appendChild(item);
});
}
updateStatistics() {
const totalFavor = Math.round(this.concubines.reduce((sum, c) => sum + c.affection, 0) / this.concubines.length);
document.getElementById('total-concubines').textContent = this.concubines.length;
document.getElementById('total-princes').textContent = this.princes.length;
document.getElementById('total-princesses').textContent = this.princesses.length;
document.getElementById('imperial-favor').textContent = totalFavor;
}
filterConcubines() {
const rankFilter = document.getElementById('rank-filter').value;
const favorFilter = document.getElementById('favor-filter').value;
const cards = document.querySelectorAll('.concubine-card');
cards.forEach((card, index) => {
const concubine = this.concubines[index];
let show = true;
if (rankFilter !== 'all' && concubine.rank.key !== rankFilter) {
show = false;
}
if (favorFilter !== 'all') {
if (favorFilter === 'high' && concubine.affection < 80) show = false;
if (favorFilter === 'medium' && (concubine.affection < 40 || concubine.affection >= 80)) show = false;
if (favorFilter === 'low' && concubine.affection >= 40) show = false;
}
if (show) {
card.style.display = 'block';
anime({
targets: card,
opacity: [0, 1],
scale: [0.8, 1],
duration: 300,
delay: index * 50
});
} else {
card.style.display = 'none';
}
});
}
generateSelectionCandidates() {
const surnames = ['李', '王', '张', '刘', '陈', '杨', '赵', '黄', '周', '吴'];
const names = ['秀英', '秀英', '玉英', '桂英', '兰英', '梅英', '淑英', '惠英', '雅英', '静英'];
const backgrounds = ['官宦世家', '书香门第', '商贾之家', '平民百姓', '将门之后'];
const candidates = [];
for (let i = 0; i < 8; i++) {
const surname = surnames[Math.floor(Math.random() * surnames.length)];
const name = names[Math.floor(Math.random() * names.length)];
candidates.push({
id: i + 100,
name: surname + name,
age: Math.floor(Math.random() * 5) + 16,
beauty: Math.floor(Math.random() * 30) + 70,
talent: Math.floor(Math.random() * 40) + 60,
scheming: Math.floor(Math.random() * 60) + 20,
health: Math.floor(Math.random() * 30) + 70,
background: backgrounds[Math.floor(Math.random() * backgrounds.length)],
personality: this.getRandomPersonality()
});
}
return candidates;
}
}
// 全局函数
function showConcubineDetail(concubineId) {
const concubine = haremManager.concubines.find(c => c.id === concubineId);
if (!concubine) return;
haremManager.selectedConcubine = concubine;
document.getElementById('concubine-name').textContent = concubine.name;
const content = document.getElementById('concubine-detail-content');
content.innerHTML = `
<div class="grid grid-cols-2 gap-6">
<div>
<h4 class="font-bold mb-3">基本信息</h4>
<div class="space-y-2 text-sm">
<div class="flex justify-between">
<span>品级:</span>
<span class="rank-badge rank-${concubine.rank.key}">${concubine.rank.name}</span>
</div>
<div class="flex justify-between">
<span>年龄:</span>
<span>${concubine.age}岁</span>
</div>
<div class="flex justify-between">
<span>性格:</span>
<span>${concubine.personality}</span>
</div>
<div class="flex justify-between">
<span>出身:</span>
<span>${concubine.background}</span>
</div>
<div class="flex justify-between">
<span>健康状况:</span>
<span class="text-green-400">${concubine.status}</span>
</div>
</div>
</div>
<div>
<h4 class="font-bold mb-3">能力属性</h4>
<div class="space-y-3">
<div>
<div class="flex justify-between mb-1">
<span>美貌</span>
<span class="mono-font">${concubine.beauty}</span>
</div>
<div class="attribute-bar">
<div class="attribute-fill fill-beauty" style="width: ${concubine.beauty}%"></div>
</div>
</div>
<div>
<div class="flex justify-between mb-1">
<span>才情</span>
<span class="mono-font">${concubine.talent}</span>
</div>
<div class="attribute-bar">
<div class="attribute-fill fill-talent" style="width: ${concubine.talent}%"></div>
</div>
</div>
<div>
<div class="flex justify-between mb-1">
<span>心计</span>
<span class="mono-font">${concubine.scheming}</span>
</div>
<div class="attribute-bar">
<div class="attribute-fill fill-scheming" style="width: ${concubine.scheming}%"></div>
</div>
</div>
<div>
<div class="flex justify-between mb-1">
<span>健康</span>
<span class="mono-font">${concubine.health}</span>
</div>
<div class="attribute-bar">
<div class="attribute-fill fill-health" style="width: ${concubine.health}%"></div>
</div>
</div>
</div>
</div>
</div>
<div class="mt-6 p-4 bg-gray-800 rounded-lg">
<h4 class="font-bold mb-2">宠爱度: ${concubine.affection}/100</h4>
<div class="attribute-bar">
<div class="attribute-fill fill-beauty" style="width: ${concubine.affection}%"></div>
</div>
<p class="text-sm text-gray-300 mt-2">
${concubine.affection >= 80 ? '深受陛下宠爱,后宫地位稳固' :
concubine.affection >= 60 ? '颇受宠爱,在宫中有一席之地' :
concubine.affection >= 40 ? '宠爱一般,需要更多关注' :
'失宠已久,需要重新获得陛下青睐'}
</p>
</div>
`;
document.getElementById('concubine-detail-modal').style.display = 'block';
}
function closeConcubineDetailModal() {
document.getElementById('concubine-detail-modal').style.display = 'none';
}
function summonConcubine(concubineId = null) {
const concubine = concubineId ?
haremManager.concubines.find(c => c.id === concubineId) :
haremManager.selectedConcubine;
if (concubine) {
alert(`陛下今夜召幸${concubine.name}。春宵一刻值千金,愿陛下与娘娘共度良宵。`);
// 增加宠爱度
concubine.affection = Math.min(100, concubine.affection + 5);
haremManager.updateStatistics();
haremManager.renderConcubines();
}
closeConcubineDetailModal();
}
function giftConcubine() {
const concubine = haremManager.selectedConcubine;
if (concubine) {
alert(`陛下赏赐${concubine.name}珠宝首饰,娘娘感激涕零,宠爱度提升。`);
concubine.affection = Math.min(100, concubine.affection + 10);
haremManager.updateStatistics();
haremManager.renderConcubines();
}
closeConcubineDetailModal();
}
function punishConcubine() {
const concubine = haremManager.selectedConcubine;
if (concubine) {
if (confirm(`确定要惩罚${concubine.name}吗?这将大幅降低她的宠爱度。`)) {
alert(`${concubine.name}因过错被陛下惩罚,降为${concubine.rank.name === '贵人' ? '常在' : concubine.rank.name},宠爱度大减。`);
concubine.affection = Math.max(0, concubine.affection - 30);
haremManager.updateStatistics();
haremManager.renderConcubines();
}
}
closeConcubineDetailModal();
}
function showSelectionCeremony() {
const candidates = haremManager.generateSelectionCandidates();
const container = document.getElementById('selection-candidates');
container.innerHTML = '';
candidates.forEach(candidate => {
const slide = document.createElement('li');
slide.className = 'splide__slide';
slide.innerHTML = `
<div class="concubine-card">
<div class="concubine-portrait">
👸
</div>
<div class="text-center mb-4">
<h3 class="font-bold text-lg">${candidate.name}</h3>
<p class="text-sm text-gray-300">${candidate.age}岁 · ${candidate.personality}</p>
</div>
<div class="space-y-2 text-sm">
<div>美貌: <span class="mono-font">${candidate.beauty}</span></div>
<div>才情: <span class="mono-font">${candidate.talent}</span></div>
<div>出身: <span class="mono-font">${candidate.background}</span></div>
</div>
</div>
`;
container.appendChild(slide);
});
// 初始化轮播
if (haremManager.carousel) {
haremManager.carousel.destroy();
}
haremManager.carousel = new Splide('#selection-carousel', {
type: 'loop',
perPage: 1,
perMove: 1,
gap: '2rem',
pagination: true,
arrows: true,
autoplay: false
});
haremManager.carousel.mount();
document.getElementById('selection-ceremony-modal').style.display = 'block';
}
function closeSelectionCeremony() {
document.getElementById('selection-ceremony-modal').style.display = 'none';
if (haremManager.carousel) {
haremManager.carousel.destroy();
}
}
function selectCandidate() {
if (haremManager.carousel) {
const currentIndex = haremManager.carousel.index;
const candidates = haremManager.generateSelectionCandidates();
const selected = candidates[currentIndex];
alert(`陛下选中了${selected.name},封为贵人,赐居翊坤宫。`);
// 添加到后宫
haremManager.concubines.push({
id: haremManager.concubines.length + 1,
name: selected.name,
rank: { name: '贵人', level: 6, key: 'ordinary-lady' },
age: selected.age,
beauty: selected.beauty,
talent: selected.talent,
scheming: selected.scheming,
health: selected.health,
affection: 60,
personality: selected.personality,
background: selected.background,
children: [],
status: 'healthy'
});
haremManager.updateStatistics();
haremManager.renderConcubines();
closeSelectionCeremony();
}
}
function showSuccessionPlanning() {
const content = document.getElementById('succession-content');
content.innerHTML = `
<div class="mb-6">
<h4 class="font-bold mb-3">选择太子</h4>
<p class="text-sm text-gray-300 mb-4">
请选择合适的皇子立为太子。太子的选择将影响王朝的稳定和未来发展。
</p>
</div>
<div class="space-y-3">
${haremManager.princes.map(prince => `
<div class="flex items-center justify-between p-4 bg-gray-800 rounded-lg">
<div class="flex items-center">
<input type="radio" name="crown-prince" value="${prince.id}" class="mr-4">
<div>
<h5 class="font-bold">${prince.name}</h5>
<p class="text-sm text-gray-300">${prince.age}岁 · ${prince.mother}</p>
</div>
</div>
<div class="text-sm">
智: ${prince.intelligence} 武: ${prince.martial} 德: ${prince.virtue}
</div>
</div>
`).join('')}
</div>
`;
document.getElementById('succession-modal').style.display = 'block';
}
function closeSuccessionModal() {
document.getElementById('succession-modal').style.display = 'none';
}
function confirmCrownPrince() {
const selectedPrince = document.querySelector('input[name="crown-prince"]:checked');
if (selectedPrince) {
const princeId = parseInt(selectedPrince.value);
const prince = haremManager.princes.find(p => p.id === princeId);
if (prince) {
// 重置所有皇子的继承顺序
haremManager.princes.forEach(p => {
p.successionOrder = p.id === princeId ? 1 : (p.id > princeId ? p.id : p.id + 1);
});
alert(`陛下立${prince.name}为太子,昭告天下!`);
haremManager.renderSuccessionList();
haremManager.renderChildren();
}
} else {
alert('请选择要立为太子的皇子');
}
closeSuccessionModal();
}
function designateCrownPrince(princeId) {
const prince = haremManager.princes.find(p => p.id === princeId);
if (prince && confirm(`确定要立${prince.name}为太子吗?`)) {
// 重置所有皇子的继承顺序
haremManager.princes.forEach(p => {
p.successionOrder = p.id === princeId ? 1 : (p.id > princeId ? p.id : p.id + 1);
});
alert(`陛下立${prince.name}为太子,昭告天下!`);
haremManager.renderSuccessionList();
haremManager.renderChildren();
}
}
function showEducationSystem() {
alert('教育管理功能开发中...');
}
function showMarriagePlanning() {
alert('婚配安排功能开发中...');
}
function showPalaceEvents() {
alert('宫廷事件功能开发中...');
}
function showPrinceDetail(princeId) {
alert('皇子详情功能开发中...');
}
function educatePrince(princeId) {
alert('皇子教育功能开发中...');
}
function showPrincessDetail(princessId) {
alert('公主详情功能开发中...');
}
function arrangeMarriage(princessId) {
alert('公主婚配功能开发中...');
}
// 初始化
let haremManager;
document.addEventListener('DOMContentLoaded', () => {
haremManager = new HaremManager();
});
</script>
</body>
</html>
3、economy.html
<!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 href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;700&family=Noto+Sans+SC:wght@300;400;500;700&family=Ma+Shan+Zheng&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet">
<!-- 核心库引入 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.4.3/echarts.min.js"></script>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<style>
:root {
--imperial-gold: #D4AF37;
--deep-red: #8B0000;
--dark-bg: #1A1A1A;
--text-light: #F5F5DC;
--success-green: #228B22;
--warning-orange: #FF8C00;
--error-red: #DC143C;
--neutral-gray: #696969;
}
body {
font-family: 'Noto Sans SC', sans-serif;
background: var(--dark-bg);
color: var(--text-light);
overflow-x: hidden;
}
.title-font {
font-family: 'Noto Serif SC', serif;
}
.decorative-font {
font-family: 'Ma Shan Zheng', cursive;
}
.mono-font {
font-family: 'JetBrains Mono', monospace;
}
.imperial-gold {
color: var(--imperial-gold);
}
.glass-effect {
background: rgba(26, 26, 26, 0.8);
backdrop-filter: blur(10px);
border: 1px solid rgba(212, 175, 55, 0.2);
}
.resource-card {
background: linear-gradient(135deg, rgba(212, 175, 55, 0.1) 0%, rgba(139, 0, 0, 0.1) 100%);
border: 1px solid rgba(212, 175, 55, 0.3);
transition: all 0.3s ease;
}
.resource-card:hover {
transform: translateY(-3px);
box-shadow: 0 8px 20px rgba(212, 175, 55, 0.3);
}
.slider-container {
position: relative;
margin: 20px 0;
}
.slider {
width: 100%;
height: 8px;
border-radius: 4px;
background: #333;
outline: none;
-webkit-appearance: none;
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: var(--imperial-gold);
cursor: pointer;
box-shadow: 0 2px 6px rgba(212, 175, 55, 0.3);
}
.slider::-moz-range-thumb {
width: 20px;
height: 20px;
border-radius: 50%;
background: var(--imperial-gold);
cursor: pointer;
border: none;
box-shadow: 0 2px 6px rgba(212, 175, 55, 0.3);
}
.project-card {
background: rgba(26, 26, 26, 0.9);
border: 1px solid rgba(212, 175, 55, 0.3);
border-radius: 8px;
padding: 20px;
margin-bottom: 15px;
transition: all 0.3s ease;
cursor: pointer;
}
.project-card:hover {
border-color: var(--imperial-gold);
box-shadow: 0 4px 15px rgba(212, 175, 55, 0.2);
}
.project-card.selected {
border-color: var(--imperial-gold);
background: rgba(212, 175, 55, 0.1);
}
.effect-indicator {
display: inline-block;
padding: 2px 6px;
border-radius: 4px;
font-size: 0.75rem;
margin-left: 5px;
}
.effect-positive {
background: #228B22;
color: white;
}
.effect-negative {
background: #DC143C;
color: white;
}
.effect-neutral {
background: #696969;
color: white;
}
.modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.8);
display: none;
z-index: 1000;
}
.modal-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: var(--dark-bg);
border: 2px solid var(--imperial-gold);
border-radius: 10px;
padding: 20px;
max-width: 500px;
width: 90%;
}
</style>
</head>
<body class="min-h-screen">
<!-- 顶部导航 -->
<header class="glass-effect fixed top-0 left-0 right-0 z-50 p-4">
<div class="flex justify-between items-center">
<div class="flex items-center">
<button onclick="window.location.href='index.html'" class="mr-4 text-2xl">🏛️</button>
<h1 class="title-font text-2xl font-bold imperial-gold">经济系统</h1>
</div>
<div class="flex space-x-4">
<button class="px-4 py-2 bg-yellow-600 text-white rounded hover:bg-yellow-700" onclick="showTaxModal()">
💰 调整税收
</button>
<button class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700" onclick="showProjectModal()">
🏗️ 建设项目
</button>
<button class="px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700" onclick="showTradeModal()">
🛒 商业贸易
</button>
</div>
</div>
</header>
<!-- 主内容区域 -->
<main class="pt-20 p-6">
<!-- 资源概览 -->
<section class="mb-6">
<h2 class="title-font text-xl font-bold imperial-gold mb-4">国家资源</h2>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div class="resource-card p-6 rounded-lg text-center">
<div class="text-4xl mb-2">💰</div>
<div class="text-2xl font-bold imperial-gold mono-font" id="money-display">100,000</div>
<div class="text-sm text-gray-300">国库银两</div>
<div class="text-xs text-green-400 mt-1">+2,500/年</div>
</div>
<div class="resource-card p-6 rounded-lg text-center">
<div class="text-4xl mb-2">🌾</div>
<div class="text-2xl font-bold imperial-gold mono-font" id="food-display">50,000</div>
<div class="text-sm text-gray-300">国家粮草</div>
<div class="text-xs text-green-400 mt-1">+1,800/年</div>
</div>
<div class="resource-card p-6 rounded-lg text-center">
<div class="text-4xl mb-2">👥</div>
<div class="text-2xl font-bold imperial-gold mono-font" id="population-display">1,000,000</div>
<div class="text-sm text-gray-300">全国人口</div>
<div class="text-xs text-green-400 mt-1">+5,000/年</div>
</div>
<div class="resource-card p-6 rounded-lg text-center">
<div class="text-4xl mb-2">⚡</div>
<div class="text-2xl font-bold imperial-gold mono-font" id="labor-display">100,000</div>
<div class="text-sm text-gray-300">可用人力</div>
<div class="text-xs text-yellow-400 mt-1">-2,000/年</div>
</div>
</div>
</section>
<!-- 税收政策 -->
<section class="glass-effect rounded-lg p-6 mb-6">
<h2 class="title-font text-xl font-bold imperial-gold mb-4">税收政策</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<h3 class="font-bold mb-3">农业税</h3>
<div class="slider-container">
<input type="range" min="5" max="30" value="15" class="slider" id="agriculture-tax">
<div class="flex justify-between text-sm text-gray-300 mt-2">
<span>5%</span>
<span class="mono-font" id="agriculture-tax-value">15%</span>
<span>30%</span>
</div>
</div>
<div class="mt-2 text-sm">
<span class="effect-indicator effect-neutral">影响: 民心</span>
<span class="effect-indicator effect-positive">收入: +1,500/年</span>
</div>
</div>
<div>
<h3 class="font-bold mb-3">商业税</h3>
<div class="slider-container">
<input type="range" min="3" max="20" value="10" class="slider" id="commerce-tax">
<div class="flex justify-between text-sm text-gray-300 mt-2">
<span>3%</span>
<span class="mono-font" id="commerce-tax-value">10%</span>
<span>20%</span>
</div>
</div>
<div class="mt-2 text-sm">
<span class="effect-indicator effect-neutral">影响: 商业繁荣</span>
<span class="effect-indicator effect-positive">收入: +3,000/年</span>
</div>
</div>
<div>
<h3 class="font-bold mb-3">人头税</h3>
<div class="slider-container">
<input type="range" min="1" max="10" value="3" class="slider" id="head-tax">
<div class="flex justify-between text-sm text-gray-300 mt-2">
<span>1%</span>
<span class="mono-font" id="head-tax-value">3%</span>
<span>10%</span>
</div>
</div>
<div class="mt-2 text-sm">
<span class="effect-indicator effect-negative">影响: 人口增长</span>
<span class="effect-indicator effect-positive">收入: +2,000/年</span>
</div>
</div>
<div>
<h3 class="font-bold mb-3">盐铁专卖</h3>
<div class="slider-container">
<input type="range" min="0" max="1" value="0.5" step="0.1" class="slider" id="salt-iron-monopoly">
<div class="flex justify-between text-sm text-gray-300 mt-2">
<span>0%</span>
<span class="mono-font" id="salt-iron-value">50%</span>
<span>100%</span>
</div>
</div>
<div class="mt-2 text-sm">
<span class="effect-indicator effect-neutral">影响: 腐败风险</span>
<span class="effect-indicator effect-positive">收入: +4,000/年</span>
</div>
</div>
</div>
<div class="mt-6 p-4 bg-gray-800 rounded-lg">
<h3 class="font-bold mb-2">税收预估</h3>
<div class="grid grid-cols-2 gap-4 text-sm">
<div>
<span>年收入: </span>
<span class="mono-font text-green-400" id="total-income">10,500</span>
<span> 两</span>
</div>
<div>
<span>民心影响: </span>
<span class="mono-font text-yellow-400" id="popularity-impact">-5</span>
</div>
<div>
<span>商业影响: </span>
<span class="mono-font text-blue-400" id="commerce-impact">-2</span>
</div>
<div>
<span>人口影响: </span>
<span class="mono-font text-red-400" id="population-impact">-3</span>
</div>
</div>
</div>
</section>
<!-- 开支分配 -->
<section class="glass-effect rounded-lg p-6 mb-6">
<h2 class="title-font text-xl font-bold imperial-gold mb-4">国家开支</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<h3 class="font-bold mb-3">军费开支</h3>
<div class="slider-container">
<input type="range" min="10" max="50" value="25" class="slider" id="military-spending">
<div class="flex justify-between text-sm text-gray-300 mt-2">
<span>10%</span>
<span class="mono-font" id="military-spending-value">25%</span>
<span>50%</span>
</div>
</div>
<div class="mt-2 text-sm">
<span class="effect-indicator effect-positive">军队战力: +15</span>
<span class="effect-indicator effect-neutral">开支: -2,625/年</span>
</div>
</div>
<div>
<h3 class="font-bold mb-3">官员俸禄</h3>
<div class="slider-container">
<input type="range" min="5" max="20" value="12" class="slider" id="salary-spending">
<div class="flex justify-between text-sm text-gray-300 mt-2">
<span>5%</span>
<span class="mono-font" id="salary-spending-value">12%</span>
<span>20%</span>
</div>
</div>
<div class="mt-2 text-sm">
<span class="effect-indicator effect-positive">官员忠诚: +8</span>
<span class="effect-indicator effect-neutral">开支: -1,260/年</span>
</div>
</div>
<div>
<h3 class="font-bold mb-3">基础建设</h3>
<div class="slider-container">
<input type="range" min="5" max="30" value="15" class="slider" id="infrastructure-spending">
<div class="flex justify-between text-sm text-gray-300 mt-2">
<span>5%</span>
<span class="mono-font" id="infrastructure-spending-value">15%</span>
<span>30%</span>
</div>
</div>
<div class="mt-2 text-sm">
<span class="effect-indicator effect-positive">国力提升: +10</span>
<span class="effect-indicator effect-neutral">开支: -1,575/年</span>
</div>
</div>
<div>
<h3 class="font-bold mb-3">赈灾救济</h3>
<div class="slider-container">
<input type="range" min="2" max="15" value="8" class="slider" id="disaster-relief">
<div class="flex justify-between text-sm text-gray-300 mt-2">
<span>2%</span>
<span class="mono-font" id="disaster-relief-value">8%</span>
<span>15%</span>
</div>
</div>
<div class="mt-2 text-sm">
<span class="effect-indicator effect-positive">民心稳定: +12</span>
<span class="effect-indicator effect-neutral">开支: -840/年</span>
</div>
</div>
</div>
<div class="mt-6 p-4 bg-gray-800 rounded-lg">
<h3 class="font-bold mb-2">开支总计</h3>
<div class="text-lg">
<span>总开支: </span>
<span class="mono-font text-red-400" id="total-spending">6,300</span>
<span> 两/年</span>
<span class="ml-4">净收入: </span>
<span class="mono-font text-green-400" id="net-income">4,200</span>
<span> 两/年</span>
</div>
</div>
</section>
<!-- 经济数据图表 -->
<section class="glass-effect rounded-lg p-6 mb-6">
<h2 class="title-font text-xl font-bold imperial-gold mb-4">经济趋势</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<h3 class="font-bold mb-3">十年收支趋势</h3>
<div id="income-expense-chart" style="height: 300px;"></div>
</div>
<div>
<h3 class="font-bold mb-3">资源储备变化</h3>
<div id="resource-chart" style="height: 300px;"></div>
</div>
</div>
</section>
<!-- 建设项目列表 -->
<section class="glass-effect rounded-lg p-6">
<h2 class="title-font text-xl font-bold imperial-gold mb-4">可用建设项目</h2>
<div id="projects-list">
<!-- 项目将通过JavaScript动态生成 -->
</div>
</section>
</main>
<!-- 税收调整模态框 -->
<div class="modal" id="tax-modal">
<div class="modal-content">
<div class="flex justify-between items-center mb-6">
<h3 class="title-font text-xl font-bold imperial-gold">调整税收政策</h3>
<button onclick="closeTaxModal()" class="text-gray-400 hover:text-white text-2xl">×</button>
</div>
<div class="mb-4">
<p class="text-sm text-gray-300 mb-4">
调整税收政策会影响国家收入和民心。过高的税收可能导致民变,过低的税收则会使国库空虚。
</p>
<div class="space-y-4">
<div>
<label class="block text-sm font-bold mb-2">农业税率</label>
<input type="range" min="5" max="30" value="15" class="slider" id="modal-agriculture-tax">
<div class="text-center text-sm mono-font" id="modal-agriculture-value">15%</div>
</div>
<div>
<label class="block text-sm font-bold mb-2">商业税率</label>
<input type="range" min="3" max="20" value="10" class="slider" id="modal-commerce-tax">
<div class="text-center text-sm mono-font" id="modal-commerce-value">10%</div>
</div>
<div>
<label class="block text-sm font-bold mb-2">人头税率</label>
<input type="range" min="1" max="10" value="3" class="slider" id="modal-head-tax">
<div class="text-center text-sm mono-font" id="modal-head-value">3%</div>
</div>
</div>
</div>
<div class="flex justify-end space-x-4">
<button onclick="closeTaxModal()" class="px-4 py-2 bg-gray-600 text-white rounded hover:bg-gray-700">
取消
</button>
<button onclick="confirmTaxAdjustment()" class="px-4 py-2 bg-yellow-600 text-white rounded hover:bg-yellow-700">
确认调整
</button>
</div>
</div>
</div>
<!-- 建设项目模态框 -->
<div class="modal" id="project-modal">
<div class="modal-content">
<div class="flex justify-between items-center mb-6">
<h3 class="title-font text-xl font-bold imperial-gold">新建项目</h3>
<button onclick="closeProjectModal()" class="text-gray-400 hover:text-white text-2xl">×</button>
</div>
<div id="project-details">
<!-- 项目详情将通过JavaScript生成 -->
</div>
<div class="flex justify-end space-x-4 mt-6">
<button onclick="closeProjectModal()" class="px-4 py-2 bg-gray-600 text-white rounded hover:bg-gray-700">
取消
</button>
<button onclick="startProject()" class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">
开始建设
</button>
</div>
</div>
</div>
<script>
// 经济系统管理器
class EconomyManager {
constructor() {
this.resources = {
money: 100000,
food: 50000,
population: 1000000,
labor: 100000,
prestige: 75
};
this.taxRates = {
agriculture: 15,
commerce: 10,
head: 3,
saltIron: 50
};
this.spending = {
military: 25,
salary: 12,
infrastructure: 15,
disaster: 8
};
this.projects = [
{
id: 1,
name: '黄河治理',
type: 'water_control',
cost: { money: 20000, food: 5000, labor: 5000 },
time: 24,
effects: { population: 50000, prestige: 10, food: 2000 },
description: '治理黄河水患,保护沿岸百姓,增加可耕种土地'
},
{
id: 2,
name: '长城修缮',
type: 'defense',
cost: { money: 15000, labor: 8000 },
time: 18,
effects: { prestige: 15, military: 20 },
description: '修缮北方长城,加强边防防御能力'
},
{
id: 3,
name: '大运河扩建',
type: 'transport',
cost: { money: 30000, food: 3000, labor: 10000 },
time: 36,
effects: { commerce: 25, money: 5000, prestige: 8 },
description: '扩建大运河,促进南北贸易往来'
},
{
id: 4,
name: '皇家书院',
type: 'education',
cost: { money: 10000, labor: 2000 },
time: 12,
effects: { intelligence: 10, prestige: 12 },
description: '建立皇家书院,培养人才,提升文化水平'
},
{
id: 5,
name: '官道修建',
type: 'infrastructure',
cost: { money: 12000, labor: 6000 },
time: 20,
effects: { commerce: 15, population: 10000 },
description: '修建连接主要城市的官道,改善交通'
},
{
id: 6,
name: '粮仓建设',
type: 'storage',
cost: { money: 8000, labor: 3000 },
time: 10,
effects: { food: 10000, disaster_resistance: 15 },
description: '在全国各地建设粮仓,储备粮食应对灾荒'
}
];
this.selectedProject = null;
this.init();
}
init() {
this.setupEventListeners();
this.renderProjects();
this.initCharts();
this.updateDisplays();
}
setupEventListeners() {
// 税收滑块
document.getElementById('agriculture-tax').addEventListener('input', (e) => {
this.taxRates.agriculture = parseInt(e.target.value);
document.getElementById('agriculture-tax-value').textContent = e.target.value + '%';
this.calculateEffects();
});
document.getElementById('commerce-tax').addEventListener('input', (e) => {
this.taxRates.commerce = parseInt(e.target.value);
document.getElementById('commerce-tax-value').textContent = e.target.value + '%';
this.calculateEffects();
});
document.getElementById('head-tax').addEventListener('input', (e) => {
this.taxRates.head = parseInt(e.target.value);
document.getElementById('head-tax-value').textContent = e.target.value + '%';
this.calculateEffects();
});
document.getElementById('salt-iron-monopoly').addEventListener('input', (e) => {
this.taxRates.saltIron = parseInt(e.target.value);
document.getElementById('salt-iron-value').textContent = e.target.value + '%';
this.calculateEffects();
});
// 开支滑块
document.getElementById('military-spending').addEventListener('input', (e) => {
this.spending.military = parseInt(e.target.value);
document.getElementById('military-spending-value').textContent = e.target.value + '%';
this.calculateSpending();
});
document.getElementById('salary-spending').addEventListener('input', (e) => {
this.spending.salary = parseInt(e.target.value);
document.getElementById('salary-spending-value').textContent = e.target.value + '%';
this.calculateSpending();
});
document.getElementById('infrastructure-spending').addEventListener('input', (e) => {
this.spending.infrastructure = parseInt(e.target.value);
document.getElementById('infrastructure-spending-value').textContent = e.target.value + '%';
this.calculateSpending();
});
document.getElementById('disaster-relief').addEventListener('input', (e) => {
this.spending.disaster = parseInt(e.target.value);
document.getElementById('disaster-relief-value').textContent = e.target.value + '%';
this.calculateSpending();
});
}
calculateEffects() {
const agricultureIncome = this.taxRates.agriculture * 100;
const commerceIncome = this.taxRates.commerce * 300;
const headIncome = this.taxRates.head * 667;
const saltIronIncome = this.taxRates.saltIron * 80;
const totalIncome = agricultureIncome + commerceIncome + headIncome + saltIronIncome;
const popularityImpact = -(this.taxRates.agriculture - 10) * 0.5 - (this.taxRates.head - 2) * 2;
const commerceImpact = -(this.taxRates.commerce - 8) * 0.8;
const populationImpact = -(this.taxRates.head - 2) * 1.5;
document.getElementById('total-income').textContent = totalIncome.toLocaleString();
document.getElementById('popularity-impact').textContent = popularityImpact.toFixed(0);
document.getElementById('commerce-impact').textContent = commerceImpact.toFixed(0);
document.getElementById('population-impact').textContent = populationImpact.toFixed(0);
this.calculateSpending();
}
calculateSpending() {
const baseIncome = 10500; // 基于当前税率的总收入
const militarySpending = Math.round(baseIncome * this.spending.military / 100);
const salarySpending = Math.round(baseIncome * this.spending.salary / 100);
const infrastructureSpending = Math.round(baseIncome * this.spending.infrastructure / 100);
const disasterSpending = Math.round(baseIncome * this.spending.disaster / 100);
const totalSpending = militarySpending + salarySpending + infrastructureSpending + disasterSpending;
const netIncome = baseIncome - totalSpending;
document.getElementById('total-spending').textContent = totalSpending.toLocaleString();
document.getElementById('net-income').textContent = netIncome.toLocaleString();
}
renderProjects() {
const container = document.getElementById('projects-list');
container.innerHTML = '';
this.projects.forEach((project, index) => {
const card = document.createElement('div');
card.className = 'project-card';
card.dataset.projectId = project.id;
const canAfford = this.canAfford(project.cost);
card.innerHTML = `
<div class="flex justify-between items-start mb-3">
<div>
<h3 class="font-bold text-lg">${project.name}</h3>
<p class="text-sm text-gray-300">${project.description}</p>
</div>
<span class="px-2 py-1 bg-blue-600 text-white rounded text-xs">
${project.time}个月
</span>
</div>
<div class="grid grid-cols-2 gap-4 mb-3">
<div>
<h4 class="font-bold text-sm mb-2">建设成本</h4>
<div class="space-y-1 text-sm">
${project.cost.money ? `<div>银两: <span class="mono-font">${project.cost.money.toLocaleString()}</span></div>` : ''}
${project.cost.food ? `<div>粮草: <span class="mono-font">${project.cost.food.toLocaleString()}</span></div>` : ''}
${project.cost.labor ? `<div>人力: <span class="mono-font">${project.cost.labor.toLocaleString()}</span></div>` : ''}
</div>
</div>
<div>
<h4 class="font-bold text-sm mb-2">预期效果</h4>
<div class="space-y-1 text-sm">
${project.effects.money ? `<div>银两: <span class="mono-font text-green-400">+${project.effects.money.toLocaleString()}</span></div>` : ''}
${project.effects.food ? `<div>粮草: <span class="mono-font text-green-400">+${project.effects.food.toLocaleString()}</span></div>` : ''}
${project.effects.population ? `<div>人口: <span class="mono-font text-green-400">+${project.effects.population.toLocaleString()}</span></div>` : ''}
${project.effects.prestige ? `<div>威望: <span class="mono-font text-green-400">+${project.effects.prestige}</span></div>` : ''}
</div>
</div>
</div>
<div class="flex justify-between items-center">
<span class="text-sm ${canAfford ? 'text-green-400' : 'text-red-400'}">
${canAfford ? '资源充足' : '资源不足'}
</span>
<button
onclick="selectProject(${project.id})"
class="px-4 py-2 ${canAfford ? 'bg-blue-600 hover:bg-blue-700' : 'bg-gray-600 cursor-not-allowed'} text-white rounded text-sm"
${canAfford ? '' : 'disabled'}
>
选择项目
</button>
</div>
`;
container.appendChild(card);
// 添加进入动画
anime({
targets: card,
translateY: [30, 0],
opacity: [0, 1],
duration: 600,
delay: index * 100,
easing: 'easeOutCubic'
});
});
}
canAfford(cost) {
return (!cost.money || this.resources.money >= cost.money) &&
(!cost.food || this.resources.food >= cost.food) &&
(!cost.labor || this.resources.labor >= cost.labor);
}
selectProject(projectId) {
this.selectedProject = this.projects.find(p => p.id === projectId);
this.showProjectModal();
}
showProjectModal() {
if (!this.selectedProject) return;
const modal = document.getElementById('project-modal');
const details = document.getElementById('project-details');
details.innerHTML = `
<div class="mb-4">
<h4 class="font-bold text-lg mb-2">${this.selectedProject.name}</h4>
<p class="text-sm text-gray-300 mb-4">${this.selectedProject.description}</p>
<div class="grid grid-cols-2 gap-4 mb-4">
<div>
<h5 class="font-bold text-sm mb-2">建设成本</h5>
<div class="space-y-1 text-sm">
${this.selectedProject.cost.money ? `<div>银两: <span class="mono-font">${this.selectedProject.cost.money.toLocaleString()}</span></div>` : ''}
${this.selectedProject.cost.food ? `<div>粮草: <span class="mono-font">${this.selectedProject.cost.food.toLocaleString()}</span></div>` : ''}
${this.selectedProject.cost.labor ? `<div>人力: <span class="mono-font">${this.selectedProject.cost.labor.toLocaleString()}</span></div>` : ''}
</div>
</div>
<div>
<h5 class="font-bold text-sm mb-2">预期效果</h5>
<div class="space-y-1 text-sm">
${this.selectedProject.effects.money ? `<div>银两: <span class="mono-font text-green-400">+${this.selectedProject.effects.money.toLocaleString()}</span></div>` : ''}
${this.selectedProject.effects.food ? `<div>粮草: <span class="mono-font text-green-400">+${this.selectedProject.effects.food.toLocaleString()}</span></div>` : ''}
${this.selectedProject.effects.population ? `<div>人口: <span class="mono-font text-green-400">+${this.selectedProject.effects.population.toLocaleString()}</span></div>` : ''}
${this.selectedProject.effects.prestige ? `<div>威望: <span class="mono-font text-green-400">+${this.selectedProject.effects.prestige}</span></div>` : ''}
</div>
</div>
</div>
<div class="p-3 bg-gray-800 rounded">
<p class="text-sm">
<strong>建设时间:</strong> ${this.selectedProject.time}个月<br>
<strong>预计完成:</strong> ${new Date(Date.now() + this.selectedProject.time * 30 * 24 * 60 * 60 * 1000).toLocaleDateString()}
</p>
</div>
</div>
`;
modal.style.display = 'block';
}
startProject() {
if (!this.selectedProject || !this.canAfford(this.selectedProject.cost)) {
alert('资源不足,无法开始建设');
return;
}
// 扣除资源
if (this.selectedProject.cost.money) {
this.resources.money -= this.selectedProject.cost.money;
}
if (this.selectedProject.cost.food) {
this.resources.food -= this.selectedProject.cost.food;
}
if (this.selectedProject.cost.labor) {
this.resources.labor -= this.selectedProject.cost.labor;
}
alert(`${this.selectedProject.name}已开始建设,预计${this.selectedProject.time}个月后完成`);
this.closeProjectModal();
this.updateDisplays();
this.renderProjects();
}
updateDisplays() {
document.getElementById('money-display').textContent = this.resources.money.toLocaleString();
document.getElementById('food-display').textContent = this.resources.food.toLocaleString();
document.getElementById('population-display').textContent = this.resources.population.toLocaleString();
document.getElementById('labor-display').textContent = this.resources.labor.toLocaleString();
}
initCharts() {
// 收支趋势图
const incomeChart = echarts.init(document.getElementById('income-expense-chart'));
const years = ['景耀元年', '景耀二年', '景耀三年', '景耀四年', '景耀五年', '景耀六年', '景耀七年', '景耀八年', '景耀九年', '景耀十年'];
const incomeData = [8500, 9200, 9800, 10100, 10500, 10800, 11200, 11500, 11800, 12000];
const expenseData = [6200, 6800, 7200, 7500, 7800, 8100, 8400, 8600, 8800, 9000];
const incomeOption = {
backgroundColor: 'transparent',
textStyle: { color: '#F5F5DC' },
title: {
text: '收支趋势',
textStyle: { color: '#D4AF37', fontSize: 14 }
},
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(26, 26, 26, 0.9)',
borderColor: '#D4AF37',
textStyle: { color: '#F5F5DC' }
},
legend: {
data: ['收入', '支出'],
textStyle: { color: '#F5F5DC' }
},
xAxis: {
type: 'category',
data: years,
axisLabel: { color: '#F5F5DC', fontSize: 10 },
axisLine: { lineStyle: { color: '#666' } }
},
yAxis: {
type: 'value',
axisLabel: { color: '#F5F5DC' },
axisLine: { lineStyle: { color: '#666' } },
splitLine: { lineStyle: { color: '#333' } }
},
series: [
{
name: '收入',
type: 'line',
data: incomeData,
itemStyle: { color: '#228B22' },
lineStyle: { color: '#228B22' }
},
{
name: '支出',
type: 'line',
data: expenseData,
itemStyle: { color: '#DC143C' },
lineStyle: { color: '#DC143C' }
}
]
};
incomeChart.setOption(incomeOption);
// 资源储备图
const resourceChart = echarts.init(document.getElementById('resource-chart'));
const resourceOption = {
backgroundColor: 'transparent',
textStyle: { color: '#F5F5DC' },
title: {
text: '资源储备',
textStyle: { color: '#D4AF37', fontSize: 14 }
},
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(26, 26, 26, 0.9)',
borderColor: '#D4AF37',
textStyle: { color: '#F5F5DC' }
},
legend: {
data: ['银两', '粮草'],
textStyle: { color: '#F5F5DC' }
},
xAxis: {
type: 'category',
data: years.slice(-6),
axisLabel: { color: '#F5F5DC', fontSize: 10 },
axisLine: { lineStyle: { color: '#666' } }
},
yAxis: [
{
type: 'value',
name: '银两',
axisLabel: { color: '#F5F5DC' },
axisLine: { lineStyle: { color: '#666' } },
splitLine: { lineStyle: { color: '#333' } }
},
{
type: 'value',
name: '粮草',
axisLabel: { color: '#F5F5DC' },
axisLine: { lineStyle: { color: '#666' } }
}
],
series: [
{
name: '银两',
type: 'bar',
data: [75000, 78000, 82000, 86000, 90000, 95000],
itemStyle: { color: '#D4AF37' }
},
{
name: '粮草',
type: 'line',
yAxisIndex: 1,
data: [35000, 38000, 42000, 45000, 48000, 50000],
itemStyle: { color: '#228B22' },
lineStyle: { color: '#228B22' }
}
]
};
resourceChart.setOption(resourceOption);
// 响应式
window.addEventListener('resize', () => {
incomeChart.resize();
resourceChart.resize();
});
}
}
// 全局函数
function showTaxModal() {
document.getElementById('tax-modal').style.display = 'block';
}
function closeTaxModal() {
document.getElementById('tax-modal').style.display = 'none';
}
function confirmTaxAdjustment() {
// 获取模态框中的值并应用到主界面
const agriTax = document.getElementById('modal-agriculture-tax').value;
const commTax = document.getElementById('modal-commerce-tax').value;
const headTax = document.getElementById('modal-head-tax').value;
// 更新主界面滑块
document.getElementById('agriculture-tax').value = agriTax;
document.getElementById('commerce-tax').value = commTax;
document.getElementById('head-tax').value = headTax;
// 更新显示值
document.getElementById('agriculture-tax-value').textContent = agriTax + '%';
document.getElementById('commerce-tax-value').textContent = commTax + '%';
document.getElementById('head-tax-value').textContent = headTax + '%';
// 重新计算效果
economyManager.taxRates.agriculture = parseInt(agriTax);
economyManager.taxRates.commerce = parseInt(commTax);
economyManager.taxRates.head = parseInt(headTax);
economyManager.calculateEffects();
closeTaxModal();
alert('税收政策已调整');
}
function showProjectModal() {
document.getElementById('project-modal').style.display = 'block';
}
function closeProjectModal() {
document.getElementById('project-modal').style.display = 'none';
}
function selectProject(projectId) {
economyManager.selectProject(projectId);
}
function startProject() {
economyManager.startProject();
}
function showTradeModal() {
alert('商业贸易功能开发中...');
}
// 模态框滑块事件
document.addEventListener('DOMContentLoaded', () => {
const modalAgriTax = document.getElementById('modal-agriculture-tax');
const modalCommTax = document.getElementById('modal-commerce-tax');
const modalHeadTax = document.getElementById('modal-head-tax');
if (modalAgriTax) {
modalAgriTax.addEventListener('input', (e) => {
document.getElementById('modal-agriculture-value').textContent = e.target.value + '%';
});
}
if (modalCommTax) {
modalCommTax.addEventListener('input', (e) => {
document.getElementById('modal-commerce-value').textContent = e.target.value + '%';
});
}
if (modalHeadTax) {
modalHeadTax.addEventListener('input', (e) => {
document.getElementById('modal-head-value').textContent = e.target.value + '%';
});
}
});
// 初始化
let economyManager;
document.addEventListener('DOMContentLoaded', () => {
economyManager = new EconomyManager();
});
</script>
</body>
</html>
4、officials.html
<!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 href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;700&family=Noto+Sans+SC:wght@300;400;500;700&family=Ma+Shan+Zheng&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet">
<!-- 核心库引入 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.4.3/echarts.min.js"></script>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<style>
:root {
--imperial-gold: #D4AF37;
--deep-red: #8B0000;
--dark-bg: #1A1A1A;
--text-light: #F5F5DC;
--success-green: #228B22;
--warning-orange: #FF8C00;
--error-red: #DC143C;
--neutral-gray: #696969;
}
body {
font-family: 'Noto Sans SC', sans-serif;
background: var(--dark-bg);
color: var(--text-light);
overflow-x: hidden;
}
.title-font {
font-family: 'Noto Serif SC', serif;
}
.decorative-font {
font-family: 'Ma Shan Zheng', cursive;
}
.mono-font {
font-family: 'JetBrains Mono', monospace;
}
.imperial-gold {
color: var(--imperial-gold);
}
.glass-effect {
background: rgba(26, 26, 26, 0.8);
backdrop-filter: blur(10px);
border: 1px solid rgba(212, 175, 55, 0.2);
}
.official-card {
background: linear-gradient(135deg, rgba(212, 175, 55, 0.1) 0%, rgba(139, 0, 0, 0.1) 100%);
border: 1px solid rgba(212, 175, 55, 0.3);
transition: all 0.3s ease;
cursor: pointer;
}
.official-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 25px rgba(212, 175, 55, 0.3);
border-color: var(--imperial-gold);
}
.faction-badge {
padding: 2px 8px;
border-radius: 12px;
font-size: 0.75rem;
font-weight: bold;
}
.faction-qingliu { background: #228B22; color: white; }
.faction-xungui { background: #D4AF37; color: black; }
.faction-wenguan { background: #4169E1; color: white; }
.faction-huanguan { background: #DC143C; color: white; }
.faction-zhongli { background: #696969; color: white; }
.loyalty-bar {
height: 6px;
border-radius: 3px;
background: #333;
overflow: hidden;
}
.loyalty-fill {
height: 100%;
transition: width 0.5s ease;
}
.appointment-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.8);
display: none;
z-index: 1000;
}
.modal-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: var(--dark-bg);
border: 2px solid var(--imperial-gold);
border-radius: 10px;
padding: 20px;
max-width: 600px;
width: 90%;
max-height: 80vh;
overflow-y: auto;
}
.position-card {
background: rgba(212, 175, 55, 0.1);
border: 1px solid rgba(212, 175, 55, 0.3);
border-radius: 8px;
padding: 15px;
margin-bottom: 10px;
cursor: pointer;
transition: all 0.3s ease;
}
.position-card:hover {
background: rgba(212, 175, 55, 0.2);
border-color: var(--imperial-gold);
}
.position-card.occupied {
background: rgba(139, 0, 0, 0.1);
border-color: rgba(139, 0, 0, 0.3);
}
</style>
</head>
<body class="min-h-screen">
<!-- 顶部导航 -->
<header class="glass-effect fixed top-0 left-0 right-0 z-50 p-4">
<div class="flex justify-between items-center">
<div class="flex items-center">
<button onclick="window.location.href='index.html'" class="mr-4 text-2xl">🏛️</button>
<h1 class="title-font text-2xl font-bold imperial-gold">官员管理</h1>
</div>
<div class="flex space-x-4">
<button class="px-4 py-2 bg-yellow-600 text-white rounded hover:bg-yellow-700" onclick="showAppointmentModal()">
📝 任命官员
</button>
<button class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700" onclick="showFactionAnalysis()">
📊 派系分析
</button>
<button class="px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700" onclick="conductExamination()">
📚 科举考试
</button>
</div>
</div>
</header>
<!-- 主内容区域 -->
<main class="pt-20 p-6">
<!-- 统计概览 -->
<section class="glass-effect rounded-lg p-6 mb-6">
<h2 class="title-font text-xl font-bold imperial-gold mb-4">朝中概况</h2>
<div class="grid grid-cols-4 gap-6">
<div class="text-center">
<div class="text-3xl font-bold imperial-gold" id="total-officials">72</div>
<div class="text-sm text-gray-300">在职官员</div>
</div>
<div class="text-center">
<div class="text-3xl font-bold text-green-400" id="high-loyalty">45</div>
<div class="text-sm text-gray-300">忠诚官员</div>
</div>
<div class="text-center">
<div class="text-3xl font-bold text-yellow-400" id="neutral-officials">20</div>
<div class="text-sm text-gray-300">中立官员</div>
</div>
<div class="text-center">
<div class="text-3xl font-bold text-red-400" id="low-loyalty">7</div>
<div class="text-sm text-gray-300">可疑官员</div>
</div>
</div>
</section>
<!-- 官员列表 -->
<section class="glass-effect rounded-lg p-6">
<div class="flex justify-between items-center mb-6">
<h2 class="title-font text-xl font-bold imperial-gold">官员列表</h2>
<div class="flex space-x-4">
<select class="bg-gray-700 text-white px-3 py-1 rounded" id="faction-filter">
<option value="all">所有派系</option>
<option value="qingliu">清流党</option>
<option value="xungui">勋贵派</option>
<option value="wenguan">文官集团</option>
<option value="huanguan">宦官势力</option>
<option value="zhongli">中立派</option>
</select>
<select class="bg-gray-700 text-white px-3 py-1 rounded" id="position-filter">
<option value="all">所有职位</option>
<option value="chancellor">丞相</option>
<option value="minister">六部尚书</option>
<option value="governor">州牧</option>
<option value="magistrate">县令</option>
</select>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4" id="officials-grid">
<!-- 官员卡片将通过JavaScript动态生成 -->
</div>
</section>
<!-- 派系势力图表 -->
<section class="glass-effect rounded-lg p-6 mt-6">
<h2 class="title-font text-xl font-bold imperial-gold mb-4">派系势力分布</h2>
<div class="grid grid-cols-2 gap-6">
<div>
<div id="faction-pie-chart" style="height: 300px;"></div>
</div>
<div>
<div id="loyalty-chart" style="height: 300px;"></div>
</div>
</div>
</section>
</main>
<!-- 任命官员模态框 -->
<div class="appointment-modal" id="appointment-modal">
<div class="modal-content">
<div class="flex justify-between items-center mb-6">
<h3 class="title-font text-xl font-bold imperial-gold">任命官员</h3>
<button onclick="closeAppointmentModal()" class="text-gray-400 hover:text-white text-2xl">×</button>
</div>
<div class="mb-4">
<h4 class="font-bold mb-3">可选职位</h4>
<div id="available-positions">
<!-- 职位列表将通过JavaScript生成 -->
</div>
</div>
<div id="candidate-selection" style="display: none;">
<h4 class="font-bold mb-3">候选人</h4>
<div id="candidates-list">
<!-- 候选人列表将通过JavaScript生成 -->
</div>
<div class="flex justify-end mt-4">
<button onclick="confirmAppointment()" class="px-4 py-2 bg-yellow-600 text-white rounded hover:bg-yellow-700">
确认任命
</button>
</div>
</div>
</div>
</div>
<!-- 官员详情模态框 -->
<div class="appointment-modal" id="official-detail-modal">
<div class="modal-content">
<div class="flex justify-between items-center mb-6">
<h3 class="title-font text-xl font-bold imperial-gold" id="official-name">官员详情</h3>
<button onclick="closeOfficialDetailModal()" class="text-gray-400 hover:text-white text-2xl">×</button>
</div>
<div id="official-detail-content">
<!-- 官员详情内容将通过JavaScript生成 -->
</div>
<div class="flex justify-end space-x-4 mt-6">
<button onclick="promoteOfficial()" class="px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700">
晋升
</button>
<button onclick="demoteOfficial()" class="px-4 py-2 bg-yellow-600 text-white rounded hover:bg-yellow-700">
降职
</button>
<button onclick="dismissOfficial()" class="px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700">
罢免
</button>
</div>
</div>
</div>
<script>
// 官员管理系统
class OfficialsManager {
constructor() {
this.officials = [];
this.selectedPosition = null;
this.selectedCandidate = null;
this.selectedOfficial = null;
this.init();
}
init() {
this.generateOfficials();
this.setupEventListeners();
this.renderOfficials();
this.initCharts();
this.updateStatistics();
}
generateOfficials() {
const surnames = ['李', '王', '张', '刘', '陈', '杨', '赵', '黄', '周', '吴', '徐', '孙', '胡', '朱', '高'];
const names = ['文', '武', '德', '明', '志', '忠', '孝', '仁', '义', '礼', '智', '信', '勇', '廉', '正'];
const positions = [
{ name: '丞相', level: 1, type: 'chancellor' },
{ name: '户部尚书', level: 2, type: 'minister' },
{ name: '礼部尚书', level: 2, type: 'minister' },
{ name: '兵部尚书', level: 2, type: 'minister' },
{ name: '刑部尚书', level: 2, type: 'minister' },
{ name: '工部尚书', level: 2, type: 'minister' },
{ name: '吏部尚书', level: 2, type: 'minister' },
{ name: '幽州牧', level: 3, type: 'governor' },
{ name: '冀州牧', level: 3, type: 'governor' },
{ name: '荆州牧', level: 3, type: 'governor' },
{ name: '长安县令', level: 4, type: 'magistrate' },
{ name: '洛阳县令', level: 4, type: 'magistrate' }
];
const factions = ['qingliu', 'xungui', 'wenguan', 'huanguan', 'zhongli'];
for (let i = 0; i < 20; i++) {
const surname = surnames[Math.floor(Math.random() * surnames.length)];
const name = names[Math.floor(Math.random() * names.length)] + names[Math.floor(Math.random() * names.length)];
const position = positions[Math.floor(Math.random() * positions.length)];
const faction = factions[Math.floor(Math.random() * factions.length)];
this.officials.push({
id: i,
name: surname + name,
position: position,
faction: faction,
loyalty: Math.floor(Math.random() * 100),
ability: Math.floor(Math.random() * 100),
integrity: Math.floor(Math.random() * 100),
ambition: Math.floor(Math.random() * 100),
age: Math.floor(Math.random() * 40) + 25,
health: Math.floor(Math.random() * 50) + 50,
relationship: Math.floor(Math.random() * 100),
salary: position.level * 1000
});
}
}
setupEventListeners() {
document.getElementById('faction-filter').addEventListener('change', (e) => {
this.filterOfficials();
});
document.getElementById('position-filter').addEventListener('change', (e) => {
this.filterOfficials();
});
}
renderOfficials() {
const container = document.getElementById('officials-grid');
container.innerHTML = '';
this.officials.forEach((official, index) => {
const card = this.createOfficialCard(official);
container.appendChild(card);
// 添加进入动画
anime({
targets: card,
translateY: [50, 0],
opacity: [0, 1],
duration: 600,
delay: index * 50,
easing: 'easeOutCubic'
});
});
}
createOfficialCard(official) {
const card = document.createElement('div');
card.className = 'official-card p-4 rounded-lg';
const loyaltyColor = official.loyalty >= 80 ? 'bg-green-500' :
official.loyalty >= 60 ? 'bg-yellow-500' : 'bg-red-500';
const factionName = this.getFactionName(official.faction);
const factionClass = `faction-${official.faction}`;
card.innerHTML = `
<div class="flex justify-between items-start mb-3">
<div>
<h3 class="font-bold text-lg">${official.name}</h3>
<p class="text-sm text-gray-300">${official.position.name}</p>
</div>
<span class="faction-badge ${factionClass}">${factionName}</span>
</div>
<div class="space-y-2 text-sm">
<div class="flex justify-between">
<span>忠诚度:</span>
<span class="mono-font">${official.loyalty}</span>
</div>
<div class="loyalty-bar">
<div class="loyalty-fill ${loyaltyColor}" style="width: ${official.loyality}%"></div>
</div>
<div class="flex justify-between">
<span>能力:</span>
<span class="mono-font">${official.ability}</span>
</div>
<div class="flex justify-between">
<span>清廉:</span>
<span class="mono-font">${official.integrity}</span>
</div>
<div class="flex justify-between">
<span>年龄:</span>
<span class="mono-font">${official.age}岁</span>
</div>
</div>
<div class="mt-4 flex space-x-2">
<button onclick="showOfficialDetail(${official.id})" class="flex-1 px-3 py-1 bg-blue-600 text-white rounded text-sm hover:bg-blue-700">
详情
</button>
<button onclick="summonOfficial(${official.id})" class="flex-1 px-3 py-1 bg-green-600 text-white rounded text-sm hover:bg-green-700">
召见
</button>
</div>
`;
return card;
}
getFactionName(faction) {
const names = {
'qingliu': '清流',
'xungui': '勋贵',
'wenguan': '文官',
'huanguan': '宦官',
'zhongli': '中立'
};
return names[faction] || '未知';
}
filterOfficials() {
const factionFilter = document.getElementById('faction-filter').value;
const positionFilter = document.getElementById('position-filter').value;
const cards = document.querySelectorAll('.official-card');
cards.forEach((card, index) => {
const official = this.officials[index];
let show = true;
if (factionFilter !== 'all' && official.faction !== factionFilter) {
show = false;
}
if (positionFilter !== 'all' && official.position.type !== positionFilter) {
show = false;
}
if (show) {
card.style.display = 'block';
anime({
targets: card,
opacity: [0, 1],
scale: [0.8, 1],
duration: 300,
delay: index * 50
});
} else {
card.style.display = 'none';
}
});
}
initCharts() {
// 派系饼图
const factionChart = echarts.init(document.getElementById('faction-pie-chart'));
const factionData = this.calculateFactionData();
const factionOption = {
backgroundColor: 'transparent',
textStyle: { color: '#F5F5DC' },
title: {
text: '派系分布',
left: 'center',
textStyle: { color: '#D4AF37', fontSize: 16 }
},
series: [{
type: 'pie',
radius: ['30%', '60%'],
data: factionData,
label: {
color: '#F5F5DC',
fontSize: 10
}
}]
};
factionChart.setOption(factionOption);
// 忠诚度分布图
const loyaltyChart = echarts.init(document.getElementById('loyalty-chart'));
const loyaltyData = this.calculateLoyaltyData();
const loyaltyOption = {
backgroundColor: 'transparent',
textStyle: { color: '#F5F5DC' },
title: {
text: '忠诚度分布',
left: 'center',
textStyle: { color: '#D4AF37', fontSize: 16 }
},
xAxis: {
type: 'category',
data: ['0-20', '20-40', '40-60', '60-80', '80-100'],
axisLabel: { color: '#F5F5DC' },
axisLine: { lineStyle: { color: '#666' } }
},
yAxis: {
type: 'value',
axisLabel: { color: '#F5F5DC' },
axisLine: { lineStyle: { color: '#666' } },
splitLine: { lineStyle: { color: '#333' } }
},
series: [{
type: 'bar',
data: loyaltyData,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#D4AF37' },
{ offset: 1, color: '#B8860B' }
])
}
}]
};
loyaltyChart.setOption(loyaltyOption);
// 响应式
window.addEventListener('resize', () => {
factionChart.resize();
loyaltyChart.resize();
});
}
calculateFactionData() {
const factionCounts = {};
this.officials.forEach(official => {
factionCounts[official.faction] = (factionCounts[official.faction] || 0) + 1;
});
const colors = {
'qingliu': '#228B22',
'xungui': '#D4AF37',
'wenguan': '#4169E1',
'huanguan': '#DC143C',
'zhongli': '#696969'
};
return Object.keys(factionCounts).map(faction => ({
value: factionCounts[faction],
name: this.getFactionName(faction),
itemStyle: { color: colors[faction] }
}));
}
calculateLoyaltyData() {
const ranges = [0, 0, 0, 0, 0]; // 0-20, 20-40, 40-60, 60-80, 80-100
this.officials.forEach(official => {
const loyalty = official.loyalty;
if (loyalty < 20) ranges[0]++;
else if (loyalty < 40) ranges[1]++;
else if (loyalty < 60) ranges[2]++;
else if (loyalty < 80) ranges[3]++;
else ranges[4]++;
});
return ranges;
}
updateStatistics() {
const total = this.officials.length;
const highLoyalty = this.officials.filter(o => o.loyalty >= 80).length;
const neutral = this.officials.filter(o => o.loyalty >= 40 && o.loyalty < 80).length;
const lowLoyalty = this.officials.filter(o => o.loyalty < 40).length;
document.getElementById('total-officials').textContent = total;
document.getElementById('high-loyalty').textContent = highLoyalty;
document.getElementById('neutral-officials').textContent = neutral;
document.getElementById('low-loyalty').textContent = lowLoyalty;
}
}
// 全局函数
function showAppointmentModal() {
document.getElementById('appointment-modal').style.display = 'block';
generateAvailablePositions();
}
function closeAppointmentModal() {
document.getElementById('appointment-modal').style.display = 'none';
}
function showOfficialDetail(officialId) {
const official = officialsManager.officials.find(o => o.id === officialId);
if (!official) return;
officialsManager.selectedOfficial = official;
document.getElementById('official-name').textContent = official.name;
const content = document.getElementById('official-detail-content');
content.innerHTML = `
<div class="grid grid-cols-2 gap-6">
<div>
<h4 class="font-bold mb-3">基本信息</h4>
<div class="space-y-2">
<div class="flex justify-between">
<span>职位:</span>
<span>${official.position.name}</span>
</div>
<div class="flex justify-between">
<span>派系:</span>
<span class="faction-badge faction-${official.faction}">${officialsManager.getFactionName(official.faction)}</span>
</div>
<div class="flex justify-between">
<span>年龄:</span>
<span>${official.age}岁</span>
</div>
<div class="flex justify-between">
<span>俸禄:</span>
<span>${official.salary}两/年</span>
</div>
</div>
</div>
<div>
<h4 class="font-bold mb-3">能力属性</h4>
<div class="space-y-2">
<div class="flex justify-between">
<span>能力:</span>
<span class="mono-font">${official.ability}</span>
</div>
<div class="flex justify-between">
<span>忠诚度:</span>
<span class="mono-font">${official.loyalty}</span>
</div>
<div class="flex justify-between">
<span>清廉度:</span>
<span class="mono-font">${official.integrity}</span>
</div>
<div class="flex justify-between">
<span>野心:</span>
<span class="mono-font">${official.ambition}</span>
</div>
</div>
</div>
</div>
`;
document.getElementById('official-detail-modal').style.display = 'block';
}
function closeOfficialDetailModal() {
document.getElementById('official-detail-modal').style.display = 'none';
}
function generateAvailablePositions() {
const container = document.getElementById('available-positions');
const positions = [
{ name: '丞相', level: 1, occupied: true, current: '王安石' },
{ name: '户部尚书', level: 2, occupied: false },
{ name: '礼部尚书', level: 2, occupied: true, current: '司马光' },
{ name: '荆州牧', level: 3, occupied: false },
{ name: '长安县令', level: 4, occupied: true, current: '狄仁杰' }
];
container.innerHTML = '';
positions.forEach((position, index) => {
const card = document.createElement('div');
card.className = `position-card ${position.occupied ? 'occupied' : ''}`;
card.innerHTML = `
<div class="flex justify-between items-center">
<div>
<h5 class="font-bold">${position.name}</h5>
<p class="text-sm text-gray-300">等级: ${position.level}</p>
</div>
<div class="text-right">
${position.occupied ?
`<p class="text-sm text-red-400">已有人担任</p>
<p class="text-xs text-gray-400">现任: ${position.current}</p>` :
`<p class="text-sm text-green-400">空缺</p>`
}
</div>
</div>
`;
if (!position.occupied) {
card.addEventListener('click', () => selectPosition(position, card));
}
container.appendChild(card);
});
}
function selectPosition(position, cardElement) {
// 移除之前的选中状态
document.querySelectorAll('.position-card').forEach(card => {
card.classList.remove('ring-2', 'ring-yellow-400');
});
// 添加选中状态
cardElement.classList.add('ring-2', 'ring-yellow-400');
officialsManager.selectedPosition = position;
// 显示候选人选择
showCandidateSelection();
}
function showCandidateSelection() {
const container = document.getElementById('candidates-list');
const candidates = [
{ name: '李白', ability: 85, loyalty: 70, faction: 'wenguan' },
{ name: '杜甫', ability: 80, loyalty: 85, faction: 'qingliu' },
{ name: '白居易', ability: 75, loyalty: 60, faction: 'wenguan' },
{ name: '苏轼', ability: 90, loyalty: 75, faction: 'qingliu' }
];
container.innerHTML = '';
candidates.forEach((candidate, index) => {
const card = document.createElement('div');
card.className = 'official-card p-3 rounded cursor-pointer';
card.innerHTML = `
<div class="flex justify-between items-center">
<div>
<h5 class="font-bold">${candidate.name}</h5>
<p class="text-sm text-gray-300">能力: ${candidate.ability} | 忠诚: ${candidate.loyalty}</p>
</div>
<span class="faction-badge faction-${candidate.faction}">${officialsManager.getFactionName(candidate.faction)}</span>
</div>
`;
card.addEventListener('click', () => selectCandidate(candidate, card));
container.appendChild(card);
});
document.getElementById('candidate-selection').style.display = 'block';
}
function selectCandidate(candidate, cardElement) {
// 移除之前的选中状态
document.querySelectorAll('#candidates-list .official-card').forEach(card => {
card.classList.remove('ring-2', 'ring-yellow-400');
});
// 添加选中状态
cardElement.classList.add('ring-2', 'ring-yellow-400');
officialsManager.selectedCandidate = candidate;
}
function confirmAppointment() {
if (!officialsManager.selectedPosition || !officialsManager.selectedCandidate) {
alert('请选择职位和候选人');
return;
}
// 这里可以添加任命逻辑
alert(`成功任命${officialsManager.selectedCandidate.name}为${officialsManager.selectedPosition.name}`);
closeAppointmentModal();
}
function showFactionAnalysis() {
alert('派系分析功能开发中...');
}
function conductExamination() {
alert('科举考试功能开发中...');
}
function summonOfficial(officialId) {
const official = officialsManager.officials.find(o => o.id === officialId);
alert(`召见${official.name}商议国事`);
}
function promoteOfficial() {
if (officialsManager.selectedOfficial) {
alert(`${officialsManager.selectedOfficial.name}晋升成功`);
closeOfficialDetailModal();
}
}
function demoteOfficial() {
if (officialsManager.selectedOfficial) {
alert(`${officialsManager.selectedOfficial.name}降职成功`);
closeOfficialDetailModal();
}
}
function dismissOfficial() {
if (officialsManager.selectedOfficial) {
if (confirm(`确定要罢免${officialsManager.selectedOfficial.name}吗?`)) {
alert(`${officialsManager.selectedOfficial.name}已被罢免`);
closeOfficialDetailModal();
}
}
}
// 初始化
let officialsManager;
document.addEventListener('DOMContentLoaded', () => {
officialsManager = new OfficialsManager();
});
</script>
</body>
</html>
5、main.js
<!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 href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;700&family=Noto+Sans+SC:wght@300;400;500;700&family=Ma+Shan+Zheng&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet">
<!-- 核心库引入 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.4.3/echarts.min.js"></script>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<style>
:root {
--imperial-gold: #D4AF37;
--deep-red: #8B0000;
--dark-bg: #1A1A1A;
--text-light: #F5F5DC;
--success-green: #228B22;
--warning-orange: #FF8C00;
--error-red: #DC143C;
--neutral-gray: #696969;
}
body {
font-family: 'Noto Sans SC', sans-serif;
background: var(--dark-bg);
color: var(--text-light);
overflow-x: hidden;
}
.title-font {
font-family: 'Noto Serif SC', serif;
}
.decorative-font {
font-family: 'Ma Shan Zheng', cursive;
}
.mono-font {
font-family: 'JetBrains Mono', monospace;
}
.imperial-gold {
color: var(--imperial-gold);
}
.glass-effect {
background: rgba(26, 26, 26, 0.8);
backdrop-filter: blur(10px);
border: 1px solid rgba(212, 175, 55, 0.2);
}
.official-card {
background: linear-gradient(135deg, rgba(212, 175, 55, 0.1) 0%, rgba(139, 0, 0, 0.1) 100%);
border: 1px solid rgba(212, 175, 55, 0.3);
transition: all 0.3s ease;
cursor: pointer;
}
.official-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 25px rgba(212, 175, 55, 0.3);
border-color: var(--imperial-gold);
}
.faction-badge {
padding: 2px 8px;
border-radius: 12px;
font-size: 0.75rem;
font-weight: bold;
}
.faction-qingliu { background: #228B22; color: white; }
.faction-xungui { background: #D4AF37; color: black; }
.faction-wenguan { background: #4169E1; color: white; }
.faction-huanguan { background: #DC143C; color: white; }
.faction-zhongli { background: #696969; color: white; }
.loyalty-bar {
height: 6px;
border-radius: 3px;
background: #333;
overflow: hidden;
}
.loyalty-fill {
height: 100%;
transition: width 0.5s ease;
}
.appointment-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.8);
display: none;
z-index: 1000;
}
.modal-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: var(--dark-bg);
border: 2px solid var(--imperial-gold);
border-radius: 10px;
padding: 20px;
max-width: 600px;
width: 90%;
max-height: 80vh;
overflow-y: auto;
}
.position-card {
background: rgba(212, 175, 55, 0.1);
border: 1px solid rgba(212, 175, 55, 0.3);
border-radius: 8px;
padding: 15px;
margin-bottom: 10px;
cursor: pointer;
transition: all 0.3s ease;
}
.position-card:hover {
background: rgba(212, 175, 55, 0.2);
border-color: var(--imperial-gold);
}
.position-card.occupied {
background: rgba(139, 0, 0, 0.1);
border-color: rgba(139, 0, 0, 0.3);
}
</style>
</head>
<body class="min-h-screen">
<!-- 顶部导航 -->
<header class="glass-effect fixed top-0 left-0 right-0 z-50 p-4">
<div class="flex justify-between items-center">
<div class="flex items-center">
<button onclick="window.location.href='index.html'" class="mr-4 text-2xl">🏛️</button>
<h1 class="title-font text-2xl font-bold imperial-gold">官员管理</h1>
</div>
<div class="flex space-x-4">
<button class="px-4 py-2 bg-yellow-600 text-white rounded hover:bg-yellow-700" onclick="showAppointmentModal()">
📝 任命官员
</button>
<button class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700" onclick="showFactionAnalysis()">
📊 派系分析
</button>
<button class="px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700" onclick="conductExamination()">
📚 科举考试
</button>
</div>
</div>
</header>
<!-- 主内容区域 -->
<main class="pt-20 p-6">
<!-- 统计概览 -->
<section class="glass-effect rounded-lg p-6 mb-6">
<h2 class="title-font text-xl font-bold imperial-gold mb-4">朝中概况</h2>
<div class="grid grid-cols-4 gap-6">
<div class="text-center">
<div class="text-3xl font-bold imperial-gold" id="total-officials">72</div>
<div class="text-sm text-gray-300">在职官员</div>
</div>
<div class="text-center">
<div class="text-3xl font-bold text-green-400" id="high-loyalty">45</div>
<div class="text-sm text-gray-300">忠诚官员</div>
</div>
<div class="text-center">
<div class="text-3xl font-bold text-yellow-400" id="neutral-officials">20</div>
<div class="text-sm text-gray-300">中立官员</div>
</div>
<div class="text-center">
<div class="text-3xl font-bold text-red-400" id="low-loyalty">7</div>
<div class="text-sm text-gray-300">可疑官员</div>
</div>
</div>
</section>
<!-- 官员列表 -->
<section class="glass-effect rounded-lg p-6">
<div class="flex justify-between items-center mb-6">
<h2 class="title-font text-xl font-bold imperial-gold">官员列表</h2>
<div class="flex space-x-4">
<select class="bg-gray-700 text-white px-3 py-1 rounded" id="faction-filter">
<option value="all">所有派系</option>
<option value="qingliu">清流党</option>
<option value="xungui">勋贵派</option>
<option value="wenguan">文官集团</option>
<option value="huanguan">宦官势力</option>
<option value="zhongli">中立派</option>
</select>
<select class="bg-gray-700 text-white px-3 py-1 rounded" id="position-filter">
<option value="all">所有职位</option>
<option value="chancellor">丞相</option>
<option value="minister">六部尚书</option>
<option value="governor">州牧</option>
<option value="magistrate">县令</option>
</select>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4" id="officials-grid">
<!-- 官员卡片将通过JavaScript动态生成 -->
</div>
</section>
<!-- 派系势力图表 -->
<section class="glass-effect rounded-lg p-6 mt-6">
<h2 class="title-font text-xl font-bold imperial-gold mb-4">派系势力分布</h2>
<div class="grid grid-cols-2 gap-6">
<div>
<div id="faction-pie-chart" style="height: 300px;"></div>
</div>
<div>
<div id="loyalty-chart" style="height: 300px;"></div>
</div>
</div>
</section>
</main>
<!-- 任命官员模态框 -->
<div class="appointment-modal" id="appointment-modal">
<div class="modal-content">
<div class="flex justify-between items-center mb-6">
<h3 class="title-font text-xl font-bold imperial-gold">任命官员</h3>
<button onclick="closeAppointmentModal()" class="text-gray-400 hover:text-white text-2xl">×</button>
</div>
<div class="mb-4">
<h4 class="font-bold mb-3">可选职位</h4>
<div id="available-positions">
<!-- 职位列表将通过JavaScript生成 -->
</div>
</div>
<div id="candidate-selection" style="display: none;">
<h4 class="font-bold mb-3">候选人</h4>
<div id="candidates-list">
<!-- 候选人列表将通过JavaScript生成 -->
</div>
<div class="flex justify-end mt-4">
<button onclick="confirmAppointment()" class="px-4 py-2 bg-yellow-600 text-white rounded hover:bg-yellow-700">
确认任命
</button>
</div>
</div>
</div>
</div>
<!-- 官员详情模态框 -->
<div class="appointment-modal" id="official-detail-modal">
<div class="modal-content">
<div class="flex justify-between items-center mb-6">
<h3 class="title-font text-xl font-bold imperial-gold" id="official-name">官员详情</h3>
<button onclick="closeOfficialDetailModal()" class="text-gray-400 hover:text-white text-2xl">×</button>
</div>
<div id="official-detail-content">
<!-- 官员详情内容将通过JavaScript生成 -->
</div>
<div class="flex justify-end space-x-4 mt-6">
<button onclick="promoteOfficial()" class="px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700">
晋升
</button>
<button onclick="demoteOfficial()" class="px-4 py-2 bg-yellow-600 text-white rounded hover:bg-yellow-700">
降职
</button>
<button onclick="dismissOfficial()" class="px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700">
罢免
</button>
</div>
</div>
</div>
<script>
// 官员管理系统
class OfficialsManager {
constructor() {
this.officials = [];
this.selectedPosition = null;
this.selectedCandidate = null;
this.selectedOfficial = null;
this.init();
}
init() {
this.generateOfficials();
this.setupEventListeners();
this.renderOfficials();
this.initCharts();
this.updateStatistics();
}
generateOfficials() {
const surnames = ['李', '王', '张', '刘', '陈', '杨', '赵', '黄', '周', '吴', '徐', '孙', '胡', '朱', '高'];
const names = ['文', '武', '德', '明', '志', '忠', '孝', '仁', '义', '礼', '智', '信', '勇', '廉', '正'];
const positions = [
{ name: '丞相', level: 1, type: 'chancellor' },
{ name: '户部尚书', level: 2, type: 'minister' },
{ name: '礼部尚书', level: 2, type: 'minister' },
{ name: '兵部尚书', level: 2, type: 'minister' },
{ name: '刑部尚书', level: 2, type: 'minister' },
{ name: '工部尚书', level: 2, type: 'minister' },
{ name: '吏部尚书', level: 2, type: 'minister' },
{ name: '幽州牧', level: 3, type: 'governor' },
{ name: '冀州牧', level: 3, type: 'governor' },
{ name: '荆州牧', level: 3, type: 'governor' },
{ name: '长安县令', level: 4, type: 'magistrate' },
{ name: '洛阳县令', level: 4, type: 'magistrate' }
];
const factions = ['qingliu', 'xungui', 'wenguan', 'huanguan', 'zhongli'];
for (let i = 0; i < 20; i++) {
const surname = surnames[Math.floor(Math.random() * surnames.length)];
const name = names[Math.floor(Math.random() * names.length)] + names[Math.floor(Math.random() * names.length)];
const position = positions[Math.floor(Math.random() * positions.length)];
const faction = factions[Math.floor(Math.random() * factions.length)];
this.officials.push({
id: i,
name: surname + name,
position: position,
faction: faction,
loyalty: Math.floor(Math.random() * 100),
ability: Math.floor(Math.random() * 100),
integrity: Math.floor(Math.random() * 100),
ambition: Math.floor(Math.random() * 100),
age: Math.floor(Math.random() * 40) + 25,
health: Math.floor(Math.random() * 50) + 50,
relationship: Math.floor(Math.random() * 100),
salary: position.level * 1000
});
}
}
setupEventListeners() {
document.getElementById('faction-filter').addEventListener('change', (e) => {
this.filterOfficials();
});
document.getElementById('position-filter').addEventListener('change', (e) => {
this.filterOfficials();
});
}
renderOfficials() {
const container = document.getElementById('officials-grid');
container.innerHTML = '';
this.officials.forEach((official, index) => {
const card = this.createOfficialCard(official);
container.appendChild(card);
// 添加进入动画
anime({
targets: card,
translateY: [50, 0],
opacity: [0, 1],
duration: 600,
delay: index * 50,
easing: 'easeOutCubic'
});
});
}
createOfficialCard(official) {
const card = document.createElement('div');
card.className = 'official-card p-4 rounded-lg';
const loyaltyColor = official.loyalty >= 80 ? 'bg-green-500' :
official.loyalty >= 60 ? 'bg-yellow-500' : 'bg-red-500';
const factionName = this.getFactionName(official.faction);
const factionClass = `faction-${official.faction}`;
card.innerHTML = `
<div class="flex justify-between items-start mb-3">
<div>
<h3 class="font-bold text-lg">${official.name}</h3>
<p class="text-sm text-gray-300">${official.position.name}</p>
</div>
<span class="faction-badge ${factionClass}">${factionName}</span>
</div>
<div class="space-y-2 text-sm">
<div class="flex justify-between">
<span>忠诚度:</span>
<span class="mono-font">${official.loyalty}</span>
</div>
<div class="loyalty-bar">
<div class="loyalty-fill ${loyaltyColor}" style="width: ${official.loyality}%"></div>
</div>
<div class="flex justify-between">
<span>能力:</span>
<span class="mono-font">${official.ability}</span>
</div>
<div class="flex justify-between">
<span>清廉:</span>
<span class="mono-font">${official.integrity}</span>
</div>
<div class="flex justify-between">
<span>年龄:</span>
<span class="mono-font">${official.age}岁</span>
</div>
</div>
<div class="mt-4 flex space-x-2">
<button onclick="showOfficialDetail(${official.id})" class="flex-1 px-3 py-1 bg-blue-600 text-white rounded text-sm hover:bg-blue-700">
详情
</button>
<button onclick="summonOfficial(${official.id})" class="flex-1 px-3 py-1 bg-green-600 text-white rounded text-sm hover:bg-green-700">
召见
</button>
</div>
`;
return card;
}
getFactionName(faction) {
const names = {
'qingliu': '清流',
'xungui': '勋贵',
'wenguan': '文官',
'huanguan': '宦官',
'zhongli': '中立'
};
return names[faction] || '未知';
}
filterOfficials() {
const factionFilter = document.getElementById('faction-filter').value;
const positionFilter = document.getElementById('position-filter').value;
const cards = document.querySelectorAll('.official-card');
cards.forEach((card, index) => {
const official = this.officials[index];
let show = true;
if (factionFilter !== 'all' && official.faction !== factionFilter) {
show = false;
}
if (positionFilter !== 'all' && official.position.type !== positionFilter) {
show = false;
}
if (show) {
card.style.display = 'block';
anime({
targets: card,
opacity: [0, 1],
scale: [0.8, 1],
duration: 300,
delay: index * 50
});
} else {
card.style.display = 'none';
}
});
}
initCharts() {
// 派系饼图
const factionChart = echarts.init(document.getElementById('faction-pie-chart'));
const factionData = this.calculateFactionData();
const factionOption = {
backgroundColor: 'transparent',
textStyle: { color: '#F5F5DC' },
title: {
text: '派系分布',
left: 'center',
textStyle: { color: '#D4AF37', fontSize: 16 }
},
series: [{
type: 'pie',
radius: ['30%', '60%'],
data: factionData,
label: {
color: '#F5F5DC',
fontSize: 10
}
}]
};
factionChart.setOption(factionOption);
// 忠诚度分布图
const loyaltyChart = echarts.init(document.getElementById('loyalty-chart'));
const loyaltyData = this.calculateLoyaltyData();
const loyaltyOption = {
backgroundColor: 'transparent',
textStyle: { color: '#F5F5DC' },
title: {
text: '忠诚度分布',
left: 'center',
textStyle: { color: '#D4AF37', fontSize: 16 }
},
xAxis: {
type: 'category',
data: ['0-20', '20-40', '40-60', '60-80', '80-100'],
axisLabel: { color: '#F5F5DC' },
axisLine: { lineStyle: { color: '#666' } }
},
yAxis: {
type: 'value',
axisLabel: { color: '#F5F5DC' },
axisLine: { lineStyle: { color: '#666' } },
splitLine: { lineStyle: { color: '#333' } }
},
series: [{
type: 'bar',
data: loyaltyData,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#D4AF37' },
{ offset: 1, color: '#B8860B' }
])
}
}]
};
loyaltyChart.setOption(loyaltyOption);
// 响应式
window.addEventListener('resize', () => {
factionChart.resize();
loyaltyChart.resize();
});
}
calculateFactionData() {
const factionCounts = {};
this.officials.forEach(official => {
factionCounts[official.faction] = (factionCounts[official.faction] || 0) + 1;
});
const colors = {
'qingliu': '#228B22',
'xungui': '#D4AF37',
'wenguan': '#4169E1',
'huanguan': '#DC143C',
'zhongli': '#696969'
};
return Object.keys(factionCounts).map(faction => ({
value: factionCounts[faction],
name: this.getFactionName(faction),
itemStyle: { color: colors[faction] }
}));
}
calculateLoyaltyData() {
const ranges = [0, 0, 0, 0, 0]; // 0-20, 20-40, 40-60, 60-80, 80-100
this.officials.forEach(official => {
const loyalty = official.loyalty;
if (loyalty < 20) ranges[0]++;
else if (loyalty < 40) ranges[1]++;
else if (loyalty < 60) ranges[2]++;
else if (loyalty < 80) ranges[3]++;
else ranges[4]++;
});
return ranges;
}
updateStatistics() {
const total = this.officials.length;
const highLoyalty = this.officials.filter(o => o.loyalty >= 80).length;
const neutral = this.officials.filter(o => o.loyalty >= 40 && o.loyalty < 80).length;
const lowLoyalty = this.officials.filter(o => o.loyalty < 40).length;
document.getElementById('total-officials').textContent = total;
document.getElementById('high-loyalty').textContent = highLoyalty;
document.getElementById('neutral-officials').textContent = neutral;
document.getElementById('low-loyalty').textContent = lowLoyalty;
}
}
// 全局函数
function showAppointmentModal() {
document.getElementById('appointment-modal').style.display = 'block';
generateAvailablePositions();
}
function closeAppointmentModal() {
document.getElementById('appointment-modal').style.display = 'none';
}
function showOfficialDetail(officialId) {
const official = officialsManager.officials.find(o => o.id === officialId);
if (!official) return;
officialsManager.selectedOfficial = official;
document.getElementById('official-name').textContent = official.name;
const content = document.getElementById('official-detail-content');
content.innerHTML = `
<div class="grid grid-cols-2 gap-6">
<div>
<h4 class="font-bold mb-3">基本信息</h4>
<div class="space-y-2">
<div class="flex justify-between">
<span>职位:</span>
<span>${official.position.name}</span>
</div>
<div class="flex justify-between">
<span>派系:</span>
<span class="faction-badge faction-${official.faction}">${officialsManager.getFactionName(official.faction)}</span>
</div>
<div class="flex justify-between">
<span>年龄:</span>
<span>${official.age}岁</span>
</div>
<div class="flex justify-between">
<span>俸禄:</span>
<span>${official.salary}两/年</span>
</div>
</div>
</div>
<div>
<h4 class="font-bold mb-3">能力属性</h4>
<div class="space-y-2">
<div class="flex justify-between">
<span>能力:</span>
<span class="mono-font">${official.ability}</span>
</div>
<div class="flex justify-between">
<span>忠诚度:</span>
<span class="mono-font">${official.loyalty}</span>
</div>
<div class="flex justify-between">
<span>清廉度:</span>
<span class="mono-font">${official.integrity}</span>
</div>
<div class="flex justify-between">
<span>野心:</span>
<span class="mono-font">${official.ambition}</span>
</div>
</div>
</div>
</div>
`;
document.getElementById('official-detail-modal').style.display = 'block';
}
function closeOfficialDetailModal() {
document.getElementById('official-detail-modal').style.display = 'none';
}
function generateAvailablePositions() {
const container = document.getElementById('available-positions');
const positions = [
{ name: '丞相', level: 1, occupied: true, current: '王安石' },
{ name: '户部尚书', level: 2, occupied: false },
{ name: '礼部尚书', level: 2, occupied: true, current: '司马光' },
{ name: '荆州牧', level: 3, occupied: false },
{ name: '长安县令', level: 4, occupied: true, current: '狄仁杰' }
];
container.innerHTML = '';
positions.forEach((position, index) => {
const card = document.createElement('div');
card.className = `position-card ${position.occupied ? 'occupied' : ''}`;
card.innerHTML = `
<div class="flex justify-between items-center">
<div>
<h5 class="font-bold">${position.name}</h5>
<p class="text-sm text-gray-300">等级: ${position.level}</p>
</div>
<div class="text-right">
${position.occupied ?
`<p class="text-sm text-red-400">已有人担任</p>
<p class="text-xs text-gray-400">现任: ${position.current}</p>` :
`<p class="text-sm text-green-400">空缺</p>`
}
</div>
</div>
`;
if (!position.occupied) {
card.addEventListener('click', () => selectPosition(position, card));
}
container.appendChild(card);
});
}
function selectPosition(position, cardElement) {
// 移除之前的选中状态
document.querySelectorAll('.position-card').forEach(card => {
card.classList.remove('ring-2', 'ring-yellow-400');
});
// 添加选中状态
cardElement.classList.add('ring-2', 'ring-yellow-400');
officialsManager.selectedPosition = position;
// 显示候选人选择
showCandidateSelection();
}
function showCandidateSelection() {
const container = document.getElementById('candidates-list');
const candidates = [
{ name: '李白', ability: 85, loyalty: 70, faction: 'wenguan' },
{ name: '杜甫', ability: 80, loyalty: 85, faction: 'qingliu' },
{ name: '白居易', ability: 75, loyalty: 60, faction: 'wenguan' },
{ name: '苏轼', ability: 90, loyalty: 75, faction: 'qingliu' }
];
container.innerHTML = '';
candidates.forEach((candidate, index) => {
const card = document.createElement('div');
card.className = 'official-card p-3 rounded cursor-pointer';
card.innerHTML = `
<div class="flex justify-between items-center">
<div>
<h5 class="font-bold">${candidate.name}</h5>
<p class="text-sm text-gray-300">能力: ${candidate.ability} | 忠诚: ${candidate.loyalty}</p>
</div>
<span class="faction-badge faction-${candidate.faction}">${officialsManager.getFactionName(candidate.faction)}</span>
</div>
`;
card.addEventListener('click', () => selectCandidate(candidate, card));
container.appendChild(card);
});
document.getElementById('candidate-selection').style.display = 'block';
}
function selectCandidate(candidate, cardElement) {
// 移除之前的选中状态
document.querySelectorAll('#candidates-list .official-card').forEach(card => {
card.classList.remove('ring-2', 'ring-yellow-400');
});
// 添加选中状态
cardElement.classList.add('ring-2', 'ring-yellow-400');
officialsManager.selectedCandidate = candidate;
}
function confirmAppointment() {
if (!officialsManager.selectedPosition || !officialsManager.selectedCandidate) {
alert('请选择职位和候选人');
return;
}
// 这里可以添加任命逻辑
alert(`成功任命${officialsManager.selectedCandidate.name}为${officialsManager.selectedPosition.name}`);
closeAppointmentModal();
}
function showFactionAnalysis() {
alert('派系分析功能开发中...');
}
function conductExamination() {
alert('科举考试功能开发中...');
}
function summonOfficial(officialId) {
const official = officialsManager.officials.find(o => o.id === officialId);
alert(`召见${official.name}商议国事`);
}
function promoteOfficial() {
if (officialsManager.selectedOfficial) {
alert(`${officialsManager.selectedOfficial.name}晋升成功`);
closeOfficialDetailModal();
}
}
function demoteOfficial() {
if (officialsManager.selectedOfficial) {
alert(`${officialsManager.selectedOfficial.name}降职成功`);
closeOfficialDetailModal();
}
}
function dismissOfficial() {
if (officialsManager.selectedOfficial) {
if (confirm(`确定要罢免${officialsManager.selectedOfficial.name}吗?`)) {
alert(`${officialsManager.selectedOfficial.name}已被罢免`);
closeOfficialDetailModal();
}
}
}
// 初始化
let officialsManager;
document.addEventListener('DOMContentLoaded', () => {
officialsManager = new OfficialsManager();
});
</script>
</body>
</html>
五、图片
1、court_scene.png

2、emperor_portrait.png

3、imperial_concubine.png

4、senior_official.png

5、throne_room.png

45

被折叠的 条评论
为什么被折叠?



