2025-12-04 16:26:16 +08:00

674 lines
19 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="product-service-page">
<!-- 产品分类导航 -->
<div class="category-nav">
<div v-for="category in panelData"
:key="category.firTitle"
class="nav-item"
:class="{ active: activeCategory === category.firTitle }"
@click="switchCategory(category)">
{{ category.firTitle }}
</div>
</div>
<!-- 产品内容区域 -->
<div class="product-content">
<!-- 左侧菜单区域只有有二级或三级菜单时才显示 -->
<div v-if="hasMenuSidebar" class="menu-sidebar">
<!-- 二级菜单 -->
<div v-if="hasSecondLevel" class="subcategory-section">
<div class="subcategory-list">
<div v-for="subItem in currentSubcategories"
:key="getSubItemKey(subItem)"
class="subcategory-item"
:class="{ active: activeSubId === getSubItemKey(subItem) }"
@click="switchSubcategory(subItem)">
<span class="subcategory-name">{{ subItem.secTitle }}</span>
<span v-if="getProductCount(subItem)" class="product-count">
{{ getProductCount(subItem) }}
</span>
</div>
</div>
</div>
<!-- 三级菜单如果有且不是算/网分类 -->
<div v-if="hasThirdLevel && !isSpecialCategory" class="third-level-section">
<div class="third-level-list">
<div v-for="thirdItem in thirdLevelData"
:key="getThirdItemKey(thirdItem)"
class="third-level-item"
:class="{ active: activeThirdId === getThirdItemKey(thirdItem) }"
@click="switchThirdLevel(thirdItem)">
{{ thirdItem.thrTitle }}
</div>
</div>
</div>
</div>
<!-- 主内容区 -->
<div class="main-content" :class="{ 'full-width': !hasMenuSidebar }">
<!-- 产品网格 -->
<div class="product-grid">
<div v-for="product in currentProducts"
:key="product.id"
class="product-card"
@click="handleProductClick(product)">
<div class="product-header">
<h3 class="product-name">{{ product.name }}</h3>
<span v-if="product.discount" class="discount-badge">
{{ product.discount }}
</span>
</div>
<div class="product-desc">
{{ getProductDescription(product) }}
</div>
<div class="product-footer">
<span class="product-type">{{ product.type }}</span>
<button class="detail-btn">查看详情</button>
</div>
</div>
</div>
<!-- 空状态 -->
<div v-if="!hasProducts" class="empty-state">
<div class="empty-icon">📦</div>
<p class="empty-text">暂无产品数据</p>
</div>
</div>
</div>
</div>
</template>
<script>
import { reqNavList, reqNewHomeSync, reqNewHomeFestival } from "@/api/newHome";
export default {
name: "ProductServicePage",
data() {
return {
panelData: [],
activeCategory: '',
activeSubId: null,
activeThirdId: null,
currentProducts: []
};
},
computed: {
currentSubcategories() {
if (!this.activeCategory || !this.panelData.length) return [];
const category = this.panelData.find(item => item.firTitle === this.activeCategory);
return category ? category.secMenu : [];
},
hasSecondLevel() {
return this.currentSubcategories && this.currentSubcategories.length > 0;
},
hasThirdLevel() {
return this.thirdLevelData && this.thirdLevelData.length > 0;
},
hasProducts() {
return this.currentProducts && this.currentProducts.length > 0;
},
hasMenuSidebar() {
return this.hasSecondLevel || this.hasThirdLevel;
},
isSpecialCategory() {
return this.activeCategory === '算' || this.activeCategory === '网';
},
thirdLevelData() {
if (!this.activeSubId || !this.currentSubcategories.length) return [];
// 从activeSubId中提取真实的subItem id
const realSubId = this.activeSubId.split('_')[0];
const subItem = this.currentSubcategories.find(item =>
item.id === realSubId || item.id?.toString() === realSubId
);
return subItem && subItem.thrMenu ? subItem.thrMenu : [];
},
// 检查是否登录
loginState() {
const userId = sessionStorage.getItem('userId');
return userId !== null && userId !== 'null' && userId !== '';
}
},
async mounted() {
await this.loadNavData();
this.initializeDefaultData();
},
methods: {
// 生成唯一的二级菜单项key
getSubItemKey(subItem) {
return `${subItem.id}_${this.activeCategory}_${subItem.secTitle}`;
},
// 生成唯一的三级菜单项key
getThirdItemKey(thirdItem) {
return `${thirdItem.id}_${this.activeSubId}_${thirdItem.thrTitle}`;
},
// 加载导航数据
async loadNavData() {
try {
const response = await reqNavList({ url_link: window.location.href });
if (response.status && response.data.product_service) {
this.panelData = this.processNavData(response.data.product_service);
}
} catch (error) {
console.error("加载产品数据失败:", error);
this.panelData = [];
}
},
// 处理导航数据 - 修复数据结构
processNavData(data) {
return data.map((category, categoryIndex) => {
// 确保一级分类有唯一标识
if (!category.uniqueId) {
category.uniqueId = `category_${categoryIndex}_${category.firTitle}`;
}
if (category.secMenu) {
category.secMenu.forEach((secItem, secIndex) => {
// 确保二级菜单项有唯一标识
if (!secItem.id) {
secItem.id = `sec_${categoryIndex}_${secIndex}`;
}
if (secItem.thrMenu) {
secItem.thrMenu.forEach((thrItem, thrIndex) => {
// 确保三级菜单项有唯一标识
if (!thrItem.id) {
thrItem.id = `thr_${categoryIndex}_${secIndex}_${thrIndex}`;
}
if (thrItem.value) {
thrItem.value.forEach(product => {
product.type = secItem.secTitle;
// 确保产品有唯一ID
if (!product.id) {
product.id = `product_${categoryIndex}_${secIndex}_${thrIndex}_${Math.random().toString(36).substr(2, 9)}`;
}
});
}
});
}
});
}
return category;
});
},
// 初始化默认数据
initializeDefaultData() {
if (this.panelData.length > 0) {
const firstCategory = this.panelData[0];
this.activeCategory = firstCategory.firTitle;
this.setDefaultSubcategory(firstCategory);
}
},
// 根据分类设置默认二级菜单
setDefaultSubcategory(category) {
if (category.secMenu && category.secMenu.length > 0) {
let defaultSubItem = category.secMenu[0];
if (category.firTitle === '算') {
const zhishuanItem = category.secMenu.find(item =>
item.secTitle && item.secTitle.includes('智算')
);
if (zhishuanItem) defaultSubItem = zhishuanItem;
} else if (category.firTitle === '网') {
const networkItem = category.secMenu.find(item =>
item.secTitle && item.secTitle.includes('算力网络')
);
if (networkItem) defaultSubItem = networkItem;
}
this.activeSubId = this.getSubItemKey(defaultSubItem);
this.updateProductList(defaultSubItem);
} else {
this.activeSubId = null;
this.activeThirdId = null;
this.currentProducts = this.getAllProductsFromCategory(category);
}
},
// 获取分类下的所有产品
getAllProductsFromCategory(category) {
let allProducts = [];
if (category.secMenu) {
category.secMenu.forEach(secItem => {
if (secItem.thrMenu) {
secItem.thrMenu.forEach(thrItem => {
if (thrItem.value) {
allProducts = allProducts.concat(thrItem.value);
}
});
}
});
}
return allProducts;
},
// 切换分类
switchCategory(category) {
this.activeCategory = category.firTitle;
this.activeSubId = null;
this.activeThirdId = null;
this.setDefaultSubcategory(category);
},
// 切换二级分类
switchSubcategory(subItem) {
this.activeSubId = this.getSubItemKey(subItem);
this.activeThirdId = null;
this.updateProductList(subItem);
},
// 切换三级分类
switchThirdLevel(thirdItem) {
this.activeThirdId = this.getThirdItemKey(thirdItem);
this.currentProducts = thirdItem.value || [];
},
// 更新产品列表
updateProductList(subItem) {
if (this.isSpecialCategory) {
this.currentProducts = this.getAllProductsFromSubcategory(subItem);
return;
}
if (subItem.thrMenu && subItem.thrMenu.length > 0) {
this.activeThirdId = null;
this.currentProducts = this.getAllProductsFromSubcategory(subItem);
} else {
this.activeThirdId = null;
this.currentProducts = [];
}
},
// 获取二级分类下的所有产品
getAllProductsFromSubcategory(subItem) {
let allProducts = [];
if (subItem.thrMenu) {
subItem.thrMenu.forEach(thrItem => {
if (thrItem.value) {
allProducts = allProducts.concat(thrItem.value);
}
});
}
return allProducts;
},
// 获取产品数量
getProductCount(subItem) {
if (!subItem.thrMenu) return 0;
return subItem.thrMenu.reduce((total, thirdItem) => {
return total + (thirdItem.value ? thirdItem.value.length : 0);
}, 0);
},
// 获取产品描述
getProductDescription(product) {
const descriptions = {
'云服务器_GPU': '高性能GPU云服务器适合AI训练、科学计算等场景',
'云服务器_BCC': '平衡型云服务器,满足大多数业务需求',
'专属服务器': '独享物理服务器,提供更高性能和安全隔离',
'轻量应用服务器': '轻量级应用部署,简单易用',
'专线接入': '高速稳定的专线网络接入服务',
'文字识别': '高精度文字识别,支持多种场景和语言',
'AI能力引擎': '强大的AI能力引擎赋能各种智能应用',
'大数据平台': '全面的大数据处理和分析平台',
'云服务平台': '一站式云服务平台,便捷高效',
'智能内容科技': '智能内容生成与处理技术',
'SME企业服务': '中小企业专属服务解决方案',
'视频云平台': '专业的视频云处理与分发平台',
'智能短信': '智能化短信服务和营销解决方案'
};
return descriptions[product.name] || '专业的云服务产品,提供稳定可靠的服务';
},
// 修复阿里云跳转逻辑
async handleAliyunProductClick() {
try {
// 第一步:同步请求
const syncResponse = await reqNewHomeSync();
if (!syncResponse.status) {
this.$message.warning(syncResponse.msg || '同步失败,请稍后重试');
return;
}
// 第二步:获取跳转链接
const festivalResponse = await reqNewHomeFestival();
if (festivalResponse.status && festivalResponse.data) {
window.open(festivalResponse.data);
} else {
this.$message.warning(festivalResponse.msg || '获取跳转链接失败');
}
} catch (error) {
console.error('阿里云跳转失败:', error);
this.$message.error('网络错误,请稍后重试');
}
},
// 点击产品
async handleProductClick(product) {
console.log('点击产品:', product);
const userId = sessionStorage.getItem('userId');
if (product.type === '百度云') {
if (userId) {
localStorage.setItem('redirectUrl', product.url);
localStorage.setItem('userRescourseUrl', product.listUrl);
this.$router.push({
name: 'baiduProductShow',
params: {
listUrl: product.listUrl,
url: product.url
}
});
} else {
this.$router.push({
path: "/login",
query: {
fromPath: 'productService',
type: 'bd',
listUrl: product.listUrl,
url: product.url
}
});
}
} else if (product.type === '阿里云') {
if (userId) {
await this.handleAliyunProductClick();
} else {
this.$router.push({
path: "/login",
query: {
fromPath: 'productService',
type: 'ali',
}
});
}
} else if (product.type === '智算' || product.type === '算力网络') {
if (product.name === '容器云') {
if (userId) {
this.$router.push('/product/productHome/k8s/createK8s');
} else {
this.$router.push({
path: "/login",
query: {
fromPath: 'productService',
type: 'rqy',
}
});
}
} else {
this.$router.push({
path: '/homePage/detail',
query: {
id: product.id,
}
});
}
} else if (product.name === '灵医智能体') {
this.$router.push('/homePage/hospital');
} else if (product.name === '客悦·智能客服') {
this.$router.push('/homePage/customerService');
}
}
}
};
</script>
<style lang="less" scoped>
.product-service-page {
margin: 0 auto;
padding: 24px;
background: #fff;
min-height: calc(100vh - 100px);
.category-nav {
display: flex;
justify-content: space-around;
margin-bottom: 32px;
border-bottom: 1px solid #f0f0f0;
.nav-item {
padding: 12px 24px;
font-size: 16px;
color: #666;
cursor: pointer;
border-bottom: 2px solid transparent;
transition: all 0.3s;
&:hover {
color: #1E6FFF;
}
&.active {
color: #1E6FFF;
border-bottom-color: #1E6FFF;
font-weight: 600;
}
}
}
.product-content {
display: flex;
gap: 24px;
.menu-sidebar {
width: 280px;
background: #f8f9fa;
border-radius: 8px;
padding: 20px;
flex-shrink: 0;
.section-title {
font-size: 16px;
font-weight: 600;
color: #1a1a1a;
margin-bottom: 16px;
padding-bottom: 8px;
border-bottom: 1px solid #e8e8e8;
}
.subcategory-section {
margin-bottom: 24px;
}
.subcategory-list,
.third-level-list {
.subcategory-item,
.third-level-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 12px;
cursor: pointer;
transition: all 0.3s;
border-radius: 6px;
margin-bottom: 4px;
&:hover {
background: rgba(30, 111, 255, 0.05);
color: #1E6FFF;
}
&.active {
background: rgba(30, 111, 255, 0.1);
color: #1E6FFF;
font-weight: 600;
}
.subcategory-name {
font-size: 14px;
}
.product-count {
background: #e8f4ff;
color: #1E6FFF;
font-size: 12px;
padding: 2px 8px;
border-radius: 10px;
min-width: 20px;
text-align: center;
}
}
}
.third-level-list {
.third-level-item {
padding-left: 20px;
font-size: 13px;
}
}
}
.main-content {
flex: 1;
&.full-width {
flex: 1;
margin-left: 0;
}
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
.product-card {
background: #fff;
border: 1px solid #f0f0f0;
border-radius: 8px;
padding: 20px;
cursor: pointer;
transition: all 0.3s;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
&:hover {
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
border-color: #1E6FFF;
}
.product-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 12px;
.product-name {
font-size: 16px;
font-weight: 600;
color: #1a1a1a;
margin: 0;
flex: 1;
}
.discount-badge {
background: linear-gradient(135deg, #ff6b6b, #ff4757);
color: #fff;
font-size: 12px;
padding: 4px 8px;
border-radius: 4px;
font-weight: 600;
margin-left: 8px;
}
}
.product-desc {
font-size: 14px;
color: #666;
line-height: 1.5;
margin-bottom: 16px;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.product-footer {
display: flex;
justify-content: space-between;
align-items: center;
.product-type {
font-size: 12px;
color: #999;
background: #f8f9fa;
padding: 4px 8px;
border-radius: 4px;
}
.detail-btn {
background: #1E6FFF;
color: #fff;
border: none;
padding: 6px 12px;
border-radius: 4px;
font-size: 12px;
cursor: pointer;
transition: background 0.3s;
&:hover {
background: #0d5ae0;
}
}
}
}
}
.empty-state {
text-align: center;
padding: 60px 20px;
.empty-icon {
font-size: 48px;
margin-bottom: 16px;
}
.empty-text {
color: #999;
font-size: 14px;
}
}
}
}
}
@media (max-width: 768px) {
.product-service-page {
padding: 16px;
.product-content {
flex-direction: column;
.menu-sidebar {
width: 100%;
order: 2;
}
.main-content {
order: 1;
&.full-width {
margin-left: 0;
}
}
}
.product-grid {
grid-template-columns: 1fr !important;
}
}
}
</style>