求助丨帮我做个教程。
733
2025.12.21
2025.12.21
发布于 浙江

<!DOCTYPE html>

<html lang="zh-CN">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>积分任务管理器(季节变色版)</title>

<script src="https://cdn.jsdelivr.net/npm/chart.js">\

<style>

* {

margin: 0;

padding: 0;

box-sizing: border-box;

font-family: Arial, Helvetica, sans-serif;

}

body {

padding-bottom: 80px;

transition: background-color 0.3s ease;

}

/* 季节颜色变量 - JS 动态切换 */

.winter {

--bg-color: #f0f8ff;

--nav-color: #1e3a8a;

--text-color: #1e3a8a;

--highlight-color: #93c5fd;

--card-shadow: 0 2px 4px rgba(30, 58, 138, 0.1);

--border-color: #dbeafe;

}

.spring {

--bg-color: #f5faf6;

--nav-color: #166534;

--text-color: #166534;

--highlight-color: #4ade80;

--card-shadow: 0 2px 4px rgba(22, 101, 52, 0.1);

--border-color: #dcfce7;

}

.summer {

--bg-color: #fef2f2;

--nav-color: #c026d3;

--text-color: #c026d3;

--highlight-color: #f0abfc;

--card-shadow: 0 2px 4px rgba(192, 38, 211, 0.1);

--border-color: #fce7f3;

}

.autumn {

--bg-color: #f9f2e8;

--nav-color: #8b4513;

--text-color: #8b4513;

--highlight-color: #ffd700;

--card-shadow: 0 2px 4px rgba(139, 69, 19, 0.1);

--border-color: #f0e6d2;

}

/* 通用样式 */

body {

background-color: var(--bg-color);

}

.nav {

display: flex;

justify-content: space-around;

background-color: var(--nav-color);

color: white;

padding: 15px 0;

position: fixed;

bottom: 0;

width: 100%;

z-index: 99;

}

.nav-item {

text-align: center;

cursor: pointer;

}

.nav-item.active {

color: var(--highlight-color);

}

.page {

padding: 20px;

display: none;

}

.page.active {

display: block;

}

.card {

background-color: #fff;

border-radius: 8px;

box-shadow: var(--card-shadow);

padding: 15px;

margin-bottom: 20px;

}

.card-title {

font-size: 18px;

font-weight: bold;

color: var(--text-color);

margin-bottom: 15px;

}

.task-item, .record-item, .reward-item {

display: flex;

justify-content: space-between;

align-items: center;

padding: 10px 0;

border-bottom: 1px solid var(--border-color);

}

.task-item:last-child, .record-item:last-child, .reward-item:last-child {

border-bottom: none;

}

.task-points {

color: var(--text-color);

font-weight: bold;

margin-right: 15px;

}

.complete-btn {

padding: 5px 10px;

background-color: #2ecc71;

color: white;

border: none;

border-radius: 4px;

cursor: pointer;

}

.complete-btn:disabled {

background-color: #ccc;

cursor: not-allowed;

}

.stat-grid {

display: grid;

grid-template-columns: repeat(2, 1fr);

gap: 10px;

margin-bottom: 20px;

}

.stat-item {

text-align: center;

padding: 10px;

background-color: #fff;

border-radius: 8px;

box-shadow: var(--card-shadow);

}

.stat-value {

font-size: 24px;

font-weight: bold;

color: var(--text-color);

margin: 5px 0;

}

.stat-label {

font-size: 14px;

color: #7f8c8d;

}

.form-item {

margin-bottom: 15px;

}

.form-item label {

display: block;

margin-bottom: 5px;

color: var(--text-color);

}

.form-item input {

width: 100%;

padding: 10px;

border: 1px solid var(--border-color);

border-radius: 4px;

}

.submit-btn {

width: 100%;

padding: 12px;

background-color: var(--text-color);

color: white;

border: none;

border-radius: 8px;

cursor: pointer;

}

.exchange-btn {

padding: 5px 10px;

background-color: #e67e22;

color: white;

border: none;

border-radius: 4px;

cursor: pointer;

}

.exchange-remain {

font-size: 12px;

color: #7f8c8d;

margin-top: 5px;

}

.node-item {

padding: 10px;

border-bottom: 1px solid var(--border-color);

}

.node-item:last-child {

border-bottom: none;

}

