摸鱼办提醒倒计时
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lunar-javascript/1.6.12/lunar.min.js"></script>
<script src="https://unpkg.com/dayjs@1.8.21/dayjs.min.js"></script>
<script src="https://unpkg.com/dayjs@1.8.21/locale/zh-cn.js"></script>
</head>
<body>
<img id="app" src="" />
<script>
dayjs.locale("zh-cn");
const year = dayjs().year();
const today = dayjs().startOf("day");
const todayText = today.format("YYYY-MM-DD dddd");
const todayDay = dayjs().day();
// icon: '🏮', 图标
// name: '春节', 节日名称
// days: '', 倒计时,
// aFewDaysOff: 放假几天
// compensatoryLeaveDate:调休日期
// year:当前年份
// isoverdue:当前年份是否过了
let template = [
{
icon: "🏮",
name: "元旦节",
days: "",
aFewDaysOff: [],
compensatoryLeaveDate: [],
year: year,
isoverdue: false,
},
{
icon: "🏮",
name: "春节",
days: "",
aFewDaysOff: [],
compensatoryLeaveDate: [],
year: year,
isoverdue: false,
},
{
icon: "🦄",
name: "清明节",
days: "",
aFewDaysOff: [],
compensatoryLeaveDate: [],
year: year,
isoverdue: false,
},
{
icon: "💖",
name: "劳动节",
days: "",
aFewDaysOff: [],
compensatoryLeaveDate: [],
year: year,
isoverdue: false,
},
{
icon: "🐟",
name: "端午节",
days: "",
aFewDaysOff: [],
compensatoryLeaveDate: [],
year: year,
isoverdue: false,
},
{
icon: "🍁",
name: "中秋节",
days: "",
aFewDaysOff: [],
compensatoryLeaveDate: [],
year: year,
isoverdue: false,
},
{
icon: "🏮",
name: "国庆节",
days: "",
aFewDaysOff: [],
compensatoryLeaveDate: [],
year: year,
isoverdue: false,
},
];
// 节日包
getDatalist();
// 获取调休日期
function getDatalist() {
// 获取调休
let holidays = HolidayUtil.getHolidays(year);
getMakeshiftShifts(holidays, year);
setDataIsoverdue();
// console.log(getTtouchTheFish());
generateImages()
}
// 生成图片
function generateImages() {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// 计算设备像素比
ctx.font = '16px Arial';
const maxWidth = canvas.width - 20;
const lineHeight = 15;
const textWidth = calculateTextWidth(ctx, getTtouchTheFish(), maxWidth, lineHeight);
const textHeight = calculateTextHeight(ctx, getTtouchTheFish(), textWidth, lineHeight);
const devicePixelRatio = window.devicePixelRatio || 1;
canvas.width = (textWidth + 20) * devicePixelRatio;
canvas.height = (textHeight + 20) * devicePixelRatio;
canvas.style.width = `${textWidth + 20}px`;
canvas.style.height = `${textHeight + 20}px`;
ctx.scale(devicePixelRatio, devicePixelRatio);
ctx.clearRect(0, 0, canvas.width, canvas.height);
wrapText(ctx, getTtouchTheFish(), 10, 0, textWidth, lineHeight);
let imageData = canvas.toDataURL('image/png');
window.onload = function () {
var app = document.getElementById('app');
app.src = imageData;
}
}
function calculateTextWidth(context, text, maxWidth, lineHeight) {
const lines = text.split('\n');
let maxLineWidth = 0;
lines.forEach(line => {
const words = line.split(' ');
let currentLine = '';
words.forEach(word => {
const testLine = currentLine + word + ' ';
const metrics = context.measureText(testLine);
if (metrics.width > maxWidth) {
maxLineWidth = Math.max(maxLineWidth, context.measureText(currentLine).width);
currentLine = word + ' ';
} else {
currentLine = testLine;
}
});
maxLineWidth = Math.max(maxLineWidth, context.measureText(currentLine).width);
});
return maxLineWidth;
}
function calculateTextHeight(context, text, maxWidth, lineHeight) {
const lines = text.split('\n');
const wrappedLines = [];
lines.forEach(line => {
const words = line.split(' ');
let currentLine = '';
words.forEach(word => {
const testLine = currentLine + word + ' ';
const metrics = context.measureText(testLine);
if (metrics.width > maxWidth) {
wrappedLines.push(currentLine);
currentLine = word + ' ';
} else {
currentLine = testLine;
}
});
wrappedLines.push(currentLine);
});
return wrappedLines.length * lineHeight;
}
function wrapText(context, text, x, y, maxWidth, lineHeight) {
const lines = text.split('\n');
const wrappedLines = [];
lines.forEach(line => {
const words = line.split(' ');
let currentLine = '';
words.forEach(word => {
const testLine = currentLine + word + ' ';
const metrics = context.measureText(testLine);
if (metrics.width > maxWidth) {
wrappedLines.push(currentLine);
currentLine = word + ' ';
} else {
currentLine = testLine;
}
});
wrappedLines.push(currentLine);
});
wrappedLines.forEach((line, index) => {
context.fillText(line, x, y + (index * lineHeight));
});
}
// 渲染数据
function getTtouchTheFish() {
let touchTheFish = `
【摸鱼办】提醒您:\n
🍁今天是${todayText}\n`;
touchTheFish += `\n`;
if(todayDay == 0){
touchTheFish += `🛌休息,明天星期一\n`;
}else{
touchTheFish += `🛌周末(双休)下班就放假\n`;
}
touchTheFish += `\n`;
template.forEach((element) => {
if (!element.isoverdue) {
let ab = '';
if (element.aFewDaysOff.length > 0) {
ab = `${element.icon}距离${element.name}还有${element.days}天(${element.aFewDaysOff.length})\n`;
} else {
ab = `${element.icon}距离${element.name}还有${element.days}天(待定)\n`;
}
const compensatoryLeaveDateLength = element.compensatoryLeaveDate.length;
if (compensatoryLeaveDateLength > 0) {
ab += `😫补班:`;
for (let i = 0; i < compensatoryLeaveDateLength; i++) {
ab += `${element.compensatoryLeaveDate[i].slice(5)}`;
if (i !== element.compensatoryLeaveDate.length - 1) {
ab += ",";
}
}
ab += `\n`;
}
ab += `\n`;
touchTheFish += ab;
}
});
return touchTheFish;
}
// 处理补班和放假
function getMakeshiftShifts(holidays, year) {
let arrFestival = holidays.map((item) => item._p);
template.forEach((itme) => {
arrFestival.forEach((v) => {
if (itme.name === v.name && v.work) {
itme.compensatoryLeaveDate.push(v.day);
} else if (itme.name === v.name && !v.work) {
itme.aFewDaysOff.push(v.day);
itme.days = remainingDays(itme.aFewDaysOff[0], "day");
}
});
});
}
// 处理本年的日期的节日是否过了
function setDataIsoverdue() {
template.forEach((itme) => {
if (hasHolidayPassed(itme.aFewDaysOff[0])) {
itme.isoverdue = true;
if (itme.name == "元旦节") {
// 下一年
const yuandan = remainingDays(`${year + 1}-01-01`, "day"); // 元旦
itme.days = yuandan;
itme.compensatoryLeaveDate = [];
itme.aFewDaysOff = [];
itme.isoverdue = false;
} else if (itme.name == "春节") {
const lunarNewYear = getChineseNewYear(`${year + 1}`); // 春节
let chunjie = remainingDays(
dayjs(lunarNewYear).format("YYYY-MM-DD"),
"day"
);
itme.days = chunjie;
itme.compensatoryLeaveDate = [];
itme.aFewDaysOff = [];
itme.isoverdue = false;
}
} else {
itme.isoverdue = false;
}
});
}
// 判断节日是否过了
function hasHolidayPassed(holidayDate) {
// 获取当前日期
const now = new Date();
// 创建节日日期对象
const holiday = new Date(holidayDate);
// 比较节日日期和当前日期
return now > holiday;
}
// 计算剩余天数
function remainingDays(future, unit, now = new Date()) {
return difference(future, unit, now);
}
// future 未来时间 unit 时间单位
function difference(future, unit, now = new Date()) {
return dayjs(future).diff(dayjs(now), unit);
}
// 获取每年春节
function getChineseNewYear(year) {
// 这是一个简化的示例,仅用于说明。实际的农历算法要复杂得多。
// 例如,可以参考农历的天干地支、月相变化等来计算春节。
const baseYear = 1900; // 这是一个参考年份
const baseLunarNewYear = new Date(baseYear, 0, 31); // 1900年的春节(大致日期)
const daysBetween =
(year - baseYear) * 365 + Math.floor((year - baseYear) / 4);
const lunarNewYear = new Date(
baseLunarNewYear.getTime() + daysBetween * 24 * 60 * 60 * 1000
);
return lunarNewYear;
}
</script>
</body>
</html>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现