Files
ziwei-power/index.html

553 lines
23 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>紫微力量 - 磁场管理</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:-apple-system,BlinkMacSystemFont,"PingFang SC","Microsoft YaHei",sans-serif;background:linear-gradient(135deg,#1a1a2e 0%,#16213e 50%,#0f3460 100%);min-height:100vh;padding:20px}
.container{max-width:800px;margin:0 auto;background:#fff;border-radius:20px;box-shadow:0 20px 60px rgba(0,0,0,.4);overflow:hidden}
.header{background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:#fff;padding:24px 30px 30px;text-align:center}
.header h1{font-size:28px;margin-bottom:6px}
.header .motto{font-size:13px;opacity:.85}
.js-badge{display:inline-block;background:rgba(255,255,255,.2);padding:3px 10px;border-radius:10px;font-size:11px;margin-top:8px}
.tabs{display:flex;border-bottom:2px solid #e0e0e0}
.tab{flex:1;padding:14px;text-align:center;cursor:pointer;background:#f8f9fa;border:none;font-size:15px;color:#666;transition:all .2s}
.tab:hover{background:#eef0ff}
.tab.active{background:#fff;color:#667eea;font-weight:bold;border-bottom:3px solid #667eea}
.tab-content{display:none;padding:20px}
.tab-content.active{display:block}
.date-row{display:flex;gap:10px;align-items:center;flex-wrap:wrap;padding:0 0 16px}
.date-row input[type="date"]{padding:10px 14px;border:2px solid #ddd;border-radius:8px;font-size:14px;flex:1;min-width:140px}
.date-row button{padding:10px 18px;border:none;border-radius:8px;cursor:pointer;font-size:14px;white-space:nowrap;font-weight:500}
.btn-save{background:#667eea;color:#fff}
.btn-save:hover{background:#5568d3}
.btn-save:active{transform:scale(.97)}
.btn-outline{background:#fff;color:#667eea;border:2px solid #667eea!important}
.btn-outline:hover{background:#eef0ff}
/* Section */
.section{margin-bottom:18px;padding:16px;background:#f6f7fb;border-radius:12px}
.section h2{font-size:16px;margin-bottom:10px;color:#333;display:flex;align-items:center;gap:8px}
.section h2 span{font-size:22px}
.section h2 .hint{font-size:11px;color:#999;margin-left:auto;font-weight:normal}
/* 动态条目 */
.item-row{display:flex;gap:8px;align-items:flex-start;margin-bottom:8px}
.item-row .item-num{width:24px;height:24px;border-radius:50%;background:#667eea;color:#fff;font-size:11px;display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-top:10px}
.item-row textarea{flex:1;padding:10px;border:2px solid #e0e0e0;border-radius:8px;font-size:13px;font-family:inherit;resize:vertical;min-height:40px}
.item-row textarea:focus{outline:none;border-color:#667eea}
.item-action{display:flex;flex-direction:column;gap:2px}
.item-action button{width:28px;height:28px;border-radius:6px;border:none;cursor:pointer;font-size:16px;display:flex;align-items:center;justify-content:center;transition:all .15s}
.btn-add{background:#10b981;color:#fff}
.btn-add:hover{background:#059669}
.btn-del{background:#ef4444;color:#fff}
.btn-del:hover{background:#dc2626}
/* Check items */
.check-item{padding:10px 12px;background:#fff;border-radius:8px;border-left:4px solid #667eea;margin-bottom:8px;display:flex;align-items:center;gap:10px}
.check-item label{flex:1;cursor:pointer;font-size:14px;line-height:1.5;display:flex;align-items:center;gap:10px}
.check-item input[type="checkbox"]{width:18px;height:18px;cursor:pointer;accent-color:#667eea;flex-shrink:0}
.check-item .del-btn{width:24px;height:24px;border-radius:6px;border:none;cursor:pointer;font-size:12px;background:#fee2e2;color:#ef4444;flex-shrink:0;display:flex;align-items:center;justify-content:center}
.check-item .del-btn:hover{background:#fca5a5;color:#dc2626}
.add-study-btn{display:flex;align-items:center;gap:6px;padding:8px 14px;border:2px dashed #667eea;border-radius:8px;background:transparent;color:#667eea;cursor:pointer;font-size:13px;margin-top:6px;width:100%;justify-content:center}
.add-study-btn:hover{background:#eef0ff}
.save-btn{display:block;width:100%;padding:14px;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:#fff;border:none;border-radius:12px;font-size:16px;cursor:pointer;margin-top:10px;transition:all .2s;font-weight:500}
.save-btn:hover{opacity:.9}
.save-btn:active{transform:scale(.98)}
/* Toast */
.toast{position:fixed;top:20px;left:50%;transform:translateX(-50%);padding:12px 28px;border-radius:10px;color:#fff;font-size:14px;z-index:9999;font-weight:500;animation:toastIn .3s ease;box-shadow:0 8px 30px rgba(0,0,0,.2)}
.toast.success{background:#10b981}
.toast.error{background:#ef4444}
.toast.info{background:#667eea}
@keyframes toastIn{from{opacity:0;transform:translateX(-50%) translateY(-20px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}
/* Week navigator */
.week-nav{display:flex;align-items:center;gap:10px;justify-content:center;margin-bottom:16px}
.week-nav button{width:36px;height:36px;border-radius:50%;border:2px solid #667eea;background:#fff;color:#667eea;font-size:18px;cursor:pointer;display:flex;align-items:center;justify-content:center}
.week-nav button:hover{background:#667eea;color:#fff}
.week-nav .week-label{font-size:14px;font-weight:500;color:#333;min-width:160px;text-align:center}
/* Score */
.score-box{text-align:center;padding:30px 20px;background:#f6f7fb;border-radius:12px}
.score-bar-wrap{height:8px;background:#e5e7eb;border-radius:4px;margin:16px 0;overflow:hidden}
.score-bar{height:100%;border-radius:4px;background:linear-gradient(90deg,#667eea,#764ba2);transition:width .5s ease}
.score-num{font-size:64px;font-weight:bold;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);-webkit-background-clip:text;-webkit-text-fill-color:transparent}
.score-txt{font-size:16px;color:#666;margin-top:6px}
.score-detail{text-align:left;font-size:13px;margin-top:16px}
.score-detail .day-row{display:flex;align-items:center;gap:10px;padding:6px 0;border-bottom:1px solid #eee;font-size:12px}
.history-item{padding:14px;border-bottom:1px solid #eee}
.history-item .date{font-weight:bold;color:#667eea}
.history-item .note{font-size:12px;color:#888;margin-top:4px;line-height:1.5}
.empty-state{text-align:center;color:#999;padding:40px;font-size:14px}
/* 紧凑标签 */
.tag{display:inline-block;padding:2px 8px;border-radius:6px;font-size:11px;margin-right:4px}
.tag.done{background:#d1fae5;color:#065f46}
.tag.miss{background:#fee2e2;color:#991b1b}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>⚡ 紫微力量</h1>
<p class="motto">立志不摇 · 责善不滥 · 改过不拖 · 勤学不辍</p>
<div class="js-badge" id="js-check">⏳ JS 加载中...</div>
</div>
<div class="tabs">
<button class="tab active" onclick="switchTab('daily',event)">📅 每日打卡</button>
<button class="tab" onclick="switchTab('weekly',event)">📊 每周评分</button>
<button class="tab" onclick="switchTab('history',event)">📜 历史记录</button>
</div>
<!-- ========== 每日打卡 ========== -->
<div id="daily-tab" class="tab-content active">
<div class="date-row">
<input type="date" id="check-date" onchange="loadChecklist()">
<button class="btn-save" onclick="saveChecklist()">💾 保存</button>
</div>
<!-- 早间立志最多3条 -->
<div class="section">
<h2><span>🌅</span> 早间立志 <span class="hint">今日最重要的事最多3条</span></h2>
<div id="morning-items"><!-- 动态生成 --></div>
<button class="add-study-btn" onclick="addMorningItem()" id="add-morning-btn">+ 增加一条</button>
</div>
<!-- 责善·改过最多5条 -->
<div class="section">
<h2><span>⚖️</span> 责善·改过 <span class="hint">今日反思最多5条</span></h2>
<div id="review-items"><!-- 动态生成 --></div>
<button class="add-study-btn" onclick="addReviewItem()" id="add-review-btn">+ 增加一条</button>
</div>
<!-- 勤学打卡:动态增加 -->
<div class="section">
<h2><span>📚</span> 勤学打卡 <span class="hint">可自由增减</span></h2>
<div id="study-items"><!-- 动态生成 --></div>
<button class="add-study-btn" onclick="addStudyItem()" id="add-study-btn">+ 增加项目</button>
</div>
<button class="save-btn" onclick="saveChecklist()">💾 保存今日打卡</button>
</div>
<!-- ========== 每周评分 ========== -->
<div id="weekly-tab" class="tab-content">
<div class="week-nav">
<button onclick="prevWeek()"></button>
<div class="week-label" id="week-label">本周</div>
<button onclick="nextWeek()"></button>
</div>
<button class="btn-outline" style="width:100%;margin-bottom:16px" onclick="goThisWeek()">📍 回到本周</button>
<div class="score-box">
<div class="score-num" id="weekly-score">--</div>
<div class="score-bar-wrap"><div class="score-bar" id="score-bar" style="width:0%"></div></div>
<div class="score-txt" id="score-text">选择一周查看评分</div>
<div class="score-detail" id="weekly-details"></div>
</div>
</div>
<!-- ========== 历史记录 ========== -->
<div id="history-tab" class="tab-content">
<h2 style="font-size:17px;margin-bottom:16px;display:flex;align-items:center;gap:8px">📜 打卡历史</h2>
<div id="history-list"><div class="empty-state">暂无打卡记录</div></div>
</div>
</div>
<script>
'use strict';
document.getElementById('js-check').textContent = '✅ JS 已就绪';
document.getElementById('js-check').style.background = 'rgba(16,185,129,.3)';
var STORAGE_KEY = 'ziwei_power_data';
var WEEK_OFFSET = 0; // 周评分偏移量0=本周,-1=上周1=下周)
// ========== Toast ==========
function showToast(msg, type) {
var t = document.createElement('div');
t.className = 'toast ' + (type || 'info');
t.textContent = msg;
document.body.appendChild(t);
setTimeout(function(){ t.remove(); }, 2500);
}
// ========== 数据 ==========
function getData() {
try { var r = localStorage.getItem(STORAGE_KEY); return r ? JSON.parse(r) : {}; }
catch(e) { return {}; }
}
function saveData(d) {
try { localStorage.setItem(STORAGE_KEY, JSON.stringify(d)); return true; }
catch(e) { return false; }
}
// ========== Tab ==========
function switchTab(tabName, ev) {
var tabs = document.querySelectorAll('.tab');
var contents = document.querySelectorAll('.tab-content');
for (var i = 0; i < tabs.length; i++) tabs[i].classList.remove('active');
for (var j = 0; j < contents.length; j++) contents[j].classList.remove('active');
if (ev && ev.target) ev.target.classList.add('active');
var el = document.getElementById(tabName + '-tab');
if (el) el.classList.add('active');
if (tabName === 'history') loadHistory();
if (tabName === 'weekly') { WEEK_OFFSET = 0; calculateWeeklyScore(); }
}
// ========== 早间立志:动态条目 ==========
var morningCount = 1;
function renderMorningItems(values) {
var container = document.getElementById('morning-items');
var html = '';
values = values || [''];
morningCount = values.length;
for (var i = 0; i < values.length; i++) {
html += '<div class="item-row" id="morning-row-' + i + '">' +
'<div class="item-num">' + (i + 1) + '</div>' +
'<textarea id="morning-' + i + '" placeholder="第' + (i + 1) + '件最重要的事..." rows="1">' + (values[i] || '') + '</textarea>' +
(values.length > 1 ? '<div class="item-action"><button class="btn-del" onclick="removeMorning(' + i + ')">×</button></div>' : '') +
'</div>';
}
container.innerHTML = html;
updateMorningAddBtn();
}
function updateMorningAddBtn() {
var btn = document.getElementById('add-morning-btn');
btn.style.display = morningCount >= 3 ? 'none' : 'flex';
}
function addMorningItem() {
if (morningCount >= 3) return;
var vals = [];
for (var i = 0; i < morningCount; i++) {
var el = document.getElementById('morning-' + i);
vals.push(el ? el.value : '');
}
vals.push('');
renderMorningItems(vals);
}
function removeMorning(idx) {
if (morningCount <= 1) return;
var vals = [];
for (var i = 0; i < morningCount; i++) {
if (i !== idx) {
var el = document.getElementById('morning-' + i);
vals.push(el ? el.value : '');
}
}
renderMorningItems(vals);
}
function getMorningValues() {
var vals = [];
for (var i = 0; i < morningCount; i++) {
var el = document.getElementById('morning-' + i);
if (el) vals.push(el.value);
}
return vals;
}
// ========== 责善·改过:动态条目 ==========
var reviewCount = 1;
function renderReviewItems(mistakes, improvements) {
var container = document.getElementById('review-items');
var html = '';
mistakes = mistakes || [''];
improvements = improvements || [''];
reviewCount = mistakes.length;
for (var i = 0; i < mistakes.length; i++) {
html += '<div class="item-row" id="review-row-' + i + '">' +
'<div class="item-num" style="background:#764ba2">' + (i + 1) + '</div>' +
'<div style="flex:1;display:flex;flex-direction:column;gap:4px">' +
'<textarea id="mistake-' + i + '" placeholder="犯的错/负能量源..." rows="1">' + (mistakes[i] || '') + '</textarea>' +
'<textarea id="improve-' + i + '" placeholder="下次1步改进行动..." rows="1">' + (improvements[i] || '') + '</textarea>' +
'</div>' +
(mistakes.length > 1 ? '<div class="item-action"><button class="btn-del" onclick="removeReview(' + i + ')">×</button></div>' : '') +
'</div>';
}
container.innerHTML = html;
updateReviewAddBtn();
}
function updateReviewAddBtn() {
var btn = document.getElementById('add-review-btn');
btn.style.display = reviewCount >= 5 ? 'none' : 'flex';
}
function addReviewItem() {
if (reviewCount >= 5) return;
var ms = [], ims = [];
for (var i = 0; i < reviewCount; i++) {
var me = document.getElementById('mistake-' + i);
var ie = document.getElementById('improve-' + i);
ms.push(me ? me.value : '');
ims.push(ie ? ie.value : '');
}
ms.push(''); ims.push('');
renderReviewItems(ms, ims);
}
function removeReview(idx) {
if (reviewCount <= 1) return;
var ms = [], ims = [];
for (var i = 0; i < reviewCount; i++) {
if (i !== idx) {
var me = document.getElementById('mistake-' + i);
var ie = document.getElementById('improve-' + i);
ms.push(me ? me.value : '');
ims.push(ie ? ie.value : '');
}
}
renderReviewItems(ms, ims);
}
function getReviewValues() {
var mistakes = [], improvements = [];
for (var i = 0; i < reviewCount; i++) {
var me = document.getElementById('mistake-' + i);
var ie = document.getElementById('improve-' + i);
mistakes.push(me ? me.value : '');
improvements.push(ie ? ie.value : '');
}
return { mistakes: mistakes, improvements: improvements };
}
// ========== 勤学打卡:动态增减 ==========
var studyItems = [];
function renderStudyItems() {
var container = document.getElementById('study-items');
if (studyItems.length === 0) {
container.innerHTML = '<div style="color:#999;font-size:13px;padding:8px">暂无项目,点击下方按钮添加</div>';
return;
}
var html = '';
for (var i = 0; i < studyItems.length; i++) {
html += '<div class="check-item">' +
'<label><input type="checkbox" id="study-' + i + '" ' + (studyItems[i].done ? 'checked' : '') + '>' + studyItems[i].name + '</label>' +
'<button class="del-btn" onclick="removeStudy(' + i + ')">×</button>' +
'</div>';
}
container.innerHTML = html;
}
function addStudyItem() {
var name = prompt('输入勤学项目名称(如:读一篇文献):');
if (!name || !name.trim()) return;
studyItems.push({ name: name.trim(), done: false });
renderStudyItems();
}
function removeStudy(idx) {
studyItems.splice(idx, 1);
renderStudyItems();
}
function getStudyValues() {
var result = [];
for (var i = 0; i < studyItems.length; i++) {
var cb = document.getElementById('study-' + i);
result.push({ name: studyItems[i].name, done: cb ? cb.checked : false });
}
return result;
}
// ========== 加载/保存打卡 ==========
function loadChecklist() {
var dateEl = document.getElementById('check-date');
if (!dateEl || !dateEl.value) return;
var date = dateEl.value;
var all = getData();
var day = all[date] || {};
// 早间立志
var mvals = day.morningItems || [''];
renderMorningItems(mvals);
// 责善·改过
var rvals = day.reviewItems || { mistakes: [''], improvements: [''] };
renderReviewItems(rvals.mistakes || [''], rvals.improvements || ['']);
// 勤学打卡:恢复当天保存的项目列表
if (day.studyItems && day.studyItems.length > 0) {
studyItems = day.studyItems;
} else {
// 默认三项
studyItems = [
{ name: 'AI能力有进步', done: false },
{ name: '管理能力有进步', done: false },
{ name: '知识储备有进步', done: false }
];
}
renderStudyItems();
}
function saveChecklist() {
var dateEl = document.getElementById('check-date');
if (!dateEl || !dateEl.value) { showToast('请先选择日期', 'error'); return; }
var date = dateEl.value;
var all = getData();
all[date] = {
morningItems: getMorningValues(),
reviewItems: getReviewValues(),
studyItems: getStudyValues(),
savedAt: new Date().toISOString()
};
if (saveData(all)) {
showToast('✅ ' + date + ' 打卡保存成功!', 'success');
} else {
showToast('❌ 保存失败', 'error');
}
}
// ========== 每周评分 ==========
function getMonday(date) {
var d = new Date(date);
var day = d.getDay();
var diff = d.getDate() - day + (day === 0 ? -6 : 1);
d.setDate(diff);
return new Date(d);
}
function formatWeekLabel(monday) {
var sun = new Date(monday);
sun.setDate(monday.getDate() + 6);
var m = monday.getMonth() + 1;
var d1 = monday.getDate();
var s = sun.getMonth() + 1;
var d2 = sun.getDate();
return m + '/' + d1 + ' - ' + s + '/' + d2;
}
function prevWeek() { WEEK_OFFSET--; calculateWeeklyScore(); }
function nextWeek() { WEEK_OFFSET++; calculateWeeklyScore(); }
function goThisWeek() { WEEK_OFFSET = 0; calculateWeeklyScore(); }
function calculateWeeklyScore() {
var today = new Date();
var baseMonday = getMonday(today);
baseMonday.setDate(baseMonday.getDate() + WEEK_OFFSET * 7);
var monday = new Date(baseMonday);
var label = formatWeekLabel(monday);
if (WEEK_OFFSET === 0) label = '本周(' + label + '';
else if (WEEK_OFFSET === -1) label = '上周(' + label + '';
document.getElementById('week-label').textContent = label;
var all = getData();
var totalDays = 0;
var totalScore = 0;
var maxScore = 0;
var details = [];
for (var i = 0; i < 7; i++) {
var cur = new Date(monday);
cur.setDate(monday.getDate() + i);
var ds = cur.toISOString().split('T')[0];
var dayData = all[ds];
if (dayData) {
totalDays++;
var dayMax = 0, dayGot = 0;
// 立志得分:填写了的重要事项数 / 总条目数
if (dayData.morningItems && dayData.morningItems.length > 0) {
dayMax += dayData.morningItems.length;
for (var j = 0; j < dayData.morningItems.length; j++) {
if (dayData.morningItems[j] && dayData.morningItems[j].trim()) dayGot++;
}
}
// 改过得分:每条反思都有文字
if (dayData.reviewItems && dayData.reviewItems.mistakes) {
dayMax += dayData.reviewItems.mistakes.length * 2; // 错 + 改进
for (var k = 0; k < dayData.reviewItems.mistakes.length; k++) {
if (dayData.reviewItems.mistakes[k] && dayData.reviewItems.mistakes[k].trim()) dayGot++;
if (dayData.reviewItems.improvements && dayData.reviewItems.improvements[k] && dayData.reviewItems.improvements[k].trim()) dayGot++;
}
}
// 勤学得分
if (dayData.studyItems && dayData.studyItems.length > 0) {
dayMax += dayData.studyItems.length;
for (var m = 0; m < dayData.studyItems.length; m++) {
if (dayData.studyItems[m].done) dayGot++;
}
}
totalScore += dayGot;
maxScore += dayMax;
var dayPct = dayMax > 0 ? Math.round((dayGot / dayMax) * 100) : 0;
var icon = dayPct >= 70 ? '✅' : dayPct >= 40 ? '⚠️' : '❌';
details.push('<div class="day-row">' +
'<span style="color:#667eea;min-width:90px">' + ds + '</span>' +
'<span style="flex:1">' + dayGot + '/' + dayMax + '</span>' +
'<span>' + icon + ' ' + dayPct + '%</span></div>');
}
}
var score = maxScore > 0 ? Math.round((totalScore / maxScore) * 100) : 0;
document.getElementById('weekly-score').textContent = score;
document.getElementById('score-bar').style.width = score + '%';
var txt = '';
if (score >= 90) txt = '🌟 卓越!磁场非常强大';
else if (score >= 70) txt = '💪 良好,继续保持';
else if (score >= 50) txt = '⚠️ 一般,需要加强';
else txt = '❌ 较弱,急需调整';
document.getElementById('score-text').textContent = txt;
document.getElementById('weekly-details').innerHTML = details.length > 0
? '<div style="font-size:12px;color:#999;margin-bottom:8px">每日得分详情:</div>' + details.join('')
: '<div style="text-align:center;color:#999;padding:16px">本周暂无打卡记录</div>';
}
// ========== 历史 ==========
function loadHistory() {
var all = getData();
var dates = Object.keys(all).sort().reverse();
var el = document.getElementById('history-list');
if (dates.length === 0) {
el.innerHTML = '<div class="empty-state">暂无打卡记录</div>';
return;
}
var html = '';
for (var i = 0; i < dates.length; i++) {
var date = dates[i];
var dd = all[date];
var morningCount = dd.morningItems ? dd.morningItems.filter(function(v){return v && v.trim()}).length : 0;
var reviewCount = dd.reviewItems && dd.reviewItems.mistakes ? dd.reviewItems.mistakes.filter(function(v){return v && v.trim()}).length : 0;
var studyDone = dd.studyItems ? dd.studyItems.filter(function(v){return v.done}).length : 0;
var studyTotal = dd.studyItems ? dd.studyItems.length : 0;
html += '<div class="history-item">' +
'<div class="date">' + date + '</div>' +
'<div class="note">' +
(morningCount > 0 ? '<span class="tag done">立志 ' + morningCount + '条</span>' : '<span class="tag miss">未立志</span>') +
(reviewCount > 0 ? '<span class="tag done">改过 ' + reviewCount + '条</span>' : '<span class="tag miss">未改过</span>') +
'<span class="tag ' + (studyDone > 0 ? 'done' : 'miss') + '">勤学 ' + studyDone + '/' + studyTotal + '</span>' +
'</div></div>';
}
el.innerHTML = html;
}
// ========== 初始化 ==========
(function init() {
var today = new Date().toISOString().split('T')[0];
var cd = document.getElementById('check-date');
if (cd) cd.value = today;
// 初始化默认 study items
studyItems = [
{ name: 'AI能力有进步', done: false },
{ name: '管理能力有进步', done: false },
{ name: '知识储备有进步', done: false }
];
loadChecklist();
})();
</script>
</body>
</html>