feat(add): 新增多页面新增和编辑表单功能
- 添加编辑和新增收货地址页面,支持表单数据加载和提交 - 新增应用密钥凭证、新增应用操作动态、新增应用成员、新增应用版本页面配置 - 实现文章新增及编辑页面,包含图片上传及多种文章属性配置 - 增加注册会员页面,支持头像上传、手机号获取和邀请人关系处理 - 引入统一表单提交成功和失败处理,支持编辑模式数据回显 - 配置统一eslint和editorconfig规则,增强代码规范和编辑体验 - 新增.gitignore规则,屏蔽无关文件和目录,优化版本管理
This commit is contained in:
472
src/pages/index/index.tsx
Normal file
472
src/pages/index/index.tsx
Normal file
@@ -0,0 +1,472 @@
|
||||
import Taro, { getCurrentInstance, useShareAppMessage } from '@tarojs/taro'
|
||||
import { View, Text } from '@tarojs/components'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { Button } from '@nutui/nutui-react-taro'
|
||||
import { useConfig } from '@/hooks/useConfig'
|
||||
import { copyText } from '@/utils/common'
|
||||
import './index.scss'
|
||||
|
||||
function Home() {
|
||||
const [ecoTab, setEcoTab] = useState<'template' | 'plugin'>('template')
|
||||
const { config } = useConfig()
|
||||
|
||||
useShareAppMessage(() => {
|
||||
// 获取当前用户ID,用于生成邀请链接
|
||||
const userId = Taro.getStorageSync('UserId')
|
||||
|
||||
return {
|
||||
title: config?.siteName
|
||||
? `${config.siteName} - 网宿软件`
|
||||
: '软件开发平台:SaaS + 私有化 + 模板/插件生态',
|
||||
path: userId
|
||||
? `/pages/index/index?inviter=${userId}&source=share&t=${Date.now()}`
|
||||
: `/pages/index/index`,
|
||||
success: function () {
|
||||
console.log('首页分享成功')
|
||||
Taro.showToast({
|
||||
title: '分享成功',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
},
|
||||
fail: function () {
|
||||
console.log('首页分享失败')
|
||||
Taro.showToast({
|
||||
title: '分享失败',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const scrollToSection = (id: string) => {
|
||||
const query = Taro.createSelectorQuery()
|
||||
const inst = getCurrentInstance()
|
||||
// 兼容 React 运行时:尽量将查询限定在当前页面作用域内
|
||||
if (inst?.page && typeof query.in === 'function') query.in(inst.page)
|
||||
query.selectViewport().scrollOffset()
|
||||
query.select(`#${id}`).boundingClientRect()
|
||||
query.exec((res: any[]) => {
|
||||
const viewport = res?.[0]
|
||||
const rect = res?.[1]
|
||||
const scrollTop = (viewport?.scrollTop || 0) + (rect?.top || 0) - 50
|
||||
if (Number.isFinite(scrollTop)) {
|
||||
Taro.pageScrollTo({ scrollTop: Math.max(scrollTop, 0), duration: 260 })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const toAbsoluteMaybe = (url: string) => {
|
||||
if (/^https?:\/\//i.test(url)) return url
|
||||
const base = (config?.domain || '').trim()
|
||||
if (!base) return url
|
||||
const withProto = /^https?:\/\//i.test(base) ? base : `https://${base}`
|
||||
// 处理 domain 末尾/ 与 url 开头/ 的组合
|
||||
const normalizedBase = withProto.replace(/\/+$/, '')
|
||||
const normalizedPath = url.startsWith('/') ? url : `/${url}`
|
||||
return `${normalizedBase}${normalizedPath}`
|
||||
}
|
||||
|
||||
const openMaybeLink = (url?: string) => {
|
||||
if (!url) return
|
||||
// 小程序内无法直接打开外链,这里统一“复制链接”降低认知成本
|
||||
const abs = toAbsoluteMaybe(url)
|
||||
if (/^https?:\/\//i.test(abs)) {
|
||||
copyText(abs)
|
||||
return
|
||||
}
|
||||
Taro.showToast({ title: '请在 PC 端访问该入口', icon: 'none', duration: 1600 })
|
||||
copyText(abs)
|
||||
}
|
||||
|
||||
const copyConsultTemplate = () => {
|
||||
const tel = config?.tel ? `\n联系电话:${config.tel}` : ''
|
||||
const text =
|
||||
'【需求咨询】\n' +
|
||||
'1) 想开通哪些产品:企业官网 / 电商 / 小程序 / 其他\n' +
|
||||
'2) 是否需要模板/插件市场:是 / 否\n' +
|
||||
'3) 是否需要“支付即开通”:是 / 否\n' +
|
||||
'4) 交付方式:SaaS / 私有化 / 混合\n' +
|
||||
'5) 合规/部署要求:\n' +
|
||||
'6) 期望上线时间:\n' +
|
||||
tel
|
||||
copyText(text)
|
||||
}
|
||||
|
||||
const callPhone = () => {
|
||||
const tel = (config?.tel || '').trim()
|
||||
if (!tel) {
|
||||
Taro.showToast({ title: '暂无联系电话', icon: 'none', duration: 1600 })
|
||||
return
|
||||
}
|
||||
Taro.makePhoneCall({ phoneNumber: tel })
|
||||
}
|
||||
|
||||
const products = useMemo(
|
||||
() => [
|
||||
{
|
||||
title: '企业官网',
|
||||
recommend: true,
|
||||
desc: '品牌展示与获客转化,支持多模板、多语言、SEO 与可视化配置。',
|
||||
tags: ['模板', 'SEO', '多语言', '私有化'],
|
||||
adminUrl: 'https://site.websoft.top',
|
||||
},
|
||||
{
|
||||
title: '小程序/公众号',
|
||||
recommend: false,
|
||||
desc: '多端渠道接入与统一管理,适配常见内容与电商场景。',
|
||||
tags: ['多端', '渠道', '可扩展'],
|
||||
adminUrl: 'https://mp.websoft.top',
|
||||
},
|
||||
{
|
||||
title: '电商系统',
|
||||
recommend: true,
|
||||
desc: '商品/订单/支付/营销基础能力,插件化扩展,支持多端触达。',
|
||||
tags: ['支付', '插件', '营销', '多租户'],
|
||||
adminUrl: 'https://shop.websoft.top',
|
||||
},
|
||||
{
|
||||
title: '管理后台',
|
||||
recommend: false,
|
||||
desc: '多租户管理、角色权限、组织架构与可扩展菜单体系。',
|
||||
tags: ['权限', '多租户', '审计'],
|
||||
adminUrl: 'https://oa.websoft.top',
|
||||
},
|
||||
{
|
||||
title: '开发者中心',
|
||||
recommend: false,
|
||||
desc: '应用开发与交付入口:应用中心、源码仓库、Git 账号绑定、权限申请与教程文档。',
|
||||
tags: ['应用', '源码', 'Git', '教程'],
|
||||
adminUrl: '/developer',
|
||||
},
|
||||
{
|
||||
title: '模板/插件市场',
|
||||
recommend: false,
|
||||
desc: '支持模板与插件购买、授权与更新,形成生态与增值体系。',
|
||||
tags: ['市场', '授权', '更新', '变现'],
|
||||
adminUrl: '/market',
|
||||
},
|
||||
],
|
||||
[]
|
||||
)
|
||||
|
||||
const capabilities = useMemo(
|
||||
() => [
|
||||
{
|
||||
title: 'SaaS 多租户平台',
|
||||
badge: '核心',
|
||||
desc: '租户隔离、组织与权限体系、配置中心与审计能力,为多业务线统一底座。',
|
||||
},
|
||||
{
|
||||
title: '私有化部署',
|
||||
badge: '可选',
|
||||
desc: '支持本地/专有云部署,提供部署文档、验收清单与升级策略,满足安全合规。',
|
||||
},
|
||||
{
|
||||
title: '模板市场',
|
||||
badge: '生态',
|
||||
desc: '行业模板一键套用,默认配置与初始化脚本配套,交付更标准、上线更快。',
|
||||
},
|
||||
{
|
||||
title: '插件市场',
|
||||
badge: '扩展',
|
||||
desc: '支付、会员、营销、工单等能力按需加购;支持授权、更新与版本管理。',
|
||||
},
|
||||
{
|
||||
title: '自动开通链路',
|
||||
badge: '交付',
|
||||
desc: '选品支付后自动创建租户、初始化模块/菜单/基础数据,并交付访问入口。',
|
||||
},
|
||||
{
|
||||
title: '模块化与可扩展',
|
||||
badge: '开发',
|
||||
desc: '支持按模块组合产品能力,插件化扩展点让二开与生态合作更高效。',
|
||||
},
|
||||
],
|
||||
[]
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
<View className="home-page">
|
||||
{/* 首屏:价值主张 + 关键动作 */}
|
||||
<View className="hero">
|
||||
<View className="hero__bgGlow" />
|
||||
<View className="hero__inner">
|
||||
<View className="hero__tag">
|
||||
<Text className="hero__tagText">v3.0 版本发布</Text>
|
||||
</View>
|
||||
|
||||
<View className="hero__title">
|
||||
<Text className="hero__titleText">SaaS + 私有化 + 模板/插件生态</Text>
|
||||
</View>
|
||||
|
||||
<View className="hero__desc">
|
||||
<Text className="hero__descText">
|
||||
面向企业官网、公众号/小程序、电商系统、企业管理后台等业务场景,提供多租户架构与模块化能力;客户下单后自动创建租户、初始化模块与基础数据,实现“支付即开通”。
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View className="hero__actions">
|
||||
<Button
|
||||
type="primary"
|
||||
block
|
||||
className="hero__btn hero__btn--primary"
|
||||
onClick={() => scrollToSection('contact')}
|
||||
>
|
||||
预约演示
|
||||
</Button>
|
||||
<View className="hero__btnRow">
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 快捷导航:减少滚动成本 */}
|
||||
<View className="quickNav">
|
||||
{[
|
||||
{ key: 'products', title: '产品矩阵' },
|
||||
{ key: 'capabilities', title: '核心能力' },
|
||||
{ key: 'flow', title: '开通流程' },
|
||||
{ key: 'ecosystem', title: '生态' },
|
||||
].map((x) => (
|
||||
<View key={x.key} className="quickNav__item" onClick={() => scrollToSection(x.key)}>
|
||||
<Text className="quickNav__text">{x.title}</Text>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
|
||||
{/* 产品矩阵 */}
|
||||
<View className="section" id="products">
|
||||
<View className="section__head">
|
||||
<Text className="section__title">产品矩阵</Text>
|
||||
<Text className="section__desc">
|
||||
面向不同业务场景的可售卖产品,支持套餐化售卖、支付即开通、模板/插件加购与私有化交付。
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View className="productGrid">
|
||||
{products.map((p) => (
|
||||
<View key={p.title} className="card productCard">
|
||||
<View className="productCard__top">
|
||||
<Text className="productCard__title">{p.title}</Text>
|
||||
{p.recommend ? (
|
||||
<View className="badge badge--green">
|
||||
<Text className="badge__text">推荐</Text>
|
||||
</View>
|
||||
) : null}
|
||||
</View>
|
||||
<Text className="productCard__desc">{p.desc}</Text>
|
||||
<View className="tagRow">
|
||||
{p.tags.map((t) => (
|
||||
<View key={t} className="tag">
|
||||
<Text className="tag__text">{t}</Text>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
<View className="productCard__actions">
|
||||
<Button size="small" type="primary" onClick={() => openMaybeLink(p.adminUrl)}>
|
||||
立即开通
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
|
||||
<View className="section__foot">
|
||||
<Button type="default" block onClick={() => scrollToSection('ecosystem')}>
|
||||
了解模板/插件生态
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 核心能力 */}
|
||||
<View className="section section--alt" id="capabilities">
|
||||
<View className="section__head">
|
||||
<Text className="section__title">核心能力</Text>
|
||||
<Text className="section__desc">用一套平台能力,覆盖产品售卖、交付开通、运营升级与生态变现。</Text>
|
||||
</View>
|
||||
|
||||
<View className="capGrid">
|
||||
{capabilities.map((c) => (
|
||||
<View key={c.title} className="card capCard">
|
||||
<View className="capCard__top">
|
||||
<Text className="capCard__title">{c.title}</Text>
|
||||
<View className="badge badge--soft">
|
||||
<Text className="badge__text">{c.badge}</Text>
|
||||
</View>
|
||||
</View>
|
||||
<Text className="capCard__desc">{c.desc}</Text>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 支付即开通 */}
|
||||
<View className="section" id="flow">
|
||||
<View className="section__head">
|
||||
<Text className="section__title">支付即开通</Text>
|
||||
<Text className="section__desc">
|
||||
客户选择产品并支付后,平台自动完成:创建租户、初始化模块、写入默认配置与基础数据、生成管理员账号并交付访问入口。
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View className="card flowCard">
|
||||
{[
|
||||
{ title: '选择产品/套餐', desc: '支持产品矩阵、模板/插件加购、增值项' },
|
||||
{ title: '下单支付', desc: '支付成功触发开通任务编排' },
|
||||
{ title: '创建租户', desc: '租户隔离、域名/应用信息绑定、管理员生成' },
|
||||
{ title: '模块初始化', desc: '按所购产品加载模块与菜单权限,写入基础数据/示例数据' },
|
||||
{ title: '交付上线', desc: 'SaaS 直接可用;私有化交付镜像/部署文档/验收清单' },
|
||||
].map((s, idx) => (
|
||||
<View key={s.title} className="flowStep">
|
||||
<View className="flowStep__dot">
|
||||
<Text className="flowStep__dotText">{idx + 1}</Text>
|
||||
</View>
|
||||
<View className="flowStep__body">
|
||||
<Text className="flowStep__title">{s.title}</Text>
|
||||
<Text className="flowStep__desc">{s.desc}</Text>
|
||||
</View>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
|
||||
<View className="section__foot">
|
||||
<Button type="primary" block onClick={() => scrollToSection('products')}>
|
||||
选择产品并开始规划
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 模板与插件生态 */}
|
||||
<View className="section section--alt" id="ecosystem">
|
||||
<View className="section__head">
|
||||
<Text className="section__title">模板与插件生态</Text>
|
||||
<Text className="section__desc">通过模板加速交付,通过插件扩展能力;支持购买、授权、更新与版本管理。</Text>
|
||||
</View>
|
||||
|
||||
<View className="segTabs">
|
||||
<View
|
||||
className={`segTabs__item ${ecoTab === 'template' ? 'segTabs__item--active' : ''}`}
|
||||
onClick={() => setEcoTab('template')}
|
||||
>
|
||||
<Text className="segTabs__text">模板</Text>
|
||||
</View>
|
||||
<View
|
||||
className={`segTabs__item ${ecoTab === 'plugin' ? 'segTabs__item--active' : ''}`}
|
||||
onClick={() => setEcoTab('plugin')}
|
||||
>
|
||||
<Text className="segTabs__text">插件</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{ecoTab === 'template' ? (
|
||||
<View className="twoCard">
|
||||
<View className="card">
|
||||
<Text className="card__title">行业模板</Text>
|
||||
<Text className="card__desc">按行业/场景提供成套页面与配置,支持一键套用、二次编辑与多版本管理。</Text>
|
||||
</View>
|
||||
<View className="card">
|
||||
<Text className="card__title">交付标准化</Text>
|
||||
<Text className="card__desc">模板与初始化脚本配套,让“开通后的默认站点”可直接验收。</Text>
|
||||
</View>
|
||||
</View>
|
||||
) : (
|
||||
<View className="twoCard">
|
||||
<View className="card">
|
||||
<Text className="card__title">能力扩展</Text>
|
||||
<Text className="card__desc">支付、会员、营销、工单、数据统计等能力按需加购,随买随用。</Text>
|
||||
</View>
|
||||
<View className="card">
|
||||
<Text className="card__title">升级与授权</Text>
|
||||
<Text className="card__desc">支持版本升级、授权校验、到期续费与灰度发布。</Text>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
|
||||
<View className="section__foot">
|
||||
<Button
|
||||
type="default"
|
||||
block
|
||||
onClick={() => {
|
||||
Taro.showToast({ title: '该入口可对接到模板/插件市场', icon: 'none', duration: 1600 })
|
||||
openMaybeLink('/market')
|
||||
}}
|
||||
>
|
||||
了解模板/插件市场
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 底部 CTA */}
|
||||
<View className="section" id="contact">
|
||||
<View className="section__head">
|
||||
<Text className="section__title">联系我们</Text>
|
||||
<Text className="section__desc">
|
||||
复制咨询模板或直接电话沟通,我们会按你的业务场景给出产品组合、开通链路与部署方案(SaaS/私有化)。
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View className="card">
|
||||
<Text className="card__title">咨询内容建议</Text>
|
||||
<View className="list">
|
||||
{[
|
||||
'你希望售卖哪些产品(官网/电商/小程序/门户等)?',
|
||||
'是否需要模板/插件市场(购买、授权、更新)?',
|
||||
'是否需要“支付即开通”(自动创建租户/初始化模块与数据)?',
|
||||
'交付方式:SaaS 或私有化部署?是否有合规要求?',
|
||||
].map((t) => (
|
||||
<View key={t} className="list__item">
|
||||
<View className="list__dot" />
|
||||
<Text className="list__text">{t}</Text>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
|
||||
<View className="contactMeta">
|
||||
{config?.tel ? (
|
||||
<View className="contactMeta__row">
|
||||
<Text className="contactMeta__label">电话</Text>
|
||||
<Text className="contactMeta__value">{config.tel}</Text>
|
||||
</View>
|
||||
) : null}
|
||||
{config?.workDay ? (
|
||||
<View className="contactMeta__row">
|
||||
<Text className="contactMeta__label">工作日</Text>
|
||||
<Text className="contactMeta__value">{config.workDay}</Text>
|
||||
</View>
|
||||
) : null}
|
||||
</View>
|
||||
|
||||
<View className="contactActions">
|
||||
<Button type="default" block onClick={copyConsultTemplate}>
|
||||
复制咨询模板
|
||||
</Button>
|
||||
<Button type="primary" block onClick={callPhone}>
|
||||
电话咨询
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View className="bottomCta">
|
||||
<View className="bottomCta__text">
|
||||
<Text className="bottomCta__title">想快速搭建并交付一个可运营的产品?</Text>
|
||||
<Text className="bottomCta__desc">预约演示,我们将按你的业务场景给出方案与报价。</Text>
|
||||
</View>
|
||||
<View className="bottomCta__actions">
|
||||
<Button type="default" block className={'bottom__view'} onClick={() => scrollToSection('products')}>
|
||||
看产品矩阵
|
||||
</Button>
|
||||
<Button type="primary" block onClick={() => scrollToSection('contact')}>
|
||||
马上联系
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Home
|
||||
Reference in New Issue
Block a user