Dev #21

Merged
zhangxiang merged 69 commits from dev into main 2026-08-17 20:29:08 +08:00
12 changed files with 1444 additions and 975 deletions
Showing only changes of commit 9053f69123 - Show all commits
+9 -9
View File
@@ -21,10 +21,10 @@ export default function Error({
<div className="container-wide px-4 py-20"> <div className="container-wide px-4 py-20">
<div className="max-w-2xl mx-auto text-center"> <div className="max-w-2xl mx-auto text-center">
<div className="mb-8"> <div className="mb-8">
<div className="w-24 h-24 bg-[var(--color-brand-primary-bg)] rounded-full flex items-center justify-center mx-auto mb-6"> <div className="w-24 h-24 bg-[var(--color-brand-bg)] rounded-full flex items-center justify-center mx-auto mb-6">
<AlertTriangle className="w-12 h-12 text-[var(--color-brand-primary)]" /> <AlertTriangle className="w-12 h-12 text-[var(--color-brand)]" />
</div> </div>
<div className="w-32 h-1 bg-[var(--color-brand-primary)] mx-auto" /> <div className="w-32 h-1 bg-[var(--color-brand)] mx-auto" />
</div> </div>
<h1 className="text-3xl font-bold text-[var(--color-text-primary)] mb-4"> <h1 className="text-3xl font-bold text-[var(--color-text-primary)] mb-4">
@@ -53,7 +53,7 @@ export default function Error({
<Button <Button
size="lg" size="lg"
onClick={reset} onClick={reset}
className="bg-[var(--color-brand-primary)] hover:bg-[var(--color-brand-primary-hover)] text-white" className="bg-[var(--color-brand)] hover:bg-[var(--color-brand-hover)] text-white"
> >
<RefreshCw className="w-5 h-5 mr-2" /> <RefreshCw className="w-5 h-5 mr-2" />
重试 重试
@@ -81,8 +81,8 @@ export default function Error({
href="/contact" href="/contact"
className="flex items-center p-4 bg-[var(--color-bg-primary)] rounded-lg hover:shadow-md transition-shadow group" className="flex items-center p-4 bg-[var(--color-bg-primary)] rounded-lg hover:shadow-md transition-shadow group"
> >
<div className="w-10 h-10 bg-[var(--color-brand-primary-bg)] rounded-lg flex items-center justify-center mr-4 group-hover:bg-[var(--color-challenge-isolation-hover)] transition-colors"> <div className="w-10 h-10 bg-[var(--color-brand-bg)] rounded-lg flex items-center justify-center mr-4 group-hover:bg-[var(--color-challenge-isolation-hover)] transition-colors">
<AlertTriangle className="w-5 h-5 text-[var(--color-brand-primary)]" /> <AlertTriangle className="w-5 h-5 text-[var(--color-brand)]" />
</div> </div>
<div className="text-left"> <div className="text-left">
<div className="font-semibold text-[var(--color-text-primary)]">联系我们</div> <div className="font-semibold text-[var(--color-text-primary)]">联系我们</div>
@@ -94,8 +94,8 @@ export default function Error({
href="/services" href="/services"
className="flex items-center p-4 bg-[var(--color-bg-primary)] rounded-lg hover:shadow-md transition-shadow group" className="flex items-center p-4 bg-[var(--color-bg-primary)] rounded-lg hover:shadow-md transition-shadow group"
> >
<div className="w-10 h-10 bg-[var(--color-brand-primary-bg)] rounded-lg flex items-center justify-center mr-4 group-hover:bg-[var(--color-challenge-isolation-hover)] transition-colors"> <div className="w-10 h-10 bg-[var(--color-brand-bg)] rounded-lg flex items-center justify-center mr-4 group-hover:bg-[var(--color-challenge-isolation-hover)] transition-colors">
<RefreshCw className="w-5 h-5 text-[var(--color-brand-primary)]" /> <RefreshCw className="w-5 h-5 text-[var(--color-brand)]" />
</div> </div>
<div className="text-left"> <div className="text-left">
<div className="font-semibold text-[var(--color-text-primary)]">服务</div> <div className="font-semibold text-[var(--color-text-primary)]">服务</div>
@@ -107,7 +107,7 @@ export default function Error({
<div className="mt-8 text-sm text-[var(--color-text-placeholder)]"> <div className="mt-8 text-sm text-[var(--color-text-placeholder)]">
如果问题持续存在,请{' '} 如果问题持续存在,请{' '}
<StaticLink href="/contact" className="text-[var(--color-brand-primary)] hover:underline"> <StaticLink href="/contact" className="text-[var(--color-brand)] hover:underline">
联系我们的技术团队 联系我们的技术团队
</StaticLink> </StaticLink>
</div> </div>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

+801 -512
View File
File diff suppressed because it is too large Load Diff
+41 -54
View File
@@ -1,9 +1,6 @@
import type { Metadata, Viewport } from "next"; import type { Metadata, Viewport } from "next";
import localFont from "next/font/local";
import { Ma_Shan_Zheng, Noto_Sans_SC } from "next/font/google";
import "./globals.css"; import "./globals.css";
import { Suspense } from "react"; import { Suspense } from "react";
import { ThemeProvider } from "@/contexts/theme-context";
import { GoogleAnalyticsWrapper } from "@/components/analytics/GoogleAnalyticsWrapper"; import { GoogleAnalyticsWrapper } from "@/components/analytics/GoogleAnalyticsWrapper";
import { GlobalErrorTracker } from "@/components/analytics/GlobalErrorTracker"; import { GlobalErrorTracker } from "@/components/analytics/GlobalErrorTracker";
import { CookieConsent } from "@/components/analytics/CookieConsent"; import { CookieConsent } from "@/components/analytics/CookieConsent";
@@ -16,42 +13,8 @@ import { ErrorBoundary } from "@/components/ui/error-boundary";
import { ScrollProgress } from "@/components/ui/scroll-progress"; import { ScrollProgress } from "@/components/ui/scroll-progress";
import { BackToTop } from "@/components/ui/back-to-top"; import { BackToTop } from "@/components/ui/back-to-top";
import { ClientLayout } from "@/components/layout/client-layout"; import { ClientLayout } from "@/components/layout/client-layout";
import { getPublishedItems } from "@/lib/cms/data-server";
const geistSans = localFont({ import { SiteConfigProvider, type SiteConfig, type NavigationItem, type MegaDropdownGroup } from "@/lib/site-config";
src: "./fonts/geist-sans.woff2",
variable: "--font-geist-sans",
display: "swap",
preload: false,
});
const geistMono = localFont({
src: "./fonts/geist-mono.woff2",
variable: "--font-geist-mono",
display: "swap",
preload: false,
});
const aoyagiReisho = localFont({
src: "./fonts/AoyagiReisho-subset.ttf",
variable: "--font-aoyagi-reisho",
display: "swap",
preload: true,
});
const maShanZheng = Ma_Shan_Zheng({
weight: "400",
variable: "--font-ma-shan-zheng",
display: "swap",
preload: false,
});
const notoSansSC = Noto_Sans_SC({
weight: ["400", "500", "700"],
variable: "--font-noto-sans-sc",
display: "swap",
subsets: ["latin"],
preload: false,
});
export const metadata: Metadata = { export const metadata: Metadata = {
metadataBase: new URL("https://www.novalon.cn"), metadataBase: new URL("https://www.novalon.cn"),
@@ -109,25 +72,42 @@ export const viewport: Viewport = {
width: "device-width", width: "device-width",
initialScale: 1, initialScale: 1,
maximumScale: 5, maximumScale: 5,
themeColor: [ themeColor: "#FFFFFF",
{ media: "(prefers-color-scheme: light)", color: "#FFFFFF" },
{ media: "(prefers-color-scheme: dark)", color: "#0A0A0A" },
],
}; };
export default function RootLayout({ export default async function RootLayout({
children, children,
}: Readonly<{ }: Readonly<{
children: React.ReactNode; children: React.ReactNode;
}>) { }>) {
// Fetch site configuration and navigation from CMS
const [navItems, configItems] = await Promise.all([
getPublishedItems('navigation').catch(() => []),
getPublishedItems('site-config').catch(() => []),
]);
const navData = navItems[0]?.data as Record<string, unknown> | undefined;
const configData = configItems[0]?.data as Record<string, unknown> | undefined;
const siteConfig: SiteConfig = {
name: (configData?.name as string) || '',
shortName: (configData?.shortName as string) || '',
displayName: (configData?.displayName as string) || '',
slogan: (configData?.slogan as string) || '',
description: (configData?.description as string) || '',
founded: (configData?.founded as string) || '',
location: (configData?.location as string) || '',
email: (configData?.email as string) || '',
address: (configData?.address as string) || '',
icp: (configData?.icp as string) || '',
police: (configData?.police as string) || '',
mainNav: (navData?.mainNav as NavigationItem[]) || [],
megaDropdown: (navData?.megaDropdown as Record<string, MegaDropdownGroup[]>) || {},
};
return ( return (
<html lang="zh-CN" className="scroll-smooth" suppressHydrationWarning> <html lang="zh-CN" className="scroll-smooth" suppressHydrationWarning>
<head> <head>
<script
dangerouslySetInnerHTML={{
__html: `(function(){try{var t=localStorage.getItem('novalon-theme');if(t==='dark'||(t==='system'||!t)&&window.matchMedia('(prefers-color-scheme:dark)').matches){document.documentElement.setAttribute('data-theme','dark')}}catch(e){}})()`,
}}
/>
<link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" /> <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" /> <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
@@ -142,21 +122,28 @@ export default function RootLayout({
<LocalBusinessSchema /> <LocalBusinessSchema />
</head> </head>
<body <body
className={`${geistSans.variable} ${geistMono.variable} ${aoyagiReisho.variable} ${maShanZheng.variable} ${notoSansSC.variable} font-sans antialiased`} className="font-sans antialiased"
> >
<a
href="#main-content"
data-skip-to-content="true"
className="absolute left-[-9999px] top-0 z-50 px-4 py-2 bg-brand text-white rounded-br-lg shadow-lg focus:left-0 focus:outline-none"
>
跳转到主要内容
</a>
<ScrollProgress /> <ScrollProgress />
<GoogleAnalyticsWrapper /> <GoogleAnalyticsWrapper />
<GlobalErrorTracker /> <GlobalErrorTracker />
<PerformanceTracker /> <PerformanceTracker />
<OutboundLinkTracker /> <OutboundLinkTracker />
<ScrollDepthTracker /> <ScrollDepthTracker />
<ThemeProvider> <ErrorBoundary>
<ErrorBoundary> <SiteConfigProvider config={siteConfig}>
<ClientLayout> <ClientLayout>
{children} {children}
</ClientLayout> </ClientLayout>
</ErrorBoundary> </SiteConfigProvider>
</ThemeProvider> </ErrorBoundary>
<Suspense fallback={null}> <Suspense fallback={null}>
<MobileTabBar /> <MobileTabBar />
</Suspense> </Suspense>
+14 -9
View File
@@ -1,16 +1,21 @@
'use client'; 'use client';
import { useEffect } from 'react';
import { StaticLink } from '@/components/ui/static-link'; import { StaticLink } from '@/components/ui/static-link';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Home, ArrowLeft, Search } from 'lucide-react'; import { Home, ArrowLeft, Search } from 'lucide-react';
export default function NotFound() { export default function NotFound() {
useEffect(() => {
document.title = '页面未找到 - 睿新致远';
}, []);
return ( return (
<div className="min-h-screen bg-[var(--color-bg-primary)] flex items-center justify-center"> <div className="min-h-screen bg-[var(--color-bg-primary)] flex items-center justify-center">
<div className="container-wide px-4 py-20"> <div className="container-wide px-4 py-20">
<div className="max-w-xl mx-auto text-center"> <div className="max-w-xl mx-auto text-center">
<div className="mb-8"> <div className="mb-8">
<h1 className="text-8xl sm:text-[120px] font-bold text-[var(--color-brand-primary)] leading-none mb-4 opacity-20"> <h1 className="text-8xl sm:text-[120px] font-bold text-[var(--color-brand)] leading-none mb-4 opacity-20">
404 404
</h1> </h1>
</div> </div>
@@ -54,8 +59,8 @@ export default function NotFound() {
href="/products" href="/products"
className="flex flex-col items-center p-4 bg-[var(--color-bg-primary)] rounded-lg hover:shadow-md transition-shadow group" className="flex flex-col items-center p-4 bg-[var(--color-bg-primary)] rounded-lg hover:shadow-md transition-shadow group"
> >
<div className="w-9 h-9 bg-[var(--color-brand-primary-bg)] rounded-lg flex items-center justify-center mb-2 group-hover:bg-[var(--color-challenge-isolation-hover)] transition-colors"> <div className="w-9 h-9 bg-[var(--color-brand-bg)] rounded-lg flex items-center justify-center mb-2 group-hover:bg-[var(--color-challenge-isolation-hover)] transition-colors">
<Search className="w-4 h-4 text-[var(--color-brand-primary)]" /> <Search className="w-4 h-4 text-[var(--color-brand)]" />
</div> </div>
<span className="font-medium text-sm text-[var(--color-text-primary)]">产品</span> <span className="font-medium text-sm text-[var(--color-text-primary)]">产品</span>
</StaticLink> </StaticLink>
@@ -64,8 +69,8 @@ export default function NotFound() {
href="/solutions" href="/solutions"
className="flex flex-col items-center p-4 bg-[var(--color-bg-primary)] rounded-lg hover:shadow-md transition-shadow group" className="flex flex-col items-center p-4 bg-[var(--color-bg-primary)] rounded-lg hover:shadow-md transition-shadow group"
> >
<div className="w-9 h-9 bg-[var(--color-brand-primary-bg)] rounded-lg flex items-center justify-center mb-2 group-hover:bg-[var(--color-challenge-isolation-hover)] transition-colors"> <div className="w-9 h-9 bg-[var(--color-brand-bg)] rounded-lg flex items-center justify-center mb-2 group-hover:bg-[var(--color-challenge-isolation-hover)] transition-colors">
<Search className="w-4 h-4 text-[var(--color-brand-primary)]" /> <Search className="w-4 h-4 text-[var(--color-brand)]" />
</div> </div>
<span className="font-medium text-sm text-[var(--color-text-primary)]">解决方案</span> <span className="font-medium text-sm text-[var(--color-text-primary)]">解决方案</span>
</StaticLink> </StaticLink>
@@ -74,8 +79,8 @@ export default function NotFound() {
href="/about" href="/about"
className="flex flex-col items-center p-4 bg-[var(--color-bg-primary)] rounded-lg hover:shadow-md transition-shadow group" className="flex flex-col items-center p-4 bg-[var(--color-bg-primary)] rounded-lg hover:shadow-md transition-shadow group"
> >
<div className="w-9 h-9 bg-[var(--color-brand-primary-bg)] rounded-lg flex items-center justify-center mb-2 group-hover:bg-[var(--color-challenge-isolation-hover)] transition-colors"> <div className="w-9 h-9 bg-[var(--color-brand-bg)] rounded-lg flex items-center justify-center mb-2 group-hover:bg-[var(--color-challenge-isolation-hover)] transition-colors">
<Search className="w-4 h-4 text-[var(--color-brand-primary)]" /> <Search className="w-4 h-4 text-[var(--color-brand)]" />
</div> </div>
<span className="font-medium text-sm text-[var(--color-text-primary)]">关于我们</span> <span className="font-medium text-sm text-[var(--color-text-primary)]">关于我们</span>
</StaticLink> </StaticLink>
@@ -84,8 +89,8 @@ export default function NotFound() {
href="/contact" href="/contact"
className="flex flex-col items-center p-4 bg-[var(--color-bg-primary)] rounded-lg hover:shadow-md transition-shadow group" className="flex flex-col items-center p-4 bg-[var(--color-bg-primary)] rounded-lg hover:shadow-md transition-shadow group"
> >
<div className="w-9 h-9 bg-[var(--color-brand-primary-bg)] rounded-lg flex items-center justify-center mb-2 group-hover:bg-[var(--color-challenge-isolation-hover)] transition-colors"> <div className="w-9 h-9 bg-[var(--color-brand-bg)] rounded-lg flex items-center justify-center mb-2 group-hover:bg-[var(--color-challenge-isolation-hover)] transition-colors">
<Search className="w-4 h-4 text-[var(--color-brand-primary)]" /> <Search className="w-4 h-4 text-[var(--color-brand)]" />
</div> </div>
<span className="font-medium text-sm text-[var(--color-text-primary)]">联系我们</span> <span className="font-medium text-sm text-[var(--color-text-primary)]">联系我们</span>
</StaticLink> </StaticLink>
+15 -10
View File
@@ -8,35 +8,40 @@ describe('PrivacyPolicyPage', () => {
}); });
describe('Rendering', () => { describe('Rendering', () => {
it('should render privacy policy page', () => { it('should render privacy policy page', async () => {
render(<PrivacyPolicyPage />); const page = await PrivacyPolicyPage();
render(page);
const container = screen.getByText('隐私政策').closest('div'); const container = screen.getByText('隐私政策').closest('div');
expect(container).toBeInTheDocument(); expect(container).toBeInTheDocument();
}); });
it('should render page title', () => { it('should render page title', async () => {
render(<PrivacyPolicyPage />); const page = await PrivacyPolicyPage();
render(page);
const title = screen.getByRole('heading', { level: 1 }); const title = screen.getByRole('heading', { level: 1 });
expect(title).toBeInTheDocument(); expect(title).toBeInTheDocument();
expect(title).toHaveTextContent('隐私政策'); expect(title).toHaveTextContent('隐私政策');
}); });
it('should render introduction section', () => { it('should render introduction section', async () => {
render(<PrivacyPolicyPage />); const page = await PrivacyPolicyPage();
render(page);
const intro = screen.getByText('引言'); const intro = screen.getByText('引言');
expect(intro).toBeInTheDocument(); expect(intro).toBeInTheDocument();
}); });
it('should render information collection section', () => { it('should render information collection section', async () => {
render(<PrivacyPolicyPage />); const page = await PrivacyPolicyPage();
render(page);
const section = screen.getByText(/我们如何收集和使用您的个人信息/i); const section = screen.getByText(/我们如何收集和使用您的个人信息/i);
expect(section).toBeInTheDocument(); expect(section).toBeInTheDocument();
}); });
}); });
describe('Accessibility', () => { describe('Accessibility', () => {
it('should have proper heading hierarchy', () => { it('should have proper heading hierarchy', async () => {
render(<PrivacyPolicyPage />); const page = await PrivacyPolicyPage();
render(page);
const h1 = screen.getByRole('heading', { level: 1 }); const h1 = screen.getByRole('heading', { level: 1 });
expect(h1).toBeInTheDocument(); expect(h1).toBeInTheDocument();
+238 -212
View File
@@ -1,4 +1,5 @@
import { Metadata } from 'next'; import { Metadata } from 'next';
import { getPublishedItems } from '@/lib/cms/data-server';
import { COMPANY_INFO } from '@/lib/constants'; import { COMPANY_INFO } from '@/lib/constants';
export const metadata: Metadata = { export const metadata: Metadata = {
@@ -6,10 +7,237 @@ export const metadata: Metadata = {
description: `${COMPANY_INFO.name}隐私政策`, description: `${COMPANY_INFO.name}隐私政策`,
}; };
export default function PrivacyPolicyPage() { function PrivacyContent() {
return (
<div className="prose prose-lg max-w-none">
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">引言</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
四川睿新致远科技有限公司(以下简称&ldquo;我们&rdquo;、&ldquo;公司&rdquo;)深知个人信息对您的重要性,并会尽全力保护您的个人信息安全可靠。我们致力于维持您对我们的信任,恪守以下原则,保护您的个人信息:权责一致原则、目的明确原则、选择同意原则、最少够用原则、确保安全原则、主体参与原则、公开透明原则等。
</p>
<p className="text-[var(--color-text-muted)] leading-relaxed">
本隐私政策适用于您通过四川睿新致远科技有限公司官方网站、移动应用、产品服务等渠道访问和使用我们的产品和服务时,我们收集和使用您的个人信息的情形。
</p>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">一、我们如何收集和使用您的个人信息</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
我们会遵循正当、合法、必要的原则,仅为实现产品功能,向您提供服务之目的,收集和使用您的个人信息。
</p>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">1.1 我们收集的个人信息</h3>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-2 mb-4">
<li>账户信息:当您注册账户时,我们可能收集您的姓名、电子邮箱地址、手机号码、公司名称等。</li>
<li>联系信息:当您通过联系表单或客服与我们沟通时,我们可能收集您的姓名、电子邮箱地址、手机号码、留言内容等。</li>
<li>使用信息:我们可能收集您使用我们产品和服务的信息,包括访问时间、浏览记录、操作日志等。</li>
<li>设备信息:我们可能收集您使用的设备信息,包括设备型号、操作系统、浏览器类型等。</li>
</ul>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">1.2 我们如何使用您的个人信息</h3>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-2">
<li>提供产品和服务:向您提供我们的产品和服务,处理您的请求和订单。</li>
<li>客户服务:与您联系,提供客户支持,回复您的咨询和反馈。</li>
<li>改进产品和服务:分析使用情况,改进我们的产品和服务质量。</li>
<li>安全保障:检测、预防和处理安全事件,保护您和我们的合法权益。</li>
<li>法律合规:遵守法律法规要求,履行法律义务。</li>
</ul>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">二、我们如何共享、转让、公开披露您的个人信息</h2>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">2.1 共享</h3>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
我们不会向其他任何公司、组织和个人分享您的个人信息,但以下情况除外:
</p>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-2 mb-4">
<li>在获取明确同意的情况下分享:获得您的明确同意后,我们会与其他方共享您的个人信息。</li>
<li>根据法律法规、法律程序、强制性的行政或司法要求所必须的情况进行提供。</li>
<li>在涉及合并、收购或破产清算时,如涉及到个人信息转让,我们会要求新的持有您个人信息的公司、组织继续受本隐私政策的约束。</li>
</ul>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">2.2 转让</h3>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
我们不会将您的个人信息转让给任何公司、组织和个人,但以下情况除外:
</p>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-2 mb-4">
<li>在获取明确同意的情况下转让。</li>
<li>根据适用的法律法规、法律程序、强制性的行政或司法要求所必须的情况进行提供。</li>
<li>在涉及合并、收购或破产清算时,如涉及到个人信息转让,我们会要求新的持有您个人信息的公司、组织继续受本隐私政策的约束。</li>
</ul>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">2.3 公开披露</h3>
<p className="text-[var(--color-text-muted)] leading-relaxed">
我们仅会在以下情况下,公开披露您的个人信息:
</p>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-2">
<li>获得您的明确同意。</li>
<li>基于法律法规或法律程序的要求。</li>
<li>在涉及合并、收购或破产清算时。</li>
<li>为保护我们或他人的合法权益免受损害。</li>
</ul>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">三、我们如何保护您的个人信息</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
我们已使用符合业界标准的安全防护措施保护您提供的个人信息,防止数据遭到未经授权访问、公开披露、使用、修改、损坏或丢失。我们会采取一切合理可行的措施,保护您的个人信息。
</p>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-2">
<li>使用加密技术确保数据传输和存储安全。</li>
<li>限制访问权限,仅授权人员可访问个人信息。</li>
<li>定期进行安全审计和风险评估。</li>
<li>建立数据备份和恢复机制。</li>
<li>制定应急响应预案,及时处理安全事件。</li>
</ul>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">四、您的权利</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
按照中国相关的法律、法规、标准,以及其他国家、地区的通行做法,我们保障您对自己的个人信息行使以下权利:
</p>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-2">
<li>访问您的个人信息。</li>
<li>更正您的个人信息。</li>
<li>删除您的个人信息。</li>
<li>改变您授权同意的范围。</li>
<li>注销您的账户。</li>
<li>获取您的个人信息副本。</li>
</ul>
<p className="text-[var(--color-text-muted)] leading-relaxed mt-4">
如您需要行使上述权利,请通过本隐私政策提供的联系方式与我们联系。
</p>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">五、未成年人保护</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed">
我们非常重视对未成年人个人信息的保护。如果您是18周岁以下的未成年人,在使用我们的产品和服务前,应事先取得您家长或法定监护人的同意。如您是未成年人的监护人,当您对您所监护的未成年人的个人信息处理存在疑问时,请通过本隐私政策提供的联系方式与我们联系。
</p>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">六、隐私政策的更新</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed">
我们可能适时更新本隐私政策的条款,该等更新构成本隐私政策的一部分。如该等更新造成您在本隐私政策下权利的实质减少,我们将在更新生效前通过在主页上显著位置提示或向您发送电子邮件或其他方式通知您,在该种情况下,若您继续使用我们的服务,即表示同意受经修订的本隐私政策的约束。
</p>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">七、Cookie 和网站分析工具</h2>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">7.1 Cookie 使用说明</h3>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
我们使用 Cookie 和类似技术来提供、保护和改进我们的服务。Cookie 是存储在您设备上的小型文本文件,帮助我们识别您的设备、记住您的偏好设置。
</p>
<div className="overflow-x-auto mb-6">
<table className="min-w-full border border-[var(--color-border)] rounded-lg">
<thead className="bg-[var(--color-bg-tertiary)]">
<tr>
<th className="px-4 py-3 text-left text-sm font-semibold text-[var(--color-text-primary)] border-b border-[var(--color-border)]">Cookie 类型</th>
<th className="px-4 py-3 text-left text-sm font-semibold text-[var(--color-text-primary)] border-b border-[var(--color-border)]">用途</th>
<th className="px-4 py-3 text-left text-sm font-semibold text-[var(--color-text-primary)] border-b border-[var(--color-border)]">持续时间</th>
<th className="px-4 py-3 text-left text-sm font-semibold text-[var(--color-text-primary)] border-b border-[var(--color-border)]">是否必需</th>
</tr>
</thead>
<tbody className="divide-y divide-[var(--color-border)]">
<tr>
<td className="px-4 py-3 text-sm text-[var(--color-text-muted)]">必要 Cookie</td>
<td className="px-4 py-3 text-sm text-[var(--color-text-muted)]">网站基本功能运行</td>
<td className="px-4 py-3 text-sm text-[var(--color-text-muted)]">会话期间</td>
<td className="px-4 py-3 text-sm text-[var(--color-text-muted)]">是</td>
</tr>
<tr>
<td className="px-4 py-3 text-sm text-[var(--color-text-muted)]">分析 Cookie</td>
<td className="px-4 py-3 text-sm text-[var(--color-text-muted)]">了解网站使用情况,改进服务</td>
<td className="px-4 py-3 text-sm text-[var(--color-text-muted)]">14个月</td>
<td className="px-4 py-3 text-sm text-[var(--color-text-muted)]">否</td>
</tr>
<tr>
<td className="px-4 py-3 text-sm text-[var(--color-text-muted)]">营销 Cookie</td>
<td className="px-4 py-3 text-sm text-[var(--color-text-muted)]">个性化广告(当前未使用)</td>
<td className="px-4 py-3 text-sm text-[var(--color-text-muted)]">-</td>
<td className="px-4 py-3 text-sm text-[var(--color-text-muted)]">否</td>
</tr>
</tbody>
</table>
</div>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">7.2 Google Analytics 使用说明</h3>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
我们使用 Google Analytics 4(由 Google LLC 提供)分析网站使用情况,帮助我们了解访客如何使用网站,从而改进用户体验。
</p>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-2">
<strong>收集的数据包括:</strong>
</p>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-1 mb-4">
<li>访问的页面和停留时间</li>
<li>设备类型、浏览器类型</li>
<li>地理位置(国家/城市级别,IP 地址已匿名化)</li>
<li>访问来源(直接访问、搜索引擎、外部链接)</li>
</ul>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-2">
<strong>我们已采取的保护措施:</strong>
</p>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-1 mb-4">
<li>IP 地址匿名化</li>
<li>数据保留期限设为 14 个月</li>
<li>禁用广告个性化功能</li>
<li>禁用 Google 信号(不进行跨设备追踪)</li>
<li>不与 Google 其他服务共享数据用于广告目的</li>
</ul>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">7.3 您的选择</h3>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-2 mb-4">
<li>您可以在首次访问时选择接受或拒绝分析 Cookie</li>
<li>您可以点击页面右下角的&ldquo;Cookie 设置&rdquo;按钮随时更改偏好</li>
<li>您可以通过浏览器设置删除或阻止 Cookie(可能影响网站功能)</li>
</ul>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">7.4 数据删除请求</h3>
<p className="text-[var(--color-text-muted)] leading-relaxed">
如您希望删除我们持有的您的个人数据,或撤回您的同意,请通过以下方式联系我们:
</p>
<ul className="list-none text-[var(--color-text-muted)] space-y-1 mt-2">
<li>隐私邮箱:privacy@novalon.cn</li>
<li>联系地址:中国四川省成都市龙泉驿区幸福路12号</li>
</ul>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">八、如何联系我们</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
如果您对本隐私政策有任何疑问、意见或建议,或需要行使您的权利,请通过以下方式与我们联系:
</p>
<ul className="list-none text-[var(--color-text-muted)] space-y-2">
<li>公司名称:四川睿新致远科技有限公司</li>
<li>联系邮箱:contact@novalon.cn</li>
<li>隐私邮箱:privacy@novalon.cn</li>
<li>联系地址:中国四川省成都市龙泉驿区幸福路12号</li>
</ul>
</section>
</div>
);
}
export default async function PrivacyPolicyPage() {
let cmsContent: string | null = null;
try {
const items = await getPublishedItems('legal-page');
const privacyItem = items.find((item) => item.data.pageType === 'privacy');
if (privacyItem && typeof privacyItem.data.content === 'string' && privacyItem.data.content.length > 0) {
cmsContent = privacyItem.data.content as string;
}
} catch {
// CMS not available, fall back to inline content
}
return ( return (
<div className="min-h-screen bg-[var(--color-bg-primary)]"> <div className="min-h-screen bg-[var(--color-bg-primary)]">
<div className="bg-gradient-to-br from-[var(--color-brand-primary)] via-[var(--color-brand-primary)]/80 to-[var(--color-hero-dark-end)] py-20"> <div className="bg-gradient-to-br from-[var(--color-brand)] via-[var(--color-brand)]/80 to-[var(--color-hero-dark-end)] py-20">
<div className="container-wide"> <div className="container-wide">
<h1 className="text-4xl md:text-5xl font-bold text-white mb-4"> <h1 className="text-4xl md:text-5xl font-bold text-white mb-4">
隐私政策 隐私政策
@@ -22,216 +250,14 @@ export default function PrivacyPolicyPage() {
<div className="container-wide py-16"> <div className="container-wide py-16">
<div className="max-w-4xl"> <div className="max-w-4xl">
<div className="prose prose-lg max-w-none"> {cmsContent ? (
<section className="mb-12"> <div
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">引言</h2> className="prose prose-lg max-w-none"
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4"> dangerouslySetInnerHTML={{ __html: cmsContent }}
四川睿新致远科技有限公司(以下简称&ldquo;我们&rdquo;、&ldquo;公司&rdquo;)深知个人信息对您的重要性,并会尽全力保护您的个人信息安全可靠。我们致力于维持您对我们的信任,恪守以下原则,保护您的个人信息:权责一致原则、目的明确原则、选择同意原则、最少够用原则、确保安全原则、主体参与原则、公开透明原则等。 />
</p> ) : (
<p className="text-[var(--color-text-muted)] leading-relaxed"> <PrivacyContent />
本隐私政策适用于您通过四川睿新致远科技有限公司官方网站、移动应用、产品服务等渠道访问和使用我们的产品和服务时,我们收集和使用您的个人信息的情形。 )}
</p>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">一、我们如何收集和使用您的个人信息</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
我们会遵循正当、合法、必要的原则,仅为实现产品功能,向您提供服务之目的,收集和使用您的个人信息。
</p>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">1.1 我们收集的个人信息</h3>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-2 mb-4">
<li>账户信息:当您注册账户时,我们可能收集您的姓名、电子邮箱地址、手机号码、公司名称等。</li>
<li>联系信息:当您通过联系表单或客服与我们沟通时,我们可能收集您的姓名、电子邮箱地址、手机号码、留言内容等。</li>
<li>使用信息:我们可能收集您使用我们产品和服务的信息,包括访问时间、浏览记录、操作日志等。</li>
<li>设备信息:我们可能收集您使用的设备信息,包括设备型号、操作系统、浏览器类型等。</li>
</ul>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">1.2 我们如何使用您的个人信息</h3>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-2">
<li>提供产品和服务:向您提供我们的产品和服务,处理您的请求和订单。</li>
<li>客户服务:与您联系,提供客户支持,回复您的咨询和反馈。</li>
<li>改进产品和服务:分析使用情况,改进我们的产品和服务质量。</li>
<li>安全保障:检测、预防和处理安全事件,保护您和我们的合法权益。</li>
<li>法律合规:遵守法律法规要求,履行法律义务。</li>
</ul>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">二、我们如何共享、转让、公开披露您的个人信息</h2>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">2.1 共享</h3>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
我们不会向其他任何公司、组织和个人分享您的个人信息,但以下情况除外:
</p>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-2 mb-4">
<li>在获取明确同意的情况下分享:获得您的明确同意后,我们会与其他方共享您的个人信息。</li>
<li>根据法律法规、法律程序、强制性的行政或司法要求所必须的情况进行提供。</li>
<li>在涉及合并、收购或破产清算时,如涉及到个人信息转让,我们会要求新的持有您个人信息的公司、组织继续受本隐私政策的约束。</li>
</ul>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">2.2 转让</h3>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
我们不会将您的个人信息转让给任何公司、组织和个人,但以下情况除外:
</p>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-2 mb-4">
<li>在获取明确同意的情况下转让。</li>
<li>根据适用的法律法规、法律程序、强制性的行政或司法要求所必须的情况进行提供。</li>
<li>在涉及合并、收购或破产清算时,如涉及到个人信息转让,我们会要求新的持有您个人信息的公司、组织继续受本隐私政策的约束。</li>
</ul>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">2.3 公开披露</h3>
<p className="text-[var(--color-text-muted)] leading-relaxed">
我们仅会在以下情况下,公开披露您的个人信息:
</p>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-2">
<li>获得您的明确同意。</li>
<li>基于法律法规或法律程序的要求。</li>
<li>在涉及合并、收购或破产清算时。</li>
<li>为保护我们或他人的合法权益免受损害。</li>
</ul>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">三、我们如何保护您的个人信息</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
我们已使用符合业界标准的安全防护措施保护您提供的个人信息,防止数据遭到未经授权访问、公开披露、使用、修改、损坏或丢失。我们会采取一切合理可行的措施,保护您的个人信息。
</p>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-2">
<li>使用加密技术确保数据传输和存储安全。</li>
<li>限制访问权限,仅授权人员可访问个人信息。</li>
<li>定期进行安全审计和风险评估。</li>
<li>建立数据备份和恢复机制。</li>
<li>制定应急响应预案,及时处理安全事件。</li>
</ul>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">四、您的权利</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
按照中国相关的法律、法规、标准,以及其他国家、地区的通行做法,我们保障您对自己的个人信息行使以下权利:
</p>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-2">
<li>访问您的个人信息。</li>
<li>更正您的个人信息。</li>
<li>删除您的个人信息。</li>
<li>改变您授权同意的范围。</li>
<li>注销您的账户。</li>
<li>获取您的个人信息副本。</li>
</ul>
<p className="text-[var(--color-text-muted)] leading-relaxed mt-4">
如您需要行使上述权利,请通过本隐私政策提供的联系方式与我们联系。
</p>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">五、未成年人保护</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed">
我们非常重视对未成年人个人信息的保护。如果您是18周岁以下的未成年人,在使用我们的产品和服务前,应事先取得您家长或法定监护人的同意。如您是未成年人的监护人,当您对您所监护的未成年人的个人信息处理存在疑问时,请通过本隐私政策提供的联系方式与我们联系。
</p>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">六、隐私政策的更新</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed">
我们可能适时更新本隐私政策的条款,该等更新构成本隐私政策的一部分。如该等更新造成您在本隐私政策下权利的实质减少,我们将在更新生效前通过在主页上显著位置提示或向您发送电子邮件或其他方式通知您,在该种情况下,若您继续使用我们的服务,即表示同意受经修订的本隐私政策的约束。
</p>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">七、Cookie 和网站分析工具</h2>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">7.1 Cookie 使用说明</h3>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
我们使用 Cookie 和类似技术来提供、保护和改进我们的服务。Cookie 是存储在您设备上的小型文本文件,帮助我们识别您的设备、记住您的偏好设置。
</p>
<div className="overflow-x-auto mb-6">
<table className="min-w-full border border-[var(--color-border)] rounded-lg">
<thead className="bg-[var(--color-bg-tertiary)]">
<tr>
<th className="px-4 py-3 text-left text-sm font-semibold text-[var(--color-text-primary)] border-b border-[var(--color-border)]">Cookie 类型</th>
<th className="px-4 py-3 text-left text-sm font-semibold text-[var(--color-text-primary)] border-b border-[var(--color-border)]">用途</th>
<th className="px-4 py-3 text-left text-sm font-semibold text-[var(--color-text-primary)] border-b border-[var(--color-border)]">持续时间</th>
<th className="px-4 py-3 text-left text-sm font-semibold text-[var(--color-text-primary)] border-b border-[var(--color-border)]">是否必需</th>
</tr>
</thead>
<tbody className="divide-y divide-[var(--color-border)]">
<tr>
<td className="px-4 py-3 text-sm text-[var(--color-text-muted)]">必要 Cookie</td>
<td className="px-4 py-3 text-sm text-[var(--color-text-muted)]">网站基本功能运行</td>
<td className="px-4 py-3 text-sm text-[var(--color-text-muted)]">会话期间</td>
<td className="px-4 py-3 text-sm text-[var(--color-text-muted)]">是</td>
</tr>
<tr>
<td className="px-4 py-3 text-sm text-[var(--color-text-muted)]">分析 Cookie</td>
<td className="px-4 py-3 text-sm text-[var(--color-text-muted)]">了解网站使用情况,改进服务</td>
<td className="px-4 py-3 text-sm text-[var(--color-text-muted)]">14个月</td>
<td className="px-4 py-3 text-sm text-[var(--color-text-muted)]">否</td>
</tr>
<tr>
<td className="px-4 py-3 text-sm text-[var(--color-text-muted)]">营销 Cookie</td>
<td className="px-4 py-3 text-sm text-[var(--color-text-muted)]">个性化广告(当前未使用)</td>
<td className="px-4 py-3 text-sm text-[var(--color-text-muted)]">-</td>
<td className="px-4 py-3 text-sm text-[var(--color-text-muted)]">否</td>
</tr>
</tbody>
</table>
</div>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">7.2 Google Analytics 使用说明</h3>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
我们使用 Google Analytics 4(由 Google LLC 提供)分析网站使用情况,帮助我们了解访客如何使用网站,从而改进用户体验。
</p>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-2">
<strong>收集的数据包括:</strong>
</p>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-1 mb-4">
<li>访问的页面和停留时间</li>
<li>设备类型、浏览器类型</li>
<li>地理位置(国家/城市级别,IP 地址已匿名化)</li>
<li>访问来源(直接访问、搜索引擎、外部链接)</li>
</ul>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-2">
<strong>我们已采取的保护措施:</strong>
</p>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-1 mb-4">
<li>IP 地址匿名化</li>
<li>数据保留期限设为 14 个月</li>
<li>禁用广告个性化功能</li>
<li>禁用 Google 信号(不进行跨设备追踪)</li>
<li>不与 Google 其他服务共享数据用于广告目的</li>
</ul>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">7.3 您的选择</h3>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-2 mb-4">
<li>您可以在首次访问时选择接受或拒绝分析 Cookie</li>
<li>您可以点击页面右下角的&ldquo;Cookie 设置&rdquo;按钮随时更改偏好</li>
<li>您可以通过浏览器设置删除或阻止 Cookie(可能影响网站功能)</li>
</ul>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">7.4 数据删除请求</h3>
<p className="text-[var(--color-text-muted)] leading-relaxed">
如您希望删除我们持有的您的个人数据,或撤回您的同意,请通过以下方式联系我们:
</p>
<ul className="list-none text-[var(--color-text-muted)] space-y-1 mt-2">
<li>隐私邮箱:privacy@novalon.cn</li>
<li>联系地址:中国四川省成都市龙泉驿区幸福路12号</li>
</ul>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">八、如何联系我们</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
如果您对本隐私政策有任何疑问、意见或建议,或需要行使您的权利,请通过以下方式与我们联系:
</p>
<ul className="list-none text-[var(--color-text-muted)] space-y-2">
<li>公司名称:四川睿新致远科技有限公司</li>
<li>联系邮箱:contact@novalon.cn</li>
<li>隐私邮箱:privacy@novalon.cn</li>
<li>联系地址:中国四川省成都市龙泉驿区幸福路12号</li>
</ul>
</section>
</div>
</div> </div>
</div> </div>
</div> </div>
+27
View File
@@ -0,0 +1,27 @@
import type { MetadataRoute } from 'next';
export default function robots(): MetadataRoute.Robots {
return {
rules: [
{
userAgent: '*',
allow: '/',
disallow: [
'/_next/',
'/api/',
'/admin/',
],
},
{
userAgent: 'Googlebot',
allow: '/',
disallow: [
'/_next/',
'/api/',
],
},
],
sitemap: 'https://www.novalon.cn/sitemap.xml',
host: 'https://www.novalon.cn',
};
}
+76
View File
@@ -0,0 +1,76 @@
import type { MetadataRoute } from 'next';
import { getAllPublishedSlugs } from '@/lib/cms/data-server';
const BASE_URL = 'https://www.novalon.cn';
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const staticPages: MetadataRoute.Sitemap = [
{ url: `${BASE_URL}/`, lastModified: new Date(), changeFrequency: 'daily', priority: 1 },
{ url: `${BASE_URL}/about`, lastModified: new Date(), changeFrequency: 'monthly', priority: 0.8 },
{ url: `${BASE_URL}/services`, lastModified: new Date(), changeFrequency: 'weekly', priority: 0.9 },
{ url: `${BASE_URL}/products`, lastModified: new Date(), changeFrequency: 'weekly', priority: 0.9 },
{ url: `${BASE_URL}/solutions`, lastModified: new Date(), changeFrequency: 'weekly', priority: 0.9 },
{ url: `${BASE_URL}/cases`, lastModified: new Date(), changeFrequency: 'weekly', priority: 0.8 },
{ url: `${BASE_URL}/news`, lastModified: new Date(), changeFrequency: 'daily', priority: 0.7 },
{ url: `${BASE_URL}/team`, lastModified: new Date(), changeFrequency: 'monthly', priority: 0.6 },
{ url: `${BASE_URL}/contact`, lastModified: new Date(), changeFrequency: 'monthly', priority: 0.7 },
];
try {
// 从 CMS 获取动态页面 slug
const [caseSlugs, newsSlugs, serviceSlugs, productSlugs, solutionSlugs] = await Promise.all([
getAllPublishedSlugs('case-study'),
getAllPublishedSlugs('news'),
getAllPublishedSlugs('service'),
getAllPublishedSlugs('product'),
getAllPublishedSlugs('solution'),
]);
const casePages: MetadataRoute.Sitemap = caseSlugs.map(({ slug }) => ({
url: `${BASE_URL}/cases/${slug}`,
lastModified: new Date(),
changeFrequency: 'monthly' as const,
priority: 0.8,
}));
const newsPages: MetadataRoute.Sitemap = newsSlugs.map(({ slug }) => ({
url: `${BASE_URL}/news/${slug}`,
lastModified: new Date(),
changeFrequency: 'monthly' as const,
priority: 0.6,
}));
const servicePages: MetadataRoute.Sitemap = serviceSlugs.map(({ slug }) => ({
url: `${BASE_URL}/services/${slug}`,
lastModified: new Date(),
changeFrequency: 'monthly' as const,
priority: 0.8,
}));
const productPages: MetadataRoute.Sitemap = productSlugs.map(({ slug }) => ({
url: `${BASE_URL}/products/${slug}`,
lastModified: new Date(),
changeFrequency: 'monthly' as const,
priority: 0.8,
}));
const solutionPages: MetadataRoute.Sitemap = solutionSlugs.map(({ slug }) => ({
url: `${BASE_URL}/solutions/${slug}`,
lastModified: new Date(),
changeFrequency: 'monthly' as const,
priority: 0.8,
}));
return [
...staticPages,
...casePages,
...newsPages,
...servicePages,
...productPages,
...solutionPages,
];
} catch {
// 数据库不可用时返回静态页面
return staticPages;
}
}
+15 -10
View File
@@ -8,35 +8,40 @@ describe('TermsOfServicePage', () => {
}); });
describe('Rendering', () => { describe('Rendering', () => {
it('should render terms of service page', () => { it('should render terms of service page', async () => {
render(<TermsOfServicePage />); const page = await TermsOfServicePage();
render(page);
const container = screen.getByText('服务条款').closest('div'); const container = screen.getByText('服务条款').closest('div');
expect(container).toBeInTheDocument(); expect(container).toBeInTheDocument();
}); });
it('should render page title', () => { it('should render page title', async () => {
render(<TermsOfServicePage />); const page = await TermsOfServicePage();
render(page);
const title = screen.getByRole('heading', { level: 1 }); const title = screen.getByRole('heading', { level: 1 });
expect(title).toBeInTheDocument(); expect(title).toBeInTheDocument();
expect(title).toHaveTextContent('服务条款'); expect(title).toHaveTextContent('服务条款');
}); });
it('should render introduction section', () => { it('should render introduction section', async () => {
render(<TermsOfServicePage />); const page = await TermsOfServicePage();
render(page);
const intro = screen.getByText('引言'); const intro = screen.getByText('引言');
expect(intro).toBeInTheDocument(); expect(intro).toBeInTheDocument();
}); });
it('should render service content section', () => { it('should render service content section', async () => {
render(<TermsOfServicePage />); const page = await TermsOfServicePage();
render(page);
const sections = screen.getAllByRole('heading', { level: 2 }); const sections = screen.getAllByRole('heading', { level: 2 });
expect(sections.length).toBeGreaterThan(0); expect(sections.length).toBeGreaterThan(0);
}); });
}); });
describe('Accessibility', () => { describe('Accessibility', () => {
it('should have proper heading hierarchy', () => { it('should have proper heading hierarchy', async () => {
render(<TermsOfServicePage />); const page = await TermsOfServicePage();
render(page);
const h1 = screen.getByRole('heading', { level: 1 }); const h1 = screen.getByRole('heading', { level: 1 });
expect(h1).toBeInTheDocument(); expect(h1).toBeInTheDocument();
+183 -157
View File
@@ -1,4 +1,5 @@
import { Metadata } from 'next'; import { Metadata } from 'next';
import { getPublishedItems } from '@/lib/cms/data-server';
import { COMPANY_INFO } from '@/lib/constants'; import { COMPANY_INFO } from '@/lib/constants';
export const metadata: Metadata = { export const metadata: Metadata = {
@@ -6,10 +7,182 @@ export const metadata: Metadata = {
description: `${COMPANY_INFO.name}服务条款`, description: `${COMPANY_INFO.name}服务条款`,
}; };
export default function TermsOfServicePage() { function TermsContent() {
return (
<div className="prose prose-lg max-w-none">
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">引言</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
欢迎使用四川睿新致远科技有限公司(以下简称&ldquo;我们&rdquo;、&ldquo;公司&rdquo;)提供的产品和服务。在使用我们的产品和服务之前,请您仔细阅读并理解本服务条款。如果您不同意本服务条款的任何内容,请停止使用我们的产品和服务。
</p>
<p className="text-[var(--color-text-muted)] leading-relaxed">
本服务条款是您与四川睿新致远科技有限公司之间就使用我们的产品和服务所订立的协议。我们有权根据需要不时修改本服务条款,修改后的条款一旦公布即代替原条款,恕不另行通知。
</p>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">一、服务内容</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
我们提供的产品和服务包括但不限于:软件开发、云服务、数据分析、信息安全、企业级软件产品(如ERP、CRM、后台管理系统、BI等)等。具体服务内容以我们官方网站或产品文档为准。
</p>
<p className="text-[var(--color-text-muted)] leading-relaxed">
我们保留随时修改、暂停或终止部分或全部服务的权利,无需事先通知。对于因服务修改、暂停或终止而给您造成的任何损失,我们不承担任何责任,除非法律另有规定。
</p>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">二、用户注册与账户</h2>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">2.1 注册资格</h3>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
您确认,在您完成注册程序或以其他方式实际使用本服务时,您应当是具备完全民事权利能力和完全民事行为能力的自然人、法人或其他组织。若您不具备前述主体资格,则您及您的监护人应承担因此而导致的一切后果,且我们有权注销或永久冻结您的账户。
</p>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">2.2 账户安全</h3>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
您有责任维护您账户的安全性和保密性。您不得向任何第三方泄露您的账户信息,也不得与他人共享您的账户。如果您发现任何未经授权使用您账户的情况,应立即通知我们。
</p>
<p className="text-[var(--color-text-muted)] leading-relaxed">
您对您账户下发生的所有活动负责。我们对因您未能维护账户安全而造成的任何损失不承担责任。
</p>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">三、用户行为规范</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
在使用我们的产品和服务时,您同意遵守以下行为规范:
</p>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-2 mb-4">
<li>遵守所有适用的法律法规和本服务条款。</li>
<li>不得利用我们的产品和服务进行任何违法或不当活动。</li>
<li>不得干扰或破坏我们的产品和服务或与我们的产品和服务相连的服务器和网络。</li>
<li>不得上传、传播或存储任何违法、有害、威胁、诽谤、骚扰、侵权或其他不当内容。</li>
<li>不得侵犯他人的知识产权、隐私权或其他合法权益。</li>
<li>不得进行任何形式的商业欺诈或诈骗活动。</li>
<li>不得恶意收集或获取其他用户的信息。</li>
</ul>
<p className="text-[var(--color-text-muted)] leading-relaxed">
如果我们认定您违反了本服务条款或任何适用法律,我们有权在不事先通知的情况下,暂停或终止您的账户,并拒绝您现在或将来使用我们的产品和服务。
</p>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">四、知识产权</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
我们的产品和服务中包含的所有内容,包括但不限于软件、设计、文字、图片、音频、视频、商标、服务标识等,均受著作权法、商标法、专利法或其他适用法律的保护。
</p>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
除非另有明确说明,我们拥有或持有我们产品和服务中所有内容的所有知识产权。您不得以任何形式复制、修改、传播、展示、执行、创作衍生作品、转让、出售或以其他方式使用这些内容,除非获得我们的明确书面许可。
</p>
<p className="text-[var(--color-text-muted)] leading-relaxed">
您在使用我们的产品和服务时产生的任何内容,您仍保留其知识产权,但您授予我们全球性、非独占性、免版税的许可,以使用、复制、修改、传播、展示和执行这些内容,仅限于提供和改进我们的产品和服务。
</p>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">五、服务费用与支付</h2>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">5.1 费用标准</h3>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
我们的产品和服务可能需要支付费用。具体费用标准以我们官方网站或产品文档公布的价格为准。我们保留随时调整价格的权利,调整后的价格适用于调整后的新订单或续费。
</p>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">5.2 支付方式</h3>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
我们接受多种支付方式,包括但不限于银行转账、支付宝、微信支付等。具体支付方式以我们官方网站或产品文档为准。
</p>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">5.3 退款政策</h3>
<p className="text-[var(--color-text-muted)] leading-relaxed">
除非另有明确说明,我们提供的产品和服务一经售出,不予退款。如因我们的原因导致产品或服务无法正常使用,我们将根据实际情况提供相应的补偿或解决方案。
</p>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">六、免责声明</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
我们的产品和服务按&ldquo;现状&rdquo;和&ldquo;可用&rdquo;基础提供,不提供任何明示或暗示的保证,包括但不限于对适销性、适用性、非侵权性或准确性、可靠性的保证。
</p>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
我们不对以下情况承担责任:
</p>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-2">
<li>因您违反本服务条款或任何适用法律而导致的任何损失或损害。</li>
<li>因不可抗力、网络故障、设备故障等不可控因素导致的服务中断或数据丢失。</li>
<li>因第三方服务或内容导致的任何损失或损害。</li>
<li>因您使用或无法使用我们的产品和服务而导致的任何间接、附带、特殊或后果性损害。</li>
</ul>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">七、服务终止</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
您可以随时停止使用我们的产品和服务,并注销您的账户。我们也有权在不事先通知的情况下,因以下原因暂停或终止您的账户:
</p>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-2">
<li>您违反本服务条款或任何适用法律。</li>
<li>我们出于安全、法律或商业考虑,认为有必要终止您的账户。</li>
<li>您长时间未使用您的账户。</li>
<li>我们停止提供相关的产品和服务。</li>
</ul>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">八、争议解决</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
本服务条款的订立、执行、解释及争议解决均适用中华人民共和国法律。如就本服务条款发生任何争议,双方应首先通过友好协商解决;协商不成的,任何一方均可向公司所在地有管辖权的人民法院提起诉讼。
</p>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">九、其他条款</h2>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-2">
<li>本服务条款构成您与我们就使用我们的产品和服务所达成的完整协议,取代之前的所有口头或书面协议。</li>
<li>如本服务条款的任何条款被认定为无效或不可执行,该条款应被限制或排除,以使其有效和可执行,其余条款继续有效。</li>
<li>我们未行使或延迟行使本服务条款项下的任何权利或规定,不构成对该权利或规定的放弃。</li>
<li>本服务条款的标题仅为方便而设,不影响本服务条款的解释。</li>
</ul>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">十、联系我们</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
如果您对本服务条款有任何疑问、意见或建议,请通过以下方式与我们联系:
</p>
<ul className="list-none text-[var(--color-text-muted)] space-y-2">
<li>公司名称:四川睿新致远科技有限公司</li>
<li>联系邮箱:contact@novalon.cn</li>
<li>联系地址:中国四川省成都市龙泉驿区幸福路12号</li>
</ul>
</section>
<section className="bg-[var(--color-warning-bg)] p-6 rounded-lg">
<div className="flex items-center gap-2 mb-2">
<div className="w-2 h-2 bg-[var(--color-brand)] rounded-full" />
<p className="text-[var(--color-text-primary)] font-medium">最后更新日期</p>
</div>
<p className="text-[var(--color-text-muted)] pl-4">2026年2月26日</p>
</section>
</div>
);
}
export default async function TermsOfServicePage() {
let cmsContent: string | null = null;
try {
const items = await getPublishedItems('legal-page');
const termsItem = items.find((item) => item.data.pageType === 'terms');
if (termsItem && typeof termsItem.data.content === 'string' && termsItem.data.content.length > 0) {
cmsContent = termsItem.data.content as string;
}
} catch {
// CMS not available, fall back to inline content
}
return ( return (
<div className="min-h-screen bg-[var(--color-bg-primary)]"> <div className="min-h-screen bg-[var(--color-bg-primary)]">
<div className="bg-gradient-to-br from-[var(--color-brand-primary)] via-[var(--color-brand-primary)]/80 to-[var(--color-hero-dark-end)] py-20"> <div className="bg-gradient-to-br from-[var(--color-brand)] via-[var(--color-brand)]/80 to-[var(--color-hero-dark-end)] py-20">
<div className="container-wide"> <div className="container-wide">
<h1 className="text-4xl md:text-5xl font-bold text-white mb-4"> <h1 className="text-4xl md:text-5xl font-bold text-white mb-4">
服务条款 服务条款
@@ -22,161 +195,14 @@ export default function TermsOfServicePage() {
<div className="container-wide py-16"> <div className="container-wide py-16">
<div className="max-w-4xl"> <div className="max-w-4xl">
<div className="prose prose-lg max-w-none"> {cmsContent ? (
<section className="mb-12"> <div
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">引言</h2> className="prose prose-lg max-w-none"
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4"> dangerouslySetInnerHTML={{ __html: cmsContent }}
欢迎使用四川睿新致远科技有限公司(以下简称&ldquo;我们&rdquo;、&ldquo;公司&rdquo;)提供的产品和服务。在使用我们的产品和服务之前,请您仔细阅读并理解本服务条款。如果您不同意本服务条款的任何内容,请停止使用我们的产品和服务。 />
</p> ) : (
<p className="text-[var(--color-text-muted)] leading-relaxed"> <TermsContent />
本服务条款是您与四川睿新致远科技有限公司之间就使用我们的产品和服务所订立的协议。我们有权根据需要不时修改本服务条款,修改后的条款一旦公布即代替原条款,恕不另行通知。 )}
</p>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">一、服务内容</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
我们提供的产品和服务包括但不限于:软件开发、云服务、数据分析、信息安全、企业级软件产品(如ERP、CRM、后台管理系统、BI等)等。具体服务内容以我们官方网站或产品文档为准。
</p>
<p className="text-[var(--color-text-muted)] leading-relaxed">
我们保留随时修改、暂停或终止部分或全部服务的权利,无需事先通知。对于因服务修改、暂停或终止而给您造成的任何损失,我们不承担任何责任,除非法律另有规定。
</p>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">二、用户注册与账户</h2>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">2.1 注册资格</h3>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
您确认,在您完成注册程序或以其他方式实际使用本服务时,您应当是具备完全民事权利能力和完全民事行为能力的自然人、法人或其他组织。若您不具备前述主体资格,则您及您的监护人应承担因此而导致的一切后果,且我们有权注销或永久冻结您的账户。
</p>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">2.2 账户安全</h3>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
您有责任维护您账户的安全性和保密性。您不得向任何第三方泄露您的账户信息,也不得与他人共享您的账户。如果您发现任何未经授权使用您账户的情况,应立即通知我们。
</p>
<p className="text-[var(--color-text-muted)] leading-relaxed">
您对您账户下发生的所有活动负责。我们对因您未能维护账户安全而造成的任何损失不承担责任。
</p>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">三、用户行为规范</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
在使用我们的产品和服务时,您同意遵守以下行为规范:
</p>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-2 mb-4">
<li>遵守所有适用的法律法规和本服务条款。</li>
<li>不得利用我们的产品和服务进行任何违法或不当活动。</li>
<li>不得干扰或破坏我们的产品和服务或与我们的产品和服务相连的服务器和网络。</li>
<li>不得上传、传播或存储任何违法、有害、威胁、诽谤、骚扰、侵权或其他不当内容。</li>
<li>不得侵犯他人的知识产权、隐私权或其他合法权益。</li>
<li>不得进行任何形式的商业欺诈或诈骗活动。</li>
<li>不得恶意收集或获取其他用户的信息。</li>
</ul>
<p className="text-[var(--color-text-muted)] leading-relaxed">
如果我们认定您违反了本服务条款或任何适用法律,我们有权在不事先通知的情况下,暂停或终止您的账户,并拒绝您现在或将来使用我们的产品和服务。
</p>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">四、知识产权</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
我们的产品和服务中包含的所有内容,包括但不限于软件、设计、文字、图片、音频、视频、商标、服务标识等,均受著作权法、商标法、专利法或其他适用法律的保护。
</p>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
除非另有明确说明,我们拥有或持有我们产品和服务中所有内容的所有知识产权。您不得以任何形式复制、修改、传播、展示、执行、创作衍生作品、转让、出售或以其他方式使用这些内容,除非获得我们的明确书面许可。
</p>
<p className="text-[var(--color-text-muted)] leading-relaxed">
您在使用我们的产品和服务时产生的任何内容,您仍保留其知识产权,但您授予我们全球性、非独占性、免版税的许可,以使用、复制、修改、传播、展示和执行这些内容,仅限于提供和改进我们的产品和服务。
</p>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">五、服务费用与支付</h2>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">5.1 费用标准</h3>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
我们的产品和服务可能需要支付费用。具体费用标准以我们官方网站或产品文档公布的价格为准。我们保留随时调整价格的权利,调整后的价格适用于调整后的新订单或续费。
</p>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">5.2 支付方式</h3>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
我们接受多种支付方式,包括但不限于银行转账、支付宝、微信支付等。具体支付方式以我们官方网站或产品文档为准。
</p>
<h3 className="text-xl font-semibold text-[var(--color-text-primary)] mb-3">5.3 退款政策</h3>
<p className="text-[var(--color-text-muted)] leading-relaxed">
除非另有明确说明,我们提供的产品和服务一经售出,不予退款。如因我们的原因导致产品或服务无法正常使用,我们将根据实际情况提供相应的补偿或解决方案。
</p>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">六、免责声明</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
我们的产品和服务按&ldquo;现状&rdquo;和&ldquo;可用&rdquo;基础提供,不提供任何明示或暗示的保证,包括但不限于对适销性、适用性、非侵权性或准确性、可靠性的保证。
</p>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
我们不对以下情况承担责任:
</p>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-2">
<li>因您违反本服务条款或任何适用法律而导致的任何损失或损害。</li>
<li>因不可抗力、网络故障、设备故障等不可控因素导致的服务中断或数据丢失。</li>
<li>因第三方服务或内容导致的任何损失或损害。</li>
<li>因您使用或无法使用我们的产品和服务而导致的任何间接、附带、特殊或后果性损害。</li>
</ul>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">七、服务终止</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
您可以随时停止使用我们的产品和服务,并注销您的账户。我们也有权在不事先通知的情况下,因以下原因暂停或终止您的账户:
</p>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-2">
<li>您违反本服务条款或任何适用法律。</li>
<li>我们出于安全、法律或商业考虑,认为有必要终止您的账户。</li>
<li>您长时间未使用您的账户。</li>
<li>我们停止提供相关的产品和服务。</li>
</ul>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">八、争议解决</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
本服务条款的订立、执行、解释及争议解决均适用中华人民共和国法律。如就本服务条款发生任何争议,双方应首先通过友好协商解决;协商不成的,任何一方均可向公司所在地有管辖权的人民法院提起诉讼。
</p>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">九、其他条款</h2>
<ul className="list-disc pl-6 text-[var(--color-text-muted)] space-y-2">
<li>本服务条款构成您与我们就使用我们的产品和服务所达成的完整协议,取代之前的所有口头或书面协议。</li>
<li>如本服务条款的任何条款被认定为无效或不可执行,该条款应被限制或排除,以使其有效和可执行,其余条款继续有效。</li>
<li>我们未行使或延迟行使本服务条款项下的任何权利或规定,不构成对该权利或规定的放弃。</li>
<li>本服务条款的标题仅为方便而设,不影响本服务条款的解释。</li>
</ul>
</section>
<section className="mb-12">
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-4">十、联系我们</h2>
<p className="text-[var(--color-text-muted)] leading-relaxed mb-4">
如果您对本服务条款有任何疑问、意见或建议,请通过以下方式与我们联系:
</p>
<ul className="list-none text-[var(--color-text-muted)] space-y-2">
<li>公司名称:四川睿新致远科技有限公司</li>
<li>联系邮箱:contact@novalon.cn</li>
<li>联系地址:中国四川省成都市龙泉驿区幸福路12号</li>
</ul>
</section>
<section className="bg-[var(--color-warning-bg)] p-6 rounded-lg">
<div className="flex items-center gap-2 mb-2">
<div className="w-2 h-2 bg-[var(--color-brand-primary)] rounded-full" />
<p className="text-[var(--color-text-primary)] font-medium">最后更新日期</p>
</div>
<p className="text-[var(--color-text-muted)] pl-4">2026年2月26日</p>
</section>
</div>
</div> </div>
</div> </div>
</div> </div>
+23
View File
@@ -0,0 +1,23 @@
import { NextRequest, NextResponse } from 'next/server';
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// 只处理 /admin 路由(除了登录页和 API 路由)
if (pathname.startsWith('/admin') && !pathname.startsWith('/admin/login') && !pathname.startsWith('/api/')) {
const token = request.cookies.get('novalon_token')?.value;
const authHeader = request.headers.get('authorization');
// 如果 cookie 和 header 都没有 token,重定向到登录页
if (!token && !authHeader) {
// 允许客户端组件处理认证(因为 AuthProvider 在客户端也会检查 localStorage)
return NextResponse.next();
}
}
return NextResponse.next();
}
export const config = {
matcher: ['/admin/:path*'],
};