.node-name {

font-weight: bold;

color: var(--text-color);

}

.node-diff {

color: #e74c3c;

margin-top: 5px;

}

</style>

</head>

<body class="autumn">

<!-- 1. 首页(默认) -->

<div class="page active" id="home-page">

<div class="card">

<div class="card-title">今日任务</div>

<div id="today-task-list">

<div style="text-align: center; padding: 10px; color: #7f8c8d;">暂无自定义任务</div>

</div>

</div>

<div class="stat-grid">

<div class="stat-item">

<div class="stat-label">今日累计积分</div>

<div class="stat-value" id="today-total">0</div>

</div>

<div class="stat-item">

<div class="stat-label">单日平均积分</div>

<div class="stat-value" id="daily-avg">0.000</div>

</div>

<div class="stat-item">

<div class="stat-label">三日累计积分</div>

<div class="stat-value" id="three-day-total">0</div>

</div>

<div class="stat-item">

<div class="stat-label">三日平均积分</div>

<div class="stat-value" id="three-day-avg">0.000</div>

</div>

</div>

<div class="card">

<div class="card-title">今日完成记录</div>

<div id="today-complete-list">

<div style="text-align: center; padding: 10px; color: #7f8c8d;">暂无完成任务</div>

</div>

</div>

</div>

<!-- 2. 添加任务 -->

<div class="page" id="add-task-page">

<div class="card">

<div class="card-title">添加自定义任务</div>

<div class="form-item">

<label for="task-name">任务名称</label>

<input type="text" id="task-name" placeholder="例如:完成作业、做家务">

</div>

<div class="form-item">

<label for="task-point">任务积分</label>

<input type="number" id="task-point" min="1" placeholder="完成任务获得的积分">

</div>

<button class="submit-btn" onclick="addTask()">添加任务</button>

</div>

</div>

<!-- 3. 积分兑换 -->

<div class="page" id="exchange-page">

<div class="card">

<div class="card-title">奖励兑换</div>

<div class="reward-item">

<div>

<div>20分钟游戏时间</div>

<div class="exchange-remain">今日剩余兑换次数:<span id="exchange-count">5</span>/5</div>

</div>

<button class="exchange-btn" onclick="exchangeReward()">兑换(3积分)</button>

</div>

<div class="form-item" style="margin-top: 20px;">

<label for="custom-reward-name">自定义奖励名称</label>

<input type="text" id="custom-reward-name" placeholder="例如:看电视、买零食">

</div>

<div class="form-item">

<label for="custom-reward-point">兑换所需积分</label>

<input type="number" id="custom-reward-point" min="1" placeholder="兑换该奖励需要的积分">

</div>

<button class="submit-btn" onclick="addCustomReward()">添加自定义奖励</button>

</div>

<div class="card" style="margin-top: 20px;">

<div class="card-title">兑换记录</div>

<div id="exchange-record-list">

<div style="text-align: center; padding: 10px; color: #7f8c8d;">暂无兑换记录</div>

</div>

</div>

</div>

<!-- 4. 积分统计与节点 -->

<div class="page" id="stat-page">

<div class="card">

<div class="card-title">积分节点管理</div>

<div class="form-item">

<label for="node-name">节点名称</label>

<input type="text" id="node-name" placeholder="例如:第一周、月考结束">

</div>

<button class="submit-btn" onclick="addNode()">添加节点</button>

</div>

<div class="card" style="margin-top: 20px;">

<div class="card-title">节点积分对比</div>

<div id="node-list">

<div style="text-align: center; padding: 10px; color: #7f8c8d;">暂无积分节点</div>

</div>

</div>

</div>

<!-- 底部导航 -->

<div class="nav">

<div class="nav-item active" onclick="switchPage('home-page')">首页</div>

<div class="nav-item" onclick="switchPage('add-task-page')">添加任务</div>

<div class="nav-item" onclick="switchPage('exchange-page')">积分兑换</div>

<div class="nav-item" onclick="switchPage('stat-page')">积分统计</div>

</div>

<script>

// 季节判断 - 根据当前月份切换类名

function setSeasonTheme() {

const now = new Date();

const month = now.getMonth() + 1; // 月份从1开始

const body = document.body;

body.classList.remove('winter', 'spring', 'summer', 'autumn');

if ([1,2,12].includes(month)) {

body.classList.add('winter');

} else if ([3,4,5].includes(month)) {

body.classList.add('spring');

} else if ([6,7,8].includes(month)) {

body.classList.add('summer');

} else {

body.classList.add('autumn');

}

}

