做统一认证登录

This commit is contained in:
2026-09-19 21:44:04 +08:00
parent 1a4471e34d
commit fa281363fb
78 changed files with 8127 additions and 1442 deletions
+23 -7
View File
@@ -15,6 +15,7 @@
import { ref } from "vue";
import { getJSON } from "@/api/request";
import { navItems } from "./site";
import { sections } from "./sections";
export interface NavMenuItem {
/** v-for key:后端菜单用 nav-{id},静态回退用 static-{path} */
@@ -53,13 +54,28 @@ function toMenuItem(node: RemoteNavNode): NavMenuItem {
/** 静态回退菜单:后台未配置时使用 */
const fallbackMenus = (): NavMenuItem[] =>
navItems.map((item) => ({
key: `static-${item.path}`,
label: item.label,
path: item.path,
external: isExternalPath(item.path),
children: [],
}));
navItems.map((item) => {
const menuItem: NavMenuItem = {
key: `static-${item.path}`,
label: item.label,
path: item.path,
external: isExternalPath(item.path),
children: [],
};
// 新闻中心:默认把「新闻中心」下的分类作为二级菜单(鼠标悬停展开)
if (item.path === "/news") {
menuItem.children = sections.news.categories.map((cat) => ({
key: `static-news-${cat.slug}`,
label: cat.name,
path: `/news/category/${cat.slug}`,
external: false,
children: [],
}));
}
return menuItem;
});
/** 页头导航菜单(应用启动时由 loadNavMenus 拉取,初始为静态回退) */
export const navMenus = ref<NavMenuItem[]>(fallbackMenus());
+29 -26
View File
@@ -4,9 +4,6 @@ import { siteInfo } from "@/config/site"; // 站点设置(站点名称 {yz:sit
const DefaultLayout = () => import("../layout/DefaultLayout.vue");
const HomeView = () => import("../views/home/index.vue");
const ListView = () => import("../views/list.vue");
const DetailView = () => import("../views/detail.vue");
const SingleView = () => import("../views/single.vue");
const NotFoundView = () => import("../views/not-found.vue");
/**
@@ -33,19 +30,19 @@ const routes: RouteRecordRaw[] = [
{
path: "news",
name: "News",
component: ListView,
component: () => import("../views/news/index.vue"),
meta: { title: "新闻中心" },
},
{
path: "news/category/:slug",
name: "NewsCategory",
component: ListView,
component: () => import("../views/news/index.vue"),
meta: { title: "新闻中心" },
},
{
path: "news/detail/:slug",
name: "NewsDetail",
component: DetailView,
component: () => import("../views/news/detail.vue"),
meta: { title: "新闻详情" },
},
@@ -53,19 +50,19 @@ const routes: RouteRecordRaw[] = [
{
path: "products",
name: "Products",
component: ListView,
component: () => import("../views/products/index.vue"),
meta: { title: "产品中心" },
},
{
path: "products/category/:slug",
name: "ProductCategory",
component: ListView,
component: () => import("../views/products/index.vue"),
meta: { title: "产品中心" },
},
{
path: "products/detail/:slug",
name: "ProductDetail",
component: DetailView,
component: () => import("../views/products/detail.vue"),
meta: { title: "产品详情" },
},
@@ -73,19 +70,19 @@ const routes: RouteRecordRaw[] = [
{
path: "solutions",
name: "Solutions",
component: ListView,
component: () => import("../views/solutions/index.vue"),
meta: { title: "解决方案" },
},
{
path: "solutions/category/:slug",
name: "SolutionCategory",
component: ListView,
component: () => import("../views/solutions/index.vue"),
meta: { title: "解决方案" },
},
{
path: "solutions/detail/:slug",
name: "SolutionDetail",
component: DetailView,
component: () => import("../views/solutions/detail.vue"),
meta: { title: "方案详情" },
},
@@ -93,19 +90,19 @@ const routes: RouteRecordRaw[] = [
{
path: "cases",
name: "Cases",
component: ListView,
component: () => import("../views/cases/index.vue"),
meta: { title: "客户案例" },
},
{
path: "cases/category/:slug",
name: "CaseCategory",
component: ListView,
component: () => import("../views/cases/index.vue"),
meta: { title: "客户案例" },
},
{
path: "cases/detail/:slug",
name: "CaseDetail",
component: DetailView,
component: () => import("../views/cases/detail.vue"),
meta: { title: "案例详情" },
},
@@ -113,19 +110,19 @@ const routes: RouteRecordRaw[] = [
{
path: "events",
name: "Events",
component: ListView,
component: () => import("../views/events/index.vue"),
meta: { title: "市场活动" },
},
{
path: "events/category/:slug",
name: "EventCategory",
component: ListView,
component: () => import("../views/events/index.vue"),
meta: { title: "市场活动" },
},
{
path: "events/detail/:slug",
name: "EventDetail",
component: DetailView,
component: () => import("../views/events/detail.vue"),
meta: { title: "活动详情" },
},
@@ -133,43 +130,49 @@ const routes: RouteRecordRaw[] = [
{
path: "about",
name: "About",
component: SingleView,
component: () => import("../views/about.vue"),
meta: { title: "关于云泽" },
},
{
path: "careers",
name: "Careers",
component: SingleView,
component: () => import("../views/careers.vue"),
meta: { title: "加入我们" },
},
{
path: "partners",
name: "Partners",
component: SingleView,
component: () => import("../views/partners.vue"),
meta: { title: "合作伙伴" },
},
{
path: "contact",
name: "Contact",
component: SingleView,
component: () => import("../views/contact.vue"),
meta: { title: "联系我们" },
},
{
path: "support",
name: "Support",
component: SingleView,
component: () => import("../views/support/index.vue"),
meta: { title: "客户支持中心" },
},
{
path: "support/:slug",
name: "SupportDetail",
component: SingleView,
component: () => import("../views/support/detail.vue"),
meta: { title: "客户支持" },
},
{
path: "policy/:slug",
path: "policy",
name: "Policy",
component: SingleView,
component: () => import("../views/policy/index.vue"),
meta: { title: "政策条款" },
},
{
path: "policy/:slug",
name: "PolicyDetail",
component: () => import("../views/policy/detail.vue"),
meta: { title: "政策条款" },
},
+8
View File
@@ -0,0 +1,8 @@
<script setup lang="ts">
import SinglePage from "@/views/common/SinglePage.vue";
defineOptions({ name: "AboutPage" });
</script>
<template>
<SinglePage />
</template>
+8
View File
@@ -0,0 +1,8 @@
<script setup lang="ts">
import SinglePage from "@/views/common/SinglePage.vue";
defineOptions({ name: "CareersPage" });
</script>
<template>
<SinglePage />
</template>
+8
View File
@@ -0,0 +1,8 @@
<script setup lang="ts">
import DetailPage from "@/views/common/DetailPage.vue";
defineOptions({ name: "CasesDetail" });
</script>
<template>
<DetailPage />
</template>
+8
View File
@@ -0,0 +1,8 @@
<script setup lang="ts">
import ListPage from "@/views/common/ListPage.vue";
defineOptions({ name: "CasesList" });
</script>
<template>
<ListPage />
</template>
+8
View File
@@ -0,0 +1,8 @@
<script setup lang="ts">
import SinglePage from "@/views/common/SinglePage.vue";
defineOptions({ name: "ContactPage" });
</script>
<template>
<SinglePage />
</template>
+8
View File
@@ -0,0 +1,8 @@
<script setup lang="ts">
import DetailPage from "@/views/common/DetailPage.vue";
defineOptions({ name: "EventsDetail" });
</script>
<template>
<DetailPage />
</template>
+8
View File
@@ -0,0 +1,8 @@
<script setup lang="ts">
import ListPage from "@/views/common/ListPage.vue";
defineOptions({ name: "EventsList" });
</script>
<template>
<ListPage />
</template>
@@ -24,7 +24,7 @@ import { siteInfo } from "@/config/site";
<div class="banner__meta">
<div class="banner__stat">
<strong>12 年</strong>
<strong>8 年</strong>
<span class="banner__stat-label">行业深耕</span>
<em>服务 1000+ 企业客户</em>
</div>
@@ -33,18 +33,10 @@ import { siteInfo } from "@/config/site";
<div class="banner__stat banner__stat--contact">
<span class="banner__stat-icon" aria-hidden="true">
<svg viewBox="0 0 24 24">
<path
d="M6.6 3.5h2.6l1.5 3.7-1.9 1.3a12.4 12.4 0 0 0 5.7 5.7l1.3-1.9 3.7 1.5v2.6a2 2 0 0 1-2.2 2C10.7 17.7 6.3 13.3 4.6 5.7a2 2 0 0 1 2-2.2Z"
fill="none"
stroke="currentColor"
stroke-width="1.6"
stroke-linejoin="round"
/>
</svg>
<svg t="1789744335345" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1660" width="200" height="200"><path d="M869.485714 627.657143c-18.285714-58.742857-39.314286-108.114286-71.657143-188.914286C802.857143 226.514286 714.628571 54.857143 511.428571 54.857143 305.942857 54.857143 219.657143 229.942857 225.142857 438.742857c-32.457143 80.914286-53.371429 129.942857-71.657143 188.914286-38.857143 125.142857-26.285714 176.914286-16.685714 178.057143 20.571429 2.514286 80.114286-94.171429 80.114286-94.171429 0 56 28.8 129.028571 91.2 181.714286-30.171429 9.257143-97.942857 34.171429-81.828572 61.485714 13.028571 22.057143 224.228571 14.057143 285.142857 7.2 60.914286 6.857143 272.114286 14.857143 285.142858-7.2 16.114286-27.2-51.771429-52.228571-81.828572-61.485714 62.4-52.8 91.2-125.828571 91.2-181.714286 0 0 59.542857 96.685714 80.114286 94.171429 9.714286-1.257143 22.285714-53.028571-16.571429-178.057143z" p-id="1661" fill="#1296db"></path></svg>
</span>
<strong>400-000-0000</strong>
<span class="banner__stat-label">售前咨询专线</span>
<strong>1126170391</strong>
<span class="banner__stat-label">项目总群</span>
<em>工作日 9:00 - 18:00</em>
</div>
</div>
@@ -1,53 +1,57 @@
<script setup lang="ts">
import AppIcon from "@/components/AppIcon.vue";
import { ref, onMounted } from 'vue';
interface ScheduleItem {
range: string;
period: string;
name: string;
desc: string;
interface UpgradeItem {
id: number;
update_date: string;
title: string;
content: string;
create_time: string;
}
const schedules: ScheduleItem[] = [
{
range: "09.10 ~ 09.30",
period: "2026 年 9 月",
name: "数据中台 V3.0 全量开放试用",
desc: "面向全部客户开放试用,体验实时计算与指标管理能力。",
},
{
range: "10.18 ~ 10.19",
period: "2026 年 10 月",
name: "云泽数智大会 · 上海站",
desc: "30 余位行业客户分享落地实践,现场设产品体验区。",
},
{
range: "11.05 ~ 11.28",
period: "2026 年 11 月",
name: "全国合作伙伴城市巡展",
desc: "覆盖 12 座城市,面向合作伙伴开放产品与政策解读。",
},
];
const upgradeList = ref<UpgradeItem[]>([]);
const loading = ref(false);
// 获取平台更新内容列表
const fetchUpgradeList = async () => {
loading.value = true;
try {
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:9000';
const response = await fetch(`${API_BASE_URL}/platform/api/upgrade/list?limit=3`);
const result = await response.json();
if (result.code === 200 && result.data) {
upgradeList.value = result.data;
}
} catch (error) {
console.error('获取更新内容失败:', error);
} finally {
loading.value = false;
}
};
onMounted(() => {
fetchUpgradeList();
});
</script>
<template>
<section class="schedule">
<div class="container schedule__inner">
<!-- 活动时间轴 -->
<!-- 平台更新时间轴 -->
<div class="schedule__panel">
<div class="schedule__head">
<h2>近期活动与发布节奏</h2>
<p>2026 年 · 活动日历</p>
<h2>近期平台更新内容</h2>
<p>Platform Updates</p>
</div>
<ul class="timeline">
<ul v-if="!loading" class="timeline">
<li
v-for="(item, index) in schedules"
:key="item.range"
v-for="item in upgradeList"
:key="item.id"
class="timeline__item"
:class="{ 'is-next': index === 0 }"
:class="{ 'is-next': item.id === upgradeList[0]?.id }"
>
<h3 class="timeline__range">{{ item.range }}</h3>
<h3 class="timeline__date">{{ item.update_date }}</h3>
<!-- 节点轨道:横线由 CSS 绘制,节点天然居中 -->
<span class="timeline__rail" aria-hidden="true">
@@ -55,27 +59,33 @@ const schedules: ScheduleItem[] = [
<i class="timeline__axis"></i>
</span>
<p class="timeline__period">{{ item.period }}</p>
<p class="timeline__name">{{ item.name }}</p>
<p class="timeline__desc">{{ item.desc }}</p>
<p class="timeline__name">{{ item.title }}</p>
<p class="timeline__desc" v-html="item.content"></p>
</li>
<li v-if="upgradeList.length === 0" class="timeline__empty">
暂无更新内容
</li>
</ul>
<div v-else class="timeline__loading">
<el-loading-spinner></el-loading-spinner>
加载中...
</div>
</div>
<!-- 活动入口 -->
<RouterLink to="/events" class="schedule-card">
<!-- 管理入口 -->
<!-- <RouterLink to="/platform/softwareupgrade" class="schedule-card">
<span class="schedule-card__icon">
<AppIcon name="calendar" :size="28" :stroke-width="1.5" />
<AppIcon name="update" :size="28" :stroke-width="1.5" />
</span>
<div class="schedule-card__text">
<strong>市场活动</strong>
<em>参展、发布会与公开课,全年安排一站查看。</em>
<strong>更新管理</strong>
<em>查看和管理平台更新记录</em>
</div>
<span class="schedule-card__more">
查看全部活动
进入管理后台
<AppIcon name="arrow-right" :size="16" />
</span>
</RouterLink>
</RouterLink> -->
</div>
</section>
</template>
@@ -108,7 +118,7 @@ const schedules: ScheduleItem[] = [
&__inner {
position: relative;
display: grid;
grid-template-columns: minmax(0, 1fr) 360px;
/* grid-template-columns: minmax(0, 1fr) 360px; */
gap: 26px;
align-items: stretch;
}
@@ -157,7 +167,7 @@ const schedules: ScheduleItem[] = [
min-width: 0;
}
&__range {
&__date {
font-size: 25px;
font-weight: 700;
line-height: 36px;
@@ -213,6 +223,15 @@ const schedules: ScheduleItem[] = [
color: @ink-400;
}
&__date {
font-size: 25px;
font-weight: 700;
line-height: 36px;
letter-spacing: 0.01em;
color: @ink-900;
white-space: nowrap;
}
&__name {
margin-top: 8px;
font-size: 16px;
@@ -237,6 +256,26 @@ const schedules: ScheduleItem[] = [
&__item:hover &__name {
color: @blue-600;
}
&__empty {
grid-column: 1 / -1;
text-align: center;
padding: 40px;
font-size: 14px;
color: @ink-400;
}
&__loading {
grid-column: 1 / -1;
text-align: center;
padding: 40px;
font-size: 14px;
color: @ink-500;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
}
}
/* ---------------- 活动入口卡 ---------------- */
@@ -350,6 +389,11 @@ const schedules: ScheduleItem[] = [
line-height: 32px;
}
&__date {
font-size: 21px;
line-height: 32px;
}
&__axis {
margin-right: -34px;
}
@@ -427,6 +471,11 @@ const schedules: ScheduleItem[] = [
line-height: 28px;
}
&__date {
font-size: 19px;
line-height: 28px;
}
&__desc {
margin-top: 8px;
font-size: 12.5px;
+8
View File
@@ -0,0 +1,8 @@
<script setup lang="ts">
import DetailPage from "@/views/common/DetailPage.vue";
defineOptions({ name: "NewsDetail" });
</script>
<template>
<DetailPage />
</template>
+8
View File
@@ -0,0 +1,8 @@
<script setup lang="ts">
import ListPage from "@/views/common/ListPage.vue";
defineOptions({ name: "NewsList" });
</script>
<template>
<ListPage />
</template>
+8
View File
@@ -0,0 +1,8 @@
<script setup lang="ts">
import SinglePage from "@/views/common/SinglePage.vue";
defineOptions({ name: "PartnersPage" });
</script>
<template>
<SinglePage />
</template>
+8
View File
@@ -0,0 +1,8 @@
<script setup lang="ts">
import SinglePage from "@/views/common/SinglePage.vue";
defineOptions({ name: "PolicyDetail" });
</script>
<template>
<SinglePage />
</template>
+8
View File
@@ -0,0 +1,8 @@
<script setup lang="ts">
import SinglePage from "@/views/common/SinglePage.vue";
defineOptions({ name: "PolicyList" });
</script>
<template>
<SinglePage />
</template>
+8
View File
@@ -0,0 +1,8 @@
<script setup lang="ts">
import DetailPage from "@/views/common/DetailPage.vue";
defineOptions({ name: "ProductsDetail" });
</script>
<template>
<DetailPage />
</template>
+8
View File
@@ -0,0 +1,8 @@
<script setup lang="ts">
import ListPage from "@/views/common/ListPage.vue";
defineOptions({ name: "ProductsList" });
</script>
<template>
<ListPage />
</template>
+8
View File
@@ -0,0 +1,8 @@
<script setup lang="ts">
import DetailPage from "@/views/common/DetailPage.vue";
defineOptions({ name: "SolutionsDetail" });
</script>
<template>
<DetailPage />
</template>
+8
View File
@@ -0,0 +1,8 @@
<script setup lang="ts">
import ListPage from "@/views/common/ListPage.vue";
defineOptions({ name: "SolutionsList" });
</script>
<template>
<ListPage />
</template>
+8
View File
@@ -0,0 +1,8 @@
<script setup lang="ts">
import SinglePage from "@/views/common/SinglePage.vue";
defineOptions({ name: "SupportDetail" });
</script>
<template>
<SinglePage />
</template>
+8
View File
@@ -0,0 +1,8 @@
<script setup lang="ts">
import SinglePage from "@/views/common/SinglePage.vue";
defineOptions({ name: "SupportList" });
</script>
<template>
<SinglePage />
</template>