diff --git a/public/downloads/2026-high-tech-enterprise-application-form.pdf b/public/downloads/2026-high-tech-enterprise-application-form.pdf new file mode 100644 index 0000000..6e02c47 --- /dev/null +++ b/public/downloads/2026-high-tech-enterprise-application-form.pdf @@ -0,0 +1,2 @@ +%PDF-1.4 +% placeholder file diff --git a/public/images/placeholder-qr.svg b/public/images/placeholder-qr.svg new file mode 100644 index 0000000..2b9bc7e --- /dev/null +++ b/public/images/placeholder-qr.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + QR PLACEHOLDER + diff --git a/src/App.tsx b/src/App.tsx index b64af25..4884600 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,6 +3,8 @@ import { motion, AnimatePresence } from 'framer-motion' import { Home } from './pages/Home' import { About } from './pages/About' import { Services } from './pages/Services' +import { HighTechEnterprise } from './pages/HighTechEnterprise' +import { ServiceDetail } from './pages/ServiceDetail' import { News } from './pages/News' import { Contact } from './pages/Contact' import { Cases } from './pages/Cases' @@ -71,6 +73,8 @@ function App() { } /> } /> } /> + } /> + } /> } /> } /> } /> @@ -82,6 +86,8 @@ function App() { } /> } /> } /> + } /> + } /> } /> } /> } /> diff --git a/src/components/Home/ServicesSection.tsx b/src/components/Home/ServicesSection.tsx index 832c1c9..a469510 100644 --- a/src/components/Home/ServicesSection.tsx +++ b/src/components/Home/ServicesSection.tsx @@ -1,7 +1,8 @@ import { motion } from 'framer-motion'; -import { TrendingUp, Cpu, Building2, Briefcase, ArrowRight } from 'lucide-react'; +import { TrendingUp, Cpu, Building2, Briefcase, ArrowRight, Wrench } from 'lucide-react'; import { Link } from 'react-router-dom'; import { SERVICES } from '../../lib/constants'; +import { getLocaleFromPathname, withLocalePath } from '../../lib/i18n' /** * ServicesSection 组件 - 核心业务展示区域 @@ -12,8 +13,10 @@ const ServiceCard: React.FC<{ service: typeof SERVICES[0]; index: number; }> = ({ service, index }) => { + const locale = getLocaleFromPathname(window.location.pathname) const iconMap: Record> = { TrendingUp, + Wrench, Cpu, Building2, Briefcase, @@ -58,7 +61,7 @@ const ServiceCard: React.FC<{ {/* 了解更多链接 */} 了解更多 diff --git a/src/components/PaymentQrModal.tsx b/src/components/PaymentQrModal.tsx new file mode 100644 index 0000000..3ccd760 --- /dev/null +++ b/src/components/PaymentQrModal.tsx @@ -0,0 +1,152 @@ +import React, { useEffect, useId, useMemo, useState } from 'react' +import { X, QrCode, ShieldCheck } from 'lucide-react' +import { grantDownloadAccess } from '../lib/downloadGate' + +type PaymentMethod = 'wechat' | 'alipay' + +export type PaymentQrModalProps = { + open: boolean + onClose: () => void + downloadKey: string + title: string + amountCny?: number + qrImageSrc?: string + onPaid: () => void +} + +function getDefaultQrImageSrc(): string { + // Placeholder SVG kept in public/ so it can be swapped easily later. + return '/images/placeholder-qr.svg' +} + +export const PaymentQrModal: React.FC = ({ + open, + onClose, + downloadKey, + title, + amountCny = 1, + qrImageSrc, + onPaid, +}) => { + const dialogTitleId = useId() + const [method, setMethod] = useState('wechat') + + const qrSrc = useMemo(() => qrImageSrc ?? getDefaultQrImageSrc(), [qrImageSrc]) + + useEffect(() => { + if (!open) return + const onKeyDown = (e: KeyboardEvent) => { + if (e.key === 'Escape') onClose() + } + window.addEventListener('keydown', onKeyDown) + return () => window.removeEventListener('keydown', onKeyDown) + }, [onClose, open]) + + if (!open) return null + + return ( +
+ + ) +} + +export default PaymentQrModal diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 2e75af2..d59fefc 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -34,6 +34,7 @@ export const NAVIGATION_MENU = [ export const FOOTER_LINKS = { products: [ { label: '金融服务', path: '/services/finance' }, + { label: '科技服务', path: '/services/tech-service' }, { label: '科技研发', path: '/services/tech' }, { label: '产业投资', path: '/services/investment' }, { label: '咨询服务', path: '/services/consulting' }, @@ -85,6 +86,14 @@ export const SERVICES = [ icon: 'TrendingUp', features: ['财富管理', '投资顾问', '资产配置', '风险管理'], }, + { + id: 'tech-service', + title: '科技服务', + description: + '围绕企业创新与资质建设,提供高新技术企业认定、研发管理体系辅导、科技项目申报等科技服务。', + icon: 'Wrench', + features: ['高新技术企业认定', '科技项目申报', '研发管理辅导', '资质与合规'], + }, { id: 'tech', title: '科技研发', diff --git a/src/lib/downloadGate.ts b/src/lib/downloadGate.ts new file mode 100644 index 0000000..7d51aae --- /dev/null +++ b/src/lib/downloadGate.ts @@ -0,0 +1,42 @@ +type DownloadGatePayload = { + key: string + paidAt: string + amountCny: number + method: 'wechat' | 'alipay' +} + +const STORAGE_PREFIX = 'downloadGate:' + +export function hasDownloadAccess(key: string): boolean { + try { + const raw = localStorage.getItem(`${STORAGE_PREFIX}${key}`) + if (!raw) return false + const parsed = JSON.parse(raw) as DownloadGatePayload + return parsed?.key === key && parsed.amountCny >= 1 + } catch { + return false + } +} + +export function grantDownloadAccess(key: string, method: DownloadGatePayload['method']): void { + const payload: DownloadGatePayload = { + key, + paidAt: new Date().toISOString(), + amountCny: 1, + method, + } + + try { + localStorage.setItem(`${STORAGE_PREFIX}${key}`, JSON.stringify(payload)) + } catch { + // ignore + } +} + +export function revokeDownloadAccess(key: string): void { + try { + localStorage.removeItem(`${STORAGE_PREFIX}${key}`) + } catch { + // ignore + } +} diff --git a/src/pages/HighTechEnterprise.tsx b/src/pages/HighTechEnterprise.tsx new file mode 100644 index 0000000..db71fb8 --- /dev/null +++ b/src/pages/HighTechEnterprise.tsx @@ -0,0 +1,175 @@ +import React, { useCallback, useMemo, useState } from 'react' +import { motion } from 'framer-motion' +import { FileText, Download, Lock, CheckCircle2 } from 'lucide-react' +import { Header } from '../components/Header' +import { Footer } from '../components/Footer' +import { usePageMeta } from '../hooks/usePageMeta' +import { getLocaleFromPathname, withLocalePath } from '../lib/i18n' +import { hasDownloadAccess } from '../lib/downloadGate' +import { PaymentQrModal } from '../components/PaymentQrModal' + +const DOWNLOAD_KEY = 'htech-application-2026' +const FILE_NAME = '2026年高新技术企业认定申请表.pdf' +const FILE_PATH = '/downloads/2026-high-tech-enterprise-application-form.pdf' + +function startFileDownload(absoluteOrPublicPath: string, fileName?: string) { + const a = document.createElement('a') + a.href = absoluteOrPublicPath + if (fileName) a.download = fileName + a.rel = 'noopener' + document.body.appendChild(a) + a.click() + a.remove() +} + +export const HighTechEnterprise: React.FC = () => { + const locale = getLocaleFromPathname(window.location.pathname) + const [payOpen, setPayOpen] = useState(false) + const [downloadUnlocked, setDownloadUnlocked] = useState(() => hasDownloadAccess(DOWNLOAD_KEY)) + + usePageMeta({ + title: locale === 'en' ? 'High-tech enterprise certification' : '高新技术企业认定要求', + description: + locale === 'en' + ? 'High-tech enterprise certification requirements and download of the 2026 application form.' + : '高新技术企业认定的核心要求说明,并提供 2026 年申请表下载入口。', + locale, + }) + + const alreadyPaid = downloadUnlocked + + const handleDownloadClick = useCallback(() => { + if (hasDownloadAccess(DOWNLOAD_KEY)) { + setDownloadUnlocked(true) + startFileDownload(FILE_PATH, FILE_NAME) + return + } + + setPayOpen(true) + }, []) + + const breadcrumbHref = useMemo(() => withLocalePath(locale, '/services'), [locale]) + + return ( + +
+ +
+
+
+ + {locale === 'en' ? 'Back to Services' : '返回服务范围'} + +

+ {locale === 'en' ? 'High-tech enterprise certification requirements' : '高新技术企业认定要求'} +

+

+ {locale === 'en' + ? 'This page provides a simplified overview. Replace with official materials later.' + : '本页为精简版概览,便于用户快速理解核心要求;后续可替换为完整政策解读与本地政策细则。'} +

+
+
+ +
+
+
+
+

{locale === 'en' ? 'Key points' : '核心要点(示例)'}

+ +
+
+ +

+ {locale === 'en' + ? 'Intellectual property, R&D activity, and revenue structure are commonly reviewed items.' + : '常见审核关注:知识产权布局、研发活动真实性、收入结构与高新产品(服务)比例等。'} +

+
+
+ +

+ {locale === 'en' + ? 'R&D expense accounting should be consistent and traceable.' + : '研发费用归集口径需一致、可追溯,建议提前建立台账与证据链。'} +

+
+
+ +

+ {locale === 'en' + ? 'Policies differ by region; always follow the latest local rules.' + : '各地细则可能存在差异,实际申报以最新的本地政策与平台要求为准。'} +

+
+
+ +
+ +

{locale === 'en' ? 'Downloads' : '资料下载'}

+

+ {locale === 'en' + ? 'Download requires a 1 CNY payment via WeChat/Alipay.' + : '下载需支付 1 元(微信/支付宝均可)。'} +

+ +
+
+
+ +
+
+
{FILE_NAME}
+
PDF · {locale === 'en' ? 'Form template' : '申请表模板'}
+
+
+ + +
+
+ + +
+
+
+
+ +
+ + setPayOpen(false)} + downloadKey={DOWNLOAD_KEY} + title={FILE_NAME} + amountCny={1} + onPaid={() => { + setDownloadUnlocked(true) + setPayOpen(false) + startFileDownload(FILE_PATH, FILE_NAME) + }} + /> + + ) +} + +export default HighTechEnterprise diff --git a/src/pages/ServiceDetail.tsx b/src/pages/ServiceDetail.tsx new file mode 100644 index 0000000..bf0f3fe --- /dev/null +++ b/src/pages/ServiceDetail.tsx @@ -0,0 +1,106 @@ +import React, { useMemo } from 'react' +import { useParams } from 'react-router-dom' +import { motion } from 'framer-motion' +import { ArrowRight, CheckCircle2, FileText } from 'lucide-react' +import { Header } from '../components/Header' +import { Footer } from '../components/Footer' +import { SERVICES } from '../lib/constants' +import { getLocaleFromPathname, withLocalePath } from '../lib/i18n' +import { usePageMeta } from '../hooks/usePageMeta' + +export const ServiceDetail: React.FC = () => { + const locale = getLocaleFromPathname(window.location.pathname) + const { serviceId } = useParams<{ serviceId: string }>() + + const service = useMemo(() => SERVICES.find((s) => s.id === serviceId), [serviceId]) + + usePageMeta({ + title: service ? (locale === 'en' ? 'Service' : service.title) : locale === 'en' ? 'Service' : '服务', + description: service?.description, + locale, + }) + + const backHref = useMemo(() => withLocalePath(locale, '/services'), [locale]) + + if (!service) { + return ( + +
+
+
+ + {locale === 'en' ? 'Back to Services' : '返回服务范围'} + +

{locale === 'en' ? 'Service not found' : '未找到该服务'}

+

{locale === 'en' ? 'Please check the URL.' : '请检查访问路径是否正确。'}

+
+
+
+ + ) + } + + const isTechService = service.id === 'tech-service' + const highTechHref = withLocalePath(locale, '/services/tech-service/high-tech-enterprise') + + return ( + +
+ +
+
+
+ + {locale === 'en' ? 'Back to Services' : '返回服务范围'} + +

{service.title}

+

{service.description}

+
+
+ +
+
+
+

{locale === 'en' ? 'What we provide' : '我们提供'}

+
+ {service.features.map((f) => ( +
+ +
{f}
+
+ ))} +
+ + {isTechService && ( +
+
+
+
+ + 高新技术企业认定 +
+

+ 查看认定要求,并下载 2026 年高新技术企业认定申请表(付费下载 1 元)。 +

+
+ + 进入页面 + + +
+
+ )} +
+
+
+
+ +
+ + ) +} + +export default ServiceDetail diff --git a/src/pages/Services.tsx b/src/pages/Services.tsx index 9a3b6d0..71cf796 100644 --- a/src/pages/Services.tsx +++ b/src/pages/Services.tsx @@ -5,6 +5,7 @@ import { Cpu, Building2, Briefcase, + Wrench, CheckCircle, Target, BarChart3, @@ -45,6 +46,38 @@ const serviceDetails = { { step: '04', title: '持续跟踪', desc: '定期调整和优化投资组合' }, ], }, + techService: { + description: + '科技服务聚焦企业创新能力建设与资质合规,提供高新技术企业认定辅导、申报材料梳理、研发费用归集与体系完善等支持,帮助企业更高效地完成申报与长期管理。', + features: [ + { + icon: Wrench, + title: '认定辅导', + desc: '对照政策要求梳理差距,形成可落地的提升与申报路径', + }, + { + icon: Shield, + title: '研发体系建设', + desc: '完善研发管理制度、知识产权与成果转化台账,提升持续合规能力', + }, + { + icon: BarChart3, + title: '费用归集与核算', + desc: '辅助研发费用归集口径与台账搭建,降低申报风险', + }, + { + icon: Target, + title: '项目申报与匹配', + desc: '结合企业业务方向,进行科技项目匹配与材料准备', + }, + ], + process: [ + { step: '01', title: '资质诊断', desc: '梳理现状,评估达标差距与可行路径' }, + { step: '02', title: '材料梳理', desc: '搭建目录清单,统一口径与证据链' }, + { step: '03', title: '申报提交', desc: '按节点推进提交与补正,提升通过率' }, + { step: '04', title: '后续管理', desc: '建立持续合规机制与年度复盘' }, + ], + }, tech: { description: '我们聚焦人工智能、大数据、云计算等前沿技术,为企业提供全方位的数字化转型解决方案。', features: [ @@ -144,6 +177,7 @@ const partners = [ const categories = [ { id: 'all', label: '全部' }, { id: 'finance', label: '金融服务' }, + { id: 'techService', label: '科技服务' }, { id: 'tech', label: '科技研发' }, { id: 'investment', label: '产业投资' }, { id: 'consulting', label: '咨询服务' }, @@ -270,6 +304,7 @@ export const Services: React.FC = () => { {SERVICES.map((service, index) => { const iconMap: Record> = { TrendingUp, + Wrench, Cpu, Building2, Briefcase, @@ -433,6 +468,63 @@ export const Services: React.FC = () => {
+ + {/* 科技服务 */} +
+ + + 科技服务 + +

+ 高新技术企业认定与科技项目申报 +

+

+ {serviceDetails.techService.description} +

+ +
+ {serviceDetails.techService.features.map((feature, index) => ( +
+
+ +
+
+

{feature.title}

+

{feature.desc}

+
+
+ ))} +
+ + + 查看科技服务详情 + +
+ + +
+ 科技服务 - 高新技术企业认定与申报支持 +
+
+