diff --git a/cms/server/src/seed.js b/cms/server/src/seed.js
index 64df1ad..407384b 100644
--- a/cms/server/src/seed.js
+++ b/cms/server/src/seed.js
@@ -64,6 +64,8 @@ const siteTexts = [
['cases.detail_note', '案例详情提示', '原状、目标、差距、根因、介入、路径、行动、结果与迭代,构成完整的案例叙事。'],
['cases.value_placeholder', '案例关联价值提示', '暂未关联价值坐标'],
['cases.service_placeholder', '案例关联服务提示', '暂未关联服务'],
+ ['cases.empty_title', '案例空状态标题', '案例内容正在整理中'],
+ ['cases.empty_description', '案例空状态说明', '如需了解与企业当前阶段匹配的实践路径,欢迎直接咨询顾问。'],
['contact.company_placeholder', '联系人企业选填提示', '选填'],
['contact.need_placeholder', '咨询需求输入提示', '请简述你的企业现状与期望'],
['contact.privacy_note', '咨询隐私说明', '提交即视为同意隐私与合规说明。'],
@@ -86,10 +88,14 @@ const siteTexts = [
['services.custom_cta', '定制服务行动文字', '咨询/获取方案(无价格)'],
['services.placeholder', '服务页补充说明', '围绕企业当前阶段,选择合适的行动路径。'],
['services.detail_note', '服务详情补充说明', '明确交付物、周期、适合对象与服务流程,让合作预期清晰可见。'],
+ ['services.empty_title', '服务空状态标题', '服务内容正在更新中'],
+ ['services.empty_description', '服务空状态说明', '欢迎联系我们,获取适合企业当前阶段的沟通与服务建议。'],
['insights.header_placeholder', '洞察页补充说明', '围绕企业进化、价值坐标与经营现场,持续记录真实观察。'],
['insights.title', '洞察页标题', '认知观察'],
['insights.header_description', '洞察页说明', '围绕企业进化、价值坐标、A/M/B 与方法论的持续观察与沉淀。'],
['insights.detail_note', '洞察详情补充说明', '从真实经营现场出发,持续记录可验证、可复盘的观察。'],
+ ['insights.empty_title', '洞察空状态标题', '内容正在持续沉淀'],
+ ['insights.empty_description', '洞察空状态说明', '欢迎关注企业进化、价值坐标与经营现场的后续观察。'],
['selfcheck.header_note', '轻量对照页头部说明', '仅做轻量对照,深度诊断需线下陪跑。'],
['selfcheck.storage_note', '轻量对照结果说明', '结果仅本地展示,不存储。'],
['selfcheck.result_title', '轻量对照结果标题', '对照结果'],
diff --git a/src/components/Layout/index.tsx b/src/components/Layout/index.tsx
index f1bbb28..f472094 100644
--- a/src/components/Layout/index.tsx
+++ b/src/components/Layout/index.tsx
@@ -5,13 +5,13 @@ import MobileStickyCTA from './MobileStickyCTA'
export default function Layout() {
return (
- <>
+
-
+
- >
+
)
}
diff --git a/src/pages/Cases/index.tsx b/src/pages/Cases/index.tsx
index aec2cc8..ec6f7de 100644
--- a/src/pages/Cases/index.tsx
+++ b/src/pages/Cases/index.tsx
@@ -1,10 +1,9 @@
import { Link } from 'react-router-dom'
-import { CASES as FALLBACK_CASES } from '@/data/mock'
import { useCMS, useCMSTexts, getCMSCases } from '@/services/cms'
import GlobalCTA from '@/components/Layout/GlobalCTA'
export default function Cases() {
- const { data: CASES } = useCMS(getCMSCases, FALLBACK_CASES)
+ const { data: CASES } = useCMS(getCMSCases, [])
const { data: texts } = useCMSTexts()
return (
@@ -22,7 +21,7 @@ export default function Cases() {
-
+ {CASES.length ?
{CASES.map(c => (
CASE · {c.status.toUpperCase()}
@@ -31,7 +30,7 @@ export default function Cases() {
{texts['cases.detail_link'] || '查看完整叙事'} →
))}
-
+
:
{texts['cases.empty_title'] || '案例内容正在整理中'}
{texts['cases.empty_description'] || '如需了解与企业当前阶段匹配的实践路径,欢迎直接咨询顾问。'}
}
diff --git a/src/pages/Insights/index.tsx b/src/pages/Insights/index.tsx
index a28a4c2..3fd9189 100644
--- a/src/pages/Insights/index.tsx
+++ b/src/pages/Insights/index.tsx
@@ -1,10 +1,9 @@
import { Link } from 'react-router-dom'
-import { INSIGHTS as FALLBACK_INSIGHTS } from '@/data/mock'
import { useCMS, useCMSTexts, getCMSInsights } from '@/services/cms'
import GlobalCTA from '@/components/Layout/GlobalCTA'
export default function Insights() {
- const { data: INSIGHTS } = useCMS(getCMSInsights, FALLBACK_INSIGHTS)
+ const { data: INSIGHTS } = useCMS(getCMSInsights, [])
const { data: texts } = useCMSTexts()
return (
@@ -22,7 +21,7 @@ export default function Insights() {
-
+ {INSIGHTS.length ?
{INSIGHTS.map(i => (
{i.category.toUpperCase()}
@@ -33,7 +32,7 @@ export default function Insights() {
))}
-
+
: {texts['insights.empty_title'] || '内容正在持续沉淀'}
{texts['insights.empty_description'] || '欢迎关注企业进化、价值坐标与经营现场的后续观察。'}
}
diff --git a/src/pages/Services/index.tsx b/src/pages/Services/index.tsx
index c2f28f1..dbfcaa9 100644
--- a/src/pages/Services/index.tsx
+++ b/src/pages/Services/index.tsx
@@ -1,10 +1,9 @@
import { Link } from 'react-router-dom'
-import { SERVICES as FALLBACK_SERVICES } from '@/data/mock'
import { useCMS, useCMSTexts, getCMSServices } from '@/services/cms'
import GlobalCTA from '@/components/Layout/GlobalCTA'
export default function Services() {
- const { data: SERVICES } = useCMS(getCMSServices, FALLBACK_SERVICES)
+ const { data: SERVICES } = useCMS(getCMSServices, [])
const { data: texts } = useCMSTexts()
return (
@@ -22,7 +21,7 @@ export default function Services() {
-
+ {SERVICES.length ?
{SERVICES.map(s => (
@@ -52,7 +51,7 @@ export default function Services() {
))}
-
+
:
{texts['services.empty_title'] || '服务内容正在更新中'}
{texts['services.empty_description'] || '欢迎联系我们,获取适合企业当前阶段的沟通与服务建议。'}
}
diff --git a/src/styles/global.css b/src/styles/global.css
index 5be1689..2637bf3 100644
--- a/src/styles/global.css
+++ b/src/styles/global.css
@@ -14,14 +14,22 @@
}
* { box-sizing: border-box; margin: 0; padding: 0; }
-html { scroll-behavior: smooth; }
+html { scroll-behavior: smooth; min-height: 100%; }
body {
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif;
color: var(--text);
background: var(--bg);
line-height: 1.7;
-webkit-font-smoothing: antialiased;
+ min-height: 100vh;
}
+#root { min-height: 100vh; }
+.app-shell { min-height: 100vh; display: flex; flex-direction: column; }
+.site-main { flex: 1; display: flex; flex-direction: column; }
+/* Each route is a page-level wrapper. Let a short page fill the available space,
+ then anchor its final CTA immediately above the footer. */
+.site-main > * { flex: 1; display: flex; flex-direction: column; }
+.site-main > * > .cta-band:last-child { margin-top: auto; }
a { color: var(--primary); text-decoration: none; }
a:hover { color: var(--primary-light); }
img { max-width: 100%; display: block; }
@@ -66,6 +74,18 @@ img { max-width: 100%; display: block; }
line-height: 1.6;
}
.placeholder strong { color: #b45309; }
+.empty-state {
+ min-height: 180px;
+ display: grid;
+ place-items: center;
+ text-align: center;
+ background: var(--bg-white);
+ border: 1px dashed var(--border);
+ border-radius: 12px;
+ padding: 32px 24px;
+}
+.empty-state h2 { color: var(--primary); font-size: 18px; margin-bottom: 8px; }
+.empty-state p { color: var(--text-secondary); font-size: 14px; max-width: 480px; }
/* Cards */
.card {