Files

160 lines
9.8 KiB
Python

"""企业开站模板。仅创建缺失内容,不修改或重新发布已有页面。"""
from django.core.exceptions import ValidationError
from django.db import transaction
from django.utils import timezone
from django.utils.html import format_html
from wagtail.models import Page, Site
from apps.blog.models import BlogIndexPage, BlogPage
from apps.cases.models import CaseStudyIndexPage, CaseStudyPage
from apps.core.management.commands.seed_contact_page import CONTACT_FORM_FIELDS
from apps.core.models import (
ContactPage, NavigationMenu, NavigationMenuItem, SimpleContentPage, SiteSettings,
)
from apps.forms.models import FormDefinition
from apps.home.models import HomePage
from apps.products.models import ProductIndexPage, ProductPage
from apps.solutions.models import SolutionIndexPage, SolutionPage
COMPANY_FIELDS = ("company_name", "contact_phone", "contact_email", "address", "icp_number")
def default_site():
site = Site.objects.filter(is_default_site=True).first()
if site is None:
raise ValidationError("未配置默认站点,请先在“设置 → 站点”中配置默认站点。")
return site
def _ensure_page(parent, model, slug, title, created, **fields):
existing = parent.get_children().filter(slug=slug).first()
if existing is not None:
if not isinstance(existing.specific, model):
raise ValidationError(f"路径 {slug} 已被其他类型的页面占用,请先调整页面路径。")
return existing.specific
page = model(title=title, slug=slug, **fields)
parent.add_child(instance=page)
page.save_revision().publish()
created.append(title)
return page
def _cta():
return ("cta", {
"heading": "一起讨论您的项目需求",
"description": "告诉我们业务目标、当前挑战与期望交付时间。",
"button": {"text": "预约项目咨询", "link": "/contact/"},
})
def _detail_body(heading, description):
return [
("richtext", str(format_html("<h2>{}</h2><p>{}</p>", heading, description))),
("feature_grid", {"heading": "服务流程", "items": [
{"icon": "1", "title": "需求梳理", "description": "明确业务场景、范围与验收标准。"},
{"icon": "2", "title": "迭代交付", "description": "分阶段演示并收集使用反馈。"},
{"icon": "3", "title": "持续维护", "description": "按约定提供培训、维护与优化支持。"},
]}),
_cta(),
]
def _create_template(site, company_name):
created = []
home = site.root_page.specific
if not isinstance(home, HomePage):
# 只允许接管全新 Wagtail 安装的空白通用欢迎页,不重绑定已有业务站点。
if type(home) is not Page or home.depth != 2 or home.get_children().exists() or home.slug != "home":
raise ValidationError("默认站点根页面不是企业首页。请先配置 HomePage,现有站点不会被替换。")
home = _ensure_page(home.get_parent(), HomePage, "company-home", "首页", created, body=[
("hero", {
"title": f"{company_name} · 软件与技术服务",
"subtitle": "从需求分析到软件交付,帮助企业构建适合自身业务的数字化系统。",
"background_image": None,
"buttons": [{"text": "了解服务", "link": "/products/"}, {"text": "项目咨询", "link": "/contact/"}],
}),
("feature_grid", {"heading": "我们可以帮助您", "items": [
{"icon": "", "title": "软件定制", "description": "围绕业务流程设计与开发应用。"},
{"icon": "", "title": "系统集成", "description": "连接现有系统,减少重复录入。"},
{"icon": "", "title": "运维支持", "description": "提供上线培训与持续维护服务。"},
]}),
("product_card", {"heading": "产品与服务", "items": [
{"title": "企业内容平台", "description": "统一管理官网内容与咨询入口。", "image": None, "link": "/products/content-platform/"},
{"title": "定制开发服务", "description": "从原型到交付,适配实际业务场景。", "image": None, "link": "/products/custom-development/"},
]}),
("faq", {"items": [
{"question": "如何开始合作?", "answer": "<p>通过咨询表单描述需求,我们会进一步确认范围与交付安排。</p>"},
{"question": "能否对接现有系统?", "answer": "<p>需要先评估现有接口、数据要求与安全边界,再确定实施方案。</p>"},
]}),
_cta(),
])
site.root_page = home
site.save(update_fields=["root_page"])
def ensure(parent, model, slug, title, **fields):
return _ensure_page(parent, model, slug, title, created, **fields)
products = ensure(home, ProductIndexPage, "products", "产品与服务", intro="探索企业内容平台与软件定制服务。")
for slug, title, summary in [
("content-platform", "企业内容平台", "集中管理品牌官网、产品内容、客户案例与咨询表单。"),
("custom-development", "定制开发服务", "根据业务流程提供 Web 应用、接口集成与运维支持。"),
]:
ensure(products, ProductPage, slug, title, summary=summary, body=_detail_body(title, summary))
solutions = ensure(home, SolutionIndexPage, "solutions", "解决方案", intro="以业务场景为起点,规划可落地的数字化方案。")
ensure(solutions, SolutionPage, "digital-workplace", "企业数字化协同", industry="企业服务",
summary="连接内容、流程与数据,减少团队之间的信息断层。",
body=_detail_body("从业务流程出发", "先梳理现有工具与协作瓶颈,再规划分阶段实施方案。"))
cases = ensure(home, CaseStudyIndexPage, "cases", "客户案例", intro="以下案例为模板演示,请上线前替换为获得授权的真实案例。")
ensure(cases, CaseStudyPage, "demo-content-project", "示例案例:企业内容管理项目(虚构)",
client_name="虚构示例企业", industry="企业服务", published_at=timezone.now(),
summary="仅用于展示案例结构,不代表真实客户、交付成果或业绩。",
body=_detail_body("示例内容,请勿作为真实业绩发布", "展示需求背景、实施过程与验收方式;请替换为客户授权的真实材料。"))
blog = ensure(home, BlogIndexPage, "blog", "技术与洞察", intro="分享技术实践、产品思考与项目经验。")
ensure(blog, BlogPage, "website-content-checklist", "示例文章:企业官网上线内容清单",
published_at=timezone.now(), intro="上线前核对品牌资料、产品信息、联系渠道与隐私说明。",
body=[("richtext", "<h2>上线前检查</h2><ul><li>替换所有示例内容与图片。</li><li>检查手机端布局与页面链接。</li><li>提交测试咨询,确认通知可达。</li><li>按实际情况审核备案和隐私说明。</li></ul>")])
about = ensure(home, SimpleContentPage, "about", "关于我们", body=str(format_html(
"<h2>关于 {}</h2><p>我们提供软件开发、系统集成与技术服务。</p>"
"<h2>我们的工作方式</h2><p>明确需求、迭代交付、持续支持。</p>"
"<p>模板提示:请补充真实的公司介绍、团队与资质,不要发布未经核实的业绩。</p>", company_name)))
privacy = ensure(home, SimpleContentPage, "privacy-policy", "隐私政策(待完善)",
body="<p>这是隐私说明占位内容。上线前请根据实际收集的数据、处理目的、保存期限、联系与删除方式完善,并完成必要审核。</p>")
contact = home.get_children().filter(slug="contact").first()
if contact is not None and not isinstance(contact.specific, ContactPage):
raise ValidationError("路径 contact 已被其他类型的页面占用,请先调整页面路径。")
if contact is None:
form = FormDefinition.objects.create(name="官网项目咨询", notification_email=SiteSettings.for_site(site).contact_email)
for order, field in enumerate(CONTACT_FORM_FIELDS):
form.fields.create(sort_order=order, **field)
contact = ensure(home, ContactPage, "contact", "联系我们", body=[
("richtext", "<h2>项目咨询</h2><p>请描述您的业务需求与预期,我们将与您进一步沟通。</p>"),
("form", {"form": form}),
])
else:
contact = contact.specific
for name, entries in [
("main", [("首页", home), ("产品与服务", products), ("解决方案", solutions), ("案例", cases), ("技术博客", blog), ("关于我们", about), ("联系咨询", contact)]),
("footer", [("关于我们", about), ("联系我们", contact), ("隐私政策", privacy)]),
]:
menu, is_new = NavigationMenu.objects.get_or_create(name=name)
if is_new:
for order, (label, page) in enumerate(entries):
if page.live:
NavigationMenuItem.objects.create(menu=menu, sort_order=order, label=label, link_page=page)
return created
@transaction.atomic
def setup_company_site(company_data, create_demo=False):
site = default_site()
# 序列化同一站点的初始化请求,避免重复页面/表单。
site = Site.objects.select_for_update().get(pk=site.pk)
settings = SiteSettings.for_site(site)
for field in COMPANY_FIELDS:
setattr(settings, field, company_data[field])
settings.full_clean()
settings.save()
site.site_name = settings.company_name
site.save(update_fields=["site_name"])
return _create_template(site, settings.company_name) if create_demo else []