公告增加每次显示模式
This commit is contained in:
@@ -457,6 +457,7 @@ dockge/komodo 等 docker compose UI 也有自动更新功能
|
|||||||
| SITE_BASE | 站点 url | 形如 https://example.com | 空 |
|
| SITE_BASE | 站点 url | 形如 https://example.com | 空 |
|
||||||
| NEXT_PUBLIC_SITE_NAME | 站点名称 | 任意字符串 | MoonTV |
|
| NEXT_PUBLIC_SITE_NAME | 站点名称 | 任意字符串 | MoonTV |
|
||||||
| ANNOUNCEMENT | 站点公告 | 任意字符串 | 本网站仅提供影视信息搜索服务,所有内容均来自第三方网站。本站不存储任何视频资源,不对任何内容的准确性、合法性、完整性负责。 |
|
| ANNOUNCEMENT | 站点公告 | 任意字符串 | 本网站仅提供影视信息搜索服务,所有内容均来自第三方网站。本站不存储任何视频资源,不对任何内容的准确性、合法性、完整性负责。 |
|
||||||
|
| ANNOUNCEMENT_DISPLAY_MODE | 公告显示模式 | once、every | once |
|
||||||
| NEXT_PUBLIC_STORAGE_TYPE | 播放记录/收藏的存储方式 | redis、kvrocks、upstash、d1 | 无默认,必填字段 |
|
| NEXT_PUBLIC_STORAGE_TYPE | 播放记录/收藏的存储方式 | redis、kvrocks、upstash、d1 | 无默认,必填字段 |
|
||||||
| KVROCKS_URL | kvrocks 连接 url | 连接 url | 空 |
|
| KVROCKS_URL | kvrocks 连接 url | 连接 url | 空 |
|
||||||
| REDIS_URL | redis 连接 url | 连接 url | 空 |
|
| REDIS_URL | redis 连接 url | 连接 url | 空 |
|
||||||
|
|||||||
@@ -357,6 +357,7 @@ interface StandaloneSourceScript {
|
|||||||
interface SiteConfig {
|
interface SiteConfig {
|
||||||
SiteName: string;
|
SiteName: string;
|
||||||
Announcement: string;
|
Announcement: string;
|
||||||
|
AnnouncementDisplayMode?: 'once' | 'every';
|
||||||
SearchDownstreamMaxPage: number;
|
SearchDownstreamMaxPage: number;
|
||||||
SiteInterfaceCacheTime: number;
|
SiteInterfaceCacheTime: number;
|
||||||
DoubanProxyType: string;
|
DoubanProxyType: string;
|
||||||
@@ -10150,6 +10151,7 @@ const SiteConfigComponent = ({
|
|||||||
const [siteSettings, setSiteSettings] = useState<SiteConfig>({
|
const [siteSettings, setSiteSettings] = useState<SiteConfig>({
|
||||||
SiteName: '',
|
SiteName: '',
|
||||||
Announcement: '',
|
Announcement: '',
|
||||||
|
AnnouncementDisplayMode: 'once',
|
||||||
SearchDownstreamMaxPage: 1,
|
SearchDownstreamMaxPage: 1,
|
||||||
SiteInterfaceCacheTime: 7200,
|
SiteInterfaceCacheTime: 7200,
|
||||||
DoubanProxyType: 'cmliussss-cdn-tencent',
|
DoubanProxyType: 'cmliussss-cdn-tencent',
|
||||||
@@ -10304,6 +10306,10 @@ const SiteConfigComponent = ({
|
|||||||
config.SiteConfig.MagnetAcgripReverseProxy || '',
|
config.SiteConfig.MagnetAcgripReverseProxy || '',
|
||||||
MagnetNyaaReverseProxy: config.SiteConfig.MagnetNyaaReverseProxy || '',
|
MagnetNyaaReverseProxy: config.SiteConfig.MagnetNyaaReverseProxy || '',
|
||||||
EnableComments: config.SiteConfig.EnableComments || false,
|
EnableComments: config.SiteConfig.EnableComments || false,
|
||||||
|
AnnouncementDisplayMode:
|
||||||
|
config.SiteConfig.AnnouncementDisplayMode === 'every'
|
||||||
|
? 'every'
|
||||||
|
: 'once',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [config]);
|
}, [config]);
|
||||||
@@ -10462,6 +10468,51 @@ const SiteConfigComponent = ({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* 公告显示模式 */}
|
||||||
|
<div>
|
||||||
|
<label className='block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2'>
|
||||||
|
公告显示模式
|
||||||
|
</label>
|
||||||
|
<div className='flex gap-4'>
|
||||||
|
<label className='inline-flex items-center gap-2 cursor-pointer'>
|
||||||
|
<input
|
||||||
|
type='radio'
|
||||||
|
name='announcementDisplayMode'
|
||||||
|
value='once'
|
||||||
|
checked={siteSettings.AnnouncementDisplayMode !== 'every'}
|
||||||
|
onChange={() =>
|
||||||
|
setSiteSettings((prev) => ({
|
||||||
|
...prev,
|
||||||
|
AnnouncementDisplayMode: 'once',
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
className='text-green-600 focus:ring-green-500'
|
||||||
|
/>
|
||||||
|
<span className='text-sm text-gray-700 dark:text-gray-300'>
|
||||||
|
单次显示
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<label className='inline-flex items-center gap-2 cursor-pointer'>
|
||||||
|
<input
|
||||||
|
type='radio'
|
||||||
|
name='announcementDisplayMode'
|
||||||
|
value='every'
|
||||||
|
checked={siteSettings.AnnouncementDisplayMode === 'every'}
|
||||||
|
onChange={() =>
|
||||||
|
setSiteSettings((prev) => ({
|
||||||
|
...prev,
|
||||||
|
AnnouncementDisplayMode: 'every',
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
className='text-green-600 focus:ring-green-500'
|
||||||
|
/>
|
||||||
|
<span className='text-sm text-gray-700 dark:text-gray-300'>
|
||||||
|
每次显示
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* 豆瓣数据源设置 */}
|
{/* 豆瓣数据源设置 */}
|
||||||
<div className='space-y-3'>
|
<div className='space-y-3'>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ export async function POST(request: NextRequest) {
|
|||||||
const {
|
const {
|
||||||
SiteName,
|
SiteName,
|
||||||
Announcement,
|
Announcement,
|
||||||
|
AnnouncementDisplayMode,
|
||||||
SearchDownstreamMaxPage,
|
SearchDownstreamMaxPage,
|
||||||
SiteInterfaceCacheTime,
|
SiteInterfaceCacheTime,
|
||||||
DoubanProxyType,
|
DoubanProxyType,
|
||||||
@@ -85,6 +86,7 @@ export async function POST(request: NextRequest) {
|
|||||||
} = body as {
|
} = body as {
|
||||||
SiteName: string;
|
SiteName: string;
|
||||||
Announcement: string;
|
Announcement: string;
|
||||||
|
AnnouncementDisplayMode?: 'once' | 'every';
|
||||||
SearchDownstreamMaxPage: number;
|
SearchDownstreamMaxPage: number;
|
||||||
SiteInterfaceCacheTime: number;
|
SiteInterfaceCacheTime: number;
|
||||||
DoubanProxyType: string;
|
DoubanProxyType: string;
|
||||||
@@ -142,6 +144,9 @@ export async function POST(request: NextRequest) {
|
|||||||
if (
|
if (
|
||||||
typeof SiteName !== 'string' ||
|
typeof SiteName !== 'string' ||
|
||||||
typeof Announcement !== 'string' ||
|
typeof Announcement !== 'string' ||
|
||||||
|
(AnnouncementDisplayMode !== undefined &&
|
||||||
|
AnnouncementDisplayMode !== 'once' &&
|
||||||
|
AnnouncementDisplayMode !== 'every') ||
|
||||||
typeof SearchDownstreamMaxPage !== 'number' ||
|
typeof SearchDownstreamMaxPage !== 'number' ||
|
||||||
typeof SiteInterfaceCacheTime !== 'number' ||
|
typeof SiteInterfaceCacheTime !== 'number' ||
|
||||||
typeof DoubanProxyType !== 'string' ||
|
typeof DoubanProxyType !== 'string' ||
|
||||||
@@ -238,6 +243,7 @@ export async function POST(request: NextRequest) {
|
|||||||
adminConfig.SiteConfig = {
|
adminConfig.SiteConfig = {
|
||||||
SiteName,
|
SiteName,
|
||||||
Announcement,
|
Announcement,
|
||||||
|
AnnouncementDisplayMode,
|
||||||
SearchDownstreamMaxPage,
|
SearchDownstreamMaxPage,
|
||||||
SiteInterfaceCacheTime,
|
SiteInterfaceCacheTime,
|
||||||
DoubanProxyType,
|
DoubanProxyType,
|
||||||
|
|||||||
@@ -58,6 +58,9 @@ export default async function RootLayout({
|
|||||||
let announcement =
|
let announcement =
|
||||||
process.env.ANNOUNCEMENT ||
|
process.env.ANNOUNCEMENT ||
|
||||||
'本网站仅提供影视信息搜索服务,所有内容均来自第三方网站。本站不存储任何视频资源,不对任何内容的准确性、合法性、完整性负责。';
|
'本网站仅提供影视信息搜索服务,所有内容均来自第三方网站。本站不存储任何视频资源,不对任何内容的准确性、合法性、完整性负责。';
|
||||||
|
// 公告显示模式:从环境变量读取,数据库模式下由管理面板配置覆盖
|
||||||
|
let announcementDisplayMode: 'once' | 'every' =
|
||||||
|
process.env.ANNOUNCEMENT_DISPLAY_MODE === 'every' ? 'every' : 'once';
|
||||||
|
|
||||||
let doubanProxyType =
|
let doubanProxyType =
|
||||||
process.env.NEXT_PUBLIC_DOUBAN_PROXY_TYPE || 'cmliussss-cdn-tencent';
|
process.env.NEXT_PUBLIC_DOUBAN_PROXY_TYPE || 'cmliussss-cdn-tencent';
|
||||||
@@ -136,6 +139,8 @@ export default async function RootLayout({
|
|||||||
const config = await getConfig();
|
const config = await getConfig();
|
||||||
siteName = config.SiteConfig.SiteName;
|
siteName = config.SiteConfig.SiteName;
|
||||||
announcement = config.SiteConfig.Announcement;
|
announcement = config.SiteConfig.Announcement;
|
||||||
|
announcementDisplayMode =
|
||||||
|
config.SiteConfig.AnnouncementDisplayMode === 'every' ? 'every' : 'once';
|
||||||
|
|
||||||
doubanProxyType = config.SiteConfig.DoubanProxyType;
|
doubanProxyType = config.SiteConfig.DoubanProxyType;
|
||||||
doubanProxy = config.SiteConfig.DoubanProxy;
|
doubanProxy = config.SiteConfig.DoubanProxy;
|
||||||
@@ -346,6 +351,7 @@ export default async function RootLayout({
|
|||||||
<SiteProvider
|
<SiteProvider
|
||||||
siteName={siteName}
|
siteName={siteName}
|
||||||
announcement={announcement}
|
announcement={announcement}
|
||||||
|
announcementDisplayMode={announcementDisplayMode}
|
||||||
tmdbApiKey={tmdbApiKey}
|
tmdbApiKey={tmdbApiKey}
|
||||||
>
|
>
|
||||||
<WatchRoomProvider>
|
<WatchRoomProvider>
|
||||||
|
|||||||
+14
-2
@@ -53,7 +53,7 @@ function HomeClient() {
|
|||||||
BangumiCalendarData[]
|
BangumiCalendarData[]
|
||||||
>([]);
|
>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const { announcement } = useSite();
|
const { announcement, announcementDisplayMode } = useSite();
|
||||||
// 首页模块配置状态
|
// 首页模块配置状态
|
||||||
const [homeModules, setHomeModules] = useState<HomeModule[]>([
|
const [homeModules, setHomeModules] = useState<HomeModule[]>([
|
||||||
{ id: 'hotMovies', name: '热门电影', enabled: true, order: 0 },
|
{ id: 'hotMovies', name: '热门电影', enabled: true, order: 0 },
|
||||||
@@ -362,6 +362,17 @@ function HomeClient() {
|
|||||||
// 检查公告弹窗状态
|
// 检查公告弹窗状态
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (typeof window !== 'undefined' && announcement) {
|
if (typeof window !== 'undefined' && announcement) {
|
||||||
|
// 会话级标记:只在首次访问站点时弹出,导航切回首页不重复弹
|
||||||
|
if (sessionStorage.getItem('announcementShown')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 每次显示模式:每次新会话首次访问弹出一次
|
||||||
|
if (announcementDisplayMode === 'every') {
|
||||||
|
setShowAnnouncement(true);
|
||||||
|
sessionStorage.setItem('announcementShown', '1');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 单次显示模式:localStorage 记住已看过的公告文本,换公告则重新弹出
|
||||||
const hasSeenAnnouncement = localStorage.getItem('hasSeenAnnouncement');
|
const hasSeenAnnouncement = localStorage.getItem('hasSeenAnnouncement');
|
||||||
if (hasSeenAnnouncement !== announcement) {
|
if (hasSeenAnnouncement !== announcement) {
|
||||||
setShowAnnouncement(true);
|
setShowAnnouncement(true);
|
||||||
@@ -369,7 +380,8 @@ function HomeClient() {
|
|||||||
setShowAnnouncement(Boolean(!hasSeenAnnouncement && announcement));
|
setShowAnnouncement(Boolean(!hasSeenAnnouncement && announcement));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [announcement]);
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [announcement, announcementDisplayMode]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const CACHE_DURATION = 60 * 60 * 1000; // 1小时
|
const CACHE_DURATION = 60 * 60 * 1000; // 1小时
|
||||||
|
|||||||
@@ -5,12 +5,14 @@ import { createContext, ReactNode, useContext } from 'react';
|
|||||||
const SiteContext = createContext<{
|
const SiteContext = createContext<{
|
||||||
siteName: string;
|
siteName: string;
|
||||||
announcement?: string;
|
announcement?: string;
|
||||||
|
announcementDisplayMode?: 'once' | 'every';
|
||||||
tmdbApiKey?: string;
|
tmdbApiKey?: string;
|
||||||
}>({
|
}>({
|
||||||
// 默认值
|
// 默认值
|
||||||
siteName: 'MoonTVPlus',
|
siteName: 'MoonTVPlus',
|
||||||
announcement:
|
announcement:
|
||||||
'本网站仅提供影视信息搜索服务,所有内容均来自第三方网站。本站不存储任何视频资源,不对任何内容的准确性、合法性、完整性负责。',
|
'本网站仅提供影视信息搜索服务,所有内容均来自第三方网站。本站不存储任何视频资源,不对任何内容的准确性、合法性、完整性负责。',
|
||||||
|
announcementDisplayMode: 'once',
|
||||||
tmdbApiKey: '',
|
tmdbApiKey: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -20,15 +22,19 @@ export function SiteProvider({
|
|||||||
children,
|
children,
|
||||||
siteName,
|
siteName,
|
||||||
announcement,
|
announcement,
|
||||||
|
announcementDisplayMode,
|
||||||
tmdbApiKey,
|
tmdbApiKey,
|
||||||
}: {
|
}: {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
siteName: string;
|
siteName: string;
|
||||||
announcement?: string;
|
announcement?: string;
|
||||||
|
announcementDisplayMode?: 'once' | 'every';
|
||||||
tmdbApiKey?: string;
|
tmdbApiKey?: string;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<SiteContext.Provider value={{ siteName, announcement, tmdbApiKey }}>
|
<SiteContext.Provider
|
||||||
|
value={{ siteName, announcement, announcementDisplayMode, tmdbApiKey }}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</SiteContext.Provider>
|
</SiteContext.Provider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ export interface AdminConfig {
|
|||||||
SiteConfig: {
|
SiteConfig: {
|
||||||
SiteName: string;
|
SiteName: string;
|
||||||
Announcement: string;
|
Announcement: string;
|
||||||
|
// 公告显示模式:once=单次显示(每个用户每条公告仅显示一次,换公告则重新显示);every=每次显示(每次打开首页都显示)
|
||||||
|
AnnouncementDisplayMode?: 'once' | 'every';
|
||||||
SearchDownstreamMaxPage: number;
|
SearchDownstreamMaxPage: number;
|
||||||
SiteInterfaceCacheTime: number;
|
SiteInterfaceCacheTime: number;
|
||||||
DoubanProxyType: string;
|
DoubanProxyType: string;
|
||||||
|
|||||||
@@ -265,6 +265,10 @@ async function getInitConfig(
|
|||||||
Announcement:
|
Announcement:
|
||||||
process.env.ANNOUNCEMENT ||
|
process.env.ANNOUNCEMENT ||
|
||||||
'本网站仅提供影视信息搜索服务,所有内容均来自第三方网站。本站不存储任何视频资源,不对任何内容的准确性、合法性、完整性负责。',
|
'本网站仅提供影视信息搜索服务,所有内容均来自第三方网站。本站不存储任何视频资源,不对任何内容的准确性、合法性、完整性负责。',
|
||||||
|
AnnouncementDisplayMode:
|
||||||
|
process.env.ANNOUNCEMENT_DISPLAY_MODE === 'every'
|
||||||
|
? 'every'
|
||||||
|
: 'once',
|
||||||
SearchDownstreamMaxPage:
|
SearchDownstreamMaxPage:
|
||||||
Number(process.env.NEXT_PUBLIC_SEARCH_MAX_PAGE) || 5,
|
Number(process.env.NEXT_PUBLIC_SEARCH_MAX_PAGE) || 5,
|
||||||
SiteInterfaceCacheTime: cfgFile.cache_time || 7200,
|
SiteInterfaceCacheTime: cfgFile.cache_time || 7200,
|
||||||
@@ -555,6 +559,11 @@ export function configSelfCheck(adminConfig: AdminConfig): AdminConfig {
|
|||||||
if (adminConfig.SiteConfig.EnableComments === undefined) {
|
if (adminConfig.SiteConfig.EnableComments === undefined) {
|
||||||
adminConfig.SiteConfig.EnableComments = false;
|
adminConfig.SiteConfig.EnableComments = false;
|
||||||
}
|
}
|
||||||
|
// 确保公告显示模式存在
|
||||||
|
if (adminConfig.SiteConfig.AnnouncementDisplayMode === undefined) {
|
||||||
|
adminConfig.SiteConfig.AnnouncementDisplayMode =
|
||||||
|
process.env.ANNOUNCEMENT_DISPLAY_MODE === 'every' ? 'every' : 'once';
|
||||||
|
}
|
||||||
if (adminConfig.SiteConfig.EnableRegistration === undefined) {
|
if (adminConfig.SiteConfig.EnableRegistration === undefined) {
|
||||||
adminConfig.SiteConfig.EnableRegistration = false;
|
adminConfig.SiteConfig.EnableRegistration = false;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user