diff --git a/lib/db/getSiteData.js b/lib/db/getSiteData.js index b7229586..66aa1f8d 100755 --- a/lib/db/getSiteData.js +++ b/lib/db/getSiteData.js @@ -1,4 +1,5 @@ import BLOG from '@/blog.config' +import { getOrSetDataWithCache } from '@/lib/cache/cache_manager' import { getAllCategories } from '@/lib/notion/getAllCategories' import getAllPageIds from '@/lib/notion/getAllPageIds' import { getAllTags } from '@/lib/notion/getAllTags' @@ -12,7 +13,6 @@ import { deepClone } from '@/lib/utils' import { idToUuid } from 'notion-utils' import { siteConfig } from '../config' import { extractLangId, extractLangPrefix, getShortId } from '../utils/pageId' -import { getOrSetDataWithCache } from '@/lib/cache/cache_manager' export { getAllTags } from '../notion/getAllTags' export { getPost } from '../notion/getNotionPost' @@ -230,7 +230,7 @@ async function convertNotionToSiteDate(pageId, from, pageRecordMap) { // 文章计数 let postCount = 0 - // 查找所有的Post和Page + // 查找所有的Post和Page const allPages = collectionData.filter(post => { if (post?.type === 'Post' && post.status === 'Published') { postCount++ @@ -344,22 +344,53 @@ function handleDataBeforeReturn(db) { db.allNavPages = cleanPages(db?.allNavPages, db.tagOptions) db.allPages = cleanPages(db.allPages, db.tagOptions) db.latestPosts = cleanPages(db.latestPosts, db.tagOptions) - - const POST_SCHEDULE_PUBLISH = siteConfig('POST_SCHEDULE_PUBLISH', null, db.NOTION_CONFIG) - if(POST_SCHEDULE_PUBLISH){ + + const POST_SCHEDULE_PUBLISH = siteConfig( + 'POST_SCHEDULE_PUBLISH', + null, + db.NOTION_CONFIG + ) + if (POST_SCHEDULE_PUBLISH) { // console.log('[定时发布] 开启检测') - db.allPages?.forEach(p=>{ - // 新特性,判断文章的发布和下架时间,如果不在有效期内则进行下架处理 - const publish = isInRange(p.title, p.date) - if (!publish) { - console.log('[定时发布] 隐藏-->', p.title) - // 隐藏 - p.status = 'Invisible' - } - }) + db.allPages?.forEach(p => { + // 新特性,判断文章的发布和下架时间,如果不在有效期内则进行下架处理 + const publish = isInRange(p.title, p.date) + if (!publish) { + const currentTimestamp = Date.now() + const startTimestamp = getTimestamp( + p.date.start_date, + p.date.start_time, + p.date.time_zone + ) + const endTimestamp = getTimestamp( + p.date.end_date, + p.date.end_time, + p.date.time_zone + ) + console.log( + '[定时发布] 隐藏--> 文章:', + p.title, + '当前时间戳:', + currentTimestamp, + '目标时间戳:', + startTimestamp, + '-', + endTimestamp + ) + console.log( + '[定时发布] 隐藏--> 文章:', + p.title, + '当前时间:', + new Date(), + '目标时间:', + p.date + ) + // 隐藏 + p.status = 'Invisible' + } + }) } - return db } @@ -620,78 +651,125 @@ function getSiteInfo({ collection, block, NOTION_CONFIG }) { /** * 判断文章是否在发布时间内 - * @param {*} param0 - * @returns + * @param {string} title - 文章标题 + * @param {Object} date - 时间范围参数 + * @param {string} date.start_date - 开始日期(格式:YYYY-MM-DD) + * @param {string} date.start_time - 开始时间(可选,格式:HH:mm) + * @param {string} date.end_date - 结束日期(格式:YYYY-MM-DD) + * @param {string} date.end_time - 结束时间(可选,格式:HH:mm) + * @param {string} date.time_zone - 时区(IANA格式,如 "Asia/Shanghai") + * @returns {boolean} 是否在范围内 */ function isInRange(title, date = {}) { - const { start_date, start_time, end_date, end_time, time_zone } = date; - - // 默认使用北京时间 (Asia/Shanghai) - const effectiveTimeZone = time_zone || "Asia/Shanghai"; - - // 辅助函数:根据时区和日期时间字符串创建 Date 对象 - function parseDateTime(date, time, timeZone) { - if (!date) return null; // 如果没有日期,返回 null - const dateTimeString = `${date}T${time || "00:00"}:00`; // 默认时间为 00:00 - // 创建时区正确的 Date 对象 - return new Date( - new Date(dateTimeString).toLocaleString("en-US", { timeZone }) - ); - } - - // 获取当前时间(基于目标时区) - function getCurrentDateTimeInZone(timeZone) { - const now = new Date(); - const localString = now.toLocaleString("en-US", { timeZone }); - return new Date(localString); - } - - // 获取当前时间(转换为目标时区) - const currentDateTimeInZone = getCurrentDateTimeInZone(effectiveTimeZone); - - // 判断开始时间范围 - let startDateTime = null; - if (start_date) { - startDateTime = parseDateTime(start_date, start_time, effectiveTimeZone); - } - - // 判断结束时间范围 - let endDateTime = null; - if (end_date) { - endDateTime = parseDateTime(end_date, end_time || "23:59", effectiveTimeZone); - } - - let isInRange = true; - - // 检查是否在开始时间之后 - if (startDateTime && currentDateTimeInZone < startDateTime) { - isInRange = false; - console.log( - "[定时发布] 未到发布时间:", - title, - "指定时间:", - startDateTime, - "当前时间:", - currentDateTimeInZone - ); - } - - // 检查是否在结束时间之前 - if (endDateTime && currentDateTimeInZone > endDateTime) { - isInRange = false; - console.log( - "[定时发布] 超过下架时间:", - title, - "指定时间:", - endDateTime, - "当前时间:", - currentDateTimeInZone - ); - } - - return isInRange; // 如果都符合条件,返回 true + const { + start_date, + start_time = '00:00', + end_date, + end_time = '23:59', + time_zone = 'Asia/Shanghai' + } = date + + // 获取当前时间的时间戳(基于目标时区) + const currentTimestamp = Date.now() + + // 获取开始和结束时间的时间戳 + const startTimestamp = getTimestamp(start_date, start_time, time_zone) + const endTimestamp = getTimestamp(end_date, end_time, time_zone) + + // 判断是否在范围内 + if (startTimestamp && currentTimestamp < startTimestamp) { + return false } - + + if (endTimestamp && currentTimestamp > endTimestamp) { + return false + } + + return true +} + +/** + * 将指定时区的日期字符串转换为 UTC 时间 + * @param {string} dateStr - 日期字符串,格式为 YYYY-MM-DD HH:mm:ss + * @param {string} timeZone - 时区名称(如 "Asia/Shanghai") + * @returns {Date} - 转换后的 Date 对象(UTC 时间) + */ +function convertToUTC(dateStr, timeZone) { + // 维护一个时区偏移映射(以小时为单位) + const timeZoneOffsets = { + // UTC 基础 + UTC: 0, + 'Etc/GMT': 0, + 'Etc/GMT+0': 0, + + // 亚洲地区 + 'Asia/Shanghai': 8, // 中国 + 'Asia/Tokyo': 9, // 日本 + 'Asia/Seoul': 9, // 韩国 + 'Asia/Kolkata': 5.5, // 印度 + 'Asia/Jakarta': 7, // 印尼 + 'Asia/Singapore': 8, // 新加坡 + 'Asia/Hong_Kong': 8, // 香港 + 'Asia/Bangkok': 7, // 泰国 + + // 欧洲地区 + 'Europe/London': 0, // 英国(GMT) + 'Europe/Paris': 1, // 法国(CET) + 'Europe/Berlin': 1, // 德国 + 'Europe/Moscow': 3, // 俄罗斯 + 'Europe/Amsterdam': 1, // 荷兰 + + // 美洲地区 + 'America/New_York': -5, // 美国东部(EST) + 'America/Chicago': -6, // 美国中部(CST) + 'America/Denver': -7, // 美国山区时间(MST) + 'America/Los_Angeles': -8, // 美国西部(PST) + 'America/Sao_Paulo': -3, // 巴西 + 'America/Argentina/Buenos_Aires': -3, // 阿根廷 + + // 非洲地区 + 'Africa/Johannesburg': 2, // 南非 + 'Africa/Cairo': 2, // 埃及 + 'Africa/Nairobi': 3, // 肯尼亚 + + // 大洋洲地区 + 'Australia/Sydney': 10, // 澳大利亚东部 + 'Australia/Perth': 8, // 澳大利亚西部 + 'Pacific/Auckland': 13, // 新西兰 + 'Pacific/Fiji': 12, // 斐济 + + // 中东地区 + 'Asia/Dubai': 4, // 阿联酋 + 'Asia/Tehran': 3.5, // 伊朗 + 'Asia/Riyadh': 3, // 沙特阿拉伯 + + // 北极与南极 + 'Antarctica/Palmer': -3, // 南极洲帕尔默 + 'Antarctica/McMurdo': 13 // 南极洲麦克默多 + } + + // 获取目标时区的偏移量(以小时为单位) + const offsetHours = timeZoneOffsets[timeZone] + if (offsetHours === undefined) { + throw new Error(`Unsupported time zone: ${timeZone}`) + } + + // 将日期字符串转换为本地时间的 Date 对象 + const localDate = new Date(`${dateStr.replace(' ', 'T')}Z`) + if (isNaN(localDate.getTime())) { + throw new Error(`Invalid date string: ${dateStr}`) + } + + // 计算 UTC 时间的时间戳 + const utcTimestamp = localDate.getTime() - offsetHours * 60 * 60 * 1000 + return new Date(utcTimestamp) +} + +// 辅助函数:生成指定日期时间的时间戳(基于目标时区) +function getTimestamp(date, time, time_zone) { + if (!date) return null + return convertToUTC(`${date} ${time}:00`, time_zone).getTime() +} /** * 获取导航用的精减文章列表 diff --git a/styles/notion.css b/styles/notion.css index ecdb2ab5..d5b89b09 100644 --- a/styles/notion.css +++ b/styles/notion.css @@ -1682,8 +1682,8 @@ code[class*='language-'] { color: inherit; } -svg.notion-page-icon { - /* @apply hidden;*/ +notion-callout svg.notion-page-icon { + @apply hidden; } svg + .notion-page-title-text {