// 数据存储结构

let taskData = JSON.parse(localStorage.getItem('taskData')) || [];

let completeData = JSON.parse(localStorage.getItem('completeData')) || [];

let rewardData = JSON.parse(localStorage.getItem('rewardData')) || [{name: "20分钟游戏时间", point: 3, dailyLimit: 5}];

let exchangeData = JSON.parse(localStorage.getItem('exchangeData')) || [];

let nodeData = JSON.parse(localStorage.getItem('nodeData')) || [];

const today = new Date().toLocaleDateString();

// 页面初始化

window.*** = function() {

setSeasonTheme();

renderTodayTasks();

renderTodayCompletes();

calculateStats();

renderExchangeRecords();

renderNodes();

updateExchangeCount();

}

// 页面切换

function switchPage(pageId) {

document.querySelectorAll('.page').forEach(page => page.classList.remove('active'));

document.querySelectorAll('.nav-item').forEach(item => item.classList.remove('active'));

document.getElementById(pageId).classList.add('active');

event.target.classList.add('active');

}

// 1. 任务管理

function addTask() {

const name = document.getElementById('task-name').value.trim();

const point = parseInt(document.getElementById('task-point').value);

if (!name || isNaN(point) || point < 1) {

alert('请填写有效的任务名称和积分');

return;

}

const task = {id: Date.now(), name, point, createDate: today};

taskData.push(task);

localStorage.setItem('taskData', JSON.stringify(taskData));

document.getElementById('task-name').value = '';

document.getElementById('task-point').value = '';

renderTodayTasks();

alert('任务添加成功');

}

function renderTodayTasks() {

const taskList = document.getElementById('today-task-list');

const todayTasks = taskData.filter(task => task.createDate === today);

if (todayTasks.length === 0) {

taskList.innerHTML = '<div style="text-align: center; padding: 10px; color: #7f8c8d;">暂无自定义任务</div>';

return;

}

let html = '';

todayTasks.forEach(task => {

const isCompleted = completeData.some(c => c.taskId === task.id && c.date === today);

html += `

<div class="task-item">

<div class="task-name">${task.name}</div>

<div class="task-points">${task.point}积分</div>

<button class="complete-btn" ${isCompleted ? 'disabled style="background-color:#ccc"' : ''} onclick="completeTask(${task.id})">

${isCompleted ? '已完成' : '完成'}

</button>

</div>

`;

});

taskList.innerHTML = html;

}

function completeTask(taskId) {

const task = taskData.find(t => t.id === taskId);

if (!task) return;

const complete = {id: Date.now(), taskId, taskName: task.name, point: task.point, date: today};

completeData.push(complete);

localStorage.setItem('completeData', JSON.stringify(completeData));

renderTodayTasks();

renderTodayCompletes();

calculateStats();

alert('任务完成,获得'+task.point+'积分');

}

// 2. 完成记录渲染

function renderTodayCompletes() {

const completeList = document.getElementById('today-complete-list');

const todayCompletes = completeData.filter(c => c.date === today);

if (todayCompletes.length === 0) {

completeList.innerHTML = '<div style="text-align: center; padding: 10px; color: #7f8c8d;">暂无完成任务</div>';

return;

}

let html = '';

todayCompletes.forEach(item => {

html += `

<div class="record-item">

<div>${item.taskName}</div>

<div class="task-points">+${item.point}积分</div>

</div>

`;

});

completeList.innerHTML = html;

}

// 3. 积分统计 - 平均数精确到小数点后三位

function calculateStats() {

// 今日累计

const todayCompletes = completeData.filter(c => c.date === today);

const todayTotal = todayCompletes.reduce((sum, item) => sum + item.point, 0);

document.getElementById('today-total').innerText = todayTotal;

// 所有日期去重

const allDates = [...new Set(completeData.map(c => c.date))];

// 单日平均

const dailyAvg = allDates.length > 0 ? (completeData.reduce((sum, item) => sum + item.point, 0) / allDates.length).toFixed(3) : '0.000';

document.getElementById('daily-avg').innerText = dailyAvg;

// 三日累计 & 三日平均

const sortedDates = [...allDates].sort((a, b) => new Date(b) - new Date(a));

const lastThreeDates = sortedDates.slice(0, 3);

const threeDayTotal = completeData.filter(c => lastThreeDates.includes(c.date)).reduce((sum, item) => sum + item.point, 0);

const threeDayAvg = lastThreeDates.length > 0 ? (threeDayTotal / lastThreeDates.length).toFixed(3) : '0.000';

document.getElementById('three-day-total').innerText = threeDayTotal;

document.getElementById('three-day-avg').innerText = threeDayAvg;

}

// 4. 积分兑换

function updateExchangeCount() {

const todayExchanges = exchangeData.filter(e => e.date === today && e.rewardName === '20分钟游戏时间').length;

const remain = 5 - todayExchanges;

document.getElementById('exchange-count').innerText = remain;

}

function exchangeReward() {

const todayTotal = completeData.filter(c => c.date === today).reduce((sum, item) => sum + item.point, 0);

const todayExchanges = exchangeData.filter(e => e.date === today && e.rewardName === '20分钟游戏时间').length;

if (todayExchanges >= 5) {

alert('今日兑换次数已达上限!');

return;

}

if (todayTotal < 3) {

alert('积分不足!需要3积分兑换20分钟游戏时间');

return;

}

// 扣除积分(模拟)

const exchangeRecord = {

id: Date.now(),

rewardName: '20分钟游戏时间',

costPoint: 3,

date: today

};

exchangeData.push(exchangeRecord);

localStorage.setItem('exchangeData', JSON.stringify(exchangeData));

updateExchangeCount();

renderExchangeRecords();

alert('兑换成功!获得20分钟游戏时间');

}

function addCustomReward() {

const name = document.getElementById('custom-reward-name').value.trim();

const point = parseInt(document.getElementById('custom-reward-point').value);

if (!name || isNaN(point) || point < 1) {

alert('请填写有效的奖励名称和所需积分');

return;

}

rewardData.push({name, point, dailyLimit: 5});

localStorage.setItem('rewardData', JSON.stringify(rewardData));

document.getElementById('custom-reward-name').value = '';

document.getElementById('custom-reward-point').value = '';

alert('自定义奖励添加成功');

}

function renderExchangeRecords() {

const recordList = document.getElementById('exchange-record-list');

if (exchangeData.length === 0) {

recordList.innerHTML = '<div style="text-align: center; padding: 10px; color: #7f8c8d;">暂无兑换记录</div>';

return;

}

let html = '';

exchangeData.forEach(record => {

html += `

<div class="record-item">

<div>${record.date} - ${record.rewardName}</div>

<div class="task-points">-${record.costPoint}积分</div>

</div>

`;

});

recordList.innerHTML = html;

}

// 5. 积分节点管理

function addNode() {

const name = document.getElementById('node-name').value.trim();

if (!name) {

alert('请输入节点名称');

return;

}

const totalPoint = completeData.reduce((sum, item) => sum + item.point, 0);

const node = {

id: Date.now(),

name,

totalPoint,

createDate: today

};

nodeData.push(node);

localStorage.setItem('nodeData', JSON.stringify(nodeData));

document.getElementById('node-name').value = '';

renderNodes();

alert('积分节点添加成功');

}

function renderNodes() {

const nodeList = document.getElementById('node-list');

if (nodeData.length === 0) {

nodeList.innerHTML = '<div style="text-align: center; padding: 10px; color: #7f8c8d;">暂无积分节点</div>';

return;

}

// 按创建时间排序

const sortedNodes = [...nodeData].sort((a, b) => new Date(a.createDate) - new Date(b.createDate));

let html = '';

for (let i = 0; i < sortedNodes.length; i++) {

const node = sortedNodes[i];

let diffHtml = '';

if (i > 0) {

const prevNode = sortedNodes[i-1];

const diff = node.totalPoint - prevNode.totalPoint;

diffHtml = `<div class="node-diff">与上一节点差值:${diff > 0 ? '+' : ''}${diff}积分</div>`;

}

html += `

<div class="node-item">

<div class="node-name">${node.name}(${node.createDate})</div>

<div>累计积分:${node.totalPoint}</div>

${diffHtml}

</div>

`;

}

nodeList.innerHTML = html;

}

</script>

</body>

</html>

评论 (0)